4.3 格式输入函数scanf
从输入设备(如键盘、磁盘、光盘、扫描仪等)向计算机输入信息的过程称为“输入”。格式输入函数scanf用于接收从键盘等终端输入设备向程序输入数据,将接收到的数据存入内存指定区域并赋给某些变量,或指向内存的数据对象,使用scanf函数对某变量输入数据后,该变量的值将变为输入的数据值,直到该变量被重新赋值为止。与printf类似,scanf函数同样需要包含头文件stdio.h。
4.3.1 标准格式输入
相对于输出函数printf,标准格式输入函数scanf对输入格式的要求更严格。scanf函数的一般形式为:
scanf(“格式输入控制表列”,输入参数地址表列);
其中,双引号内是格式输入控制表列,格式输入控制表列是除特殊符号外均需从键盘输入的字符。输入参数地址表列用于指定输入参数的地址,且输入参数的个数及类型应与格式控制表列中特殊控制符的个数与类型一一对应。
使用scanf输入变量值时,输入参数地址表列中一定是某个内存区域的地址值。C语言中,变量等数据类型在定义时都由系统分配一定的内存空间,且每个变量都有两部分构成,一部分为首地址,另一部分为变量值。例如:
int x = 0;
系统将为变量x分配4字节内存,并将初值0以补码形式存放到该内存区域中,系统使用32位数据作为该段内存首地址,并以该地址作为对变量x的索引,本例假定地址为0x0012ff7c,如图4-2所示。
图4-2 x地址与数值
使用scanf函数输入变量x值时,可使用如下语句:
scanf("%d", &x);
C语言中,通常使用&获取变量的地址,称为取地址运算符,如上述定义中x的首地址可使用&x表示。scanf函数中,必须使用变量地址作为输入参数地址表列,因此,&在scanf函数中使用非常广泛,同时也是程序初学者经常忘记的特殊符号之一。
1. %d格式
%d格式用于接收从键盘输入的整型和字符型数据。使用scanf格式输入数据时,接收输入数据的变量应先定义,否则程序将出现编译错误。例如:
int a = 0;
scanf("%d", &a);
当有多变量同时需要输入时,应分别指定输入格式及变量地址。
范例4.4 ScanfWithIntegerInput.c
ScanfWithIntegerInput.c使用scanf函数输入3个int型变量值,求这三个变量的和与积,并将结果打印到屏幕上,注意结果的精度与取值范围。(光盘\chat4\ ScanfWithIntegerInput.c)
01 #include<stdio.h> 02 03 main() 04 { 05 int a=0, b=0, c=0; 06 double Sum=0, Product=0; //定义double型变量 07 printf("请输入a, b, c的值:\n"); //输入参数提示 08 scanf("%d %d %d", &a, &b, &c); //输入语句 09 Sum=a+b+c; //计算变量之和 10 Product=a*b*c; //计算变量之积 11 printf("a+b+c=%f, a*b*c=%f\n", Sum, Product); 12 }
输入格式表列中,各控制格式间可以使用空格分开,也可以不使用空格,此时输入不同参数数值时应使用一个或多个空格分开。
程序运行时,输入1、2和3,键入回车键。
请输入a,b,c的值:
1 2 3
输出结果为:
a+b+c = 6.000000, a*b*c = 6.000000
当控制格式使用逗号或其他字符分开时,逗号或字符应按原样输入,否则程序将把字符作为数据一起输入。例如,程序第8行修改为:
scanf("%d,%d,%d",&a,&b,&c);
输入数据时需要把逗号原样输入。
1,2,3
否则程序将不能把正确数值赋给相应的变量。
作者心得:
程序中应注意避免数学运算时结果溢出,如上述范例中3个变量的和与积应使用double型数据来存储,否则系统可能由于数值溢出而得不到正确结果,读者可尝试将Sum和Product变量以int定义,并对a, b, c分别赋予较大的数值,验证是否能够获得正确结果。
2. %f格式
%f格式用于输入float型或double型变量的数据。与%d格式类似,使用%f格式时应与输入参数中变量格式匹配。例如:
float f = 0.0;
double d = 0.0;
scanf("%f , %f", &d, &f);
键盘输入:123.456,789.987后,变量f的值变为: 789.987,变量d的值变为123.456。这里一定注意输入参数地址表列中变量f和d的地址前后位置。即先输入的是变量d的值,因此为123.456,后输入的是变量f的值,为789.987。
3. %c格式
%c格式用于输入字符类型数据。ASCII码中所有的字符都可以作为字符数据由键盘输入,因此,使用%c格式输入字符数据时一定注意,空格、回车以及逗号等均作为字符处理。例如:
char c1, c2, c3;
scanf("%c%c%c", &c1, &c2, &c3);
printf("c1=%c, c2=%c, c3=%c\n", c1, c2, c3);
键盘输入:a_b_c
输出语句输出为:a_b,即c1被赋值为'a',c2被赋值为'_',c3被赋值为'b',另外两个字符'_'和'c'将被作为无效字符丢弃。
范例4.5 ScanfCharacterVariable.c
ScanfCharacterVariable.c使用键盘输入字符串"Hello world",定义11个字符变量用以存储各字符,并将其打印在屏幕上,注意输入的顺序以及输出的顺序。(光盘\chat4\ ScanfCharacterVariable.c)
01 #include<stdio.h> 02 main() 03 { 04 char c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11; 05 printf("请输入:\n"); 06 scanf("%c%c%c%c%c%c%c%c%c%c%c", 07 &c1, &c2, &c3, &c4, &c5, &c6, &c7, &c8, &c9, &c10, &c11); 08 printf("%c%c%c%c%c%c%c%c%c%c%c\n", 09 c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11); 10 }
使用scanf函数输入字符时,键盘的每一次按键都会被作为字符存储到字符型变量中。运行程序时,键盘输入Hello world,然后按回车键。
请输入:
Hello world
输出结果为:
Hello world
若程序输入时在Hello与world之间有多个空格,程序将不能正确输出。以Hello与world之间有4个空格为例:
Please input:
Hello_ _ _ _world>/
Hello_ _ _ _wo
作者心得:
使用%c格式时一定要尽量避免输入不必要的符号,如果误操作输入冗余符号,可能使结果出现偏差。例如,上述程序中若Hello与world之间键入回车键,则出现:
Please input:
Hello>/
world>/
Hello
world。
此时,程序也将回车键作为一个字符赋给c6。而执行输出时,程序也将c6按其功能输出,因此输出换行。
4. %s格式
%s用于输入字符串。由于字符串地址占用可变长内存单元,因此字符串地址表达方式比较复杂,通常可使用字符数组名或指针来作为字符串输入地址。需要注意的是,程序将空格作为字符'\0'处理,即作为字符串结束标志,因此,程序输出时将影响屏幕打印效果,但这并不影响整个字符串在内存中的存储。例如:
char s[15];
scanf("%s", s);
printf("%s", s);
若输入:Hello world,则输出为:Hello。
需要注意的是,字符串输入地址不需要取地址符&,有关字符串地址的内容后续章节将作详细介绍。
4.3.2 格式输入控制
除了基本的格式输入控制,C语言还提供了扩展的格式输入控制。这些格式用于控制输入数据的接收和输入数据位的忽略等。
1. %md和%*md格式
扩展的控制格式输入常见于整型数据输入时,此时可以使用%md或%*md进一步控制输入数据。%md用于获取输入数据序列的前m位数,当m大于输出数据位数时,按实际数据赋给变量。%*md用于忽略前m位的数据输入。例如:
01 int a=0, b=0;
02 scanf("%3d %2d", &a, &b);
03 printf("a=%d, b=%d\n", a, b);
程序输入:123456,则输出:a=123, b=45。程序将123赋给变量a,将45赋给变量b,并丢弃数据6。
若程序第2行改为:
scanf("%2d %*3d %2d",&a,&b);
程序输入:12345678,则输出:a=12, b=67。程序将12赋给变量a,并忽略数据345,将67赋给变量b,并丢弃数据8。
2. 控制输入表列中的普通字符
当控制输入表列中存在普通字符时,一定要原样输入,否则系统将因为匹配错误而不能将正确数据赋给相应变量。例如:
int i=0;
scanf("i=%d", &i);
printf("i=%d\n", i);
程序输入:100,则输出:i=0。程序中,由于scanf函数中控制输入表列中含有普通字符串"i=",而输入时直接输入数字100时导致系统运行时无法匹配该字符串,因此也就不能将数据赋给i,因此输出其初始值0。若输入:i=100,则输出i=100。
3. 控制输入格式与输入参数变量类型一一对应
scanf函数中,控制输入格式一定要与要输入的数据变量的类型一致,否则程序无法将正确的数值赋给该变量。例如:
int a=0;
scanf("%f", &i);
printf("%d", i);
程序输入:10,输出为:1092616192。输出无法预期的垃圾值。因此,程序初学者一定要注意按照数据类型的一一对应关系输入变量的数值。
此外,对于程序初学者,取地址符&也会经常忘记,一定记住使用scanf函数时要执行取地址操作,否则程序运行时将出现崩溃性错误。