【问题标题】:After freopen(..,"r",stdin) + fclose(stdin), further std::cin doesn't work在 freopen(..,"r",stdin) + fclose(stdin) 之后,进一步的 std::cin 不起作用
【发布时间】:2019-03-21 02:45:40
【问题描述】:
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) 在这里没有作用。

【问题讨论】:

  • stdincin 通常是同一个文件。您如何期望在关闭文件后能够读取文件?
  • 类似于this question

标签: c++ file cin fclose freopen


【解决方案1】:

根据c++ draft 27.4.2

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

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

这正是第三种情况发生的情况,其中fclose(stdin) 在读取std::cin 之前被调用。相比之下,案例 1-3 的代码在 fclose(stdin) 之前读取 std::cin

从关闭的stdin 读取可能是未定义的。以下是c11 draft 对此的评价:

7.21.7.1 fgetc 函数

...

int fgetc(FILE *stream);

...

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

本文涵盖了从打开的标准输入中读取的所有情况(成功、文件结束和读取错误),但它们不涉及由于fclose 而关闭流的情况。我在标准中找不到任何涵盖这种情况的内容,这意味着该情况未定义。

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

【讨论】:

  • 非常感谢!但是经过我的小测试,我也可以得出这个结论。所以现在让我感到困惑的是如何让我的 std::cin 返回从终端接收单词。你知道如何实现吗?
  • @ysgc 你可以在开始saved_fd = strdup(0)之前保存原来的stdin描述符,当你最终需要恢复stdin时,你close(0)然后strdup(saved_fd)。但不要忘记清除任何 eof 和错误标志以及缓冲的数据。
  • 嗨迈克尔,我试过了:saved_fd = strdup(0);关闭(0);但是close函数没有定义,是否需要包含一些头文件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
  • 2017-08-05
相关资源
最近更新 更多