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 Walkswould 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:
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
| 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 |
++, --, 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