【问题标题】:Stuck in an infinite loop when validating user input as an int将用户输入验证为 int 时陷入无限循环
【发布时间】:2015-02-16 04:22:28
【问题描述】:

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

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);

【问题讨论】:

  • 我打赌你不知道selection != (1) or (2) or (3) or (4)是什么意思
  • anything or true 始终是true

标签: c++ while-loop switch-statement cin


【解决方案1】:
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 而不是 &amp;&amp;or 而不是 ||,以及 not 而不是 ! 等。你必须“禁用语言扩展”以在 MSVC 上查看此内容。

[更新]

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

【讨论】:

  • 啊,是的,谢谢@Armen Tsirunyan - 现在已经向我指出了这个错误看起来非常明显。我已经更新了上面的代码以反映这些以及其他一些更改,但是当用户输入字母字符时,我仍然陷入无限循环
  • 好吧,行为仍然与更新前完全相同,但是我可以看到我的 while 条件存在缺陷 - 所以我确信更新的至少一部分会有所帮助,尽管这没有反映出来在代码的输出中。
【解决方案2】:

显而易见的方法是实际检查输入是否成功,如果不是,则处理错误,例如,编写错误消息,清除流,忽略字符或行,然后重试:

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()) << "') ignored\n";
}

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

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

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";
}

The alternative of checking each selection individually may be viable for a small number of selection but isn't really viable when the range of options grows bigger.诚然,一旦您有更多的选择范围,您实际上会将密钥和操作放在一起:

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, world\n"; }));
actions.insert(std::make_pair(2, [&](){ done = true; std::cout << "goodbye\n"; }))

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';
    }
}

【讨论】:

    【解决方案3】:

    试试这个

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

    【讨论】:

      【解决方案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)
      

      【讨论】:

        【解决方案5】:

        (2), (3, (4) 总是正确的,这就是你被困在无限循环中的原因。试试:

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

        【讨论】:

          【解决方案6】:

          更短的版本:

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

          【讨论】:

          • 这是错误的,因为表达式总是正确的。
          【解决方案7】:

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

          还要感谢为此线程做出贡献的每个人,尤其是 99% 的人,他们这样做并没有显得居高临下 :-) 不过总有一个。可以在here 中找到我从中识别出我丢失的语句的线程,并且添加到代码中的行在下面的代码中用注释标识。再次感谢!

          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);
          

          【讨论】:

            猜你喜欢
            • 2013-10-29
            • 2019-06-15
            • 1970-01-01
            • 1970-01-01
            • 2020-05-13
            • 1970-01-01
            相关资源
            最近更新 更多