cin error recovery

R

Roman Gavrilov

Have following snippet:

int i1, i2;
cin >> i1;
cin >> i2;
cout << i1 << ", " << i2;

If on first prompt I enter non-numeric value, then second value is not
prompted and i1, i2 are set to some weird value.

Q: is there something I can do to be able to enter second value even
if first value was invalid?

Note: cin.clear() - does not help.
Note: cin.clear() does help under Windows (WinXP), but does not work
under SunOS (5.2)

Thank you,
Regards,
Roman
 
J

Jonathan Turkanis

Roman Gavrilov said:
Have following snippet:

int i1, i2;
cin >> i1;
cin >> i2;
cout << i1 << ", " << i2;

If on first prompt I enter non-numeric value, then second value is not
prompted and i1, i2 are set to some weird value.

Q: is there something I can do to be able to enter second value even
if first value was invalid?

Did you trying clearing the error state, then reading and discarding
the remainder of the line? E.g.

if (!(cin >> i1)) {
cin.clear();
std::string s;
cin >> s;
cout << "Did I tell you to write " << s << "?\n";
cout << "I said, input a *number*, stupid!\n";
}

Jonathan
 
J

Jon Bell

Have following snippet:

int i1, i2;
cin >> i1;
cin >> i2;
cout << i1 << ", " << i2;

If on first prompt I enter non-numeric value, then second value is not
prompted and i1, i2 are set to some weird value.

Note: cin.clear() - does not help.

Actually, cin.clear() *does* help, but it's not all you need to do.

When stream input encounters an illegal character, input stops at that
character, leaving it in the input stream so you can try to read it a
different way if you want. In your case, you probably want to skip past
it to the next hopefully valid input item.

cin.clear() resets the stream status flags, which allows further input to
take place, but it doesn't actually move the input point in the file. So
if you try to read again, you just hit the bad data again.

One common way to skip past the bad data is to assume that the items are
separated by newlines, and use something like cin.ignore(1000, '\n') which
skips to just past the next newline, or 1000 chars, whichever comes first.
This works better if you prompt for the two numbers separately so they
have to be on separate lines.

If the two numbers are supposed to be on the same line, you could probably
simply read the bad data into a dummy string using >>, which will read
until the next whitespace; then try to read the next number normally.
 
R

Roman Gavrilov

My bad, full text would be:

int i1, i2;
cin >> i1;
cin.clear();
cin.ignore(cin.rdbuf()->in_avail());
cin >> i2;
cout << i1 << " " << i2 << endl;

so, I do clear the rest of the input buffer. Problem goes even deaper - does
not matter how many times after the error I try to read cin - it always
returns an error.

while (true) {
int i1;
cin >> i1;
cout << i1;
}

if in the snippet above I enter error once, it will output the "weird" value
forever.

Regards,
Roman
 
J

Jonathan Turkanis

Roman Gavrilov said:
My bad, full text would be:

int i1, i2;
cin >> i1;
cin.clear();
cin.ignore(cin.rdbuf()->in_avail());
cin >> i2;
cout << i1 << " " << i2 << endl;

so, I do clear the rest of the input buffer. Problem goes even deaper - does
not matter how many times after the error I try to read cin - it always
returns an error.

What compiler/standard library are you using?

Jonathan
 
E

E. Robert Tisdale

Roman said:
while (true) {
int i1;
cin >> i1;
cout << i1;
}

if in the snippet above
I enter error once, it will output the "weird" value forever.

Of course. That's what it's supposed to do. Try this:

cat main.cc
#include <iostream>

int main(int argc, char* argv[]) {
int i1 = 666;
while (std::cin >> i1) {
std::cout << i1 << std::endl;
}
std::cout << i1 << std::endl;
return 0;
}
g++ -Wall -ansi -pedantic -o main main.cc
./main www
666
./main
777
777
www
777

The input function

istream& operator>>(istream&, int&)

looks at the first character of "www" and knows that
it can't be part of an int so it returns with i1 unchanged.
It doesn't actually read any characters so "www"
will still be there the next time that you try to read.
Notice that if I enter 777 operator>> succeeds
and i1 is set to 777.
 
D

David Harmon

cin.clear();
cin.ignore(cin.rdbuf()->in_avail());

in_avail() is probably not useful for this purpose (maybe any purpose.)

Suggest you try our instead:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
 
R

Roman Gavrilov

David,

Thank you, you were right - in_avail was returning a 0.

Works now as expected

Regards,
Roman
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,160
Messages
2,570,889
Members
47,423
Latest member
henerygril

Latest Threads

Top