简体   繁体   中英

How to validate numeric input C++

我想知道如何使用std::cin将输入值限制为带符号的小数。

If the backing variable of the cin is a number, and the string provided is not a number, the return value is false, so you need a loop:

int someVal;

while(!(cin >> someVal)) {
   cin.reset();
   cout << "Invalid value, try again.";
}
double i;

//Reading the value
cin >> i;

//Numeric input validation
if(!cin.eof())
{
    peeked = cin.peek();
    if(peeked == 10 && cin.good())
    {
             //Good!
             count << "i is a decimal";
        }
        else
        {
             count << "i is not a decimal";
         cin.clear();
         cin >> discard;
        }
}

This also gives an error message with the input -1a2.0 avoiding the assignation of just -1 to i.

cin's >> operator works by reading one character at a time until it hits whitespace. That will slurp the whole string -1a2.0 , which is obviously not a number so the operation fails. It looks like you actually have three fields there, -1, a, and 2.0. If you separate the data by whitespace, cin will be able to read each one without problem. Just remember to read a char for the second field.

Combining the techniques from the top answer here and this website, I get

input.h

#include <ios>  // Provides ios_base::failure
#include <iostream>  // Provides cin

template <typename T>
T getValidatedInput()
{
    // Get input of type T
    T result;
    cin >> result;

    // Check if the failbit has been set, meaning the beginning of the input
    // was not type T. Also make sure the result is the only thing in the input
    // stream, otherwise things like 2b would be a valid int.
    if (cin.fail() || cin.get() != '\n')
    {
        // Set the error state flag back to goodbit. If you need to get the input
        // again (e.g. this is in a while loop), this is essential. Otherwise, the
        // failbit will stay set.
        cin.clear();

        // Clear the input stream using and empty while loop.
        while (cin.get() != '\n')
            ;

        // Throw an exception. Allows the caller to handle it any way you see fit
        // (exit, ask for input again, etc.)
        throw ios_base::failure("Invalid input.");
    }

    return result;
}

Usage

inputtest.cpp

#include <cstdlib>  // Provides EXIT_SUCCESS
#include <iostream>  // Provides cout, cerr, endl

#include "input.h"  // Provides getValidatedInput<T>()

int main()
{
    using namespace std;

    int input;

    while (true)
    {
        cout << "Enter an integer: ";

        try
        {
            input = getValidatedInput<int>();
        }
        catch (exception e)
        {
            cerr << e.what() << endl;
            continue;
        }

        break;
    }

    cout << "You entered: " << input << endl;

    return EXIT_SUCCESS;
}

Sample run

Enter an integer:
Invalid input.
Enter an integer:
Invalid input.
Enter an integer:
You entered: 3.

I'm not trying to be rude. I just wanted to share a solution I provided which I believe is more robust and allows for better input validation.

Please refer to: My Solution to Input Validation

I tried many techniques for reading integer input from the user using the >> operator, but in a way or another all my experiments have failed.

Now I think that getline() function (not the method with the same name on std::istream ) and the strtol() function from the include cstdlib is the only predictable consistent solution for this problem. I would appreciate if someone proved me wrong. Here is something like the one I use:

#include <iostream>
#include <cstdlib>

// @arg prompt The question to ask. Will be used again on failure.
int GetInt(const char* prompt = "? ")
{
    using namespace std; // *1
    while(true)
    {
        cout << prompt;
        string s;
        getline(cin,s);
        char *endp = 0;
        int ret = strtol(s.c_str(),&endp,10);
        if(endp!=s.c_str() && !*endp)
            return ret;
    }
}
  • *1: Placing using namespace whatever; to the global scope may lead to broken "unity builds" (google!) on larger projects, so should be avoided. Practice to not use that way, even on smaller projects!
  • Reading integers from files is a very different matter. Raúl Roa's approach can be good for that if properly worked out. I also suggest that wrong input files should not be tolerated, but it really depends on the application.
  • Be warned that using >> and getline() in the same program on cin will lead to some problems. Use one of them only, or google to know how to handle the issue (not too hard).

Something like:

double a;
cin >> a;

Should read your signed "decimal" fine.

You'll need a loop and some code to make sure it handles invalid input in a sensible way.

Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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