如何使 cin 只接受整数输入

how to make cin only take integer inputs

我是编程新手,我们需要创建一个程序,当用户输入错误的输入时不会退出,但到目前为止我只学到了基础知识。当数字高于和低于 100 时我已经解决了但是当用户不小心插入一个非整数时,它将进入错误循环。顺便说一句,这是一个普通的计算器。

#include <iostream>

using namespace std;

int main()
{
    int num[100];
    int n;
    double sum, average;

    cout << "how many numbers will you input?: ";
    cin >> n;

    while ( n > 100 || n <= 0 )
    {
        cout << "Error! number should in range of (1 to 100) only." << endl;
        cout << "Enter the number again: ";
        cin >> n;
    }

    for ( int i = 0; i < n; ++i )
    {
        cout << i + 1 << ". Enter number: ";
        cin >> num[i];
        sum += num[i];
    }

    average = sum / n;
    cout << "Average = " << average;
}
 #include <iostream>
 #include <limits>
    using namespace std;
    int avg(int sum, int n)
    {
        int average;
        average = sum/n;
        cout<<"Avg = "<<average;
    }
    int main()
    {
    int n;
    cout << "how many numbers will you input?: ";
    cin >> n;
    int w = n;
    int num[w];
    int sum;
    while(n>100||n<=0)
    {
    cout << "Error! number should in range of (1 to 100) only." << endl;
    cout << "Enter the number again: ";
    cin >> n;
    }
    for(int i = 0; i < n; ++i)
    {
    cout << i + 1 << "Enter number: ";
    cin >> num[i];
    if(!cin)
    {
          cout << "Wrong Choice. " << endl;
          cin.clear();
          cin.ignore( numeric_limits<std::streamsize>::max(), '\n' );
           n++;
          continue;
    }
    else
    {
    sum += num[i];
    }
    }
    cout<<"Sum  = "<<sum<<endl;
    avg(sum,w);
    }
  

如果std::istream::operator >> fails, it will set failbit. Therefore, you should check failbit (for example by calling std::cin.fail())先看是否转换成功,再使用转换结果。

如果由于输入错误导致转换失败,那么下一次调用 std::istream::operator >> 将自动失败,因为设置了 failbit。这就是你陷入无限循环的原因。如果你想在转换失败后再次尝试输入,你将首先必须使用函数 std::cin.clear().

清除 failbit

此外,您必须丢弃导致转换失败的错误输入,否则,下次您调用 std::istream::operator >> 时,转换将因同样的原因再次失败。为了清除错误的输入,你可以使用std::cin.ignore(),像这样:

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

要使用 std::numeric_limits,您必须 #include <limits>

对您的代码执行这些修复后,它应该如下所示:

#include <iostream>
#include <limits>

using namespace std;

int main()
{
    int num[100];
    int n;
    double sum, average;
    bool input_ok;

    //repeat until input is valid
    do
    {
        cout << "How many numbers will you input? ";
        cin >> n;

        if ( cin.fail() )
        {
            cout << "Error: Conversion to integer failed!\n";

            input_ok = false;
        }
        else if ( n > 100 || n <= 0 )
        {
            cout << "Error: Number should in range of (1 to 100) only!\n";
            input_ok = false;
        }
        else
        {
            input_ok = true;
        }

        //clear failbit
        cin.clear();

        //discard remainder of line
        cin.ignore( numeric_limits<streamsize>::max(), '\n' );
    } while ( !input_ok );

    for ( int i = 0; i < n; ++i )
    {
        do
        {
            cout << i + 1 << ". Enter number: ";
            cin >> num[i];

            if ( cin.fail() )
            {
                cout << "Error: Conversion to integer failed!\n";

                input_ok = false;
            }
            else
            {
                input_ok = true;
            }

            //clear failbit
            cin.clear();

            //discard remainder of line
            cin.ignore( numeric_limits<streamsize>::max(), '\n' );
        } while ( !input_ok );

        sum += num[i];
    }

    average = sum / n;
    cout << "Average = " << average;
}

该程序具有以下行为:

How many numbers will you input? 200
Error: Number should in range of (1 to 100) only!
How many numbers will you input? -31
Error: Number should in range of (1 to 100) only!
How many numbers will you input? test
Error: Conversion to integer failed!
How many numbers will you input? 4abc
1. Enter number: 1
2. Enter number: 2
3. Enter number: 3
4. Enter number: 4
Average = 2.5

