另一个C CIN循环问题

Yet another C++ cin loop issue

本文关键字:问题 循环 CIN 另一个      更新时间:2023-10-16

update

我发现了问题的原因。我一直在尝试鱼壳。我看到的评论说有人已经在Mac上成功运行了我的代码,并决定在标准的bash壳中尝试。它运作完美。所以,我猜没有更多的鱼壳。:)

我仍然很感激知道CIN如何以及为什么按照自己的方式工作。这是我问题的主要部分。


我遇到了一个流行的问题:在循环中使用cin。该代码很简单,但是我找不到解决方案。Google为我提供的答案有所不同,但通常涉及cin.clear()cin.ignore()cin.get()的某种组合。不幸的是,我找不到解决问题的组合或订购。此外,我感到沮丧的是,我对cin的功能没有完全的了解。我宁愿不使用反复试验来解决此问题。我想确切了解发生了什么。

应该发生什么

运行代码时,我应该看到一个带有选项列表的提示。我应该能够输入一个可以运行其中一个选项的字符。然后,它应该再次显示提示,然后重复该过程,直到我选择 exit 选项。

实际发生了什么

我一旦运行代码,它就会将提示打印到屏幕上的任意次数,并最终在提示的一半停止。然后,我什么也没做任何事情,只用^C杀死它。

$ ./run
Choose an option:
[A]dd a score
[R]emove a player
[E]xit
    : That is not a valid input.
[repeated a bunch of times]
Choose an option:
[A]dd a score
[R]emove a player
[E]xit
    : That is not a valid input.

Choose ^C
$ 

我的问题

是什么导致CIN做到这一点?作为经验丰富的Java开发人员(但是初学者C 开发人员),我熟悉缓冲区和流的概念,但我不知道cin是如何工作的。我知道cin.clear()清除了错误状态,cin.ignore()忽略了流中的许多字符。到目前为止,我的Google-Fu无法找到简洁的参考。

cin为什么以其方式行动?在循环中使用cin时,如何可视化引擎盖下会发生什么?在C 中实现此无限菜单想法的最优雅方法是什么?

我的代码

这是我的代码的简化版本,它与完整版本完全相同:

#include <iostream>
using namespace std;
int main () {
    //infinite menu 
    char input;
    while(true) {
        //prompt
        cout << "nnChoose an option:n";
        cout << "[A]dd a scoren";
        cout << "[R]emove a playern";
        cout << "[E]xitn";
        cout << "nt: ";
        //input
        cin >> input;
        //decide what the input means
        switch(input) {
            case 'a':
            case 'A':
                cout << "Add a score.n";
                break;
            case 'r':
            case 'R':
                cout << "Remove a player.n";
                break;
            case 'e':
            case 'E':
                cout << "Program Complete.n";
                return 0;
                break;
            default:
                cout << "That is not a valid input.n";
        }
    }
    return 0;
}

我编译并运行:

$ g++ Test.cpp -o run
$ ./run

我在Mac OS X 10.8.2上运行gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)

帮自己一个忙,不要直接从std::cin提取令牌。而是用getline逐行读取行,然后解释每行。另外,您必须始终在布尔上下文中评估输入操作的结果,否则您将无法正确处理任意输入。

为了进行测试,如果您致电echo "abc" | ./run,则必须生存。这应该永远是您的第一个测试之一。

现在,按照代码:

#include <string>
#include <iostream>
int main()
{
    for (std::string line; std::getline(std::cin, line); )
    {
        if (line.empty()) { continue; }

        if (line == "A" || line == "a") { /* ... */ continue; }
        if (line == "R" || line == "r") { /* ... */ continue; }
        if (line == "E" || line == "e") { break; }
        std::cout << "Sorry, I did not understand.n";
    }
    std::cout << "Goodbye!n";
}