使用错误处理循环捕获用户输入 int 的最佳方法

The best way to capture user input int with error handling loop

在我的例子中,我必须确保用户输入是 1 或 2,或 3。

这是我的代码:

#include <iostream>

using namespace std;

void invalid_choice_prompt() {
    string msg = "\nInvalid Command! Please try again.";
    cout << msg << endl;
}

int ask_user_rps_check_input(int user_choice) {
    if (user_choice == 1 || user_choice == 2 || user_choice == 3) return 1;
    return 0;
}

int ask_user_rps() {
    // ask user's choice of Rock or Paper or Scissors
    while (1) {
        string msg =
            "\nPlease enter your choice:\nRock - 1\nPaper - 2\nScissors - 3";
        cout << msg << endl;

        int user_choice;
        cin >> user_choice;

        if (ask_user_rps_check_input(user_choice)) {
            return user_choice;
        }
        invalid_choice_prompt();
    }
}

int main() {
    ask_user_rps();

    return 0;
}

当输入是整数时,代码能够处理这种情况,但是当输入是字符或字符串时,程序将陷入死循环。

有什么优雅的方法可以做到这一点吗?我找到了一些关于使用 cin.ignore 来忽略指定长度的 io 缓冲区的方法,但我认为这种方法不够灵活。我正在寻找更灵活的解决方案。

以字符形式输入

string user_choice;
cin >> user_choice;

检查输入是否有效if(user_choice=='1')

使用运算符 >> 从流中读取目标类型接受的字符数;其余的将保留在流中以供后续读取。如果输入有格式错误(例如,当需要整数时是前导字母字符),那么也会设置错误标志。这个错误标志可以用 cin.fail() 检查。它保持设置,直到它被明确清除。因此,如果您的代码是...

int user_choice;
cin >> user_choice;

然后如果您输入的不是数字,例如asdf,然后 user_choice 有一个未定义的值,一个错误标志 cin.fail() 被(和 reamins)设置。因此任何后续读取也会失败。

要克服这个问题,您必须做三件事:

首先,检查错误标志。您可以通过在读取尝试后调用 cin.fail() 或检查表达式 (cin >> user_choice) 的 return 值来执行此操作,这与调用 cin.fail().[=23 相同=]

其次,如果出现错误,您需要使用cin.clear()清除错误标志。否则,之后任何读取任何内容的尝试都将失败。

第三,如果要继续读取整数值,需要从流中取出无效字符。否则,你会一次又一次地把asdf读入一个整数类型的变量,然后又一次又一次失败。您可以使用 cin.ignore(numeric_limits<streamsize>::max(),'\n'); 从输入缓冲区中获取 EOF 或行尾之前的所有字符。 使用错误处理读取整数值的完整代码如下所示:

int readNumber() {

    int result;
    
    while (!(cin >> result)) {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(),'\n');
        cout << "Input is not a number." << std::endl;
    }

    return result;
}

我认为一个选项是将用户输入收集到一个字符串中,然后使用类似这样的 getline 将其移动到字符串流:

std::string input;
std::getline(std::cin, input);
//Now check if the input is correct. if it is, then:
std::stringstream stream;
stream << input;
int num;
stream >> num; 

我不确定这是否是个好方法,但它确实有效。

最简单的解决方案之一是检查 cin 流故障,如下所示:

int ask_user_rps() {
// ask user's choice of Rock or Paper or Scissors
while (1) {
    string msg =
        "\nPlease enter your choice:\nRock - 1\nPaper - 2\nScissors - 3";
    cout << msg << endl;

    int user_choice;
    cin >> user_choice;
    
    if(cin.fail()) {
        invalid_choice_prompt();
        std::cin.clear();
        std::cin.ignore(256,'\n');
        continue;
    }

    if (ask_user_rps_check_input(user_choice)) {
        return user_choice;
    }
    invalid_choice_prompt();
}
}