关于scanf()函数的一些问题(后续遇到再补充)

问题一:测试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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值