温馨提示:本文正文阅读时间大约为3分钟,主要说明scanf的缓冲区机制以及getchar的吸收用法和注意事项。本人现电子信息工程大一,写该笔记纯粹为了记录思考过程和易错点,方便以后查阅。其中的定义是个人的说法,仅便于更好的理解。如果表达有误欢迎指正,同时也感谢指正!
一、先说结论:
1、getchar()的吸收用法:
(1)在哪用:scanf后和gets之前,防止留在缓冲区的空白字符(回车)被gets读入
(2)用几次:取决于最后一次使用的scanf的有效空白字符
对于实际问题:还是在每一个scanf后都都加一个getchar为好,以防忘记释放缓冲区。
2、scanf("%x",&xxx)输入的用法:
对于scanf("%s",str);因为%s会跳过空白字符,从第一个非空白字符开始一直读到第一个空白字符为止(空白字符一般指空格(0x20),回车(0x0D)、换行(0x0A),制表符(0x09)、垂直制表符(0x0B)和换页(0x0C)。即scanf是在有效输入后再遇到回车,空格就结束,但并不会自动将回车、空格从缓冲区中释放,剩余的字符将会留在输入缓冲区中等待下一次读取。
解释:(1)scanf不会读入空白字符,故不会吸收回车等空白字符。这些空白字符只有部分会留在缓冲区(接下来讲解为什么是部分)
(2)从第一个非空白字符开始一直读到第一个空白字符:就是先打一堆空格、回车都不会作为输入,直到遇到非空白字符才输入,再次遇到空白字符就作为结束标志。
二、疑惑的点:为什么上一次输入后的scanf的回车不会直接作为下一次scanf的结束标志?
三、定义:先定义一个概念,在有效输入(对于%d:输入整型,对于%s:输入字符串(不包含空白字符))前的空白字符叫无效空白字符,而有效输入后的空白字符叫有效空白字符。
之所以区分有效和无效:
- 是因为前面输入的在缓冲区中会被自动释放,故后文都解释为不会输入到缓冲区中,而有效输入和有效空白字符才都会输入到缓冲区中。
- 无效空白字符不会作为结束输入的标志,而有效空白字符才会作为结束输入的标志。
这里要注意的是,在有效空白字符的组成:若干个空格,且仅有一个回车(这个回车在最后作为输入到缓冲区结束的标志)
例1:scanf读取整型变量
int a=2;
scanf("%d",&a);
printf("a=%d",a);
输入:[空格] 1[空格] [回车]
输出:a=1
分析:无效空白字符([空格])不会作为结束输入的标志,有效输入1以及后面的有效空白字符([空格] [回车])会传入到缓冲区,其中1赋给a,同时从缓冲区释放,而有效空白字符则会留在缓冲区中。
例2:scanf读取字符串
void main() {
FILE *in, *out;
char ch,infile[10],outfile[10],str[30];
printf("Please enter the infile name:\n");
scanf("%s",infile);
printf("Please enter the outfile name:\n");
scanf("%s",outfile);
getchar();
if((in = fopen(infile,"w"))== NULL) {
printf("Cannot open infile.\n");
exit(0);
}
gets(str);
fprintf(in,"%s",str);
fprintf(stdout,"%s",str);
fclose(in);
}
输入:a1.txt[回车]b1.txt[回车]
现象:到最后缓冲区中只有b1.txt后面的[回车],所以用一个getchar()来吸收[回车],以保证后续可以正常输入str(避免被后续的gets(str);作为结束的标志)
getchar();
getchar();
如果改为两个getchar(),那么输入:a1.txt[回车]b1.txt[空格][回车]
其b1.txt后只能跟一个空格和一个回车(根据无效空白字符的定义)
//正常来说有效空白字符就一个回车吧……对于正常人来说,谁在知道了scanf读不了空格的前提下还在回车前输入空格啊喂,所以用一次getchar()就行,在gets()前。
例2程序的具体分析:
两个scanf连续输入,第一次输入的a1.txt时,其前面的无效空白字符不会输入到缓冲区中,而只有有效输入和其后面的有效空白字符才都会输入到缓冲区中。
到了下一次的输入时,之前的有效空白字符会作为a2.txt有效输入前的无效空白字符,故并不会影响第二次的输入(这也是我一开始疑惑的点,为什么第一次输入后的scanf的回车不会直接作为下一次scanf的结束标志)。
关键点来了:上一次输入时的有效空白字符变成了无效空白字符,即被释放,此时缓冲区中只剩下第二次有效输入后的有效空白字符。
所以对于连续的scanf而言,只需在最后一个scanf后释放,即一个scanf跟一个getchar();并不需要每个scanf后都加getchar()
printf("Please enter the infile name:\n" );
scanf("%s",infile);
getchar();//没必要
printf("Please enter the outfile name:\n" );
scanf("%s",outfile);
getchar();
总结:
1、getchar()的吸收用法:
在哪用:scanf后和gets之前,防止留在缓冲区的空白字符(回车)被gets读入
用几次:取决于最后一次使用的scanf的有效空白字符
对于实际问题:还是在每一个scanf后都都加一个getchar为好,以防忘记释放缓冲区。
2、scanf("%s",str)的输入注意事项:
上一次的scanf的有效空白字符会留在缓冲区里,新的scanf输入会覆盖缓冲区,其新的有效输入后的有效空白字符会留在缓冲区里,故连续使用scanf时,只需在最后一个scanf后吸收即可。
感谢观看~