Reputation: 105
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.
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
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
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