小兔网

scanf() 是带有缓冲区的。遇到 scanf() 函数,程序会先检查输入缓冲区中是否有数据:

  • 如果没有,就等待用户输入。用户从键盘输入的每个字符都会暂时保存到缓冲区,直到按下回车键,输入结束,scanf() 再从缓冲区中读取数据,赋值给变量。
  • 如果有数据,哪怕是一个字符,scanf() 也会直接读取,不会等待用户输入。


请看下面的例子:

#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b, c;
scanf("%d", &a);
scanf("%d", &b);
scanf("%d", &c);
printf("a=%d, b=%d, c=%d\n", a, b, c);

system("pause");
return 0;
}

运行结果:
100 200 300↙
a=100, b=200, c=300

程序执行到第一个 scanf(),由于缓冲区中没有数据,所以会等待用户输入。从键盘输入100 200 300后按下回车键,输入就结束了,scanf() 开始从缓冲区中读取数据。由于控制字符串是"%d",所以它会读取一个整数,这里匹配到的整数是100。接下来将100赋值给变量 a,并将100从缓冲区中删除,此时缓冲区中剩下200 300

注意:scanf() 匹配到想要的数据后,会将匹配到的数据从缓冲区中删除,而没有匹配到的数据仍然会留在缓冲区中。

执行到第二个 scanf() 时,检测到缓冲区中有内容,所以不会等待用户输入,而是直接从缓冲区中读取。此时缓冲区中的内容为200 300,scanf() 会匹配到整数200,并将200从缓冲区中删除,剩下300。

执行到第三个 scanf() 时,同理会匹配到300,并将300赋值给变量 c。

再来看一个例子:

#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b=999;
char str[30];
printf("b=%d\n", b);
scanf("%d", &a);
scanf("%d", &b);
scanf("%s", str);
printf("a=%d, b=%d, str=%s\n", a, b, str);

system("pause");
return 0;
}

运行结果:
b=999
100 c.biancheng.net↙
a=100, b=999, str=c.biancheng.net

程序执行到第一个 scanf() 时等待用户输入。从键盘输入100 c.biancheng.net,按下回车键,scanf() 匹配到100,赋值给变量a,同时将100从缓冲区中删除。

执行到第二个 scanf() 时,缓冲区中有数据,会直接读取。由于此时缓冲区中的内容为 c.biancheng.net,并不是 scanf() 想要的整数,所以匹配失败,不会给变量b赋值,这就是两次输出变量b的值相同的原因。匹配失败也意味着不会从缓冲区中删除任何数据。

执行到第三个 scanf() 时,缓冲区中的内容仍然是 c.biancheng.net,明显是字符串,所以匹配成功并赋值给 str。

值得一提的是,在控制台中输入的任何内容本质上都是字符串,都会被%s所匹配。对于上面的程序,不妨换成下面的输入内容:

 

b=999
100 200 300↙
a=100, b=200, str=300

看,300 也被 %s 匹配成功。

缓冲区引发的问题

缓冲区虽然能够让输入更加方便,但有时也会引发奇怪的问题。例如:

#include <stdio.h>
#include <stdlib.h>
int main()
{
int a=0, b=0;
scanf("a=%d", &a);
scanf("b=%d", &b);
printf("a=%d, b=%d\n", a, b);

system("pause");
return 0;
}

运行结果:
a=100↙
a=100, b=0

遇到第一个 scanf(),输入a=100并回车,就会将100赋值给a,并将a=100从缓冲区中删除。遇到第二个 scanf() 时,缓冲区中不是没有内容了吗,为什么不会等待用户输入呢?

其实当用户按下回车键时,回车换行符也会被保存到缓冲区,只是大多数情况下 scanf() 会忽略,前面的两个例子就是这样。但是当控制字符串不是以 %xxx 开头时,回车换行符就起作用了,scanf() 会对它进行匹配,只是匹配失败而已。该例中第二个 scanf() 就是匹配回车换行符失败,所以既不等待用户输入,也不给b赋值。

将第二个 scanf() 的控制字符串改成下面的样子:

scanf("%d", &b);

运行结果:
a=100↙
200↙
a=100, b=200

此时 scanf() 就会忽略缓冲区中的回车换行符,等待用户输入。