C++ 中 EOF 的无限循环

发布于 2024-08-07 22:41:31 字数 1108 浏览 13 评论 0原文

此代码在大多数情况下按预期工作,即提示用户输入单个字符,执行关联的操作,提示用户按回车键,然后重复。但是,当我在提示符下输入 ^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
...

This code works as desired for the most part, which is to prompt the user for a single character, perform the associated action, prompt the user to press return, and repeat. However, when I enter ^D (EOF) at the prompt, an infinite loop occurs. I am clearing the error state via std::cin.clear() and calling std::cin.ignore(...) to clear the buffer. What could be causing the infinite loop?

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

I am running this in the Mac OS X terminal, if it matters.


UPDATE: What I am really asking here is, when the user enters EOF (^D) at the prompt, how do I (a) detect it and (b) reset the stream so that the user can continue to enter data.

The following example is different from the code above, but illustrates the same principle of clearing the stream after a ^D has been detected and continuing to read from that stream.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

别念他 2024-08-14 22:41:31

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

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

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

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

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

You should always check whether any of a stream's failure flags are set after calling formatted extraction operation, in your example you are checking response without checking whether response was correctly extracted.

Also, you are using std::endl in your prompt output where it doesn't make sense. std::endl prints \n and then flushes the buffer, but you then immediately print more characters so the flush is redundant. As cin and cout are (usually) tied, calling an input function for std::cin will cause std::cout to be flushed in any case so you may as well put a \n into your prompt string and save on the verbose extra << operators.

Why not make a prompting function that prints the prompt, retrieves the input an returns a reference to the stream so that you can test it for success using the usual stream to boolean type conversion.

This way you can get rid of the while true and explicit break.

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();
    }
}
何时共饮酒 2024-08-14 22:41:31

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

所以我想你会从终端明确地阅读。在 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)
}

The question does not really make sense for standard input. It will be hard to read something from standard input after that stream has ended -- you'll have to re-open it somehow, but there is no way to re-open standard input. It might be connected to a pipe, or to a file, or to a terminal -- and there's no behaviour suitable for all of these.

So you're going to be reading explicitly from the terminal, I assume. On UN*X systems, that means reading /dev/tty, and re-opening it when needed. Here's a simple example that does it; most error-checking omitted.

// 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)
}
℡Ms空城旧梦 2024-08-14 22:41:31

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

You'll need to clear the flags to get the stream to do much of anything after it encounters EOF.

挽梦忆笙歌 2024-08-14 22:41:31

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

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

Err, I may be missing something, but I don't ever see you break out of the while (true) loop.

// ...
while (true) {
    if (std::cin.eof()) {
        break;
    }
    // ...
}
绮筵 2024-08-14 22:41:31

读取 EOF 后,您只需忽略它并循环返回,而不退出循环,因此您将不断读取 EOF 并不断循环。如果您想在看到 EOF 时执行某些操作,则需要在 switch 中或之前处理它。

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

Upon reading an EOF, you just ignore it and loop back, without exiting the loop, so you'll continually read the EOF and continually loop. If you want to do something on seeing an EOF, you need to handle it either in your switch or before.

Perhaps you want to read input from somewhere after the user has closed your stdin with ^D? In that case, you'll have to close cin and reopen it to read from the other place you want to read input from.

如果没有你 2024-08-14 22:41:31

如前所述,您需要确保流状态良好。我会改变 while 条件以使用 good()。不要只检查 EOF,因为除了 EOF 之外,流还有多种方式可能变得“糟糕”。

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

As mentioned, you need to make sure the stream is not in a bad state. I would change while condition to use good(). Don't just check EOF as there are several ways a stream can become "bad" other than EOF.

while (std::cin.good()) {...
我们只是彼此的过ke 2024-08-14 22:41:31
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');

}

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

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文