使用cin.fail()时的无限循环

时间:2014-10-10 15:22:37

标签: c++ cin

每当我输入无法转换为整数的内容时,我就会得到一个无限循环。有什么建议吗?

cout << "Selection: ";
cin >> choice;
while((choice < 0)||(choice > 6)||(cin.fail())) {
    cout << "That isn't a number." << endl;
    cin.clear();
    cout << "Selection: ";
    cin >> choice;
}

2 个答案:

答案 0 :(得分:6)

仅仅clear还不够:cin会一次又一次地读取该字符。 您需要ignore

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')是实现这一目标的常用方法。


另一种方法是将整行读作字符串,然后解析它(如C#/ Java ecc。)。在代码方面,它可能是:

string s;
getline(cin, s);
int n = std::stoi(s);

请注意,std::stoi可以投放std::invalid_argumentstd::out_of_range。使用这种方法,您不必忽略任何事情(因此更容易处理/学习),尽管您可能需要捕获可能的异常。

考虑到这一点,即使被其他语言使用,此方法在逻辑上也不正确:例外情况应该仅针对特殊情况(例如内部I / O故障)抛出 。错误的用户输入是您所期望的,而不是。

答案 1 :(得分:1)

isocpp.org faq中介绍了这一点。它建议使用while (std::cin >> i)形式的循环,以便在提取失败时循环终止。提取将继续失败,因为std::cin不从输入流中提取无效字符。要丢弃这些,您需要使用std::cin.ignore。通常,您可以将任意大的数字作为第一个参数,但使用std::numeric_limits<std::streamsize>::max() #include <limits> )代替它是惯用的。

循环可以简洁地写成:

while(!(std::cin >> choice) || (choice < 0) || (choice > 6)) {
    cout << "Invalid choice." << endl;
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

或者,您可以将提示放在循环条件中:

while((std::cout << "Selection: ")
        && (!(std::cin >> choice) || (choice < 0) || (choice > 6))) {
    cout << "Invalid choice." << endl;
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

不需要“无效字符”诊断,因为!(std::cin >> choice)涵盖了该字符。示例运行:

Selection: a
Invalid choice.
Selection: b
Invalid choice.
Selection: c
Invalid choice.
Selection: d
Invalid choice.
Selection: 15
Invalid choice.
Selection: 10
Invalid choice.
Selection: 5