20-参数和陷阱
3.6 参数和陷阱
有必要再次提醒读者注意 printf() 函数的用法。读者应该还记得,传递给函数的信息被称为参数。例如, printf("Hello,pal.") 函数调用有一个参数: "Hello,pal." 。双引号中的字符序列(如, "Hello,pal." )被称为字符串(string),第 4 章将详细讲解相关内容。现在,关键是要理解无论双引号中包含多少个字符和标点符号,一个字符串就是一个参数。
与此类似, scanf("%d", &weight) 函数调用有两个参数: "%d" 和 &weight 。C语言用逗号分隔函数中的参数。 printf() 和 scanf() 函数与一般函数不同,它们的参数个数是可变的。例如,前面的程序示例中调用过带一个、两个,甚至三个参数的 printf() 函数。程序要知道函数的参数个数才能正常工作。 printf() 和 scanf() 函数用第 1 个参数表明后续有多少个参数,即第 1 个字符串中的转换说明与后面的参数一一对应。例如,下面的语句有两个 %d 转换说明,说明后面还有两个参数:
printf("%d cats ate %d cans of tuna\n", cats, cans);
后面的确还有两个参数: cats 和 cans 。
程序员要负责确保转换说明的数量、类型与后面参数的数量、类型相匹配。现在,C语言通过函数原型机制检查函数调用时参数的个数和类型是否正确。但是,该机制对 printf() 和 scanf() 不起作用,因为这两个函数的参数个数可变。如果参数在匹配上有问题,会出现什么情况?假设你编写了程序清单 3.9 中的程序。
程序清单3.9 badcount.c 程序
/* badcount.c -- 参数错误的情况 */
#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); /* 参数太多 */
printf("%d %d %d\n", n); /* 参数太少 */
printf("%d %d\n", f, g); /* 值的类型不匹配 */
return 0;
}
XCode 4.6(OS 10.8)的输出如下:
4
4 1 -706337836
1606414344 1
Microsoft Visual Studio Express 2012(Windows 7)的输出如下:
4
4 0 0
0 1075576832
注意,用 %d 显示 float 类型的值,其值不会被转换成 int 类型。在不同的平台下,缺少参数或参数类型不匹配导致的结果不同。
所有编译器都能顺利编译并运行该程序,但其中大部分会给出警告。的确,有些编译器会捕获到这类问题,然而C标准对此未作要求。因此,计算机在运行时可能不会捕获这类错误。如果程序正常运行,很难觉察出来。如果程序没有打印出期望值或打印出意想不到的值,你才会检查printf()函数中的参数个数和类型是否得当。