1.关于缓冲区
缓冲区其实就是一段内存,通常是在一个设备向另一个设备传输数据时用来临时保存数据的一段存储区。凡是速度不匹配的场合都需要设立缓冲区。
执行scanf语句时,需要等待用户手动输入数据,无论我们输入速度再快,相较于处理器的处理速度也是极其低效的。此时,外部输入设备的运行速度远远低于处理器的处理速度,为了保证处理器的工作效率,处理器先转去执行其他任务,输入设备(如键盘)输入数据并按下回车键,所输入的内容送到缓冲区中,等输入完成处理器再回来执行原任务,而不是输入设备输入一个数据,处理器处理一个数据。
2.关于阻塞状态
阻塞状态,即等待输入状态。在处理器转去执行其他任务、输入设备进行数据输入的过程中,当前任务则处于暂停执行、等待输入的状态,即为阻塞状态。
#include <stdio.h>
int main()
{
int a;
printf("请输入一个整数:");
scanf("%d",&a);
printf("a=%d\n",a);
}
例:执行该程序,先是输出一个提示语句“请输入一个整数:”,然后等待用户进行输入,此时已经进入阻塞状态,当输入数据“1234”后程序仍然处于阻塞状态。只有在按下回车键之后才能完成输入,结束阻塞状态,继续执行下面的语句。
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,<回车>;
第二种方式:每输入一个数据回车一次,即输入10<回车>A<回车>12.34<回车>abcd<回车>。赋值出现问题,输入10<回车>A<回车>之后程序直接向下继续执行输出结果(并且是错误的结果)。此时,缓冲区的数据分别为10,<回车>,A,<回车>;并且将10赋值给了a,回车符赋值给了c,变量f为浮点型,未成功匹配,直接输出了变量f内存里原本存放的随机数值,A赋值给了str。
第三种方式:输入10A<回车>12.34<回车>abcd<回车>。赋值也是没有问题的,缓冲区的数据分别为10,A,<回车>,12.34,<回车>,abcd,<回车>;根据前面所说的匹配规则就可理解,只有字符型数据是可以读取回车符、空格符等符号(其他符号同理),所以,即便是数据12.34和abcd前面有回车符,也不会被读取而是被直接忽略,从缓冲区中删除,然后继续匹配下一个数据。
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,缓冲区数据为:<回车>;