整理gets、getchar、scanf的异同前,一个很重要的概念是输入流缓冲区及键盘缓冲区。
键盘缓冲区就是当你键盘键入内容时,内容存储的地方。
而当里面的内容遇到回车的时候,它们就会被存入输入流缓冲区。
注意,回车的"\n"也会被存入输入流缓冲区。
getchar和scanf就是从输入流缓冲区中读取数据的。这就意味着,用它们读东西的时候别忘了"\n"的存在。
先说说getchar()
getchar()就是从输入流缓冲区一位一位地取内容。当输入流缓冲区还没有内容的时候,getchar()处于待命状态。
看个例子:
#include<stdio.h>
int main()
{
char s1, s2;
s1 = getchar();
s2 = getchar();
printf("%d %d\n", s1, s2);
}
我们会发现s2取的值其实是空格。因为"\n"也会存在输入流缓冲区,所以同理,会出现如下情况:
解决的办法很简单,在两次getchar()中间调用清除缓冲区数据的函数就可以了,例如fflush(stdin)
或者,因为getchar()是把第一位取走,我们可以在两次getchar()中间在写一个getchar(),问题同样可以得到解决(无视字体)
#include<stdio.h>
int main()
{
char s1, s2;
s1 = getchar();
getchar();
s2 = getchar();
printf("%d %d\n", s1, s2);
}
再说说scanf()
其实scanf里面的过程可以看作是多个getchar()组合而成的
先举一个在别的文章里看到的小例子:
#include<stdio.h>
int main()
{
char s1, s2;
scanf("%c %c", &s1, &s2);
printf("%d %d\n", s1, s2);
scanf("%c %c", &s1, &s2);
printf("%d %d\n", s1, s2);
}
可以看到,第二次输出的第一个数并不是a的ascii码值,而是\n的。这是因为第一次读入时回车产生的\n被保存在了输入流缓冲区中,在"%c %c"的后面。
再举个例子:
#include<stdio.h>
int main()
{
char s1, s2;
scanf("%c%c", &s1, &s2);
printf("%d %d\n", s1, s2);
scanf("%c %c", &s1, &s2);
printf("%d %d\n", s1, s2);
}
可以看到第二个输出是空格的ascii码值。
所以总的来说就是:
scanf()内的""从左往右一位一位getchar(),遇到空格则表示跳过所有空格和回车,准备getchar()下一个非空格(或回车)位
显然当读完"%c %c"最后一个%c,输入流缓冲区为空,又没有空格,则退出。(我是这么理解的,至于底层是否真的是这样实现的还得看源代码)
所以当出现"%c %c "的时候,读完最后一个%c,它往后找第一个非空格的字符(不包括回车),找不到,则不会退出,看个例子:
#include<stdio.h>
int main()
{
char s1, s2;
scanf("%c %c ", &s1, &s2);
printf("%d %d\n", s1, s2);
scanf("%c %c", &s1, &s2);
printf("%d %d\n", s1, s2);
}
同时通过这个例子我们发现,未退出状态下,回车是不会被保存在输入流缓冲区里面的。
同样的代码,我们再看另一个例子:
把第二个scanf()里面的空格去掉看看:
#include<stdio.h>
int main()
{
char s1, s2;
scanf("%c %c ", &s1, &s2);
printf("%d %d\n", s1, s2);
scanf("%c%c", &s1, &s2);
printf("%d %d\n", s1, s2);
}
我们发现,输入完三个字符后整个程序就已经执行完了。所以其实可以把两段scanf()放在一起看就是
"%c %c %c%c"
如此看我们可以把scanf()理解为一个扩展的getchar(),新增了一个识别空格的功能。
举最后一个例子结束scanf()部分:
#include<stdio.h>
int main()
{
char s1, s2, s3;
scanf("%c%c%c", &s1, &s2, &s3);
printf("%d %d %d\n", s1, s2, s3);
}
这个例子我认为更加说明了getchar()在scanf()中的体现。
当我键入a+回车,输入并没有退出,并不是输出"97 10 0"(0是null),而当我再输入一个a才结束。
我们可以理解为每个占位符都会引发一个getchar(),没有退出则是在等待缓冲区中新内容的读入。
当然以上所谓getchar()在scanf()中的体现只是我借来更好理解scanf()的方式,至于是否真的是这样还有待查证,不过任何读取肯定是建立在输入流的基础之上的,这点毋庸置疑。(如果这句有错也请斧正qwq)
下面来说说gets()
gets()相对来说就比较好理解了,可以读取空格,不限长度,不会影响到输入流缓冲区,即读完后缓冲区内不会有"\n"
最后看个例子:
#include<stdio.h>
int main()
{
char s1, s2;
char s[2];
gets(s);
printf("%s", s);
scanf("%c %c", &s1, &s2);
printf("%d %d\n", s1, s2);
}
就是这样。
如果有不对的地方
请记得告诉我
merci