使用C语言怎样清空输入缓冲区?这里有多种方法值得借鉴


本文摘自PHP中文网,作者php是最好的语言,侵删。

C语言中有几个基本输入函数:

1

<span style="color:#008000;">//获取字符系列</span><br>

1

int fgetc(FILE *stream);

1

int getc(FILE *stream);

1

int getchar(void);

1

//获取行系列

1

char *fgets(char * restrict s, int n, FILE * restrict stream);

1

char *gets(char *s);//可能导致溢出,用fgets代替之。

1

//格式化输入系列

1

int fscanf(FILE * restrict stream, const char * restrict format, …);

1

int scanf(const char * restrict format, …);

1

int sscanf(const char * restrict str, const char * restrict format, …);

这里仅讨论输入函数在标准输入(stdin)情况下的使用。纵观上述各输入函数,

  • 获取字符系列的的前三个函数fgetc、getc、getchar。以getchar为例,将在stdin缓冲区为空时,等待输入,直到回车换行时函数返回。若stdin缓冲区不为空,getchar直接返回。getchar返回时从缓冲区中取出一个字符,并将其转换为int,返回此int值。

MINGW 4.4.3中FILE结构体源码

1

_iobuf

1

{

1

char*   _ptr;//指向当前缓冲区读取位置

1

int _cnt;//缓冲区中剩余数据长度

1

char*   _base;

1

int _flag;

1

int _file;

1

int _charbuf;

1

int _bufsiz;

1

char*   _tmpfname;

1

} FILE;

各编译器实现可能不一样,这里获取字符系列函数只用到_ptr和_cnt。

MINGW 4.4.3中getchar()实现

1

__CRT_INLINE int __cdecl __MINGW_NOTHROW getchar (void)

1

{

1

return (--stdin->_cnt >= 0)

1

?  (int) (unsigned char) *stdin->_ptr++

1

: _filbuf (stdin);

1

}

其中stdin为FILE指针类型,在MINGW 4.4.3中,getc()和getchar()实现为内联函数,fgetc()实现为函数。顺便说一句,C99标准中已经加入对内联函数的支持了。

  • 获取行系列的fgets和gets,其中由于gets无法确定缓冲区大小,常导致溢出情况,这里不推荐也不讨论gets函数。对于fgets函数,每次敲入回车,fgets即返回。fgets成功返回时,将输入缓冲区中的数据连换行符’\n’一起拷贝到第一个参数所指向的空间中。若输入数据超过缓冲区长度,fgets会截取数据到前n-1(n为fgets第二个参数,为第一个参数指向空间的长度),然后在末尾加入’\n’。因此fgets是安全的。通常用fgets(buf, BUF_LEN, stdin);代替gets(buf);。

  • 格式化输入系列中,fscanf从文件流进行格式化输入很不好用。常用的还是scanf,格式化输入系列函数舍去输入数据(根据函数不同可能是标准输入也可能是字符串输入,如:sscanf)前的空白字符(空格、制表符、换行符)直至遇到非空白字符,然后根据格式参数尝试对非空白字符及后续字符进行解析。该系列函数返回成功解析赋值的变量数,若遇文件尾或错误,返回EOF。

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

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

1

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

1

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陷阱和缺陷》上有提到:

1

main()

1

{

1

int c;

1

char buf[BUFSIZ];

1

<br>

1

setbuf(stdout,buf);

1

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

1

putchar(c);

1

<br>

1

return 0;

1

}

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

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

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

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

  • fflush(stdin);式

由C99标准文档中:

1

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

1

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

1

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

1

unde?ned.

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

1

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

1

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

1

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’会留下来,需要额外操作来单独丢弃换行符。

  • 经典式

1

 

1

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

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

相关文章:

禁止页面缓存的方法 多语言下禁止页面缓存

如何批量清理系统临时文件(语言:C#、 C/C++、 php 、python 、java )

相关视频:

C 语言教程

以上就是使用C语言怎样清空输入缓冲区?这里有多种方法值得借鉴的详细内容!

相关阅读 >>

使用c语言怎样清空输入缓冲区?这里有多种方法值得借鉴

c语言是一种什么编译形式的语言

c++中string类的常用方法有哪些

更多相关阅读请进入《方法》频道 >>



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...