`
VincentZheng
  • 浏览: 52166 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

【转】C/C++ 误区二:fflush(stdin)

    博客分类:
  • C
 
阅读更多
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) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(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 版本 */
#include<stdio.h>

int main( void )
{
    int i, c;
    for (;;) {
        fputs("Please input an integer: ", stdout);
        if ( scanf("%d", &i) != EOF ) { /* 如果用户输入的不是 EOF */
            /* while循环会把输入缓冲中的残留字符清空 */
            /* 读者可以根据需要把它改成宏或者内联函数 */
            /* 注:C99中也定义了内联函数,gcc3.2支持 */
            while ( (c=getchar()) != '\n' && c != EOF ) {
                  ;
            } /* end of while */
        }
        printf("%d\n", i);
    }
    return 0;
}

/* C++ 版本 */
#include <iostream>
#include <limits>  // 为了使用numeric_limits

using std::cout;
using std::endl;
using std::cin;

int main( )
{
	int value;
	for (;;) {
		cout << "Enter an integer: ";
		cin >> value;
		/* 读到非法字符后,输入流将处于出错状态,
		 * 为了继续获取输入,首先要调用clear函数
		 * 来清除输入流的错误标记,然后才能调用
		 * ignore函数来清除输入缓冲区中的数据。 */          
		cin.clear( );
		/* numeric_limits<streamsize>::max( ) 返回缓冲区的大小。
		 * ignore 函数在此将把输入缓冲区中的数据清空。
		 * 这两个函数的具体用法请读者自行查询。 */
		cin.ignore( std::numeric_limits<std::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语言难点分析整理

    68. C/C++ 误区二:fflush(stdin) 376 69. C/C++ 误区三:强制转换 malloc() 的返回值 380 70. C/C++ 误区四:char c = getchar(); 381 71. C/C++ 误区五:检查 new 的返回值 383 72. C 是 C++ 的子集吗? 384 73. C...

    C/C++/VC++文件操作

    在C/C++编程中,文件操作是至关重要的,它允许我们与磁盘上的文件进行交互,包括读取、写入和处理数据。本篇将详细解释如何在VC++环境中使用MFC实现文件的读取与写入,以及可能遇到的问题。 1. **文件的读取**: -...

    C/C++ 拳皇争霸

    fflush(stdin); gets(name); if(Checktoseek(name)==-1) { strcpy(player[n].name,name); player[n].Hp=rand()%1000; player[n].AP=rand()%(100+1)+50; player[n].Dp=rand()%(10-5+2)+5; player[n].Rp...

    C、C++函数集(速查).pdf

    标题:“C、C++函数集(速查).pdf”描述:“C、C++函数集(速查).pdf”标签:“技术及资料”内容:(2^exp)1.10atan1.11atan2x/yxxx/yx0.512^exp101.27powxy__isasciiASCII***.**.**.**.**.**.**.**.**.9_chgsign_...

    C/C++实现控制台输出不同颜色字体的方法

    C/C++实现控制台输出不同颜色字体的方法 C/C++实现控制台输出不同颜色字体的方法是指在控制台中输出不同颜色的文字,以达到美化控制台输出的效果。这种方法在实际应用中非常有用,例如,在命令行界面中输出不同颜色...

    免费下载:C语言难点分析整理.doc

    C/C++ 误区二:fflush(stdin) 这部分解释了`fflush(stdin)`的不正确使用。 ### 69. C/C++ 误区三:强制转换 malloc() 的返回值 这部分解释了为什么不应该强制转换`malloc()`的返回值。 ### 70. C/C++ 误区四:...

    C标准库源代码(学习C/C++必备)

    C标准库源代码\FFLUSH.C C标准库源代码\FGETC.C C标准库源代码\FGETCHAR.C C 标准库源代码\FGETPOS.C C标准库源代码\FGETS.C C标准库源代码\FGETWC.C C标准库源代码\FGETWCHR.C C标准库源代码\FGETWS.C C标准库源...

    教师管理系统(c/c++)

    fflush(stdin);//清空缓存,以便不影响后面的输入 scanf("%d",&i); fflush(stdin); if(i==0) { printf("是否保存更改?1:是 0:否\t"); scanf("%d",&s); fflush(stdin); if(s==1) save(); exit(0); } ...

    c/c++文件操作,包括MFC的文件操作

    通过以上详细的介绍,我们可以看到C/C++中文件操作的各种方式,从标准C语言到C++流式操作,再到Win32 API以及MFC框架下的文件操作,每种方法都有其适用场景和特点。开发者可以根据实际需求选择最合适的方法来进行...

    高级C语言 学完C语言来看这个绝对收获

    C/C++误区二:fflush(stdin) `fflush(stdin)`通常用于清除标准输入流,但这并不是标准C/C++的一部分。 #### 65. C/C++误区三:强制转换malloc()的返回值 强制类型转换`malloc()`的返回值可能会导致类型不匹配的...

    Linux c function

    在Linux系统中,C语言是核心开发语言,它提供了丰富的函数库来支持各种操作。本文将深入探讨Linux C函数,包括文件操作、进程控制、内存管理、网络编程等多个方面,帮助开发者更好地理解和运用这些功能。 1. **文件...

    c/c++函数库说明(api)html版

    所有的 C / C++ 函数 Constructors (cppstring) Constructors (cppvector) Operators (cppbitset) Operators (cppdeque) Operators (cppstack) Operators (cppstring) Operators (cppvector) abort (stdother...

    C语言课程设计报告-购物系统设计.docx

    - 输入处理时使用 `fflush(stdin)` 清空输入缓冲区,避免输入错误。 - **用户注册验证**: - 循环读取用户输入的信息,并检查用户名是否已被注册。 - 如果用户名已经存在,提示用户重新输入;如果用户名可用,...

    Linux系统编程学习笔记

    #### 二、文件系统 - **目录和文件**: 包括文件属性的查询 (`stat`)、文件类型和权限的设置 (`chmod`)、文件系统的类型 (`FAT`, `UFS`) 以及目录操作 (`mkdir`, `rmdir`, `opendir`, `readdir`, `closedir`)。 - *...

    关于fflush关于fflush关于fflush关于fflush

    C 和 C++ 的标准中从来没有定义过 fflush(stdin)。虽然某些编译器(如 VC6)支持使用 fflush(stdin) 来清空输入缓冲,但并不是所有编译器都支持这个功能(gcc3.2 不支持),因为标准中根本没有定义 fflush(stdin)。 ...

    sdcard.rar_文件操作_C/C++_

    在C/C++编程中,文件操作是至关重要的一个部分,特别是在涉及到存储和处理大量数据时。"sdcard.rar"这个压缩包显然包含了与SD卡相关的源代码,这可能包括读取、写入、创建、删除以及移动文件等功能。在本文中,我们...

    C库函数0[文].pdf

    C库函数是C语言编程中不可或缺的部分,它们提供了一系列用于处理文件、输入输出、字符串操作、数学计算等任务的功能。以下是一些关键的C库函数的详细解释: 1. 文件操作函数: - `fopen`: 用指定的模式(如"r","w...

    c语言版汇款系统c语言学习后整合的小项目

    fflush(stdin); switch (choice) { case 0: exit(0); case 1: // 存款 break; case 2: // 取款 break; case 3: // 查询 break; case 4: // 开户 break; case 5: // 销户 break; default: ...

    53-2按键加减操作.rar_C/C++_

    在C和C++编程中,按键交互通常是通过标准输入(stdin)或者图形用户界面(GUI)库来处理的。这个项目可能涉及到以下几个关键知识点: 1. **键盘输入处理**:在命令行环境中,C和C++通常使用`scanf`或`getchar`函数...

Global site tag (gtag.js) - Google Analytics