scanf的缓冲区问题
Posted 望北i
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scanf的缓冲区问题相关的知识,希望对你有一定的参考价值。
在写图书馆管理系统的时候,利用scanf输入函数时,莫名其妙把自己用死了。
这里用简单的代码来描述我遇到的问题
#include<stdio.h>
int main(){
int a, b;
char c;
printf("输入两个整数");
scanf("%d %d", &a, &b);
printf("输入一个字符");
scanf("%c", &c);
printf("%d %d %c\\n", a, b, c);
}
输入的格式为: 1 2 c
输出为:
当我输入完 1 2后,本应该在输入字符a可结果就显示成这样。
这就是典型的scanf缓冲区问题
当我们输入完 1 2后按下回车键,输入缓冲区里存放着1 2 \\n,第一次scanf读走1给a,2给b,中间的空格丢弃,此时第一句scanf已经读完。但是缓冲区里还留着一个\\n,当第二scanf读入时,首先检查缓冲区,发现缓冲区里还有\\n,而且正好匹配%c,于是直接读走\\n给c。
关于缓冲区(我遇到的这个问题显然时行缓冲区)
缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内冲空间预留了一定的储存空间,这些储存空间用来缓冲输入或者输出的数据,这部分预留的空间就叫做缓冲区。
缓冲区根据其对应的时输入还是输出,分为输入缓冲区和输出缓冲区。
缓冲区时一块内存区,它在输入输出设备和cpu之间,用来缓存数据。他是低速的输入输出设备和高速的cpu能够协调共工作,避免低速的输入和输出设备占用cpu。
缓冲区分为三种类型:全缓冲,行缓冲和不带缓冲
-
全缓冲:当填满标准I/O缓存后才进行实际的I/0操作。其经典代表就是对磁盘文件的读写。
-
行缓冲:当输入和输出中遇到换行符,执行真正的I/O操作。这时,我们输入的字符优先存放在缓冲区,当按下回车键换行时,才进行实际的I/O操作。其经典的标准输入(stdin)和标准输出(stdout)
-
不带缓冲也就是不进行缓冲,标准出错情况stderr时其典型代表,这使得出错信息可以直接尽快显示出来。
C对stdin、stdout和stderr的缓存特征没有强行的规定,以至于不同的系统可能有不同的stdin、stdout和stderr的缓存特征。目前主要的缓存特征是:stdin和stdout是行缓存;而stderr是无缓存的。
缓冲区的大小
如果我们没有自己设置缓冲区的话,系统就会默认为标准输入输出设置一个缓冲区,这个缓冲区的大小通常时512个字节的大小。
缓冲区大小由stdio.h头文件中宏BUFSIZ定义
缓存区的刷新
下列情况会发生缓冲区的刷新: -
缓冲区满
-
缓冲区遇到\\n的时候
-
程序结束
-
使用特定函数刷新缓存区
c语言中在读取键盘数据时,一般时带缓存的数据输入,需要回去键才能完成该行数据的输入确认
而scanf()函数对这个回车确认符并不进行处理,回车符会留在输入缓冲区中,因此,在下一个读‘字符’操作函数(getchar(),scanf(“%c”),gets())运行时,会读到这个字符,而在读取值型数据或者字符串时,scanf()会从第一个非空白字符(空白字符指:回车,空格,TAB键)开始读取,自动忽略前面的空白字符,而遇到空白字符结束该类型数据的输入。
解决方法 -
用fflush(stdin)命令强行刷新输入缓存,丢弃输入缓存中的数据
#include<stdio.h>
int main(){
int a, b;
char c;
printf("输入两个整数");
scanf("%d %d", &a, &b);
printf("输入一个字符");
fflush(stdin); //不管缓存中有没有数据,强行清除
scanf("%c", &c);// //这里用户输入一个字符
printf("%d %d %c\\n", a, b, c);//结果没有问题
}
- 前面有读数据操作,现在要执行读字符操作,则可用getchar()来吃掉前面的回车确认
#include<stdio.h>
int main(){
int a, b;
char c;
printf("输入两个整数");
scanf("%d %d", &a, &b);
printf("输入一个字符");
getchar(); //吃掉回车确认符
scanf("%c", &c);// //这里用户输入一个字符
printf("%d %d %c\\n", a, b, c);//结果没有问题
}
- rewind(stdin)清除标准输入的按键缓冲区。rewind函数是把指定流的读写指针重新指向开头
#include<stdio.h>
int main(){
int a, b;
char c;
printf("输入两个整数");
scanf("%d %d", &a, &b);
printf("输入一个字符");
rewind(stdin) ;//是把文件指针回绕到文件起始处。
scanf("%c", &c);// //这里用户输入一个字符
printf("%d %d %c\\n", a, b, c);//结果没有问题
}
总结:
在网上看了很多关于scanf缓冲区的问题所总结出来的,scanf还有很多其他用法。
以上是关于scanf的缓冲区问题的主要内容,如果未能解决你的问题,请参考以下文章