目录
如何让scanf()函数正确接受有空格的字符串?如: I love you!
Hello!!!我又来了,来写一篇关于scanf的用法,为什么要放到这写呢?害----因为今天在写程序中出现了一个关于scanf的问题,使小田(我)纠结了半个多小时。那么下面给大家看看我的问题,希望你们不要出现!!!
错误
错在哪里了呢(经过我长达半个小时的观察........)
正确
要怪就怪自己学艺不精…………(我要把它搞懂!!!!)
scanf
scanf()是C语言中的一个输入函数。与printf函数一样,都被声明在头文件stdio.h里,因此在使用scanf函数时要加上#include <stdio.h>。(在有一些实现中,printf函数与scanf函数在使用时可以不使用预编译命令#include 。)它是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中。
函数原型
int
scanf
(
const
char
* restrict format,...);
函数的第一个参数是格式字符串,它指定了输入的格式,并按照格式说明符解析输入对应位置的信息并存储于可变参数列表中对应的指针所指位置。每一个指针要求非空,并且与字符串中的格式符一一顺次对应。
scanf的第一个参数是需要输入的字符串以及需要被读取的占位符。scanf的后续参数,是依次被读取并赋值的变量地址。占位符的类型和数量需要与后续的参数类型和数量对应。
返回值
scanf函数返回成功读入的数据项数,读入数据时遇到了“文件结束”则返回EOF。
scanf("%d %d",&a,&b);
函数返回值为int型。如果a和b都被成功读入,那么scanf的返回值就是2;如果只有a被成功读入,返回值为1;如果a读取失败,返回值为0;如果遇到错误或遇到end of file,返回值为EOF。end of file为Ctrl+z 或者Ctrl+d
格式说明符
c 读入域宽指定的数目个字符组成的字符序列(后面不会加上空字节),如果省略宽度则读入单字符。如%c或%1c读入单字符,%2c读入两个字符(后面不会加上空字节),以此类推。
s读入一个的字符序列,后面会加上空字节,遇到空白字符(\t \r \n 空格等)完成读取。
d 读入可选有符号(可选有符号表示输入时可以带符号也可以不带符号,不带符号则视为非负)十进制整数。输入格式应该像strtol函数的base实参为10调用时识别的字符序列一样。
u 读入无符号符号十进制整数。输入格式应该像strtol函数的base实参为10调用时识别的字符序列一样。
p 读入一个指针值。读入的字符序列应该与fprintf的%p产生的字符序列形式相同。
下面这些了解了解就好(上面的 要搞懂且会用)
i 读入可选有符号整数。输入格式应该像strtol函数的base实参为0调用时识别的字符序列一样。
a,e,f,g,A,E,F,G 读入可选有符号浮点数,输入格式应该像strtod函数识别的字符序列一样。
o 读入可选有符号八进制整数。输入格式应该像strtoul函数的base实参为8调用时识别的字符序列一样。
x,X读入可选有符号十六进制整数。输入格式应该像strtoul函数的base实参为16调用时识别的字符序列一样。
n 不读入任何字符,而是把到该位置已读入的字符数存储到与之对应的int*指向的位置。本转换说明符如果带有*或者带有域宽信息(如:%*n或%3n等),则后果是未定义的。
扫描字符集合
% 读入% 符号(百分号)
无效的转换说明符将引起未定义的行为。
长度修饰符
hh与d, i, o, u, x, X, or n配合使用,表示对应一个signed char或unsigned char数据。
h与d, i, o, u, x, X, or n配合使用,表示对应一个short int或unsigned short int数据。
l 与d, i, o, u, x, X, or n配合使用,表示对应一个long int或unsigned long int数据;
ll与d, i, o, u, x, X, or n配合使用,表示对应一个long long int或unsigned long long int数据。
long a = 10; scanf("%ld",&a);
空白字符
空白字符会使scanf函数在读操作中略去输入中的一个或多个空白字符。
控制串中的空白符使 scanf() 在输入流中跳过一个或多个空白行。空白符可以是空格(space)、制表符(tab)和新行符(newline)。 本质上,控制串中的空白符使 scanf() 在输入流中读,但不保存结果,直到发现非空白字符为止。
#include<stdio.h> int main() { int a = 0; int b = 0; scanf("%d %d", &a, &b);//数据之间不可以用逗号分隔,只能用空白字符(空格或tab键或者回车键)分隔,例如:2 3 printf("%d %d\n", a, b); return 0; }
非空白字符
一个非空白字符会使scanf()函数在读入时剔除掉与这个非空白字符相同的字符。
非空白符使 scanf() 在流中读一个匹配的字符并忽略之。例如,"%d,%d" 使 scanf() 先读入一个整数,读入中放弃逗号,然后读另一个整数。如未发现匹配,scanf() 返回。
#include<stdio.h> int main() { int a = 0; int b = 0; scanf("%d,%d", &a, &b);//输入数据时必须要加“,”,例如:2,3 printf("%d %d\n", a, b); return 0; }
格式命令可以说明最大域宽。 在百分号(%)与格式码之间的整数用于限制从对应域读入的最大字符数。例如,希望向 address 读入不多于 3 个字符时,可以书写成如下形式:
scanf("%3s",arr);
如果输入流的内容多于3 个字符,则下次 scanf() 从此次停止处开始读入。 若达到最大域宽前已遇到空白符,则对该域的读立即停止;此时,scanf() 跳到下一个域。
虽然空格、制表符和新行符都用做域分割符号,但读单字符操作中却按一般字符处理。例如,对输入流 "x y" 调用:
scanf("%c%c%c",&a,&b,&c);
返回后,x 在变量 a 中,空格在变量 b 中,y 在变量 c 中。
注意事项
- 对于字符串数组或字符串指针变量,由于数组名可以转换为数组和指针变量名本身就是地址,因此使用scanf()函数时,不需要在它们前面加上"&"操作符。
- 可以在格式化字符串中的"%"各格式化规定符之间加入一个整数,表示任何读操作中的最大位数。
- scanf函数中没有类似printf的精度控制。
- 如: scanf("%5.2f",&a); 是非法的。不能企图用此语句输入小数为2位的实数。
scanf中要求给出变量地址,如给出变量名则会出错
如 scanf("%d",a);是非法的,应改为scanf("%d",&a);才是合法的。
在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔,则可用空格,TAB或回车作间隔。
C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。
在输入字符数据(%c)时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。如:"%c"输入' '空格也算
scanf("%c%c%c",&a,&b,&c);
输入为:d e f
则把'd'赋予a, ' '(空格)赋予b,'e'赋予c。因为%c 只要求读入一个字符,后面不需要用空格作为两个字符的间隔,因此把' '作为下一个字符送给b。 只有当输入为:def(字符间无空格) 时,才能把'd'赋于a,'e'赋予b,'f'赋予c。 如果在格式控制中加入空格作为间隔.
scanf("%c %c %c",&a,&b,&c);
则输入时各数据之间可加空格。
问题
如何让scanf()函数正确接受有空格的字符串?如: I love you!
#include <stdio.h> int main(void) { char str[80]; scanf("%s",str); printf("%s",str); return 0; }
输入:
I love you!
输出:
I
上述程序并不能达到预期目的。因为scanf扫描到"I"后面的空格就认为对str的扫描结束(空格没有被扫描),并忽略后面的" love you!"。
原因
#include<stdio.h> #include<windows.h> int main(void) { char str[80],str1[80],str2[80]; scanf("%s",str);/*此处输入:I love you!*/ printf("%s\n",str); Sleep(5000);/*这里等待5秒,告诉你程序运行到什么地方*/ /** *不是sleep(5) *1,函数名是Sleep不是sleep。 * 2,Windows API中,unsigned Sleep(unsigned)应该是毫秒ms. */ scanf("%s",str1);/*这两句无需你再输入,是对stdin流再扫描*/ scanf("%s",str2);/*这两句无需你再输入,是对stdin流再扫描*/ printf("%s\n",str1); printf("%s\n",str2); return 0; }
输入:
I love you!
输出:
I
love
you!
好了,原因知道了,所以结论是:残留的信息 love you是存在于stdin流中,而不是在键盘缓冲区中。
正确
#include<stdio.h> int main(void) { char str[50]; scanf("%[^\n]",str);/*scanf("%s",string);不能接收空格符*/ printf("%s\n",str); return 0; }
键盘缓冲区残余信息问题
#include<stdio.h> int main(void) { int a; char c=0; while(c!='N') { scanf("%d",&a); scanf("%c",&c); printf("a=%dc=%c\n",a,c);/*printf("c=%d\n",c);*/ } return 0; }
scanf("%c", &c);这句不能正常接收字符,什么原因呢? 我们用printf("c = %d\n", c);将C用int表示出来,启用printf("c = %d\n", c);这一句,看看scanf()函数赋给C到底是什么,结果是c=10 ,ASCII值为10是什么?换行即\n.对了,我们每击打一下"Enter"键,向键盘缓冲区发去一个“回车”(\r),一个“换行"(\n),在这里\r被scanf()函数处理掉了(姑且这么认为吧^_^),而\n被scanf()函数“错误”地赋给了c. 解决办法 可以在两个scanf()函数之间加getchar(),但是要视具体scanf()语句加那个
#include<stdio.h> int main(void) { int a; char c=0; while (c != 'N') { scanf("%d", &a); getchar(); scanf("%c", &c); printf("a=%d c=%c\n", a, c);/*printf("c=%d\n",c);*/ } return 0; }
输入类型与格式化字符串不匹配导致stdin流的阻塞。
#include<stdio.h> int main(void) { int a=0,b=0,c=0,ret=0; ret=scanf("%d%d%d",&a,&b,&c); printf("第一次读入数量:%d\n",ret); ret=scanf("%d%d%d",&a,&b,&c); printf("第二次读入数量:%d\n",ret); return 0; }
正确输入的话:
但是当输入内容与格式换字符串不匹配时,结果会令人大跌眼镜
执行到第一个scanf时,当输入字符’b’的时候与ret=scanf("%d%d%d",&a,&b,&c);中的格式化字符串不匹配,stdin流被阻塞,scanf函数不在读取后面的部分,直接将1返回,表示只将stdin流中的1读入到了变量a中。
执行到第二个scanf时,字符’b’还是与格式化字符串不匹配,stdin流仍然被阻塞,所以没有提示输入,scanf函数将0返回。 正确
#include<stdio.h> int main(void) { int a=0,b=0,c=0,ret=0; ret=scanf("%d%d%d",&a,&b,&c); fflush(stdin);//fflush(stdin)清空输入缓冲区. printf("第一次读入数量:%d\n",ret); ret=scanf("%d%d%d",&a,&b,&c); fflush(stdin); printf("第二次读入数量:%d\n",ret); return 0; }
在scanf("%d ",&a) %d后面加空格
在"%d" 里是一个%d加一 个空格,这是程序读入数据时的格式,这个格式是什么意思呢?这个格式的意思是说是在读完-个整数后, 格式中的空格还需要匹配次有效的输入, 就是需要再读一个整数。 所以也就造成了输入6个数据只读取了5个。所以把格式中的空格去除即可。
结束语:
世界上只有两句真理:1、人一定会死。
2、程序一定会有Bug。
谢谢观看!!!