首页 > 解决方案 > 在 freopen(..,"r",stdin) + fclose(stdin) 之后,进一步的 std::cin 不起作用

问题描述

int main(){

    int a,b;

    std::cin >> a >> b;           // first

    freopen("test.txt","r",stdin);
    std::cin >> a >> b;           // second
    fclose(stdin);
    cout << a << ", " << b << endl;

    freopen("test2.txt","r",stdin);
    std::cin >> a >> b;          // third
    fclose(stdin);
    cout << a << ", " << b << endl;

    std::cin >> a >> b;          // fourth

    return 0;
}

此代码块将混合来自终端和文件的输入。第一个、第二个和第三个 cin 工作正常,但第四个失败了。似乎 fclose(stdin) 在这里没有功能。

标签: c++filecinfclosefreopen

解决方案


根据c++ 草案 27.4.2

对象 cin 控制来自与对象 stdin 关联的流缓冲区的输入,该对象在 <cstdio> 中声明。

读取std::cin与读取相同stdin。这意味着fclose(stdin)使用后std::cin就像调用scanf("%d", &a).

这正是在第三种情况下发生的情况, where fclose(stdin)is called before reading std::cin。相比之下,代码读取的案例 1-3std::cin之前fclose(stdin).

从封闭stdin的读取可能是未定义的。以下是c11 草案对此的看法:

7.21.7.1 fgetc 函数

...

int fgetc(FILE *stream);

...

返回: 如果设置了流的文件结束指示符,或者如果流处于文件结束位置,则设置流的文件结束指示符并且 fgetc 函数返回 EOF。否则,fgetc 函数从 stream 指向的输入流中返回下一个字符。如果发生读取错误,则设置流的错误指示符并且 fgetc 函数返回 EOF。

本文涵盖了从打开的 stdin 读取的所有情况(成功、文件结束和读取错误),但它们不涉及流因fclose. 我在涵盖此案例的标准中找不到任何内容,这意味着该案例未定义。

结论std::cin:从after读取fclose(stdin),没有任何进一步freopen是未定义的行为。尝试读取已关闭的 C 流可能会引用已释放的资源。


推荐阅读