Arguments and Pitfalls
It's worth repeating and amplifying a caution made earlier in this chapter about using printf(). The items of information passed to a function, as you may recall, are termed arguments. For instance, the function call printf("Hello, pal.") has one argument: "Hello, pal.". A series of characters in quotes, such as "Hello, pal.", is called a string. We'll discuss strings in Chapter 4. For now, the important point is that one string, even one containing several words and punctuation marks, counts as one argument.
Similarly, the function call scanf("%d", &weight) has two arguments: "%d" and &weight. C uses commas to separate arguments to a function. The printf() and scanf() functions are unusual in that they aren't limited to a particular number of arguments. For example, we've used calls to printf() with one, two, and even three arguments. For a program to work properly, it needs to know how many arguments there are. The printf() and scanf() functions use the first argument to indicate how many additional arguments are coming. The trick is that each format specification in the initial string indicates an additional argument. For instance, the following statement has two format specifiers, %d and %d:
printf("%d cats ate %d cans of tuna\n", cats, cans);
This tells the program to expect two more arguments, and indeed, there are two morecats and cans.
Your responsibility as a programmer is to make sure that the number of format specifications matches the number of additional arguments and that the specifier type matches the value type. C now has a function-prototyping mechanism that checks whether a function call has the correct number and correct kind of arguments, but it doesn't work with printf() and scanf() because they take a variable number of arguments. What happens if you don't live up to the programmer's burden? Suppose, for example, you write a program like that in Listing 3.9.
Listing 3.9 The badcount.c Program
/* badcount.c -- incorrect argument counts */ #include <stdio.h> int main(void) { int f = 4; int g = 5; float h = 5.0f; printf("%d\n", f, g); /* too many arguments */ printf("%d %d\n",f); /* too few arguments */ printf("%d %f\n", h, g); /* wrong kind of values */ return 0; }
Here's the output from Microsoft Visual C++ 7.1 (Windows XP):
4 4 34603777 0 0.000000
Next, here's the output from Digital Mars (Windows XP):
4 4 4239476 0 0.000000
And the following is the output from Metrowerks CodeWarrior Development Studio 9 (Macintosh OS X):
4 4 3327456 1075052544 0.000000
Note that using %d to display a float value doesn't convert the float value to the nearest int; instead, it displays what appears to be garbage. Similarly, using %f to display an int value doesn't convert an integer value to a floating-point value. Also, the results you get for too few arguments or the wrong kind of argument differ from platform to platform.
None of the compilers we tried raised any objections to this code. Nor were there any complaints when we ran the program. It is true that some compilers might catch this sort of error, but the C standard doesn't require them to. Therefore, the computer may not catch this kind of error, and because the program may otherwise run correctly, you might not notice the errors, either. If a program doesn't print the expected number of values or if it prints unexpected values, check to see whether you've used the correct number of printf() arguments. (Incidentally, the Unix syntax-checking program lint, which is much pickier than the Unix compiler, does mention erroneous printf() arguments.)