本文摘自PHP中文网,作者php是最好的语言,侵删。
C语言中有几个基本输入函数:1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
这里仅讨论输入函数在标准输入(stdin)情况下的使用。纵观上述各输入函数,
获取字符系列的的前三个函数fgetc、getc、getchar。以getchar为例,将在stdin缓冲区为空时,等待输入,直到回车换行时函数返回。若stdin缓冲区不为空,getchar直接返回。getchar返回时从缓冲区中取出一个字符,并将其转换为int,返回此int值。
MINGW 4.4.3中FILE结构体源码:
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
各编译器实现可能不一样,这里获取字符系列函数只用到_ptr和_cnt。
MINGW 4.4.3中getchar()实现:
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
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。
=================分 割 线=================
提到缓冲区,就不得不提setbuf和setvbuf两个缓冲区设置函数,其声明如下:
1 |
|
1 |
|
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 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
问题是这样的:程序交回控制给操作系统之前C运行库必须进行清理工作,其中一部分是刷新输出缓冲,但是此时main函数已经运行完毕,buf缓冲区作用域在main函数中,此时buf字符数组已经释放,导致输出诡异乱码。
解决方案:可以将buf设置为static,或者全局变量,或者调用malloc来动态申请内存。
=================分 割 线=================
下面来看看几种流行的缓冲区清空方法:
fflush(stdin);式
由C99标准文档中:
1 |
|
1 |
|
1 |
|
1 |
|
可以看出fflush对输入流为参数的行为并未定义。但由MSDN上的fflush定义:
1 |
|
1 |
|
1 |
|
可以看出fflush(stdin)在VC上还是有效地!鉴于各编译器对fflush的未定义行为实现不一样,不推荐使用fflush(stdin)刷新输入缓冲区。
setbuf(stdin, NULL);式
由前面对setbuf函数的介绍,可以得知,setbuf(stdin, NULL);是使stdin输入流由默认缓冲区转为无缓冲区。都没有缓冲区了,当然缓冲区数据残留问题会解决。但这并不是我们想要的。
scanf("%*[^\n]");式(《C语言程序设计 现代方法 第二版》中提到)
这里用到了scanf格式化符中的“*”,即赋值屏蔽;“%[^集合]”,匹配不在集合中的任意字符序列。这也带来个问题,缓冲区中的换行符’\n’会留下来,需要额外操作来单独丢弃换行符。
经典式
1 |
|
1 |
|
由代码知,不停地使用getchar()获取缓冲区中字符,直到获取的字符c是换行符’\n’或者是文件结尾符EOF为止。这个方法可以完美清除输入缓冲区,并且具备可移植性。
相关文章:
禁止页面缓存的方法 多语言下禁止页面缓存
如何批量清理系统临时文件(语言:C#、 C/C++、 php 、python 、java )
相关视频:
C 语言教程
以上就是使用C语言怎样清空输入缓冲区?这里有多种方法值得借鉴的详细内容!
相关阅读 >>
更多相关阅读请进入《方法》频道 >>