在将用户输入验证为 int 时陷入无限循环

Stuck in an infinite loop when validating user input as an int

本文关键字:无限循环 int 用户 输入 验证      更新时间:2023-10-16

所以我使用 do while 循环显示一个菜单,如下所示,我希望用户收到菜单提示,直到他们做出有效的选择 - 通过输入数字 1、2、3 或 4。然后,我想使用开关大小写语句来识别用户选择并执行相关的代码块。但是,在输入验证方面,如何解释用户输入字母而不是数字?下面的代码成功地继续到下一次迭代,以便在用户输入字母时重新提示用户,只是它进入连续循环。

int selection;
do{
    cout << "Which option would you like to select? (select 1, 2, or 3)";
    cout << "1: Option 1" << endl;
    cout << "2: Option 2" << endl;
    cout << "3: Option 2" << endl;
    if(!(cin >> selection)){
        cout << "Please select an integer from 1-4." << endl;
        cin.clear()
    }
}while(selection != (1) or (2) or (3) or (4));

我尝试使用 istringstream 插入下面的代码,将用户响应从字符串流式传输到 while 循环内的 int 中,作为尝试解决问题的替代方法,但无济于事。

string temp;
cin >> temp;
clearInputBuffer();
istringstream is(temp);
is >> selection;

更新的代码 - 仍然得到无限循环(仅当用户输入字母时
字符;整数的行为符合预期(

int selection;
do{
    cout << "Which option would you like to select? (select 1, 2, or 3)";
    cout << "1: Option 1" << endl;
    cout << "2: Option 2" << endl;
    cout << "3: Option 2" << endl;
    if(std::cin >> selection){
       cout << "Enter the new price: ";
    }
    else if(!std::cin.eof()){
       cout << "Please select an integer from 1-4." << endl;
       cin.clear();
    }

    }while(selection != 1 && selection != 2 && selection != 3 && selection != 4);
while(selection != (1) or (2) or (3) or (4));

在语法上是有效的,尽管您很可能想要

while(selection != 1 && selection != 2 && selection != 3 && selection != 4);

您的原始表达式等效于

while((selection != 1) || (2) || (3) || (4)) 

(2)(3)(4) 的计算结果为 true,这使得你的循环是无限的,因为anything || truetrue的。

如果有人想知道,是的,C++允许写and而不是&&or而不是||not而不是!等。您必须"禁用语言扩展"才能在MSVC上看到此信息。

[更新]

另一个问题是,在非整数输入的情况下,变量选择保持未初始化状态。例如,在 else clase 中,为其指定值 -1。

显而易见的

方法是实际检查输入是否成功,如果不是这种情况,请处理错误,例如,编写错误消息,清除流,忽略字符或行,然后重试:

if (std::cin >> selection) {
    // do something with the good selection
}
else if (!std::cin.eof()) {
    std::cin.clear();
    std::cout << "invalid character ('" << char(std::cin.get()) << "') ignoredn";
}

您的代码会检查流并清除它,但它不会提取有问题的字符。当您检查选择是否在范围内时,事情已经很糟糕了,并且会保持这种状态。

你会继续检查范围。您的方法不太有效,因为逻辑或运算符会评估每个单独的元素。一种方法是检查输入的值是否是特定rnage的成员,例如,使用

int const valid[] = { 1, 2, 3, 4 };
if (std::end() == std::find(std::begin(valid), std::end(valid), selection)) {
    std::cout << "chosen invalid selection (" << selection << ")n";
}

单独检查每个选择的替代方法对于少量选择可能是可行的,但当选项范围变大时,就不真正可行了。诚然,一旦你有更大的选择范围,你实际上还是会把密钥和操作放在一起:

std::unordered_map<int, std::function<void()>> actions;
bool done = false;
// set up different operations for the respective actions, e.g.:
actions.insert(std::make_pair(1, [](){ std::cout << "hello, worldn"; }));
actions.insert(std::make_pair(2, [&](){ done = true; std::cout << "goodbyen"; }))
int selection;
if (std::cin >> selection) {
    auto it = actions.find(selection);
    if (it != actions.end()) {
        (it->second)();
    }
    else {
        std::cout << "unknown action selection " << selection << 'n';
    }
}

试试这个

while(selection != (1) and selection != (2) and selection != (3) and selection != (4));
selection != (1) or (2) or (3) or (4)

非零整数的计算结果为 true因此这相当于:

(selection != (1)) or true or true or true

这将始终评估为true.

解决此问题的方法是单独比较每个

while(selection != 1 && selection != 2 && selection != 3 && selection != 4)

(2(, (3, (4( 总是正确的,这就是为什么你被困在一个无限的 cicle 中。 尝试:

while(selection != 1 && selection != 2 && selection != 3 and selection != 4);

较短的版本:

while (selection <= 4 && selection >= 1)

我让它工作了,原始帖子中提供的更新缺少一行额外的代码,这是我从筛选有关在 while 循环中验证输入的其他问题中确定的。我认为@Dietmar Kühl 试图在他的建议中说明类似的东西,但是我的编译器不喜欢代码,我不太理解它,所以我不确定如何让它工作。我会考虑你关于通过 Dietmar 验证范围的建议,所以感谢您的投入。

还要感谢所有为这个线程做出贡献的人,尤其是你们中 99% 的人这样做而没有听起来居高临下:-(不过总有一个。我可以在此处找到我识别缺失语句的线程,并且添加到代码中的行由下面的代码中的注释标识。再次感谢!

int selection;
do{
    cout << "Which option would you like to select? (select 1, 2, or 3)";
    cout << "1: Option 1" << endl;
    cout << "2: Option 2" << endl;
    cout << "3: Option 2" << endl;
    if(std::cin >> selection){
        cout << "Enter the new price: ";
    }
    else if(!std::cin.eof()){
        cout << "Please select an integer from 1-4." << endl;
        cin.clear();
        cin.ignore(10000,'n'); // this line eliminated the infinite loop issue
    }

}while(selection != 1 && selection != 2 && selection != 3 && selection != 4);