问题一:测试scanf()返回值
vs2019中,用scanf()函数会提示不安全,要用scanf_s()。scanf()函数按照对应的格式控制字符串进行输入,返回正确读取输入字符的个数,空白字符(空格、tab、回车)不算在内。
测试代码1:
#include <stdio.h>
int main()
{
int a,b;
int i;
i = scanf_s("%d %d",&a,&b);
printf("%d\n",i);
return 0;
}
当输入两个整数,如1 3时,运行结果为:
结果表明正确读入了2个整数。当输入1 a时,结果为:
可见,当输入字符与格式控制不匹配时,程序结束,且只读入格式匹配的第一个字符。当输入a 1时,运行结果为:
同样,遇到非法字符(格式不匹配),程序随即结束,成功读取字符数为0.
另外,scanf会跳过空白字符,如:
问题二:scanf()接收带有空格的字符串问题
测试程序:
#include <stdio.h>
int main(void)
{
char str[80];
scanf_s("%s", str,80);//这里格式控制为%s,要加一个参数80,表明缓冲区大小
printf("%s\n", str);
return 0;
}
如果输入I love you,结果是:
原因在于当读取到I后面的空格后,按照规则程序就结束了。这里有两个概念:stdin流和键盘缓冲区。(对理解有一些启发,转自百度)
这里是引用
键盘缓冲区:应该和你的程序没有关系,也就是说由键盘的硬件部分完成,其功能是当键盘有按键按下,但CPU却忙于其他事物,暂时没时间去取走键盘根据按键所产生的编码的时候由键盘硬件(软件)来暂时存储“已”按键信息,发送与否不是考虑的问题,对于键盘来说已经发送,所以键盘不存在按某个键后再发送的问题。(其实这个缓冲理论上基本没用,人按键最快也要100毫秒级,对于CPU来讲比蜗牛慢太多了)
stdin流:即标准输入流。不过可以这样来理解,系统自动去执行标准输入设备的输入数据,读取并存放于自定义的一个缓冲空间内(大小、位置不用你管),对你来说,stdin的这个缓冲你可以理解为一个文件,文件名就叫stdin。你的程序输入语句比如scanf()就是系统已经做好的访问这个文件的函数,对你来说这个函数具体怎么执行的不关心,只需关心函数返回的数据。
通过具体的例子来看:
测试程序2:
#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;
}
这里要注意两点:
(1)在输入多个数值数据(%d)时,若格式控制串中没有非格式字符作输入数据之间的间隔,则可用空格,TAB或回车作间隔。
C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。
(2)在输入字符数据(%c)时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。
若输入正确:
但当输入内容与格式转换字符串不匹配时,结果为:
为什么?原因是在扫描到输入为b时,即为非法字符,程序结束。第一次输出只读取到前面输入的1,而b仍保存在stdin流中,同理第二次输出时,首先扫描的流中的b为非法字符,结束程序。若未执行清空缓冲区,b3仍在流中。
将代码作如下修改,可以有力的证明上述结论。
测试代码2.1:
#include<stdio.h>
int main(void)
{
int a = 0,b = 0,c = 0,ret = 0;
ret = scanf_s("%d%d%d",&a,&b,&c);
printf("第一次读入数量%d\n",ret);
ret = scanf_s("%c%d%d",&a,1,&b,&c);
//用scanf_s时,
//在读入%c或者%s时,必须多传入一个参数用来指定读取的长度,不然会出错
printf("第二次读入数量:%d\n",ret);
return 0;
}
第一次输入1 a 2,第二次输入3,运行结果为:
由于第一次读取到a时,程序即结束,只成功读取到1,stdin流阻塞,此时第二个scanf控制字符串匹配成功,stdin疏通,成功读取了a 2 3三个字符,返回3。
如何清空输入缓冲区?
(1)可以使用rewind(stdin)来解决问题。fflush(stdin)在vs2019中不起作用,也不报错。
(2)用 while((ch = getchar()) != ‘\n’ && ch != EOF)
continue; //将输入流中的余留字符清除
测试代码3:
#include<stdio.h>
int main(void)
{
int a = 0,b = 0,c = 0,ret = 0;
ret = scanf_s("%d%d%d",&a,&b,&c);
rewind(stdin);
printf("第一次读入数量%d\n",ret);
ret = scanf_s("%d%d%d",&a,&b,&c);
rewind(stdin);
printf("第二次读入数量:%d\n",ret);
return 0;
}
测试结果:
说明的确清空了输入缓冲区。先写到这。
补充
测试代码:关于scanf_s格式控制%d\n出错
#include <stdio.h>
int main()
{
int num;
scanf_s("%d\n",&num);//%d\n这种格式控制有问题
printf("%d\n",num);
return 0;
}
输入一个整数按回车不会跳过scanf_s函数,程序会停在这一步,而直接用scanf_s("%d",&num);是没问题的。网上查了下,比较认同该博主的理解。搬运过来了:
scanf("%d\n",&n);这样一条语句,输入一个数字加回车,5\n全部被读入到了scanf中去了,然后5被赋给了n,但是这样在缓冲区内此时却没有空白符,因此无法结束,然后根据scanf的规定,必须要有一个空白符才能够结束输入,因此还会要求继续输入,而\n后面需要遇到一个非空白符才能继续读入,否则会一直提示输入,因此再输入一个非空白符,一个空白符即可成功完成scanf的停止。
————————————————
版权声明:本文为CSDN博主「Robin_Yao_Wenbin」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39805362/article/details/82820642