cin and cin.clear() problem

T

TaiwanNoWhere

// case 1
int Option = 0;

for(;;)
{
cin >> Option;

switch(Option)
{
case 1:
return Option;
break;
case 2:
return Option;
break;
case 3:
return Option;
break;
default:
cout <<"Please enter the valid input!";
}
}

// case 2
int Option = 0;

do{
cin >> Option;

if(cin.fail())
{
cout << "Error! Please enter integer value! " << endl;
cin.clear();
}
}while(!(Option>=1&&Option<=3));

return Option;



// I have made the two cases to cin valid Option,
// but both re-cin cannot work when loop repeats.
// Can anyone explain to me the reason?

// I have read the function of clear()
// and still do not get how clear(iostate state=goodbit) works.
// Do I need to declare goodbit before I use it?
// My instructor gives this code to me, but still cannot work:(

// Thanks :)
 
M

Mike Wahler

do{
cin >> Option;

if(cin.fail())
{
cout << "Error! Please enter integer value! " << endl;
cin.clear();
}
}while(!(Option>=1&&Option<=3));

return Option;

// I have made the two cases to cin valid Option,
// but both re-cin cannot work when loop repeats.
// Can anyone explain to me the reason?

Yes. 'cin' goes into a 'fail' state if it encounters
invalid characters for the extracted type ('int' in
this case). E.g. if you type "ABC" instead of "123".
These offending characters are not extracted from the
stream, and will be presented again to the next input
request. Thus the 'endless loop' scenario. You need
to specifically extract and discard them. See below.
// I have read the function of clear()
// and still do not get how clear(iostate state=goodbit) works.

You don't really need any 'deep' knowledge of how it works.
cin.clear(); will reset the stream into a 'good' state.
// Do I need to declare goodbit before I use it?

No. All you need is #include <iostream> for invoking
cin's member functions.

There are several possible ways to remove the unwanted
characters. Here's one:

cin.clear(); /* reset stream state to 'good' */
cin.ignore(numeric_limits<streamsize>::max(), '\n');

This means: "extract and discard all characters up
to the first newline character, or the maximum possible
number of characters in a stream, whichever occurs first."

You'll need to add:
#include <limits> // for declaration of 'numeric_limits'
#include said:
// My instructor gives this code to me, but still cannot work:(

Have you considered consulting with him/her about this? :)

-Mike
 
T

TaiwanNoWhere

There are several possible ways to remove the unwanted
characters. Here's one:

cin.clear(); /* reset stream state to 'good' */
cin.ignore(numeric_limits<streamsize>::max(), '\n');

This means: "extract and discard all characters up
to the first newline character, or the maximum possible
number of characters in a stream, whichever occurs first."

You'll need to add:
#include <limits> // for declaration of 'numeric_limits'


Have you considered consulting with him/her about this? :)

-Mike


I tried to email him, but today is Thanksgiving in Canada. I can
understand why to use cin.ignore()function, but why cin.clear()? Do
you mean what the value we cin has 2 characteristics? abstract data
type? one is state and one is value; therefore, we have to use
cin.clear to reset the state and cin.ignore() to discard the value. Is
my gusess correct?

Thanks for your helping :)
 
M

Mike Wahler

TaiwanNoWhere said:
I tried to email him, but today is Thanksgiving in Canada.

What, he won't work on holidays? :)
I can
understand why to use cin.ignore()function, but why cin.clear()?

When 'cin' encounters a character that is invalid for the
type being extracted, not only does it not read the invalid
character, it goes into a 'fail' state. This is how it
informs you that something went wrong. You check for it
with e.g. if(!cin). The stream remains in this 'fail'
state until explicitly reset. That's what 'clear()' does,
sets the state back to 'good'.
Do
you mean what the value we cin has 2 characteristics? abstract data
type? one is state and one is value;

Yes, cin (as well as any stream) has a 'state'. One could
say that it has a 'value' as well, but this 'value' doesn't
really have a useful meaning to the programmer. When you
write an expression such as if(cin) or if(!cin), it looks
like you're evaluating it's value, but something is happening
'behind your back' :)

A special member function of 'cin' intercepts this attempt
to determine it's 'value' and returns the stream's 'state'
instead. When evaluating 'cin' (or any stream object) in
a boolean context, (as in an if() expression), it produces
a value of 'true' if the stream is in the 'good' state, and
'false' if it is not.
therefore, we have to use
cin.clear to reset the state and cin.ignore() to discard the value.
Yes.

Is
my gusess correct?

