目录
一、运行原理
scanf函数、getchar函数、gets函数等这类函数是这样的运行的:
可以看出来,scanf函数并不是键盘按什么,就读取什么,换种说法是键盘输入和函数读取不是同步的,而是从键盘输入后,会先保存到输入缓冲区,然后函数从输入缓冲区读取输入进缓冲区内的内容。
二、从代码角度观察
#include<stdio.h>
int main()
{
char ch[3] = { 0 };
int i = 3;
int j = 0;
while (i--)
{
scanf("%c", &ch[j++]);
}
if (ch[1] == 'a')printf("ok");
return 0;
}
●上述代码的意思是,输入三次,分别保存到字符型数组中,如果第二次输入的是a则会输出ok,我们现在来运行这段代码,看看结果:
本来的想法是输入'd'按确认键表示第一次输入结束,紧接着输入'a'按确认键,然后输入第三个字符,可是当第二次输入a按确认键后程序运行结束了,可以看出来的是,此时ch[1]是'\n',ch[2]是'a',跟我们最初想的每次输入一个字符,输入三次的预想结果完全不一样。
●比较一下下面这个代码,运行如下:
#include<stdio.h>
int main()
{
char ch[3] = { 0 };
int i = 3;
int j = 0;
while (i--)
{
scanf("%c", &ch[j++]);
}
if (ch[1] == '\n')printf("ok");
return 0;
}
可以看出来它输出了ok。ch[0]、ch[1]、ch[2]的值分别是a、\n、d。
●再来运行这段代码:
#include<stdio.h>
int main()
{
char ch;
while (1)
{
scanf("%c", &ch);
printf("%c", ch);
}
return 0;
}
你先猜一下会是怎么运行的呢 ????☕
第一次运行只输入了a然后按下确认,可以看到输出了a,并将光标移动到下一行开始,所以其实是while循环运行了两次,第一次从输入缓冲区读取到a,然后输出a,第二次从缓冲区读取'\n',然后输出。
第二次运行,在屏幕上输入了a、b、c、d、e、f、g、h按下确定键,此时缓冲区中是a、b、c、d、e、f、g、h、'\n'然后scanf函数读取到的也是a、b、c、d、e、f、g、h、'\n',所以光标会到下一行开始位置,说明scanf读取了'\n',printf函数将其输出。
三、总结
键盘先输入到输入缓冲区,当识别到程序员按下确认键,scanf函数便会开始从输入缓冲区读取内容。最开始笔者认为键盘输入的时候scanf函数就同步读取内容,当按下确认键后,scanf函数暂停读取输入的内容,如果这样理解正确的话,就不会像上面运行的结果那样输出一个“换行符”,使得光标移动到下一行开始位置,ch[1]里面也不会保存成'\n'。
所以总结一下就是,输入型函数的运行过程是,程序员先从键盘输入到输入缓冲区,当识别到按下确认键后,函数开始从缓冲区读取内容。
四、那怎么解决这种情况呢
(1)、方法一
在%c前面加个\n,变成scanf("\n%c",&ch),首先\n在这里会匹配到缓冲区中0个或多个\n,当scanf函数中的\n匹配到了输入缓冲区的\n,scanf把\n获取后直接扔了,\n不会被赋给任何变量,然后我们再输入一个字符,被%c获取并赋值给ch变量。
#include<stdio.h>
int main()
{
char ch;
while (1)
{
scanf("\n%c", &ch);
printf("%c", ch);
}
return 0;
}
可以看出来,光标没有换到第二行,也就是没有读到'\n',没有将回车赋值给ch变量。就解决了\n在输入过程中的乱换行问题。
(2)、方法二
对于数字%d,%f,字符串%s等等这个\n就影响不大了,当然也可以用在格式符前面加\n来清除缓存,但是通常会用如下方法,来解决这一问题:
#include <stdio.h>
int main()
{
int a;
while(1){
scanf("\n %d",&a);
printf("%d\n",a);
while('\n' != getchar()){//清空缓冲
continue;
}
}
return 0;
}
五、补充
这里单独补充%s的一些内容
#include<stdio.h>
int main()
{
char ch[20] = { 0 };
scanf("%s", ch);
printf("%s", ch);
return 0;
}
当按下确认键后可以看出来输出完字符串后光标没有移动到下一行,也就是没有读取到输入缓冲区中的'\n',这是因为%s 是从输入流中读取一个字符串,输入流中字符串以空白(空格,tab, 回车换行) 为分隔, 所以读得的字符串不含回车。