scanf() 是带有缓冲区的。遇到 scanf() 函数,程序会先检查输入缓冲区中是否有数据:
- 如果没有,就等待用户输入。用户从键盘输入的每个字符都会暂时保存到缓冲区,直到按下回车键,输入结束,scanf() 再从缓冲区中读取数据,赋值给变量。
- 如果有数据,哪怕是一个字符,scanf() 也会直接读取,不会等待用户输入。
请看下面的例子:
#include #include 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 #include 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 #include 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() 就会忽略缓冲区中的回车换行符,等待用户输入。