(Last Mod: 27 November 2010 21:38:36 )
It is somewhat traditional that the first program a person writes in C does nothing more than print a simple phrase to the screen - the time honored phrase being, "Hello World!"
By successfully doing this, the person has demonstrated the ability to write a minimal program including writing a function, gaining access to some of the standard C functions, calling at least one of those functions, and passing data to one or more functions. They then demonstrated that they could do so without error, could successfully complete the process of compiling the source code file to obtain the intermediate level object code files, and could then link those files together to create the final executable code file. They should not be too quick to dismiss this as a trivial accomplishment, not if they are new to C and especially not if they are new to computer programming in general.
While your first program will also follow in the footsteps of this tradition, you will not use the same function that most people use. The typical first program uses the printf() function which is a very powerful function. By beginning with it the new programmer can get up and going much quicker than if they had to work at a much lower level - but they also lose out on the opportunity to learn things that can only be learned by working at that lower level. By putting these things off until later, it is hoped that the person will be better prepared to understand the lower level concepts when they are reached. What frequently happens, however, is that a mental model has build up of how things work and it is usually well at odds with how they really work. When this happens, the new material becomes extremely confusing and a lot of effort is required to breakdown this subconscious mental model before the newer, correct one can take its place.
In an effort to prevent this from happening, we will take a slower starting pace - learning to crawl - and be sure that we understand what it is we are doing, and how to work at that level, before moving on.
The following is a code listing for our version of the Hello.c program:
#include <stdio.h> // putc(), stdout
#include <stdlib.h> // EXIT_SUCCESS
int main(void)
{
putc('H', stdout);
putc('e', stdout);
putc('l', stdout);
putc('l', stdout);
putc('o', stdout);
putc(' ', stdout);
putc('W', stdout);
putc('o', stdout);
putc('r', stdout);
putc('l', stdout);
putc('d', stdout);
putc('!', stdout);
putc('\n', stdout);
return EXIT_SUCCESS;
}
The above program consists of a function named "main". Throughout the modules, assignments, quizzes, and exams for this course quite a bit of effort is made to use a consistent nomenclature and syntax and the way that functions are indicated is by following them with a pair of parentheses. So the above sentence would generally written as saying that the above program consists of the function main().
Let's now walk through this program line by line and discuss some of the basic elements of a C program.
The first thing we encounter is a #include statement which is one of the preprocessor directives. This statement includes the entire contents of the indicated file as though it were physically included at the same point as the statement. The two files included in these two particular #include statements give use access to the Standard Iinput/Output Library <stdio.c> and a variety of miscellaneous elements grouped together in the Standard Libraray <stdlib.c>.
The comments to the right of the statements document which elements from those libraries are actually used in the current program. The putc() function allows us to write single characters to an output stream. The EXIT_SUCCESS is a predefined symbolic constant used the the return statement to tell the operating system whether the program ended with an error or not.
The main() function is declared so that it receives no arguments from the host system - as indicated by the "void" parameter list - and is expected to return a value of type int - as indicated by the "int" preceding the function name.
The code for this function is everything in the compound statement that starts with the left-curly-brace immediately after the function header and the matching right-curly brace.
Other than the final return statement, every line in this function is a call to the putc() function. These are executed one after another and each one puts the character associated with the character code passed as the first argument to the output stream indicated by the second argument. In this case, all calls to this function are told to direct their output to the standard output device - as indicated by the stdout identifier.
The final putc() function call passes the character code '\n' to the function. This is not two characters, it is an "escape sequence" that is translated by the preprocessor into a single character that happens to be one that we can't indicate directly - in this case it is the new line (also known as a Line Feed) character.
In order for characters to appear on the screen, they must first be passed from the program to the host as it is the host's responsibility to actually cause the characters to be displayed. If the output stream is buffered - which is probably is - then the program will hold off sending any characters to the host until one of five things happens:
It is therefore a good practice to always end any output to the screen either with a new line character. If that is not desirable for the intended program behavior, then a call to the function fflush(stdout) should be issued.
int putc(int c, FILE *stream);
The putc() function is one of the standard function that can be accessed by including the header file for the Standard I/O library. The "function prototype" for this function is located above. A function prototype is simply a copy of the function header followed by a semicolon instead of the function body. It's purpose is to inform you of how to communicate with this function. In the case of putc(), it returns a value of type 'int' and we are expected to supply two arguments when we call it. The first is a value of type 'int' (a signed integer value with a specific number of bytes) and the second is a pointer (indicated by the *) to a value of type 'FILE'. A "pointer" is simply the memory location, or address, where the actual data is stored.
If we look up the description of this function, we find that the first value we pass, 'c', is the ASCII code of the character we want printed to a file. The second value that we pass, 'stream', is the address of where information about the file we want to print to can be found. The "C-speak" way of expressing this is to say that 'stream' is a pointer to a FILE object.
The return value of the function is either the value that was printed to the file or, if an error occurred, the function will return a special value defined symbolically as EOF. We will discuss defining and using symbolic constants in an upcoming lesson.
When you use putc() or any other function to display text on a display device such as a monitor screen, where will that character be displayed?
By definition, this location is known as the "active position" of the display. Where is starts out when your program is launched is implementation dependent. In TurboC v4.5 is starts out in the upper left corner of the console window that is launched for your program to run in.
Normally, after displaying a printing character, the active position is advanced to the next position on the same line. If the line has a specific maximum length, then the active position after writing to the final position is unspecified by the C standard. Most implementations will "wrap" the active position to the beginning of the next line. If the current line is also the last line on the display, then most implementations will scroll the entire contents of the display up one line. Again, this is implementation dependent and the safest approach is to avoid printing to the last character on any line - particularly the last line - to avoid this issue entirely.
If we look at the first invocation of the putc() function we see:
putc('H', stdout);
The claim is that the second argument is a value that represents the address in memory of where information about the file that we want to print to is stored. So, what file is "stdout" going to print to?
In a later lesson we will work extensively with files - how to open them, read from them, write to them, and so on. At that time we will be passing functions like this pointers to the FILE objects for the files we have opened. But for now we will use what are known as the Standard I/O Devices. There are five of them, although we are only particularly interested in two - stdin and stdout. Both of these words are actually symbolic constants whose value we pass instead of a FILE pointer when we want to indicate the use of the standard device. Like many other things, the actual values of these constants may be different from compiler to compiler but any given compiler will define and use them consistently - so as long as we use the symbolic names in our code instead of specific values our code will compile properly.
This is generally the console keyboard, although it could be something else. The next lesson will deal extensively with how to get data from the Standard Input Device.
respectively, that input is to come from the Standard Input Device (generally the keyboard) or that output is to go to the Standard Output Device (generally the monitor screen).