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 more—cats 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 n = 4; int m = 5; float f = 7.0f; float g = 8.0f; printf("%d\n", n, m); /* too many arguments */ printf("%d %d %d\n", n); /* too few arguments */ printf("%d %d\n", f, g); /* wrong kind of values */ return 0; }
Here’s a sample output from XCode 4.6 (OS 10.8):
4 4 1 -706337836 1606414344 1
Next, here’s a sample output from Microsoft Visual Studio Express 2012 (Windows 7):
4 4 0 0 0 1075576832
Note that using %d to display a float value doesn’t convert the float value to the nearest int. Also, the results you get for too few arguments or the wrong kind of argument differ from platform to platform and can from trial to trial.
None of the compilers we tried refused to compile this code; although most did issue warnings that something might be wrong. 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.