如您所见,该程序现在可以正常工作,因为它现在可以处理错误的输入,例如 test。它拒绝该输入并重新提示用户进行新输入。

但是,此程序的一个问题是它接受 4abc 作为数字 4 的有效输入。相反,拒绝此类输入可能是合适的。解决此问题的一种方法是检查该行的其余部分,而不是简单地丢弃它。

另一个问题是此解决方案包含大量代码重复。除了范围检查之外,两个 do...while 循环几乎相同。因此,最好将此循环放入一个函数中,可以从您的代码中的多个位置调用它。

但是,我通常不建议您使用 std::istream::operator >>,因为它的行为并不总是直观的。例如,如上所述:

  1. 它并不总是读取整行输入,因此您必须明确丢弃该行的剩余部分。
  2. 它接受 4abc 作为数字 4 的有效输入。

根据我的经验,如果您想对整数输入进行正确的输入验证,通常最好编写自己的函数来使用 std::getline and converts it with std::stoi 读取整行输入。如果输入无效,则该函数应自动重新提示用户。

在下面的示例中,我调用此函数 get_int_from_user

如果你想额外保证输入在一定范围内,那么你可以在无限循环中调用函数get_int_from_user,一旦确定输入有效就跳出那个循环.

#include <iostream>
#include <string>
#include <sstream>
#include <cctype>

int get_int_from_user( const std::string& prompt );

int main()
{
    int nums[100];
    int n;
    double sum;

    //repeat loop forever, until input is good
    for (;;) //equivalent to while(true)
    {
        n = get_int_from_user( "How many numbers will you input? " );

        if ( 1 <= n && n <= 100 )
            //input is good
            break;

        std::cout << "Error! Number should in range of (1 to 100) only.\n";
    }

    //read one number per loop iteration
    for( int i = 0; i < n; i++ )
    {
        std::ostringstream prompt;

        prompt << "Enter number #" << i + 1 << ": ";

        nums[i] = get_int_from_user( prompt.str() );

        sum += nums[i];
    }

    std::cout << "Average: " << sum / n << '\n';
}

int get_int_from_user( const std::string& prompt )
{
    std::string line;
    std::size_t pos;
    int i;

    //repeat forever, until an explicit return statement or an
    //exception is thrown
    for (;;) //equivalent to while(true)
    {
        //prompt user for input
        std::cout << prompt;

        //attempt to read one line of input from user
        if ( !std::getline( std::cin, line ) )
        {
            throw std::runtime_error( "unexpected input error!\n" );
        }

        //attempt to convert string to integer
        try
        {
            i = std::stoi( line, &pos );
        }
        catch ( std::invalid_argument& )
        {
            std::cout << "Unable to convert input to number, try again!\n";
            continue;
        }
        catch ( std::out_of_range& )
        {
            std::cout << "Out of range error, try again!\n";
            continue;
        }

        //The remainder of the line is only allowed to contain
        //whitespace characters. The presence of any other
        //characters should cause the entire input to get rejected.
        //That way, input such as "6sdfj23jlj" will get rejected,
        //but input with trailing whitespace will still be accepted
        //(just like input with leading whitespace is accepted by
        //the function std::stoi).
        for ( ; pos < line.length(); pos++ )
        {
            if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
            {
                std::cout << "Invalid character found, try again!\n";

                //we cannot use "continue" here, because that would
                //continue to the next iteration of the innermost
                //loop, but we want to continue to the next iteration
                //of the outer loop
                goto continue_outer_loop;
            }
        }

        //input is valid
        return i;

    continue_outer_loop:
        continue;
    }
}

该程序具有以下行为:

How many numbers will you input? 200
Error! Number should in range of (1 to 100) only.
How many numbers will you input? -31
Error! Number should in range of (1 to 100) only.
How many numbers will you input? test
Unable to convert input to number, try again!
How many numbers will you input? 4abc
Invalid character found, try again!
How many numbers will you input? 4
Enter number #1: 1
Enter number #2: 2
Enter number #3: 3
Enter number #4: 4
Average: 2.5

如您所见,它现在可以正确拒绝输入 4abc

我相信使用函数 get_int_from_user 会使 main 中的代码更清晰。

请注意,上面的代码使用了一个 goto 语句。在大多数情况下,您应该避免使用 gotobut for breaking out of nested loops, it is considered appropriate.