简体   繁体   English

卡在无限的while循环中

[英]stuck in infinite while loop

In C++, for handling wrong inputs (like when the program asks for an integer but you type a character) it should be able to do something and then loop to repeat the input. 在C ++中,为了处理错误的输入(例如程序要求输入整数但您键入字符时),它应该能够执行某些操作,然后循环以重复输入。

My loop iterates infinitely when you input a character when an integer is needed and vice versa: 当需要整数时,输入字符时,我的循环将无限循环,反之亦然:

#include<iostream>

int main()
{
    while (cout << "Enter a number" && !(cin >> num)) 
    {
        cin.sync(); 
        cin.clear();
        cout << "Invalid input; please re-enter.\n";
    }
}

What should I do so that the program prompts for the new input again? 我应该怎么做才能使程序再次提示输入新的信息?

If cin >> num fails the invalid input needs to be removed from the stream. 如果cin >> num失败,则需要从流中删除无效的输入。 I suggest using ignore instead of sync to accomplish this. 我建议使用ignore而不是sync来完成此操作。 The reason is sync is not guaranteed to remove the remaining input in all implementations of the Standard Library. 原因是sync 不能保证在标准库的所有实现中删除剩余的输入。

#include <iostream>
#include <limits>

int main()
{
    int num;
    while (cout << "Enter a number" && !(cin >> num)) 
    {
        cin.clear();    // clear the error

        // Remove input up to a new line
        cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
        cout << "Invalid input; please re-enter.\n";
    }
}

The above example uses std::numeric_limits<std::streamsize>::max() is used to retrieve the maximum number of characters the input buffer can hold. 上面的示例使用std::numeric_limits<std::streamsize>::max()来检索输入缓冲区可以容纳的最大字符数。 This allows ignore() to remove as many characters as possible up to the new line. 这允许ignore()删除尽可能多的字符,直到新行为止。 It is idiomatic C++ and is preferred over using magic numbers which are likely to just hide the problem you are currently having. 它是惯用的C ++,比使用魔术数字更可取, 魔术数字可能只是隐藏您当前遇到的问题。

This works well but does not handle situations where the input contains extra characters after the number. 这很好用,但是不能处理数字后面输入包含多余字符的情况。 To deal with those situations the loop needs to be changed a bit to handle the additional validation. 为了应对这些情况,需要对循环进行一些更改以处理其他验证。 One option is to read an entire line from cin , place it into a std::stringstream , read the number from that and then do additional validation. 一种选择是从cin读取整行,将其放入std::stringstream ,从中读取数字,然后进行其他验证。 There is one special case that might need to be taken into account though - a line where the only characters after the number are whitespaces. 不过,可能需要考虑一种特殊情况-该行中数字之后的唯一字符是空格。 Luckily the Standard Library provides the stream modifier std::skipws that allows the situation to be handled easily. 幸运的是,标准库提供了流修饰符std::skipws ,可以轻松处理这种情况。 The example below shows how to do this without much effor 下面的示例显示了如何在不费劲的情况下执行此操作

#include <iostream>
#include <sstream>

int main()
{
    int num;

    for(;;)
    {
        std::cout << "Enter a number: " << std::flush;

        std::string line;
        std::getline(std::cin, line); // Read a line from console
        std::stringstream text(line); // store in a string stream

        char ch = 0;
        if(!(text >> num).fail() && (text >> std::skipws >> ch).fail())
        {
            break;
        }

        std::cout << "Invalid input; please re-enter.\n";
    }

    return 0;
}

The expression (text >> std::skipws >> ch).fail() will skip all white spaces that appear after the number and then attempts to read a single character. 表达式(text >> std::skipws >> ch).fail()将跳过数字后面出现的所有空白,然后尝试读取单个字符。 If no character is available the read will fail indicating the user entered only a number and nothing else. 如果没有可用的字符,则读取将失败,表明用户仅输入了一个数字而没有输入其他任何内容。 If we tried to do this with cin it would wait for the user to enter more text even if the input is valid. 如果我们尝试使用cin进行操作,即使输入有效,它也会等待用户输入更多文本。

Use cin.ignore() instead of cin.sync() and see why from this answer 使用cin.ignore()代替cin.sync()从此答案中了解原因

while (cout << "Enter a number" && !(cin >> num)) {
    cin.clear();           // clear error
    cin.ignore(100, '\n'); // ignore characters until next '\n' (or at most 100 chars)
    cout << "Invalid input; please re-enter.\n";
}

More on cin.ignore 有关cin.ignore的更多信息

Note that you can extend the scope of the number of ignored characters, up to the maximum 请注意,您可以将忽略字符的数量范围扩展到最大

    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 

You could just read the input as a string, convert it to an integer and validate it.. 您可以将输入作为字符串读取,将其转换为整数并进行验证。

#include <iostream>
#include <string>
using namespace std;
int main()
{
    int number = 0;
    string input;
    do {
        cout << "Enter a number: ";
        cin >> input;
        number = atoi(input.c_str()); // atoi returns 0 on error..
        if (number != 0 || input.compare("0") == 0) // but maybe the user really entered "0".
            break;
        cout << endl;
        cout << "Invalid input; please re-enter.\n";
    } while (1);
    cout << "You entered " << number << endl;
    return 0;
}

Sample program execution: 示例程序执行:

% ./foo
Enter a number: abc

Invalid input; please re-enter.
Enter a number: 2
You entered 2
% ./foo
Enter a number: 0
You entered 0

.. though this probably isn't the most elegant solution. ..虽然这可能不是最优雅的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM