scanf的输入缓冲区及数据匹配问题

1.关于缓冲区

        缓冲区其实就是一段内存,通常是在一个设备向另一个设备传输数据时用来临时保存数据的一段存储区。凡是速度不匹配的场合都需要设立缓冲区。
        执行scanf语句时,需要等待用户手动输入数据,无论我们输入速度再快,相较于处理器的处理速度也是极其低效的。此时,外部输入设备的运行速度远远低于处理器的处理速度,为了保证处理器的工作效率,处理器先转去执行其他任务,输入设备(如键盘)输入数据并按下回车键,所输入的内容送到缓冲区中,等输入完成处理器再回来执行原任务,而不是输入设备输入一个数据,处理器处理一个数据。

2.关于阻塞状态

        阻塞状态,即等待输入状态。在处理器转去执行其他任务、输入设备进行数据输入的过程中,当前任务则处于暂停执行、等待输入的状态,即为阻塞状态。

#include <stdio.h>
int main()
{
	int a;
	printf("请输入一个整数:");
	scanf("%d",&a);
	printf("a=%d\n",a);
}

        例:执行该程序,先是输出一个提示语句“请输入一个整数:”,然后等待用户进行输入,此时已经进入阻塞状态,当输入数据“1234”后程序仍然处于阻塞状态。只有在按下回车键之后才能完成输入,结束阻塞状态,继续执行下面的语句。

 c38f700e9c62484b86c335a1aa38fd46.png   d36c08e852af4782bda6c757d4310522.png   a5949b3892774ed0a417d6a6c9896bf9.png

 3.缓冲区的数据匹配问题

        匹配规则:scanf函数从缓冲区读取整型数、浮点数、字符串时,会忽略回车符('\n') 、空格符等字符,在读取单个字符时不会忽略任何字符(一般的大部分问题就是结束输入的回车符被下一个字符读取)。匹配之后的数据要从缓冲区中删除。

#include <stdio.h>
int main()
{
	//定义整型数a,字符c,浮点数f,字符数组str(可看做字符串)
	int a;
	char c;
	float f;
	char str[20];
	scanf("%d",&a);
	scanf("%c",&c);
	scanf("%f",&f);
	scanf("%s",&str);
	printf("a=%d,c=%c,f=%f,str=%s\n",a,c,f,str);
}

例:假如要给例中的程序变量a赋值10,c赋值A,f赋值12.34,str赋值abcd:

第一种方式:直接输入10A12.34abcd。赋值是没有问题的,缓冲区的数据分别为10,A,12.34,abcd,<回车>;

b85ae1ed4381497f8e5bb529155c4766.png

 第二种方式:每输入一个数据回车一次,即输入10<回车>A<回车>12.34<回车>abcd<回车>。赋值出现问题,输入10<回车>A<回车>之后程序直接向下继续执行输出结果(并且是错误的结果)。此时,缓冲区的数据分别为10,<回车>,A,<回车>;并且将10赋值给了a,回车符赋值给了c,变量f为浮点型,未成功匹配,直接输出了变量f内存里原本存放的随机数值,A赋值给了str。

b669c71fa86748dea646b320ae8616a0.png

 第三种方式:输入10A<回车>12.34<回车>abcd<回车>。赋值也是没有问题的,缓冲区的数据分别为10,A,<回车>,12.34,<回车>,abcd,<回车>;根据前面所说的匹配规则就可理解,只有字符型数据是可以读取回车符、空格符等符号(其他符号同理),所以,即便是数据12.34和abcd前面有回车符,也不会被读取而是被直接忽略,从缓冲区中删除,然后继续匹配下一个数据。

bd62396f299a48bc8c0ef4edec5dece9.png

 4.清除缓冲区

        使用"fflush(stdin);"语句可以实现清除scanf函数的输入缓冲区的功能。修改上例程序如下:

#include <stdio.h>
int main()
{
	//定义整型数a,字符c,浮点数f,字符数组str(可看做字符串)
	int a;
	char c;
	float f;
	char str[20];
	scanf("%d",&a);
	fflush(stdin);
	scanf("%c",&c);
	scanf("%f",&f);
	scanf("%s",&str);
	printf("a=%d,c=%c,f=%f,str=%s\n",a,c,f,str);
}

在输入变量a后通过"fflush(stdin);"语句清除缓冲区,以上述第二种方式进行输入,程序详解如下:

(1)输入10<回车>,缓冲区的数据为:10,<回车>;

(2)数据10赋值给变量a,缓冲区的数据为:<回车>;

(3)执行fflush(stdin)清除缓冲区,缓冲区为空,无数据;

(4)输入A<回车>12.34<回车>abcd<回车>,缓冲区数据为:A,<回车>,12.34,<回车>,abcd,<回车>;

(5)数据A赋值给变量c,缓冲区数据为:<回车>,12.34,<回车>,abcd,<回车>;

(6)变量f为浮点型,忽略回车符,直接从缓冲区删除,缓冲区数据为:12.34,<回车>,abcd,<回车>;

(7)数据12.34与变量f匹配,赋值给了变量f,缓冲区数据为:<回车>,abcd,<回车>;

(8)同理,str为字符串,忽略回车符,直接从缓冲区删除,缓冲区数据为:abcd,<回车>;

(9)数据abcd与str匹配,赋值给了str,缓冲区数据为:<回车>;

92f4a0f6f3714878880ef7c3c5bb8ca3.png

 

 

  • 12
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
scanf输入缓冲区问题是指在使用scanf函数进行输入时,输入缓冲区中可能会残留上一次输入的换行符\n,导致下一次输入不符合预期。例如,当我们输入完1 2后按下回车键,输入缓冲区里存放着1 2 \n。第一次scanf读走1给a,2给b,中间的空格丢弃,此时第一句scanf已经读完。但是缓冲区里还留着一个\n,当第二次scanf读入时,首先检查缓冲区,发现缓冲区里还有\n,而且正好匹配%c,于是直接读走\n给c。这就是典型的scanf缓冲区问题。 为了解决scanf输入缓冲区问题,可以使用以下方法: 1. 使用fflush(stdin)命令强行刷新输入缓冲,丢弃输入缓冲中的数据。这个方法可以清除缓冲区中的换行符等残留数据,确保输入的正确性。 2. 使用getchar()函数吃掉前面的回车确认符。在执行读取字符操作之前,使用getchar()读取并丢弃缓冲区中的回车符,确保下一次输入的正确性。 3. 使用rewind(stdin)清除标准输入的按键缓冲区。rewind函数是把指定流的读写指针重新指向开头,可以清除输入缓冲区中的残留数据。 通过使用上述方法,可以有效地解决scanf输入缓冲区问题,确保输入的准确性和一致性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [scanf缓冲区问题](https://blog.csdn.net/qq_45908718/article/details/117394732)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

源煦晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值