Well, I didn't think you'd need to guess, since I thought
I'd already explained it, but I suppose I might not have
explained it well enough. :) But yes, that's correct.
Thanks for your helping :)

You're quite welcome. :)

-Mike
 
J

J. Campbell

This is a little off-topic to your original post, but may be useful.

Rather than dealing with cin errors, I've made 2 functions that I use
when I want to get numeric keyboard input from the user. The
functions gint() and gun() are simple to use...

cout << "please enter a number";
int a_number = gint();

which works like...

cout << "please enter a number";
int a_number;
cin >> a_number;

however it avoids the pitfalls that can occur with cin entering an
error state.

Anyway...here's a demo that uses my functions. Note there are other
ways to do the same. I choose the ascii code route rather than
"string-class" manipulations, and not to use atoi(). Also, my
requrements are pretty strict...only numbers and (optional) leading
sign are accepted.

#include <iostream>
#include <string>

using namespace std;
void wait(); // portable equivalent of system("pause");
int gint(); // Get int
unsigned int gun(); // Get unsigned int

int main(){

cout << "This program demos 2 failsafe \"int getter\" functions.\n"
<< "Enter an Integer ";
int i = gint();
cout << "Enter an Unsigned Integer ";
unsigned int ui = gun();
cout << "\nI've got 'em...\nyour int is " << i
<< "\nyour unsigned int is: " << ui << "\nover and out!\n";

wait(); return 0;
}

void wait(){
cout<<"<Enter> to continue..";
string z; getline(cin,z);
}


int gint(){ // get *int*eger
string a;
bool badNum;
int myint, tens, sign;
do{
badNum = false;
getline(cin, a);
sign = 1 - (2 * (a[0] == 45)); // sign depends on a[0]
a.erase(0,(a[0] == 45) || (a[0] == 43)); //strips sign-if
present
tens = 1;
myint = 0;
for(int i = a.size(); --i >= 0; ){ //starts at (a.size() - 1)
if((a < 58) && (a >= 48)){
myint += ((a & 15) * tens);
tens *= 10;
}else{
cout << "Input Error.\n"
<< "Please enter a valid INTEGER: ";
badNum = true;
a.erase(); //to prevent large num warning if a.size() > 10
break;
}
}
myint *= sign;
if(a.size() > 10) cout << "Large number warning\n";
}while(badNum == true);
return myint;
}


unsigned int gun(){ // get *un*signed int
string a;
int myuint, tens;
bool badNum;
do{
myuint = 0; tens = 1;
badNum = false;
getline(cin, a);
a.erase(0,(a[0] == 43));
for(int i = a.size(); --i >= 0; ){
if((a < 58) && (a >= 48)){
myuint += ((a & 15) * tens);
tens *= 10;
}else{
cout << "Input Error.\n"
<< "Please enter a valid UNSIGNED INTEGER: ";
badNum = true;
a.erase();
break;
}
}
if(a.size() > 10) cout << "Large number warning\n";
} while(badNum == true);
return myuint;
}
 
T

TaiwanNoWhere

Thanks everyone's response
I have not read campell's answer yet, but I will read it after I finish MT :(

I have try the cin.clear() cin.ignore().
They work quite well with one exception.
If I type 2.34, then cin will cin 2 instead of 2.34.
Anyways to avoid this user error?
:(
 
K

Karl Heinz Buchegger

TaiwanNoWhere said:
Thanks everyone's response
I have not read campell's answer yet, but I will read it after I finish MT :(

I have try the cin.clear() cin.ignore().
They work quite well with one exception.
If I type 2.34, then cin will cin 2 instead of 2.34.
Anyways to avoid this user error?
:(

Use a double to read in the number!!

double number
cin >> number;
 
T

TaiwanNoWhere

But all I want is integer input instead of double

I mean when user inputs 2.34,
the program will consider input is 2.

However, 2.34 is not correct input. My correct input is 1,2,and 3.
Therefore, in this program, 2.34 will become a valid input since
computer will not reject this input. And this is not what I want :(
 
P

P.J. Plauger

But all I want is integer input instead of double

I mean when user inputs 2.34,
the program will consider input is 2.

However, 2.34 is not correct input. My correct input is 1,2,and 3.
Therefore, in this program, 2.34 will become a valid input since
computer will not reject this input. And this is not what I want :(

Then you want something beyond the standard extractors. Read the
entire candidate field into a string object, convert it with strtol,
and check the end pointer that strtol returns to ensure that the
entire field is consumed.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 

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

No members online now.

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top