【问题标题】:Infinite loop on EOF in C++C ++中EOF的无限循环
【发布时间】:2009-10-21 02:59:42
【问题描述】:

此代码在大多数情况下按预期工作,即提示用户输入单个字符,执行相关操作,提示用户按回车键,然后重复。但是,当我在提示符下输入 ^D (EOF) 时,会发生无限循环。我正在通过 std::cin.clear() 清除错误状态并调用 std::cin.ignore(...) 来清除缓冲区。什么可能导致无限循环?

#include <iostream>
#include <limits>

void wait()
{
    std::cout << std::endl << "press enter to continue.";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.clear();
    std::cin.get();
}

int main()
{
    char response;

    while (true)
    {
        std::cout << "enter a character at the prompt." << std::endl << "> ";
        std::cin >> response;
        switch (response)
        {
            case 'q':
                exit(0);
                break;
        }
        wait();
    }
}

如果重要的话,我会在 Mac OS X 终端上运行它。


更新:我在这里真正要问的是,当用户在提示符下输入 EOF (^D) 时,我如何 (a) 检测它以及 ( b) 重置流,以便用户可以继续输入数据。

下面的示例与上面的代码不同,但说明了在检测到 ^D 后清除流并继续从该流中读取的相同原理.

>一个 你输入了: > 乙 你输入了:b > ^D 你输入了EOF > c 你输入了:c ...

【问题讨论】:

  • 你确定它是一个无限循环吗?您的代码中没有 while-for 语句。你调试了吗?
  • 谢谢,汤姆。我的代码中有一个循环,但忘记将它包含在这个 sn-p 中。
  • while(true) 导致无限循环。
  • +1。你似乎已经解决了你的问题

标签: c++ eof cin std


【解决方案1】:

在调用格式化提取操作后,您应该始终检查是否设置了任何流的失败标志,在您的示例中,您正在检查 response 而没有检查 response 是否被正确提取。

此外,您在提示输出中使用了std::endl,这没有任何意义。 std::endl 打印 \n 然后刷新缓冲区,但您随后会立即打印更多字符,因此刷新是多余的。由于cincout (通常)绑定,调用std::cin 的输入函数将导致std::cout 在任何情况下都被刷新,所以你不妨放一个\n进入您的提示字符串并保存在冗长的额外 &lt;&lt; 运算符上。

为什么不创建一个提示函数来打印提示,检索输入并返回对流的引用,以便您可以使用通常的流到布尔类型转换来测试它是否成功。

这样你就可以摆脱 while true 和明确的中断。

std::istream& prompt_for_input( std::istream& in, std::ostream& out, char& response )
{
    out << "enter a character at the prompt.\n> ";
    in >> response;
    return in;
}

int main()
{
    char response;

    while ( prompt_for_input( std::cin, std::cout, response ) && response != 'q' )
    {
        wait();
    }
}

【讨论】:

  • 感谢您的回答,但您的代码与我的问题相同。在用户输入 EOF (^D) 后,我需要继续循环。一旦我将 prompt_for_input 放入一个不受其返回值控制的循环中(例如,while(true)),我就会得到一个无限循环。
  • 基本上我想做的,(我意识到这不是我发布的,但它需要相同的功能)是读取用户输入的名称列表,每行一个,后跟 EOF (^D)。然后程序需要继续执行(例如,从 std::cin 读取),以便用户可以响应进一步的提示。
  • 在 EOF 之后尝试重新启动流只会给您带来完全相同的问题。如果流确实在末尾,您将无法从中读取任何内容。重置eofbit 并继续仅在非常有限的情况下有效。您说输入应该是“每行一个”,那么为什么还需要等待 EOF?
  • 我正在研究的一种情况是用户在多行上输入消息并在最后一行输入 ^D 以结束消息。
  • 您是说一旦读取 EOF 就无法重置 std::cin 吗?如果是这种情况,我可以通过另一个流或其他方式路由 std::cin 吗?
【解决方案2】:

这个问题对标准输入没有意义。在该流结束后,将很难从标准输入中读取某些内容——您必须以某种方式重新打开它,但没有办法重新打开标准输入。它可能连接到管道、文件或终端——没有适合所有这些的行为。

所以我想你会从终端显式读取。在 UN*X 系统上,这意味着读取 /dev/tty,并在需要时重新打开它。这是一个简单的例子;大多数错误检查被省略。

// Warning: UN*X-specific

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    for(unsigned i=0; ; i++) {
        ifstream tty("/dev/tty");
        if (! tty) {
            cerr << "Failed to open TTY" << endl;
            return 2;
        }
        string s;
        while (getline(tty,s))
            cout << i << ": " << s << endl;
    }
    return 0;   // (unreached)
}

【讨论】:

    【解决方案3】:

    您需要清除标志以使流在遇到 EOF 后执行大部分操作。

    【讨论】:

      【解决方案4】:

      呃,我可能遗漏了一些东西,但在 while (true) 循环之外我从未见过你 break

      // ...
      while (true) {
          if (std::cin.eof()) {
              break;
          }
          // ...
      }
      

      【讨论】:

      • 该代码未显示,因为它是(空)switch 语句的一部分。我想连续读取单个字符,然后是回车符(永远)。
      【解决方案5】:

      在读取 EOF 时,您只需忽略它并循环返回,而不退出循环,因此您将不断读取 EOF 并不断循环。如果你想在看到 EOF 时做一些事情,你需要在你的 switch 中或者之前处理它。

      也许您想在用户使用 ^D 关闭您的标准输入后从某处读取输入?在这种情况下,您必须关闭 cin 并重新打开它才能从您要读取输入的其他位置读取。

      【讨论】:

        【解决方案6】:

        如前所述,您需要确保流没有处于错误状态。我会更改 while 条件以使用 good()。不要只检查 EOF,因为除了 EOF 之外,流可以通过多种方式变得“坏”。

        while (std::cin.good()) {...
        

        【讨论】:

          【解决方案7】:
          while ((std::cout << "Enter a character at the prompt ")
                && (!(std::cin >> response) || response =='q')) {
           std::cout << "Not a valid input";
           std::cin.clear();
           std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          

          }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-03-05
            • 1970-01-01
            • 1970-01-01
            • 2013-07-31
            • 1970-01-01
            • 2013-02-22
            • 1970-01-01
            • 2017-08-19
            相关资源
            最近更新 更多