Weblog -- Computer Programming

By Paul Quek (e-mail: quekpaul@hotmail.com), in Singapore



Thursday, 24 April 2003


The following is adapted from Macro & Buxton's Craft of Software Engineering ... note that the reference to SDI ( the so-called Strategic Defence Initiative, or "Star Wars", of a non-space cowboy President ) is, of course, obsolete now [ where now = 2003 ] :

The programming of non-trivial applications is, without doubt, an extremely complicated and difficult affair.

The fact that a child can program a PC in something like BASIC does not confute that point -- it confuses it.

The control program in the washing machine that has just flooded the kitchen floor is a few thousand instructions of assembler code, but it took people a year and a half to develop.

The SDI 'Starwars' research will require a software system of anything between 10 million and 100 million source statements of code and must work right (or at least adequately) first time -- unless it is to be tested on a spare planet. Nor will it be done in BASIC, or at least it is to be hoped not.






Tuesday, 11 March 2003 -- C's Data Types

Okay, first off, of course, my old English teacher would throw up his hands at the title of this webpage:  C's Data Types.

That is, he would have said that it is "wrong", or grammatically incorrect, to use an apostrophe in an object like C, because a NON-LIVING OBJECT cannot possibly "possess" anything.

Hey, old English teacher! On all counts, I beg to differ. ( And you didn't have to SHOUT! )

While C may be an object in the normal English sense, C as a language is not object-oriented ( for that, I would have to go to C++, which is essentially "C with classes" ), so I think, for programming purposes, we shouldn't think of C as an object.

And for C being "non-living", I again beg to differ in that I see C as very much alive -- hack, even if the whole world no longer uses C, I always will.

So! Long live C!

Of course, I am not addled -- I don't really think of C as being alive in the narrow carbon-based-lifeform sense of "being alive" that we, at our present stage of technology on this one lone planet, are familiar with ( never mind that some silicon-based lifeforms may exist on Terra ).

Right! So much for a preamble that has nothing much to do with the matter of Data Types in C  ( okay, old English teacher, you win! ).

In a computer program, what essentially happens is that the programmer codes a "model" of the problem situation, or more accurately, the programmer translates various aspects of the problem situation into the programming language of choice, which becomes a "model" of the real problem.

Usually, the data in a program serves as "data models" for those aspects of the problem that we can call "variables" or "data" in the real world. We also use the term "variables" and "data" in the programming world, so that there is almost a one-to-one correspondence between the real world and our programs. This makes it simple to "do programming". It also makes it easier to understand and "update" our programs if there is a one-to-one "mapping" between the real world and the "model" ( our computer programs ): if the real world changes drastically, we "update" our programs drastically.

But we sometimes become too didactic in programming, and so some of us insist on using the term data models ( instead of just "data" ) to refer to the data in our programs. After all, the "data" in our programs MODEL after the data in the real world, right? ( Yes, right, but you didn't have to SHOUT! )

Another possible reason for using the term "data models" ( besides reminding ourselves that the data are just "models" ) is to distinguish them from "operations models", which model the operations that are required to be performed on the data ( because in the real world various kinds of "operations", or "activities", occur which result in changes in the variables or data ).

Actually, there is a third, slightly more technical, reason why we may choose to use the term "data models". And it is this: a ( modern, electronic, digital ) computer basically relies on "computer bits, bytes, and words" in its electronic innards. ( A computer "word" can be 8 bytes long, one byte being 8 bits in length, where a "bit" means a "binary digit", computers being binary devices. In more modern computers, a "word" is usually 16 bytes or 32 bytes or even 64 bytes in length. )

But when we are programming ( or, more accurately, "coding" ), we no longer wish to code in zeros and ones: we don't choose to manipulate our data in bits, bytes and words. No, siree! With a modern programming language, we can use higher-level abstractions known as "data types" ( whether simple or otherwise ) -- of, if you prefer, "data models", simple or otherwise -- since these "data models" are actual models of the bits, bytes and words inside the electronic mazes of our modern, electronic, digitial computers.

Okay, enough of semantics.

In a programming language such as C, a set of simple, or "built-in", or "basic", data types, is provided for the programmer to code the data. Hence, our set of data models can consist simply of these simple / built-in / basic data types.

What are the simple / built-in / basic data types in C? Well, I am glad you ask! The simple data types in C are, for examples:

1. int
2. char
3. double
4. float
But we need not limit ourselves to these simplified data models. Why should we?

In a modern programming language, these simple data types can be "extended" -- that is, combined in various ways to produce new / more complex / complicated data types.

For example, a set of related variables of the built-in data type "int" can be combined into an array of "ints", an array being a more complicated data type. ( As the name implies, an array is a sequence of contiguous data; this meaning makes sense if we mean "linear array", but the "linear" is usually dropped. So, don't go thinking about antenna arrays, such as the Yagi Array! ) We end up with an array of type "int". Of course, we can also built arrays comprising variables of different data types, so that we end up with an array that has elements of "int", "char" and so forth -- the array would then have a "mixed" data type.

Sometimes, we use the term "data structures" to refer to these more complicated data types ( such as arrays ), but this is by no means a "standard" usage of the term. Even in an activity that relies on syntactically-rigid tools like programming languages, we still can use some words in as loose a fashion as we would in ordinary English usage. So the term, "data structures", can be used in many contexts, one of which is "complicated data models or types".

Here are some other examples of complicated data types:

1. lists
2. queues
3. pointers -- extremely common in C, but doesn't exist in most OOPLs*
4. "structs" -- i.e., short for "structures"; very common in C
5. unions -- also very common in C

[ *OOPLs:- object-oriented programming languages ]


Anyway, because of this possibility of extension from the simple to the complex, the ( simple and complicated ) data models in our program becomes a hierarchy of ( simple and complicated ) data models. We would end up with a "data hierarchy". Our set of data models is our data hirerachy.

Actually, we can have a "data hierarchy" even if never create any complicated data type. For example, for a really simple program, our data hierarchy can comprise simply of "ints", or "chars", or "doubles", or "floats", or "ints" and "chars" -- or, of any combination thereof.

Then, also, we can have a data hierarchy where we have both simple and extended data types. Why not? Often, you need the simple data types, if you are modelling the "simpler" aspects of the problem situation.

Once more, to complicate the issue, some people in the computer programming world choose to distinguish at least two types of the new data types that can be constructed from the basic data types:

1. extended simple types -- which are made using enumerations ( lists; queues)
2. structured types -- via replication ( "arrays" ); as aggregates ( "structs" and "unions" ); using "pointers"
Oh, well, such is life! ( in the programming world )



Construction Methods

Since we are not talking about C++, or of any object-oriented programming languages ( OOPLs ), we are using the word "methods" here in the normal, everyday English sense, and not to mean "functions" or "procedures" or "routines" that are the "operations" part of an "object". Think of "methods" here as "ways of doing something".

As indicated above, there are several ways to make new data types ( i.e., there are several methods of constructing complicated data types ):

1. enumeration ( example: lists )
2. replication ( note: arrays )
3. aggregation ( note: structures )
4. referencing ( note: pointers )






Monday, 31 March 2003 -- Turbo BASIC Programming: Visualising the Trigonometric Functions

One of the greatest thrills with those adult toys called "computers" is the ability that the machines give us to visualise things that may sometimes be a little abstract.

And too many, including moi, maths can be a little too abstract. In maths, lots and lots of pictures would definitely be helpful.

For trigonometric functions (such as sine, cosine and tangent), we can draw pictures of these functions -- otherwise known as "graphs" of such functions -- on paper, but it gets a little tedious to do it in this way. The computer comes to our rescue, but we need to do a little programming, if we don't intend to use some expensive and sophisticated software to do the visualisation.

For such simple programming tasks, it may be a little of an overkill to use languages such as C or C++, although we can do so for the sake of exercising our minds ....

For a quick-and-dirty programming solution, one cannot beat using the teaching language known as BASIC, or Basic All-purpose Symbolic Instruction Code.

In fact, one of my fond memories of early programming languages was that incarnation of BASIC for the PC -- I am referring, of course, to Turbo BASIC, from that excellent company Borland, International, which also gave PC users other programming gems like Turbo C, Turbo C++, Turbo C++ for Windows and other later versions of C++, as well as Turbo Pascal and other later versions, not to mention Turbo Prolog.

But it was Turbo BASIC that first caught the attention of those of us during the early days of the PC, when we were struggling to learn programming using the BASIC language (and assembly and FORTRAN), and on either some now-obsolete mini-computers or even mainframes as well as on our own microcomputers, a.k.a. PCs. Ah! Those were, indeed, the days!

Turbo BASIC was, first and foremost, a compiled BASIC -- it wasn't just your average interpreted BASIC. Secondly, Borland really put in the effort to use the graphics capability of the PC, which at the time, was all about using CGA, EGA and VGA. It was this graphics capability that allows us to whip up neat little programs in order to have a bit of visualisation fun.

Borland, of course, has discontinued Turbo BASIC, which has become Power Basic under another company ....

Anyway, I manage to get hold of an old copy of Turbo BASIC and found, to my delight, that I can still get the compiler to work in a DOS box -- i.e., DOS prompt in Windows 98, or Command Prompt in Windows XP ....


Okay, here are the simple visualisation programs for the trigonometric functions (for the moment, only the SINE graph program is available):


      Sine Graph: Click here to go to the visualisation of the SINE function ....







Thursday, 27 February 2003 -- A C Program from K&R: Fahrenheit-Celsius Conversion

In the Preface to the Second Edition, K&R mentioned about the "growing popularity of C" as well as re-iterate what was said in the Preface to the First Edition about the fact that "C wears well as one's experience with it grows."

Both claims are completely true, except that nowadays most programmers probably prefer to write in C++ rather than in mere C.

However, I am probably convinced to some extent, that C++ also "wears well as one's experience with it grows."

Hope this doesn't rile either K or R too much! But, let's face it: much as I like C, one simply cannot ignore C++, right?

Okay, back to C ...

Let's see ... the second program -- after the hello, world program -- that K&R used for illustration was the Fahrenheit-Celsius conversion program, using the formula C = (5/9)(F-32).

Here's the original C program:



/* print Fahrenheit-Celsius table
     for f = 0, 20, ..., 300 */
main()
{
     int lower, upper, step;
     float fahr, celsius;

     lower = 0;     /* lower limit of temperature table */
     upper = 300;   /* upper limit */
     step = 20;     /* step size */

     fahr = lower;
     while (fahr <= upper)   {
          celsius = (5.0/9.0) * (fahr-32.0);
          printf("%4.0f %6.1f\n", fahr, celsius);
          fahr = fahr + step;
     }
}


Okay, as it stands, of course, the program won't run, since printf() is a library function ( it's not part of the set of C keywords ). Now, printf() is prototyped and defined in "stdio.h", so we simply add the line:



#include < stdio.h >


just above main(), and we are "good to go". Note: there should not be any space character before or after "stdio.h". In fact, we should be able to use the following:



#include "stdio.h"


so that the compiler searches in the current directory first for stdio.h before searching in other (standard) directory, like the include directory for headers ( or header files ) -- unless your compiler is a little addled!

One more thing: modern C/C++ compilers would complain if we don't specify a return value for main(), so let's add "void" to the left of "main()" before we compile, link and run this short program.


Naturally, the above is just another trivial program, used for educational purposes.

Now, just for the hack of it, and because modern PC hardware have enough CPU power ( say, a Pentium 3 or Pentium 4 or equivalent ) and enough RAM ( say, 256MB ) so that we aren't bothered too much with such issues as program speed and memory requirement, let's just make our identifiers -- or, at least, just the variables -- a little more expressive ( rather than short and somewhat cryptic ) by renaming the variables.

Additionally, let us use a modified form of the Hungarian Notation ( HN ) to our program so that every identifier ( or, more accurately, variable ) has a "type" attached as a prefix, like thus:



/* print Fahrenheit-Celsius table
     for fFahrenheit = 0, 20, ..., 300 */

#include "stdio.h"

void main()
{
     int iLowerLimit, iUpperLimit, iStep;
     float fFahrenheit, fCelsius;

     iLowerLimit = 0;     /* lower limit of temperature table */
     iUpperLimit = 300;   /* upper limit */
     iStep = 20;     /* step size */

     fFahrenheit = iLowerLimit;
     while (fFahrenheit <= iUpperLimit)   {
          fCelsius = (5.0/9.0) * (fFahrenheit-32.0);
          printf("%4.0f %6.1f\n", fFahrenheit, fCelsius);
          fFahrenheit = fFahrenheit + iStep;
     }
}


The modified program works as accurately before, naturally. But it is, of course, still very raw! A lot more improvements can be made!


Okay, before we go further, and for my own usage on the PC platform ( thus, platform portability is ignored ), let's just add some Turbo C code to improve on the visual presentation aspects of our little temperature-conversion program. That is, we will tackle the visual portion of the "user interface".

Now, from the webpage http://www.programmersheaven.com/zone3/cat352/index.htm we can get hold of a C/C++ library called "ACTLIB", which stands for "Another C Tools LIBrary".

ACTLIB, which was apparently released in 1993 by Marc Stern, "contains several libraries and their source code. ... The goal of this package is to provide useful tools for developers and also to serve as example codes either for beginners programmers or for non-novice ones that want to use some low-level tricks of MS-DOS ...".

The code that I am now interested in is the border() function, which draws double lines border, in "text mode" ( 80 columns by 25 lines display ). The function uses four parameters of type "int" -- namely, int left, int top, int right, int bottom -- to specify the border coordinates. If int right or int bottom = 0, window limit is assumed. There is no return value -- i.e., "void" is the return value.

Here's the modified code for border():

[ remember: no space character before and after "conio.h" ]




#include < conio.h >

/* function prototype */
void border(int, int, int, int);

void border(int left, int top, int right, int bottom)
{ 
     int i, scroll = _wscroll;
     struct text_info info;

     gettextinfo( &info );     /*  Get current window settings  */

     if ( ! left   ) left = 1;
     if ( ! top    )  top = 1;
     if ( ! right  ) right  = info.winright - info.winleft + 1;
     if ( ! bottom ) bottom = info.winbottom - info.wintop + 1;

     _wscroll = 0;    /* Disable scrolling */

     gotoxy( left, top );
     putch( 'É' );
     for ( i = left + 1; i < right; i++ ) putch( 'Í' );
     putch( '»' );

     for ( i = top + 1; i < bottom; i ++ )
     {
          gotoxy( left, i );
          putch( 'º' );
          gotoxy( right, i );
          putch( 'º' );
     }

     gotoxy( left, bottom );
     putch( 'È' );
     for ( i = left + 1; i < right; i++ ) putch( 'Í' );
     putch( '¼' );

     _wscroll = scroll;    /* Restore scrolling */
}


Combining the border() code and our short program ( that is, we are not creating any code library of our own yet ), we have the following:



/* print Fahrenheit-Celsius table
     for fFahrenheit = 0, 20, ..., 300 */

#include < stdio.h >
#include < conio.h >

/* function prototype */
void border(int, int, int, int);


void main()
{
     int iLowerLimit, iUpperLimit, iStep;
     float fFahrenheit, fCelsius;

     iLowerLimit = 0;     /* lower limit of temperature table */
     iUpperLimit = 300;   /* upper limit */
     iStep = 20;     /* step size */

     clrscr();

     fFahrenheit = iLowerLimit;
     while (fFahrenheit <= iUpperLimit)   {
          fCelsius = (5.0/9.0) * (fFahrenheit-32.0);
          printf("   %4.0f %6.1f\n", fFahrenheit, fCelsius);
          fFahrenheit = fFahrenheit + iStep;
     }

     border(0, 0, 19, 17);

     getch();

}


void border(int left, int top, int right, int bottom)
{ 
     int i, scroll = _wscroll;
     struct text_info info;

     gettextinfo( &info );     /*  Get current window settings  */

     if ( ! left   ) left = 1;
     if ( ! top    )  top = 1;
     if ( ! right  ) right  = info.winright - info.winleft + 1;
     if ( ! bottom ) bottom = info.winbottom - info.wintop + 1;

     _wscroll = 0;    /* Disable scrolling */

     gotoxy( left, top );
     putch( 'É' );
     for ( i = left + 1; i < right; i++ ) putch( 'Í' );
     putch( '»' );

     for ( i = top + 1; i < bottom; i ++ )
     {
          gotoxy( left, i );
          putch( 'º' );
          gotoxy( right, i );
          putch( 'º' );
     }

     gotoxy( left, bottom );
     putch( 'È' );
     for ( i = left + 1; i < right; i++ ) putch( 'Í' );
     putch( '¼' );

     _wscroll = scroll;    /* Restore scrolling */
}






Thursday, 20 February 2003 -- I Love C: It's a Continuing Saga!

Yes, let's face it ...

No matter how many new-fangled computer programming languages are out there or being created / developed, it is still  the old-fashined C language that I love, especially the original K&R version. Which explains why I treasure the two aging-yellowing books I have on C ...

I am referring, of course, to the First and  Second Editions of The C Programming Language, written by Brian W. Kernighan and Dennis M. Ritchie -- the one and only "K&R" referred to earlier.

While acknowledging the debt to K&R, I find that I still like to "muck around" with other versions of C, notably proprietary C from various vendors in the PC world -- after all, the PC is really ubiquitous.

My favorite proprietary C for the PC platform is still Borland's Turbo C  ( as well as Borland's Turbo C++ and Borland's Turbo C++ for Windows ), mainly because Borland made graphics programming on the PC really easy ( even in MS-DOS ) and they made Windows programming somewhat of a breeze.

Of course, today -- i.e., in the early years of the 21st century -- Turbo C, Turbo C++ and Turbo C++ for Windows are "obsolete" compared to their descendants.

But these products are still usable. ( Note: you can still write in C using proprietary C++ products. )

The PC world is crazy with regards to the speed in which things become "obsolete", but I have always thought -- and still do -- that what are considered "obsolete" do not automatically equate to "useless".

Anyway, occasionally, I also "muck around" with Microsoft's Quick C, various versions of Microsoft C/C++ and Microsoft Visual C++.

And, naturally, during the late 20th century and early 21st century, it was a privilege to have had experience the newer multi-language/multi-suite IDE-based products from Borland, Microsoft and others.

Okay, back to the K&R books ...

The First Edition of the K&R book on C was published in 1978, and the Second Edition was published ten years later, i.e., in 1988.

Meanwhile, the book on C++ -- namely, The C++ Programming Language, written by C++'s creator, Bjarne Stroustrup -- was published in 1986, although the copy I have was published in 1987. But I refer more often to the K&R books than I do to Stroustrup's book, so that my love affair with C is readily apparent.

But don't get me wrong: C++ is great, because C++ is, after all is said and done, "C with classes"!

Now, in 1983, ANSI -- that's the American National Standards Institute -- set up a committee to come up with a formal standard definition of the C language, and the result became known as ANSI C  from about 1988 onwards. Despite this -- and especially because of graphics programming on the PC platform with either / both DOS and Windows -- I still prefer to write in some form of non-standard, proprietary C ( and C++ ) -- usually, either Borland's or Microsoft's version.

Occasionally, when I want to write something to use OpenGL or the like, on some UNIX platform ( including Linux from the Red Hat camp, although I have yet to do any programming with Lindows ), I would then use some sort of standard C ( such as ANSI C ), plus all the necessary extensions to achieve whatever results I want. Luckily, the newer C++ compilers ( and newer versions of OS's, including Windows ) also have support for OpenGL and the like, so, really, no great hardship is involved.

Lately, for both Windows and Linux platforms, I have been exploring other ( especially freeware! ) C/C++ compilers, including Pacific C for MS-DOS, Miracle C, and various C's/C++'s associated with GNU and/or the open-source movement ( such as lcc-win32, Bloodshed Dev-C++ and cygwin ).

Hey, I also found Steve Donovan's UnderC ( including UnderC for Windows ), which is touted as an "interactive C++ system" and a "half-compiler" -- it compiles to intermediate stack code. Check out Donovan's book, entitled C++ by Example: UnderC Learning Edition ( 2001-2002 ) as well as the following website for downloads:

        http://home.mweb.co.za/sd/sdonovan/ccbx.htm
For the Macintosh ( I use an iBook, which is beautiful with its titanium casing, but lacks all those lights I have come to rely on in PC-desktops and PC-notebooks ), especially for Mac OS X, one has to explore CodeWarrior and all that Carbon stuff!

Whew, what a life! And I am not even a professional programmer, despite having a Masters of Applied Science in computing science from Glasgow University ( actually, I run a mini-mart in Singapore! ).







Return to Contents Page