来源: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++)的更多相关文章

  1. C语言清空输入缓冲区的N种方法对比

    转自C语言清空输入缓冲区的N种方法对比 C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int get ...

  2. C语言清空输入缓冲区的N种方法对比【转】

    转自:http://www.cnblogs.com/codingmylife/archive/2010/04/18/1714954.html C语言中有几个基本输入函数: //获取字符系列 int f ...

  3. [转][修]C清空输入缓冲区

    为何要清空输入缓存区     读取时输入缓冲区中的内容会被scanf函数逐个取走,正常case下scanf()函数可以根据返回值判断成功取走的数目:但当发生读取异常之后,输入缓冲区中的内容并未被取走, ...

  4. C语言清空输入缓冲区的N种方法对比(转)

    C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void); //获取行系列 ...

  5. C 清空输入缓冲区,以及fflush(stdin)的使用误区和解决方法

    转载:https://blog.csdn.net/Veniversum/article/details/62048870 对C 语言初学者来说,fflush(stdin)函数被解释为会清空输入缓冲区的 ...

  6. fflush(stdin)的对错?

    C和C++的标准里从来没有定义过 fflush(stdin).也许有人会说:"可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?"的确,某些编译器(如VC6 ...

  7. linux下fflush(stdin)的使用问题

    参考自linux下如何清空(刷新)stdin缓冲区 首先,fflush在C/C++/POSIX标准中只定义了处理输出流的行为,对于像stdin这种输入流,这是未定义行为undefined behavi ...

  8. fflush(stdin)与fflush(stdout)

    1.fflush(stdin): 作用:清理标准输入流,把多余的未被保存的数据丢掉.. 如: int main() { int num; char str[10]; cin>>num; c ...

  9. C语言清空输入缓冲区

    来源:http://blog.csdn.net/guanyasu/article/details/53153705 https://zhidao.baidu.com/question/5241738. ...

随机推荐

  1. 转载Liferay PortletPreference store()方法研究

    我们对于PortletPreference 的store()用的非常广泛,很多情况下,我们一般对其进行一些设定,然后最后调用store()存储之,类似以下代码: PortletPreferences ...

  2. Hadoop 编写WordCount

    本文发表于本人博客. 前面几次讲了关于Hadoop的环境搭建.HDFS操作,今天接着继续.本来Hadoop源码中就有一个例子WordCount,但是今天我们来自己实现一个加深对这个Mapper.Red ...

  3. uva1292 树形dp

    这题说的是给了一个n个节点的一棵树,然后 你 从 这 棵 树 的 n 个 节点中 选择 尽量少的 点使得 每条边都至少有一个 士兵看守 dp[0][i]+=dp[1][j] dp[1][i]+=min ...

  4. 如何有规律的备份 WordPress 博客(转)

    转自:http://blog.wpjam.com/m/backup-your-blog-regularly/   我们都知道备份 WordPress 博客应该是规律性的操作,但是事实上往往我们都会因为 ...

  5. bzoj1602 / P2912 [USACO08OCT]牧场散步Pasture Walking(倍增lca)

    P2912 [USACO08OCT]牧场散步Pasture Walking 求树上两点间路径--->lca 使用倍增处理lca(树剖多长鸭) #include<iostream> # ...

  6. Linux 中各个文件夹的作用

    /  根目录 包含了几乎所的文件目录.相当于中央系统.进入的最简单方法是:cd /. /boot  引导程序,内核等存放的目录 这个目录,包括了在引导过程中所必需的文件.在最开始的启动阶段,通过引导程 ...

  7. POJ 2115 C Looooops(模线性方程)

    http://poj.org/problem?id=2115 题意: 给你一个变量,变量初始值a,终止值b,每循环一遍加c,问一共循环几遍终止,结果mod2^k.如果无法终止则输出FOREVER. 思 ...

  8. 爬虫模拟登陆之formdata表单数据

    首先HTTP协议是个无连接的协议,浏览器和服务器之间是以循环往复的请求回复来交互的,交互的形式是以文件形式来进行的.比如在chrome开发者工具network中看到了 每一行是一个文件,又文件大小啊, ...

  9. Hardcoded string should use @string resource 警告

    在布局文件中,文本的设置使用如下写法时会有警告:Hardcoded string "下一步", should use @string resource <Button and ...

  10. QWebEngineView_CssVariables

    1.测试代码,参考网址:http://blog.sina.com.cn/s/blog_1508519340102wgq0.html 2.测试下来,结果: 2.1.Qt5.6开始,没有 WebKit了. ...