(转)关于fflush(stdin)清空输入缓存流(C/C++)
来源:http://my.oschina.net/deanzhao/blog/79790
1. 为什么 fflush(stdin) 是错的?
首先请看以下程序:
#include <stdio.h>
int main( void )
{
int i;
for (;;)
{
fputs("Please input an integer: ", stdout);
scanf("%d", &i);
printf("%d\n", i);
}
return 0;
}
这个程序首先会提示用户输入一个整数,然后等待用户输入,如果用户输入的是整数,
程序会输出刚才输入的整数,并且再次提示用户输入一个整数,然后等待用户 输入。
但是一旦用户输入的不是整数(如小数或者字母),假设 scanf 函数最后一次得到的整数是 2 ,
那么程序会不停地输出“Please input an integer: 2”。
这是因为 scanf("%d", &i); 只能接受整数,如果用户输入了字母,则这个字母会遗留在“输入缓冲区”中。
因为缓冲中有数据,故而 scanf 函数不会等待用户输入,直接就去缓冲中读取,可是缓冲中的却是字母,
这个字母再次被遗留在缓冲中,如此反复,从而导致不停地输出“Please input an integer: 2”。
也许有人会说:“居然这样,那么在 scanf 函数后面加上‘fflush(stdin);’,把输入缓冲清空掉不就行了?”
然而这是错的!
C和C++的标准里从来没有定义过 fflush(stdin)。
也许有人会说:“可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?”
的确,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,
但是并非所有编译器都要支持这个功能(linux 下的 gcc 就不支持),
因为标准中根本没有定义 fflush(stdin)。
MSDN 文档里 也清楚地写着
fflush on input stream is an extension to the C standard(fflush 操作输入流是对 C 标准的扩充)。
当然,如果你毫不在乎程序的移植性,用 fflush(stdin) 也没什么大问题。
以下是 C99 对 fflush 函数的定义:
int fflush(FILE *stream);
如果 stream 指向输出流或者更新流(update stream),
并且这个更新流最近执行的操作不是输入,
那么 fflush 函数将把这个流中任何待写数据传送至宿主环境(host environment)写入文件。
否则,它的行为是未定义的。
原文如下:
int fflush(FILE *stream);
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.
其中,宿主环境可以理解为操作系统或内核等。
由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用 fflush(stdin) 是不正确的,至少是移植性不好的。
2. 清空输入缓冲区的方法
虽然不可以用 fflush(stdin),但是我们可以自己写代码来清空输入缓冲区。只需要在 scanf 函数后面加上几句简单的代码就可以了。
/* C 版本 */
#include <stdio.h>
int main( void )
{
int i, c;
for ( ; ; )
{
fputs("Please input an integer: ", stdout);
scanf("%d", &i);
if ( feof(stdin) || ferror(stdin) )
{ /* 如果用户输入文件结束标志(或文件已被读完), */
/* 或者发生读写错误,则退出循环 */
/* do something */
break;
}
/* 没有发生错误,清空输入流。 */
/* 通过 while 循环把输入流中的余留数据“吃”掉 */
while ( (c = getchar()) != '\n' && c != EOF ) ; /*可直接将这句代码当成fflush(stdio)的替代,直接运行可清除输入缓存流*/
/* 使用 scanf("%*[^\n]"); 也可以清空输入流, */
/* 不过会残留 \n 字符。 */
printf("%d\n", i);
}
return 0;
}
/* C++ 版本 */
#include <iostream>
#include <limits> // 为了使用numeric_limits
using std::cout;
using std::endl;
using std::cin;
using std::numeric_limits;
using std::streamsize;
int main()
{
int value;
for ( ; ; )
{
cout << "Enter an integer: ";
cin >> value;
if ( cin.eof() || cin.bad() )
{ // 如果用户输入文件结束标志(或文件已被读完),
// 或者发生读写错误,则退出循环
// do something
break;
}
// 读到非法字符后,输入流将处于出错状态,
// 为了继续获取输入,首先要调用 clear 函数
// 来清除输入流的错误标记,然后才能调用
// ignore 函数来清除输入流中的数据。
cin.clear();
// numeric_limits<streamsize>::max() 返回输入缓冲的大小。
// ignore 函数在此将把输入流中的数据清空。
// 这两个函数的具体用法请读者自行查询。
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
cout << value << '\n';
}
return 0;
}
参考资料:
ISO/IEC 9899:1999 (E) Programming languages— C 7.19.5.2 The fflush function
The C Programming Language 2nd Edition By Kernighan & Ritchie
ISO/IEC 14882(1998-9-01)Programming languages — C++
本文版权归 蚂蚁的 C/C++ 标准编程 以及 作者 antigloss 共同所有,转载请注明原作者和出处。谢谢。
(转)关于fflush(stdin)清空输入缓存流(C/C++)的更多相关文章
- C语言清空输入缓冲区的N种方法对比
转自C语言清空输入缓冲区的N种方法对比 C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int get ...
- C语言清空输入缓冲区的N种方法对比【转】
转自:http://www.cnblogs.com/codingmylife/archive/2010/04/18/1714954.html C语言中有几个基本输入函数: //获取字符系列 int f ...
- [转][修]C清空输入缓冲区
为何要清空输入缓存区 读取时输入缓冲区中的内容会被scanf函数逐个取走,正常case下scanf()函数可以根据返回值判断成功取走的数目:但当发生读取异常之后,输入缓冲区中的内容并未被取走, ...
- C语言清空输入缓冲区的N种方法对比(转)
C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void); //获取行系列 ...
- C 清空输入缓冲区,以及fflush(stdin)的使用误区和解决方法
转载:https://blog.csdn.net/Veniversum/article/details/62048870 对C 语言初学者来说,fflush(stdin)函数被解释为会清空输入缓冲区的 ...
- fflush(stdin)的对错?
C和C++的标准里从来没有定义过 fflush(stdin).也许有人会说:"可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?"的确,某些编译器(如VC6 ...
- linux下fflush(stdin)的使用问题
参考自linux下如何清空(刷新)stdin缓冲区 首先,fflush在C/C++/POSIX标准中只定义了处理输出流的行为,对于像stdin这种输入流,这是未定义行为undefined behavi ...
- fflush(stdin)与fflush(stdout)
1.fflush(stdin): 作用:清理标准输入流,把多余的未被保存的数据丢掉.. 如: int main() { int num; char str[10]; cin>>num; c ...
- C语言清空输入缓冲区
来源:http://blog.csdn.net/guanyasu/article/details/53153705 https://zhidao.baidu.com/question/5241738. ...
随机推荐
- Smarty小结提纲
Smarty:模板技术 实现功能:前后分离. 原理:主要通过Smarty核心类实现,调用display方法,将模板文件读取,用正则进行替换,替换完保存到临时文件,将临时文件加载到当前页面. 配置文件( ...
- http之状态码含义
状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别: 1xx:指示信息--表示请求已接收,继续处理 2xx:成功--表示请求已被成功接收.理解.接受 3xx:重定向--要完成请求必须进行 ...
- Kylo 入坑记
一.概述 Kylo,作为一个基于 Spark 和 NiFi 的开源数据湖编排框架,解决对数据湖获取.治理.感知和技术支持等诸多问题.Kylo 将数据湖的很多功能自动化,包括数据接入.准备.分析发现.P ...
- 2018 Multi-University Training Contest 6 Solution
A - oval-and-rectangle 题意:给出一个椭圆的a 和 b,在$[0, b]中随机选择c$ 使得四个顶点在椭圆上构成一个矩形,求矩形周长期望 思路:求出每种矩形的周长,除以b(积分) ...
- JAVA构建高并发商城秒杀系统——架构分析
面试场景 我们打算组织一个并发一万人的秒杀活动,1元秒杀100个二手元牙刷,你给我说说解决方案. 秒杀/抢购业务场景 商品秒杀.商品抢购.群红包.抢优惠劵.抽奖....... 秒杀/抢购业务特点 秒杀 ...
- 20165207 预备作业3 Linux安装及学习
Linux安装及学习 假期我没有把我的电脑带回家,受到家里的台式机内存和网吧的一些条件的限制我只在台式机安装了32位系统然后学习了实验楼的Vim课程以及Linux的前八课. 问题与解决 安装过程 我家 ...
- Core Java 3
p270~p272 1.创建异常类. 步骤:1)定义一个派生于(继承)Exception或者其子类的类. 2)添加两个构造方法:一个是默认构造器,另一个是带有详细描述信息的构造器. import ja ...
- 20155201 2016-2017-2 《Java程序设计》第一周学习总结
20155201 2016-2017-2 <Java程序设计>第一周学习总结 教材学习内容总结 每一章的问题: 第一章 Java ME都有哪些成功的平台? 第二章 哪些情况可以使用impo ...
- 20162314 Experiment 3 - Sorting and Searching
Experiment report of Besti course:<Program Design & Data Structures> Class: 1623 Student N ...
- Rsync+sersync实现实时同步
介绍: sersync主要用于服务器同步,web镜像等功能.基于boost1.43.0,inotify api,rsync command.开发.目前使用的比较多的同步解决方案是inotify-too ...