Sadman Ahmed
Sadman Ahmed

Reputation: 105

how to stop integer variable from taking double input (digits before decimal) and any other values?

Why doesn't the .fail() work if I put any double or integer with character as input for the last vabiable e?

I have added some output pictures for this problem.

Output sample

Code:

int main() {
    string a,b,line;
    double c;
    int d,e;
    stringstream ss;
    getline(cin,line);
    ss<<line;
    ss>>a>>b>>c>>d>>e;
    cout<<"command: "<<a<<endl<<"arg1: "<<b<<endl<<"arg2: "<<c<<endl<<"arg3: "<<d<<endl<<"arg4: "<<e<<endl;
    if(ss.fail())
        cout<<"Error: invalid command"<<endl;
    else
        cout<<"perfect"<<endl;
    return 0;
}

How can I fix this problem?

Upvotes: 4

Views: 1406

Answers (2)

Ajish Kb
Ajish Kb

Reputation: 480

template< typename From,typename To>
static inline bool superConvert(const From& fromVar,To& toVar)
{
    stringstream ss;
    ss<<fromVar;
    ss>>toVar;
    if(ss.fail())
    {
        return false;
    }
    else
    {
        From tempFrom;
        stringstream ss;
        ss<<toVar;
        ss>>tempFrom;
        if(tempFrom != fromVar)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}

For integers this function works fine. Since it double check, the proper way is to use stdol but in case if it is not allowed u can use this.

int i;
bool convertSuccess = superConvert<string,int>("25",i);
cerr<<i;

Upvotes: 0

user4581301
user4581301

Reputation: 33932

>> stops reading as soon as it finds input that cannot be parsed into whatever data type it's been told to read into. Input of 7.5 read into an int is a perfectly acceptable 7 and the .5, which cannot be part of an int, is left in the stream to bedevil the next read from the stream. If OP had input 7.5 for the third argument (int d), the read of .5 into the fourth argument (int e) would have failed.

Ah. Totally neglected the How To Fix part.

My personal preference is to read all data in as a string and parse it myself. In this case I'd use good ol' strtol, mostly because I haven't warmed to the idea of throwing exceptions over bad user input. Typos happen. They happen too often to be exceptional. Deal with it.

So we would read into std::string e, not int e and then...

char * endp; // strtol will point endp to character that ended the parsing. 
             // If that's not the end of the string there was stuff we couldn't parse
errno = 0; // clear the error code so we can catch an overflow error 
           // if the number parsed was too big
long num = std::strtol(e.c_str(), &endp, 10); // parse the string as a decimal number
if (*endp != '\0' || errno == ERANGE)
{
    // handle error. Abort, nag user and repeat, whatever
}
// use num

OP has added that they are not permitted to use C library calls. So be it. The C++ library equivalent is std::stoi. My rant on exceptions above explains why I don't like this option, but here we go!

size_t end; 
int num = std::stoi(e, &end); // parse the string as a decimal number
if (end != e.length())
{
    // handle error. Abort, nag user and repeat, whatever
}
// use num

If it utterly fails to convert, std::stoi will throw std::invalid_argument. If the number provided was too big, it throws std::out_of_range, so either catch and handle the exceptions or let the program abort. Your call.

Upvotes: 3

Related Questions