C的输入整理(gets、getchar、scanf的异同)

整理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

猜你喜欢

转载自blog.csdn.net/weixin_38623697/article/details/80158998