cin and cin.clear() problem

Discussion in 'C++' started by TaiwanNoWhere, Oct 13, 2003.

  1. // 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 :)
    TaiwanNoWhere, Oct 13, 2003
    #1
    1. Advertising

  2. TaiwanNoWhere

    Mike Wahler Guest

    "TaiwanNoWhere" <> wrote in message
    news:...

    > 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 <ios> // for declaration of 'streamsize'

    > // My instructor gives this code to me, but still cannot work:(


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

    -Mike
    Mike Wahler, Oct 14, 2003
    #2
    1. Advertising

  3. > 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 <ios> // for declaration of 'streamsize'
    >
    > > // My instructor gives this code to me, but still cannot work:(

    >
    > 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 :)
    TaiwanNoWhere, Oct 14, 2003
    #3
  4. TaiwanNoWhere

    Mike Wahler Guest

    "TaiwanNoWhere" <> wrote in message
    news:...
    > > 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 <ios> // for declaration of 'streamsize'
    > >
    > > > // My instructor gives this code to me, but still cannot work:(

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

    >
    >
    > 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
    Mike Wahler, Oct 14, 2003
    #4
  5. TaiwanNoWhere

    J. Campbell Guest

    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;
    }
    J. Campbell, Oct 14, 2003
    #5
  6. 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?
    :(
    TaiwanNoWhere, Oct 17, 2003
    #6
  7. TaiwanNoWhere wrote:
    >
    > 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;

    --
    Karl Heinz Buchegger
    Karl Heinz Buchegger, Oct 17, 2003
    #7
  8. 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 :(
    TaiwanNoWhere, Oct 17, 2003
    #8
  9. TaiwanNoWhere

    P.J. Plauger Guest

    "TaiwanNoWhere" <> wrote in message
    news:...

    > 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
    P.J. Plauger, Oct 17, 2003
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Mantoulidis

    std::cin.ignore() and std::cin.clear()

    Chris Mantoulidis, Jan 6, 2004, in forum: C++
    Replies:
    5
    Views:
    17,160
    Kevin Saff
    Jan 6, 2004
  2. voidstar
    Replies:
    3
    Views:
    10,088
    Mark R Rivet
    Jul 27, 2004
  3. Aleander

    cin and cin.getline()

    Aleander, Mar 6, 2005, in forum: C++
    Replies:
    5
    Views:
    8,688
    Alex Vinokur
    Mar 6, 2005
  4. AD
    Replies:
    1
    Views:
    454
    Daniel T.
    Mar 26, 2006
  5. Fernando
    Replies:
    4
    Views:
    1,675
    Fernando
    Nov 16, 2011
Loading...

Share This Page