freopen()函数文件流重定向和文件流的清除

来源:互联网 发布:sql万能钥匙 编辑:程序博客网 时间:2024/05/16 10:18
http://blog.csdn.net/pipisorry/article/details/38727087
调试往往不能一次成功,每次运行时,都要重新输入一遍测试数据,对于有大量输入数据的题目,输入数据需要花费大量时间。 使用freopen函数可以解决测试数据输入问题,避免重复输入函数名:freopen 声明:FILE *freopen( const char *path, const char *mode, FILE *stream ); 所在文件: stdio.h 参数说明: path: 文件名,用于存储输入输出的自定义文件名。 mode: 文件打开的模式。stream: 一个文件,通常使用标准流文件。 返回值:成功,则返回一个path所指定文件的指针;失败,返回NULL。(一般可以不使用它的返回值) 功能:实现重定向,把预定义的标准流文件定向到由path指定的文件中。
标准流文件具体是指stdin、stdout和stderr。其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。
VC下调试“计算a+b”的程序举例。 C语法: 
<pre name="code" class="cpp">#include <stdio.h> int main() { int a,b; freopen("debug\\in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取 freopen("debug\\out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中 while(scanf("%d %d",&a,&b)!=EOF) printf("%d\n",a+b); fclose(stdin);//关闭文件 fclose(stdout);//关闭文件 return 0; }





C++语法 
#include <stdio.h> #include <iostream.h> int main() { int a,b; freopen("debug\\in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取 freopen("debug\\out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中 while(cin>>a>>b) cout<<a+b<<endl; // 注意使用endl fclose(stdin);//关闭文件 fclose(stdout);//关闭文件 return 0; } 

 freopen("debug\\in.txt","r",stdin)的作用就是把标准输入流stdin重定向到debug\\in.txt文件中,这样在用scanf或是用cin输入时便不会从标准输入流读取数据,而是从in.txt文件中获取输入。只要把输入数据事先粘贴到in.txt,调试时就方便多了。 类似的,freopen("debug\\out.txt","w",stdout)的作用就是把stdout重定向到debug\\out.txt文件中,这样输出结果需要打开out.txt文件查看。         需要说明的是:         1. 在freopen("debug\\in.txt","r",stdin)中,将输入文件in.txt放在文件夹debug中,文件夹debug是在VC中建立工程文件时自动生成的调试文件夹。如果改成freopen("in.txt","r",stdin),则in.txt文件将放在所建立的工程文件夹下。in.txt文件也可以放在其他的文件夹下,所在路径写正确即可。         2. 可以不使用输出重定向,仍然在控制台查看输出。         3. 程序调试成功后,提交到oj时不要忘记把与重定向有关的语句删除。
1.为什么 fflush(stdin) 是错的
<pre name="code" class="cpp">#include <stdio.h>int main( ){    int i;    while(1){        fputs("Please input an integer: ", stdout);        scanf("%d", &i);//fflush(stdin);        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( ){int i, c;while(1){fputs("Please input an integer: ", stdout);scanf("%d", &i);if ( feof(stdin) || ferror(stdin) ){ /* 如果用户输入文件结束标志(或文件已被读完),或者发生读写错误,则退出循环 *//* do something */break; }/* 没有发生错误,清空输入流,通过 while 循环把输入流中的余留数据“吃”掉 */while ( (c = getchar()) != '\n' && c != EOF ) ;/* 使用 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;          while(1) {                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;        }


from:

http://blog.csdn.net/pipisorry/article/details/38727087

ref:

http://blog.163.com/anby1314125@126/blog/static/288754042008717102648440

http://www.cnblogs.com/moonlit/archive/2011/06/12/2078712.html


1 0