C ++中EOF的无限循环

时间:2009-10-21 02:59:42

标签: c++ eof cin std

此代码大部分都可以正常工作,即提示用户输入单个字符,执行相关操作,提示用户按返回,然后重复。但是,当我在提示符处输入^ 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并继续从该流中读取后清除流的相同原理

> a
you entered: a
> b
you entered: b
> ^D
you entered EOF
> c
you entered: c
...

7 个答案:

答案 0 :(得分:3)

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

此外,您在提示输出中使用std::endl,这是没有意义的。 std::endl打印\n然后刷新缓冲区,然后立即打印更多字符,以便刷新多余。由于cincout(通常)绑定,调用std::cin的输入函数会导致std::cout在任何情况下都被刷新,所以你也可以将\n放入提示字符串中,并保存在详细的额外<<运算符上。

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

通过这种方式,您可以摆脱真实而明确的突破。

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();
    }
}

答案 1 :(得分: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)
}

答案 2 :(得分:0)

您需要清除标记,以便在遇到EOF后让流做很多事情。

答案 3 :(得分:0)

呃,我可能会遗漏一些东西,但我从未见过break循环中的while (true)

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

如上所述,您需要确保流未处于错误状态。我会改变条件使用good()。不要只检查EOF,因为除了EOF之外,流有几种方式变得“坏”。

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

答案 6 :(得分:0)

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');

}