Next: Operators, Precedence and Associativity Up: The C Language Previous: A Simple C Program

The Second C Program

We now consider a somewhat more complicated C program which introduces a number of new ideas. The program my_echo.c echoes back to the user the input typed on the my_echo command line. Executing the command:

    my_echo Ministry of Silly Walks
would result in the output to the screen of:
    Program name = my_echo    Found argc = 5
    Ministry
while executing the command
    my_echo "Ministry of Silly Walks"
would result in the output to the screen of:
    Program name = my_echo    Found argc = 2
    Ministry of Silly Walks
The difference is caused by the fact that the first attempt passes a total of 5 arguments to the my_echo program (including the program name), while the use of the double-quotes around the character string results in it being passed to my_echo as a single argument. The difference is quite apparent in the difference in the two values reported for the argument count, argc. In fact, the two values, 5 and 2, initially appear quite odd, until one learns that the name of the program (in this case my_echo) is always considered to be the first argument, so argc is always at least 1.



    /*
    FILE = my_echo.c:

    This is a simple echo program that echoes one character
    string, when a character string is given. If the character
    string consists of more than one word (as delimited by
    white-space) then the string should be "bound together" by
    enclosing it in double-quotes or in single-quotes.

    If no arguments are given to the program, it indicates this
    by responding with:

    **** Nothing to echo!

    */
    #include <stdio.h>

    main(argc,argv)
    int argc;       /* number of arguments (words) in call */
    char *argv[];   /* argv[0], argv[1], ... are the arguments */
    {
        printf("Program name = %s   Found argc = %d\n",argv[0],argc);
        if( argc > 1 ) {                /* Check if argc is greater than 1 */
            printf("%s\n",argv[1]);     /* There is something to print */
            }
        else {                          /* argc must have been 1 or less */
            printf("**** Nothing to echo!\n");
            }
        }


In analyzing the structure of the my_echo.c text file, we must introduce some new symbols and their meanings in a C program. The main function definition now includes some arguments, as indicated in the main(argc,argv) statement. This statement indicates that this main function expects two arguments to be passed to it. The types of these two arguments is indicated in the two subsequent lines. The statement int argc; indicates that the first argument to main will be treated as an integer, as opposed to a number with a fractional part. In the case at hand, this parameter is a count of the total number of words typed on the command line (including the command name itself).

The second argument to the main function introduces two new ideas. The first idea is quite simple - the idea of an array of character strings, as indicated by the declaration char *argv[];. This tells the compiler (and us!) that main expects to be given an array, argv[], of character strings. These character strings are referred to as argv[0] (the name of the program), argv[1] (the first argument beyond the program name), etc. Since each of these array elements, such as argv[2], represents a sequence of characters forming a character string, each argv[] must simply point to the location of the first character of the character string in question.

We point out that the form of the declaration of the types of the arguments to a function used above can be replaced by a slightly more recent form, adopted in the ANSI definition of the C language. The ANSI declaration for main would become:

    main(int argc, char *argv[])
which would replace the three line form discussed above, though the interpretation remains unchanged.

The function with the special name main is supplied its arguments by the operating system using the text entered on the command line by the user. This allows a user to supply meaningful information to be easily passed to the program. The function main is the only function that will normally have arguments supplied in this way. Other functions will be passed their arguments by the C statements which call them. Thus the main function can be viewed as the root of every program the user may write and run.

The first executable statement of my_echo.c simply reports the name of the program, and the number of arguments passed to it. The printf statement is similar to that used in the hello.c program, but with significant additions. The first argument to printf consists of a string, all of which will be printed, except for the sequences beginning with %. These format control strings are very flexible, and due to the complexity of all the possible options, the reader should get full details by using the ``man fprintf'' command in UNIX. In the case at hand, the %s sequence directs the printf function to replace that %s by the next unused argument to the printf function, in this case argv[0], which is the name of the program. Similarly, the %d directs printf to replace the %d sequence by the next unused argument to printf, interpreting it as a decimal integer.

