C语言清空输入缓冲区的N种方法对比
C语言中有几个基本输入函数:
//获取字符系列int fgetc(FILE *stream);int getc(FILE *stream);int getchar(void);//获取行系列char *fgets(char * restrict s, int n, FILE * restrict stream);char *gets(char *s);//可能导致溢出,用fgets代替之。//格式化输入系列int fscanf(FILE * restrict stream, const char * restrict format, …);int scanf(const char * restrict format, …);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结构体源码:
typedef struct _iobuf{char* _ptr;//指向当前缓冲区读取位置int _cnt;//缓冲区中剩余数据长度char* _base;int _flag;int _file;int _charbuf;int _bufsiz;char* _tmpfname;} FILE;
各编译器实现可能不一样,这里获取字符系列函数只用到_ptr和_cnt。
MINGW 4.4.3中getchar()实现:
__CRT_INLINE int __cdecl __MINGW_NOTHROW getchar (void){return (--stdin->_cnt >= 0)? (int) (unsigned char) *stdin->_ptr++: _filbuf (stdin);}
其中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。
=================分 割 线=================
提到缓冲区,就不得不提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 recentoperation was not input, the fflush function causes any unwritten data for that streamto be delivered to the host environment to be written to the file; otherwise, the behavior isundefined.
可以看出fflush对输入流为参数的行为并未定义。但由MSDN上的fflush定义:
If the file associated with stream is open for output, fflush writes to that file thecontents 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语言清空输入缓冲区的N种方法对比的更多相关文章
- C语言清空输入缓冲区的N种方法对比【转】
转自:http://www.cnblogs.com/codingmylife/archive/2010/04/18/1714954.html C语言中有几个基本输入函数: //获取字符系列 int f ...
- C语言清空输入缓冲区的N种方法对比(转)
C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void); //获取行系列 ...
- C语言清空输入缓冲区
来源:http://blog.csdn.net/guanyasu/article/details/53153705 https://zhidao.baidu.com/question/5241738. ...
- scanf()中清除输入缓冲区的几种方法归纳
应用场景:我们使用多个scanf()的时候,如果输入缓冲区还有数据的话,那么scanf()就不会询问用户输入,而是直接就将输入缓冲区的内容拿出来用了,这就导致了前面的错误影响到后面的内容,为了隔离这种 ...
- C 清空输入缓冲区,以及fflush(stdin)的使用误区和解决方法
转载:https://blog.csdn.net/Veniversum/article/details/62048870 对C 语言初学者来说,fflush(stdin)函数被解释为会清空输入缓冲区的 ...
- c++中清空输入缓冲区的方法(做cf的时候炸了)
C/C++ 四种清空输入缓冲区的方法 比较实用的一种 char c; while(c=getchar()!='\n'); 或者是这种 cin.ignore(count,c); count代表要清除的字 ...
- vs2019清空输入缓冲区
发现用cin.sync()在vs2019中不能清空输入缓冲区,以前的vs版本没试过,我看别人在vc中用cin.sync()可以清除,估计是IDE的问题..以下是我学习C++四个多月写的一整段代码 运行 ...
- linux清空文件内容的三种方法
linux系统中清空文件内容的三种方法 1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下:vim file_name:%d: ...
- linux中快速清空文件内容的几种方法
这篇文章主要介绍了linux中快速清空文件内容的几种方法,需要的朋友可以参考下 $ : > filename $ > filename $ echo "" > f ...
随机推荐
- haproxy部署及配置
HAProxy介绍 (1)HAProxy 是一款提供高可用性.负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费.快速并且可靠的一种解决方案. HAProxy特 ...
- Java json工具类,jackson工具类,ObjectMapper工具类
Java json工具类,jackson工具类,ObjectMapper工具类 >>>>>>>>>>>>>>> ...
- 别了 oi——一篇高三狗的滚粗遗言
/* 开始于2015年12月 结束于2016年11月 一年的oi生涯有很多值得怀念的事 还记得去年旺哥找我学oi 当时是一脸的蒙逼 要知道 高二才开始搞是很晚了 然而 也就是那一晚之后 许多事情都变了 ...
- (转)ASP.net的url重写
1. 有关于URL的重写,本文也只是拿来主意.相继有MS的组件“URLRewriter”和在Global.asax里的“Application_BeginRequest()”编码方式,以及IIS里的I ...
- 转载-优秀程序员的十个tips
理解技术债务 技术债务就像信用卡一样,会有很高的利息,时间越长,修复所化的代价就越大.团队应该培养一种保证设计质量的文化,鼓励重构.同时应当鼓励其它有关代码质量的实践. 保持对原理的好奇心 做Andr ...
- SqlServer Change Data Capture(CDC)数据变更捕获
最近在使用SqlServer2008r2数据库做系统的时候,在某些重要的.经常涉及到修改的表上,想加上一些恢复机制,一开始想找找看看有没有类似Oracle数据库闪回那样的功能,后来发现CDC的功能可以 ...
- 关于ligerui 中 grid 表格的扩展搜索功能在远程数据加载时无法使用的解决办法
要想使用grid里的扩展搜索功能,除了要引用ligerui主要的js文件外,还必须引入下面的JS文件: 1.Source\demos\filter\ligerGrid.showFilter.js 2. ...
- gdal中文路径无法打开问题
在C#中使用OGR读写矢量数据时,需要引用“using OSGeo.OGR;”. 同时为了处理中文路径和中文字段,需要在开始设置下面两个属性,代码如下: //为了支持中文路径,请添加下面这句代码(大多 ...
- OC - 4.OC核心语法
一.点语法 1> 基本使用 点语法本质上是set方法/get方法的调用 2> 使用注意 若出现在赋值操作符的右边,在执行时会转换成get方法 若出现在赋值操作符的左边,在执行时会转换成se ...
- Content by query webpart 自定义样式的使用方法
今天研究一个非常实用的webpart 如果在office365 上 的webpart中一直没“内容查询”, 这里需要开启2个features:http://community.office365.co ...