C语言知识汇总 | 29-C语言scanf函数中的缓冲区

一、认识缓冲区

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 blog.csdn.net↙
a=100, b=999, str=blog.csdn.net

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

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

执行到第三个 scanf() 时,缓冲区中的内容仍然是 blog.csdn.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,并将100从缓冲区中删除。遇到第二个 scanf() 时,缓冲区中不是没有内容了吗,为什么不会等待用户输入呢?

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

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

scanf("%d", &b);

运行结果:

a=100↙
200↙
a=100, b=200

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

猜你喜欢

转载自blog.csdn.net/Neutionwei/article/details/108454907