Once the information about the arguments passed to the my_echo program is printed, the remainder of the program branches to one of two actions based on the outcome of a conditional test of the form:

\begin{displaymath}
\mbox{\tt if( {\it condition} ) \{ {\it action1} \} else \{ {\it action2} \}}
\end{displaymath}

The statement condition is evaluated and if it returns a value which is true, then action1 is taken, while if condition evalutes to false, then action2 is taken, resulting in what is called a two-way branch. The value of condition is taken to be true if condition evaluates to any non-zero value and taken to be false if it evaluates to zero. Thus the sequence

\begin{displaymath}
\mbox{\tt if( 37 ) \{ {\it action1} \} else \{ {\it action2} \}}
\end{displaymath}

would always result in action1 being taken, while

\begin{displaymath}
\mbox{\tt if( 2*0 ) \{ {\it action1} \} else \{ {\it action2} \}}
\end{displaymath}

would always result in action2 being taken since the condition always evaluates to zero. In the simple case at hand, such a test is used to determine if there is any data worth printing (argc > 1 means argc greater than 1), and if not, an informative message is printed.

Each of the actions, such as action1, can consist of a block of any number of C statements separated by the semicolon character in the usual way as in the example:

    if( x > 0 ) {
        w = sqrt(x);
        v = sqrt(y + x);
        }
    else {
        w = sqrt(-x);
        v = sqrt(y - x);
        }
This has the effect of setting w to be the square root of the absolute value of x, and v to be the square root of the sum of y and the absolute value of x.

While we have already included some arithmetic expressions, we need to introduce the arithmetic operations commonly used in C. For scientific calculations, the most important arithmetic operators are listed in table 2.1


Table 2.1: Aritmetic Operators in C
C arithmetic operator Operation unary or binary
++ increment unary
-- decrement sign unary
- change sign unary
* multiplication binary
/ division binary
% remainer binary
+ addition binary
- subtraction binary
= assign value binary
+= add to value binary
-= subtract from value binary
*= subtract from value binary
/= subtract from value binary
%= subtract from value binary

These are listed in their order of precedence, beginning with the highest. The operators ++, --, and unary - are of equal priority. The operators *, /, and % are equal and next in priority, followed by + and binary -. The assignment operators =, +=, and -= have equal, and lowest pririty.

When the action consists of only one C statement, the enclosing {...} is not required, so we could write:

    if( x >= 0 ) printf("Absolute value is %d\n",x);
else printf("Absolute value is %d\n",-x);

Frequently we only need to check a condition, which if satisfied requires some action and otherwise the execution should just continue. This eliminates the need for the else statement, as in the example:

    if( count > maximum ) {
        printf("Maximum count exceeded: Count = %d\n",count);
        exit(1);        /* EXIT - serious difficulties! */
        }
    printf("About to process %d records ...\n",count);
... more statements ...

In many situations we need to use a multi-way branch decision structure based on testing a sequence of conditions. This can be done by simply stringing together a number of if ... else statements in the general form:

    if( condition1 ) { action1 }         /* first condition/action pair    */
    else if ( condition2 ) { action2 }   /* second condition/action pair   */
    else if ( condition3 ) { action3 }   /* third condition/action pair    */
    else { action4 }                     /* default if all conditions fail */
The multi-way branch must be distinguished from the nested if statements where the intention is to have conditional branching inside a block of C statements comprising the action of a higher level conditional branch structure. Consider the example:
    if( y > 0 ) {
        if( x > 0 ) root = sqrt(y/x);
        else if( x < 0 ) root = sqrt(-y/x);
        else root = -1;
        }
    else if( y < 0 ) {
        if( x < 0 ) root = sqrt(y/x);
        else if( x > 0 ) root = sqrt(-y/x);
        else root = -1;
        }
    else root = 0;
This returns the positive square root of the absolute value of y/x unless x = 0, when it returns the negative value -1. Of course it is not the easiest way to get this result, but it does illustrate the use of nested multi-way branching. This nesting requires a clear understanding of the scope implied for each block of C statements by the matching {...} pairs.


Cengiz Şeker
2000-12-15