简体   繁体   中英

Distinguishing between an int and a double

I've searched for this answer, and no one seems to know how to fix this error. I want the input to be strictly an int. If the input is a double, I want it to send an error.

int creatLegs = 0;
string trash;
bool validLegs = true;
do
{
    cout << "How many legs should the creature have? ";
    cin >> creatLegs;

    if(cin.fail())
    {
        cin.clear();
        cin >> trash; //sets to string, so that cin.ignore() ignores the whole string.
        cin.ignore(); //only ignores one character
        validLegs = false;
    }

    if (creatLegs > 0)
    {

        validLegs = true;
    }

    if (!validLegs)
    {
        cout << "Invalid value, try again.\n";
    }

} while (!validLegs);

It seems to almost work. It sends the error, but only after moving onto the next loop. How can I fix this? And why is it still showing the error message but still moving on before showing it?

An input can be something else than a representation of an integer or of a floating point number.

Remember that numbers are not their representation(s): 9 (decimal), 017 (octal, à la C), 0b1001 (binary, à la Ocaml), IX (Roman notation), 8+1 (arithmetic expression), neuf (French) are all representations of the same number nine.

So you have to decide if you accept an input like 9 x , or 9 (with several spaces after the digit), ... More generally you have to define what are the acceptable inputs (and if the input is ending at end of line or not, if spaces or punctuation should be accepted, etc...).

You could read an entire line (eg with std::getline ) and use eg sscanf (where the %n control format is useful, and so is the item count returned by sscanf ) or std::stol (where you use the end pointer) to parse it

Notice also that the phrasing of your question ("Distinguishing between an int and a double") is wrong. There is no single " int or double " type in C++ (but int is a scalar type, and double is a scalar type in C++, and you could define a class with a tagged union to hold either of them). AFAIU, if you declare int x; then use std::cin >> x; with the user inputting 12.64 the dot and the digits 64 after it won't be parsed and x would become 12.

int creatLegs = 0;
do
{
    cout << "How many legs should the creature have? ";
    cin >> creatLegs;    // trying to get integer
    if(!cin.fail())      // if cin.fail == false, then we got an int and leave loop
        break;
    cout << "Invalid value, try again.\n"; // else show err msg and try once more
    cin.clear();
} while (1);

I think that you should read data as string, and then check it char by char to verify that it is integer - if every char is a digit, then we have integer and we can parse it.

Problem with streams is, that if you're trying to read integer but decimal is passed, it reads the number up to the dot. And this part is a proper integer, so cin.fail() returns false .

Sample code:

#include <iostream>
#include <string>
#include <cctype>
#include <cstdlib>

using namespace std;

int main() {
    int creatLegs = 0;
    bool validLegs = true;
    do
    {
        cout << "How many legs should the creature have? ";
        string input;
        getline(cin, input);

        validLegs = true;
        for (string::const_iterator i = input.begin(); validLegs && i != input.end(); ++i) {
            if (!isdigit(*i)) {
                validLegs = false;
            }
        }

        if (!validLegs)
        {
            cout << "Invalid value, try again.\n";
        } else {
            creatLegs = atoi(input.c_str());
        }

    } while (!validLegs);

    cout << creatLegs << endl;
}

This of course is not a perfect solution. If there any leading or trailing spaces (or any other characters like + or - ), the program will fail. But you always can add some code to handle those situations, if you need to.

This question already has an accepted answer, however I'll contribute a solution that handles all numbers that are integral, even those that are expressed as a floating point number (with no fractional part) and rejects input that contains anything other than spaces following the number.

Examples of accepted values, these all represent the number 4:

 4 4. 4.0 +4 004.0 400e-2 

Examples of rejected values:

 3.999999 4.000001 40e-1x 4, 
#include <iostream>
#include <sstream>
#include <cctype>
#include <string>

using namespace std;

bool get_int( const string & input, int & i ) {
    stringstream ss(input);
    double d;
    bool isValid = ss >> d;
    if (isValid) {
        char c;
        while( isValid && ss >> c ) isValid = isspace(c);
        if (isValid) { 
            i = static_cast<int>(d);
            isValid = (d == static_cast<double>(i));
        }
    }
    return isValid;
}

int main( int argc, char *argv[] )
{
    int creatLegs = 0;
    bool validLegs = false;

    do
    {
        string line;
        do {
            cout << "How many legs should the creature have? ";
        } while (not getline (cin,line));

        validLegs = get_int( line, creatLegs );

        if (creatLegs <= 0)
        {
            validLegs = false;
        }

        if (not validLegs)
        {
            cout << "Invalid value, try again." << endl;
        }

    } while (not validLegs);

    cout << "Got legs! (" << creatLegs << ")" << endl;

    return 0;
}

If you want strictly integers (no decimal period and no scientific notation) then use this simpler get_int function:

bool get_int( const string & input, int & i ) {
    stringstream ss(input);
    bool isValid = ss >> i;
    if (isValid) {
        char c;
        while(isValid && ss >> c) isValid = isspace(c);
    }
    return isValid;
}

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