-->
Page 468
Interestingly, if the structure pointer is incremented, the address is increased not by 1, but by the size of the structure.
Functions are an easy way to group statements and to give them a name. These are usually related statements that perform repetitive tasks such as I/O. printf, described earlier, is a function. It is provided with the standard C library. Listing 23.4 illustrates a function definition, a function call, and a function.
NOTE |
The three-dot ellipsis simply means that some lines of sample code are not shown here in order to save space. |
Listing 23.4. An example of a function.
int swapandmin( int *, int *); /* Function declaration */ ... int i,j,lower; i=2; j=4; lower=swapandmin(&i, &j); /* Function call */ ... int swapandmin(int *a,int *b) /* Function definition */ { int tmp; tmp=(*a); (*a)=(*b); (*b)=tmp; if ((*a)<(*b)) return(*a); return(*b); }
ANSI C and K&R differ most in function declarations and calls. ANSI C requires that function arguments be prototyped when the function is declared. K&R required only the name and the type of the returned value. The declaration in Listing 23.4 states that a function swapandmin will take two pointers to integers as arguments and that it will return an integer. The function call takes the addresses of two integers and sets the variable named lower to the return value of the function.
Page 469
When a function is called from a C program, the values of the arguments are passed to the function. Therefore, if any of the arguments will be changed for the calling function, you can't pass only the variableyou must pass the address, too. Likewise, to change the value of the argument in the calling routine of the function, you must assign the new value to the address.
In the function in Listing 23.4, the value pointed to by a is assigned to the tmp variable. b is assigned to a, and tmp is assigned to b. *a is used instead of a to ensure that the change is reflected in the calling routine. Finally, the values of *a and *b are compared, and the lower of the two is returned.
If you include the line
printf("%d %d %d",lower,i,j);
after the function call, you will see 2 4 2 as output.
This sample function is quite simple, and it is ideal for a macro. A macro is a technique used to replace a token with different text. You can use macros to make code more readable. For example, you might use EOF instead of (-1) to indicate the end of a file. You can also use macros to replace code. Listing 23.5 is the same as Listing 23.4 except that it uses macros.
Listing 23.5. An example of macros.
#define SWAP(X,Y) {int tmp; tmp=X; X=Y; Y=tmp; } #define MIN(X,Y) ((X<Y) ? X : Y ) ... int i,j,lower; i=2; j=4; SWAP(i,j); lower=MIN(i,j);
When a C program is compiled, macro replacement is one of the first steps performed. Listing 23.6 illustrates the result of the replacement.
Listing 23.6. An example of macro replacement.
int i,j,lower; i=2; j=4; {int tmp; tmp=i; i=j; j=tmp; }; lower= ((i<j) ? i : j );
The macros make the code easier to read and understand.
Page 470
CAUTION |
Macros can have side effects. Side effects occur because the programmer expects a variable to be evaluated once when it is actually evaluated more than once. Replacing the variable i with i++ changes things dramatically:lower=MIN(i++,j); is converted to lower= ((i++ < j) ? i++ : j ); |
For the next example, you'll write a program that prints a chart of the first ten integers and their squares, cubes, and square roots.
Using the text editor of your choice, enter all the code in Listing 23.7 and save it in a file called sample.c.
Listing 23.7. Source code for sample.c.
#include <stdio.h> #include <math.h> main() { int i; double a; for(i=1;i<11;i++) { a=i*1.0; printf("%2d. %3d %4d %7.5f\n",i,i*i,i*i*i,sqrt(a)); } }
The first two lines are header files. The stdio.h file provides the function definitions and structures associated with the C input and output libraries. The math.h file includes the definitions of mathematical library functions. You need it for the square root function.
The main loop is the only function that you need to write for this example. It takes no arguments. You define two variables: One is the integer i, and the other is a double-precision floating-point number calleda. You don't have to use a, but you can for the sake of convenience.
Page 471
The program is a simple for loop that starts at 1 and ends at 11. It increments i by 1 each time through. When i equals 11, the for loop stops executing. You also could have written i<=10 because the expressions have the same meaning.
First, you multiply i by 1.0 and assign the product to a. A simple assignment would also work, but the multiplication reminds you that you are converting the value to a double-precision floating-point number.
Next, you call the print function. The format string includes three integers of widths 2, 3, and 4. After the first integer is printed, you print a period. After the next integer is printed, you print a floating-point number that is seven characters wide with five digits following the decimal point. The arguments after the format string show that you print the integer, the square of the integer, the cube of the integer, and the square root of the integer.
To compile this program by using the GNU C compiler, enter the following command:
gcc sample.c -lm
This command produces an output file called a.out. This is the simplest use of the C compiler. gcc is one of the most powerful and flexible commands of a UNIX system.
A number of different flags can change the compiler's output. These flags are often dependent on the system or compiler. Some flags are common to all C compilers. These are described in the following paragraphs.
The -o flag tells the compiler to write the output to the file named after the flag. The gcc -o sample sample.c command puts the program in a file named sample.
NOTE |
The output discussed here is the compiler's output, not the sample program. Compiler output is usually the program, and in every example here, it is an executable program. |
The -g flag tells the compiler to save the symbol table (the data used by a program to associate variable names with memory locations) in the executable, which is necessary for debuggers. Its opposite is the -O flag, which tells the compiler to optimize the codethat is, to make it more efficient. You can change the search path for header files with the -I flag, and you can add libraries with the -l and -L flags.
The compilation process takes place in several steps: