C语言清空缓冲区

提到缓冲区,就不得不提setbuf和setvbuf两个缓冲区设置函数,其声明如下:

void setbuf(FILE * restrict stream, char * restrict buf);

int setvbuf(FILE * restrict stream, char * restrict buf, int mode, size_t size);

setvbuf的mode参数有:

_IOFBF(满缓冲):缓冲区空时读入数据;缓冲区满时向流写入数据。

_IOLBF(行缓冲):每次从流读入一行数据或向流写入数据。如:stdio,stdout

_IONBF(无缓冲):直接从流读入数据,或者直接向流写入数据,而没有缓冲区。如:stderr

setbuf(stream, buf);在:

buf == NULL:等价于(void)setvbuf(stream, NULL, _IONBF, 0);

buf指向长度为BUFSIZ的缓冲区:等价于(void)setvbuf(stream, buf, _IOFBF, BUFSIZ);

注:BUFSIZ宏在stdio.h中定义。

这里还要提一下传说中的setbuf的经典错误,在《C陷阱和缺陷》上有提到:

int main()

{

int c;

char buf[BUFSIZ];

setbuf(stdout,buf);

while((c = getchar()) != EOF)

putchar(c);

return 0;

}

问题是这样的:程序交回控制给操作系统之前C运行库必须进行清理工作,其中一部分是刷新输出缓冲,但是此时main函数已经运行完毕,buf缓冲区作用域在main函数中,此时buf字符数组已经释放,导致输出诡异乱码。

解决方案:可以将buf设置为static,或者全局变量,或者调用malloc来动态申请内存。

=================分 割 线=================

下面来看看几种流行的缓冲区清空方法:

fflush(stdin);式

由C99标准文档中:

If stream points to an output stream or an update stream in which the most recent

operation was not input, the fflush function causes any unwritten data for that stream

to be delivered to the host environment to be written to the file; otherwise, the behavior is

undefined.

可以看出fflush对输入流为参数的行为并未定义。但由MSDN上的fflush定义:

If the file associated with stream is open for output, fflush writes to that file the

contents of the buffer associated with the stream. If the stream is open for input,

fflush clears the contents of the buffer.

可以看出fflush(stdin)在VC上还是有效地!鉴于各编译器对fflush的未定义行为实现不一样,不推荐使用fflush(stdin)刷新输入缓冲区。

setbuf(stdin, NULL);式

由前面对setbuf函数的介绍,可以得知,setbuf(stdin, NULL);是使stdin输入流由默认缓冲区转为无缓冲区。都没有缓冲区了,当然缓冲区数据残留问题会解决。但这并不是我们想要的。

scanf("%*[^\n]");式(《C语言程序设计 现代方法 第二版》中提到)

这里用到了scanf格式化符中的“*”,即赋值屏蔽;“%[^集合]”,匹配不在集合中的任意字符序列。这也带来个问题,缓冲区中的换行符’\n’会留下来,需要额外操作来单独丢弃换行符。

经典式

int c;

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

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

你可能感兴趣的:(C语言清空缓冲区)