代码之家  ›  专栏  ›  技术社区  ›  titaniumdecoy Mr. T

C++中EOF的无限循环

  •  1
  • titaniumdecoy Mr. T  · 技术社区  · 16 年前

    这段代码在大多数情况下都是按需要工作的,即提示用户输入单个字符,执行相关操作,提示用户按回车键,然后重复。但是,当我在提示下输入^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();
        }
    }

    我在MacOSX终端上运行这个,如果它很重要的话。


    更新: 我真正想问的是, 当用户在提示下输入eof(^d)时 ,如何(a)检测它和(b)重置流,以便用户可以继续输入数据。

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

    > a
    you entered: a
    > b
    you entered: b
    > ^D
    you entered EOF
    > c
    you entered: c
    ...
    7 回复  |  直到 16 年前
        1
  •  3
  •   CB Bailey    16 年前

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

    另外,您正在使用 std::endl 在提示输出中,它没有意义。 STD::Endol 印刷品 \n 然后刷新缓冲区,但随后立即打印更多字符,因此刷新是多余的。AS cin 和 cout (通常) 捆绑 ,为调用输入函数 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();
        }
    }
    
        2
  •  2
  •   ariels    16 年前

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

    我想,你将要从终端上明确地阅读。在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
  •  0
  •   Jerry Coffin    16 年前

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

        4
  •  0
  •   Bernard    16 年前

    嗯,我可能错过了什么,但我从来没见过你 break 走出 while (true) 循环。

    // ...
    while (true) {
        if (std::cin.eof()) {
            break;
        }
        // ...
    }
    
        5
  •  0
  •   Chris Dodd    16 年前

    在读取一个EOF时,您只需忽略它并循环返回,而不退出循环,因此您将继续读取EOF并继续循环。如果你想在看到一个EOF时做些什么,你需要在你的开关或者之前处理它。

    也许您想在用户用^d关闭stdin后从某个地方读取输入?在这种情况下,您必须关闭CIN并重新打开它,才能从另一个您想要读取输入的地方读取。

        6
  •  0
  •   jmucchiello    16 年前

    如前所述,您需要确保流没有处于错误状态。我会改变使用good()的条件。不要只是检查eof,因为有几种方法可以使流变得“坏”而不是eof。

    while (std::cin.good()) {...
    
        7
  •  0
  •   navigator    16 年前
    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');
    

    }