fflush(stdin)使用的问题

为什么 fflush(stdin) 是错的

首先请看以下程序:

                  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. int main( void )  
  3. {  
  4.     int i;  
  5.     for (;;)   
  6.     {  
  7.         fputs("Please input an integer: ", stdout);  
  8.         scanf("%d", &i);  
  9.         printf("%d\n", i);  
  10.     }  
  11.     return 0;  
  12. }  

这个程序首先会提示用户输入一个整数,然后等待用户输入,如果用户输入的是整数,程序会输出刚才输入的整数,并且再次提示用户输入一个整数,然后等待用户输入。但是一旦用户输入的不是整数(如小数或者字母),假设 scanf 函数最后一次得到的整数是 2 ,那么程序会不停地输出“Please input an integer: 2”。这是因为 scanf("%d", &i); 只能接受整数,如果用户输入了字母,则这个字母会遗留在“输入缓冲区”中。因为缓冲中有数据,故而 scanf 函数不会等待用户输入,直接就去缓冲中读取,可是缓冲中的却是字母,这个字母再次被遗留在缓冲中,如此反复,从而导致不停地输出“Please input an integer: 2”。

也许有人会说:“居然这样,那么在 scanf 函数后面加上‘fflush(stdin);’,把输入缓冲清空掉不就行了?”然而这是错的!CC++标准里从来没有定义过 fflush(stdin)。也许有人会说:“可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?”的确,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(gcc3.2不支持),因为标准中根本没有定义 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函数将把任何未被写入的数据写入stream
指向的文件(如标准输出文件stdout)。否则,fflush函数的行为是不确定的。
fflush(NULL)清空所有输出流和上面提到的更新流。如果发生写错误,fflush
函数会给那些流打上错误标记,并且返回EOF,否则返回0。

由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用
fflush(stdin) 是不正确的,至少是移植性不好的。

2.       清空输入缓冲区的方法

虽然不可以用 fflush(stdin),但是我们可以自己写代码来清空输入缓冲区。只需要在 scanf 函数后面加上几句简单的代码就可以了。

              /* C 版本 */

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. int main( void )  
  3. {  
  4.     int i, c;  
  5.     for (;;)   
  6.     {  
  7.         fputs("Please input an integer: ", stdout);  
  8.         if ( scanf("%d", &i) != EOF ) { /* 如果用户输入的不是 EOF */  
  9.             /* while循环会把输入缓冲中的残留字符清空 */  
  10.             /* 读者可以根据需要把它改成宏或者内联函数 */  
  11.             /* 注:C99中也定义了内联函数,gcc3.2支持 */  
  12.             while ( (c=getchar()) != '\n' && c != EOF ) {  
  13.                   ;  
  14.             } /* end of while */  
  15.         }  
  16.         printf("%d\n", i);  
  17.     }  
  18.     return 0;  
  19. }  

/* C++ 版本 */

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <iostream>  
  2. #include <limits> // 为了使用numeric_limits  
  3. using std::cout;  
  4. using std::endl;  
  5. using std::cin;  
  6. int main( )  
  7. {  
  8.        int value;  
  9.        for (;;)   
  10.       {  
  11.               cout << "Enter an integer: ";  
  12.               cin >> value;  
  13.              /* 读到非法字符后,输入流将处于出错状态, 
  14.               * 为了继续获取输入,首先要调用clear函数 
  15.               * 来清除输入流的错误标记,然后才能调用 
  16.               * ignore函数来清除输入缓冲区中的数据。 */            
  17.               cin.clear( );  
  18.               /* numeric_limits<streamsize>::max( ) 返回缓冲区的大小。 
  19.                * ignore 函数在此将把输入缓冲区中的数据清空。 
  20.        * 这两个函数的具体用法请读者自行查询。 */  
  21.               cin.ignore( std::numeric_limits<std::streamsize>::max( ), '\n' );  
  22.               cout << value << '\n';  
  23.        }  
  24.        return 0;  
  25. }  

参考资料

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++

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值