C语言清空缓冲区 此为收费教程,尊重作者的原创,请到http://c.biancheng.net/cpp/u/jiaocheng/,缴费学习,我这边隐藏文章内容,供自己学习之用。

在《结合C语言缓冲区谈scanf()函数》一节中讲到,scanf() 的缓冲区有时会引发奇怪的问题,多个 scanf() 之间要注意清空缓冲区。清空缓冲区主要有两种思路:一是将缓冲区中的数据丢弃,二是将缓冲区中的数据读取出来,但是却不使用。

fflush(stdin)

fflush() 函数用来清空文件缓冲区,它的原型为:

int fflush(FILE *stream)

stream 为流指针,可以理解问一个文件指针。在C语言中,为了便于操作,键盘和显示器也被看作是文件,这样对硬件的操作就等同于对文件的操作。键盘称为标准输入文件(stdin),显示器称为标准输出文件(stdout),这在《C语言文件概述》一节中有详细讲解。

如此就可以使用 fflush() 来清空输入缓冲区中的数据,具体用法为:

fflush(stdin);

请看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
#include<stdlib.h>
int main()
{
    int a, b;
    scanf("%d", &a);
    fflush(stdin);
    scanf("%d", &b);
    printf("a=%d, b=%d\n", a, b);
    system("pause");
    return 0;
}

运行结果:

100 200300↙
a=100, b=300

第一个 scanf() 读取完成后,将100赋值给变量 a,缓冲区中剩下200。然后调用 fflush() 函数将200从缓冲区中清除。执行到第二个 scanf() 时由于缓冲区中没有数据,所以会等待用户输入,将300赋值给变量 b。

如果把第7行代码注释掉,运行结果为:

100 200↙
a=100, b=200

由于没有清空缓冲区,执行到第二个 scanf() 时直接将缓冲区中的200赋值给变量 b。

fflush(stdin) 直接将缓冲区中的数据丢弃,是初学者常用的清空输入缓冲区的方法,它在 Windows 下一般是有效的,但在 Linux GCC 下可能无效,因为C语言标准规定:对于以 stdin 为参数的 fflush() 函数,它的行为是不确定的,fflush() 操作输入流是对标准C语言的扩充。

循环读取缓冲区中的数据

从缓冲区中读取剩余数据的方法也很多,这里讲解常用的两种。

1) 使用 getchar() 读取数据:

1
2
int c;
while((c = getchar()) != '\n' && c != EOF);

该代码不停地使用 getchar() 获取缓冲区中的字符,直到获取的字符是换行符\n或者是文件结尾符EOF为止。这个方法可以完美清空输入缓冲区,并且具备可移植性。

2) 使用 scanf() 读取:

1
scanf("%*[^\n]%*c");

%*[^\n]将逐个读取缓冲区中的 '\n' 字符之前的其它字符,% 后面的 * 表示将读取的这些字符丢弃,遇到 '\n' 字符时便停止读取。此时,缓冲区中尚有一个 '\n' 字符遗留,所以后面的%*c将读取并丢弃这个遗留的换行符,这里的星号和前面的星号作用相同。由于所有从键盘的输入都是以回车结束的,而回车会产生一个 '\n' 字符,所以将 '\n' 连同它之前的字符全部读取并丢弃之后,也就相当于清除了输入缓冲区。

请看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
#include<stdlib.h>
int main()
{
    int a, b;
    char c;
    scanf("%d", &a);
    scanf("%*[^\n]%*c");
    scanf("%d", &b);
    printf("a=%d, b=%d\n", a, b);
 
    scanf("%d", &a);
    while((c = getchar()) != '\n' && c != EOF);
    scanf("%d", &b);
    printf("a=%d, b=%d\n", a, b);
    system("pause");
    return 0;
}

运行结果:

100 200300↙
a=100, b=300
9 99999↙
a=9, b=999

虽然两种方法都能起到清空缓冲区的作用,但第一种方法需要额外定义一个 char 类型的变量,略显繁琐,并且 while 循环也会导致效率不高,所以建议使用第二种方法。

综上所述:如果只考虑Windows,建议使用fflush(stdin);,简单明了;如果兼顾移植和效率,建议使用scanf("%*[^\n]%*c");,虽然有点蹩脚,但确实能够奏效。

» 订阅本站: http://www.0523jz.com/feed