Verifying valid input in a loop

Discussion in 'C++' started by JR, Sep 11, 2004.

  1. JR

    JR Guest

    Hey all,

    I have read part seven of the FAQ and searched for an answer but can
    not seem to find one.

    I am trying to do the all too common verify the data type with CIN.
    The code from the FAQ looks like this:

    #include <iostream>

    int main()
    {
    std::cout << "Enter a number, or -1 to quit: ";
    int i = 0;
    while (std::cin >> i) { // GOOD FORM
    if (i == -1) break;
    std::cout << "You entered " << i << '\n';
    }
    }


    This works well except that I do not want to exit the loop unless a
    valid input is entered. So if I enter an 'a' I want to stay in the
    loop to allow for another chance at input not exit the loop. Can
    someone please provide a modified version of this code that will allow
    this?


    Thanks,

    James
     
    JR, Sep 11, 2004
    #1
    1. Advertising

  2. "JR" <> wrote in message
    news:...
    > Hey all,
    >
    > I have read part seven of the FAQ and searched for an answer but can
    > not seem to find one.
    >
    > I am trying to do the all too common verify the data type with CIN.
    > The code from the FAQ looks like this:
    >
    > #include <iostream>
    >
    > int main()
    > {
    > std::cout << "Enter a number, or -1 to quit: ";
    > int i = 0;
    > while (std::cin >> i) { // GOOD FORM
    > if (i == -1) break;
    > std::cout << "You entered " << i << '\n';
    > }
    > }
    >
    >
    > This works well except that I do not want to exit the loop unless a
    > valid input is entered. So if I enter an 'a' I want to stay in the
    > loop to allow for another chance at input not exit the loop. Can
    > someone please provide a modified version of this code that will allow
    > this?
    >


    It's difficult to validate input, it gets very fiddly. C++ cannot provide a
    standard solution because what is valid input for one program is not valid
    for another. And since you don't say what is valid input for your program
    its impossible to give a detailed answer. I would guess that only positive
    integers and -1 are valid for you.

    However the general approach is simple enough. Read the input as a string,
    check to see if the string is a valid number (whatever that means for your
    program) and only then convert the string to an integer.

    John
     
    John Harrison, Sep 11, 2004
    #2
    1. Advertising

  3. JR

    osmium Guest

    JR writes:

    > I am trying to do the all too common verify the data type with CIN.
    > The code from the FAQ looks like this:
    >
    > #include <iostream>
    >
    > int main()
    > {
    > std::cout << "Enter a number, or -1 to quit: ";
    > int i = 0;
    > while (std::cin >> i) { // GOOD FORM
    > if (i == -1) break;
    > std::cout << "You entered " << i << '\n';
    > }
    > }
    >
    >
    > This works well except that I do not want to exit the loop unless a
    > valid input is entered. So if I enter an 'a' I want to stay in the
    > loop to allow for another chance at input not exit the loop. Can
    > someone please provide a modified version of this code that will allow
    > this?


    The overloaded >> specifies conversion. There is no back door way to get
    the faulty input (for example, a letter), the stream goes into a fail state
    if it gets bad input. So base your solution on getline() and do the
    conversion "manually". Also, see ios::fail() and ios::clear(). The
    simplest conversion would probably be strtol() in cstdlib. Using the stuff
    in the iostreams package would be more elegant, but IMO harder.

    You would have to give up the ability to display the faulty input to the
    user if you wanted to persist in using cin.
     
    osmium, Sep 11, 2004
    #3
  4. JR

    Jon Bell Guest

    In article <>,
    JR <> wrote:
    >
    >#include <iostream>
    >
    > int main()
    > {
    > std::cout << "Enter a number, or -1 to quit: ";
    > int i = 0;
    > while (std::cin >> i) { // GOOD FORM
    > if (i == -1) break;
    > std::cout << "You entered " << i << '\n';
    > }
    > }
    >
    >
    >This works well except that I do not want to exit the loop unless a
    >valid input is entered. So if I enter an 'a' I want to stay in the
    >loop to allow for another chance at input not exit the loop. Can
    >someone please provide a modified version of this code that will allow
    >this?


    First, let's just do the error checking for a single input, and not worry
    about the "-1 to quit" yet:

    int i;
    cout << "Please enter an integer, and press ENTER: ";
    while (! (cin >> i))
    {
    cin.clear(); // reset stream status flags
    cin.ignore(1000,'\n'); // skip past next newline (ENTER), or 1000
    // chars, whichever comes first
    cout << "Hey dummy, I said enter an integer! Try again: ";
    }

    If you want to input repeatedly until the user enters -1, wrap this in
    another loop that tests for end of data:

    int i = 0;
    while (i != -1)
    {
    cout << "Please enter an integer, and press ENTER: ";
    while (! (cin >> i))
    {
    cin.clear();
    cin.ignore(1000,'\n');
    cout << "Hey dummy, I said enter an integer! Try again: ";
    }
    if (i != -1)
    {
    // process i normally
    }
    }

    Or you can make the real processing-code a bit cleaner by writing a
    function to do the input and error-checking:

    bool GetNumber (int& num)
    {
    cout << "Please enter an integer, and press ENTER: ";
    while (! (cin >> num))
    {
    cin.clear();
    cin.ignore(1000,'\n');
    cout << "Hey dummy, I said enter an integer! Try again: ";
    }
    return (num != -1); // returns true if not at end of input yet
    }

    // the real processing-code

    int i;
    while (GetNumber(i))
    {
    // process i normally
    }

    --
    Jon Bell <> Presbyterian College
    Dept. of Physics and Computer Science Clinton, South Carolina USA
     
    Jon Bell, Sep 11, 2004
    #4
  5. JR

    JR Guest

    (Jon Bell) wrote in message news:<chvsup$hql$>...
    <snip>>

    First, let's just do the error checking for a single input, and not
    worry
    > about the "-1 to quit" yet:
    >
    > int i;
    > cout << "Please enter an integer, and press ENTER: ";
    > while (! (cin >> i))
    > {
    > cin.clear(); // reset stream status flags
    > cin.ignore(1000,'\n'); // skip past next newline (ENTER), or 1000
    > // chars, whichever comes first
    > cout << "Hey dummy, I said enter an integer! Try again: ";
    > }
    >
    > If you want to input repeatedly until the user enters -1, wrap this in
    > another loop that tests for end of data:
    >
    > int i = 0;
    > while (i != -1)
    > {
    > cout << "Please enter an integer, and press ENTER: ";
    > while (! (cin >> i))
    > {
    > cin.clear();
    > cin.ignore(1000,'\n');
    > cout << "Hey dummy, I said enter an integer! Try again: ";
    > }
    > if (i != -1)
    > {
    > // process i normally
    > }
    > }
    >
    > Or you can make the real processing-code a bit cleaner by writing a
    > function to do the input and error-checking:
    >
    > bool GetNumber (int& num)
    > {
    > cout << "Please enter an integer, and press ENTER: ";
    > while (! (cin >> num))
    > {
    > cin.clear();
    > cin.ignore(1000,'\n');
    > cout << "Hey dummy, I said enter an integer! Try again: ";
    > }
    > return (num != -1); // returns true if not at end of input yet
    > }
    >
    > // the real processing-code
    >
    > int i;
    > while (GetNumber(i))
    > {
    > // process i normally
    > }


    Thanks All,

    Jon I really like your solution. I came across is a couple hours
    after I posted in this post .

    http://groups.google.com/groups?hl=...t+loop+cin&meta=group%3Dcomp.lang.c.moderated

    This is essentially what I did and it is similar to the solution you
    provided. It seems very elegant and easy to use. The ironic thing is
    he posted that code to help him solve another problem. So his problem
    was my solution. :)

    Thank you again.
     
    JR, Sep 12, 2004
    #5
  6. "JR" <> wrote in message
    news:...
    > (Jon Bell) wrote in message
    > news:<chvsup$hql$>...
    > <snip>>
    >
    > First, let's just do the error checking for a single input, and not
    > worry
    >> about the "-1 to quit" yet:
    >>
    >> int i;
    >> cout << "Please enter an integer, and press ENTER: ";
    >> while (! (cin >> i))
    >> {
    >> cin.clear(); // reset stream status flags
    >> cin.ignore(1000,'\n'); // skip past next newline (ENTER), or
    >> 1000
    >> // chars, whichever comes first
    >> cout << "Hey dummy, I said enter an integer! Try again: ";
    >> }
    >>
    >> If you want to input repeatedly until the user enters -1, wrap this in
    >> another loop that tests for end of data:
    >>
    >> int i = 0;
    >> while (i != -1)
    >> {
    >> cout << "Please enter an integer, and press ENTER: ";
    >> while (! (cin >> i))
    >> {
    >> cin.clear();
    >> cin.ignore(1000,'\n');
    >> cout << "Hey dummy, I said enter an integer! Try again: ";
    >> }
    >> if (i != -1)
    >> {
    >> // process i normally
    >> }
    >> }
    >>
    >> Or you can make the real processing-code a bit cleaner by writing a
    >> function to do the input and error-checking:
    >>
    >> bool GetNumber (int& num)
    >> {
    >> cout << "Please enter an integer, and press ENTER: ";
    >> while (! (cin >> num))
    >> {
    >> cin.clear();
    >> cin.ignore(1000,'\n');
    >> cout << "Hey dummy, I said enter an integer! Try again: ";
    >> }
    >> return (num != -1); // returns true if not at end of input yet
    >> }
    >>
    >> // the real processing-code
    >>
    >> int i;
    >> while (GetNumber(i))
    >> {
    >> // process i normally
    >> }

    >
    > Thanks All,
    >
    > Jon I really like your solution. I came across is a couple hours
    > after I posted in this post .
    >


    It has a weakness. Most people would consider 123abc to be erroneous input.
    But the code above will read this as the integer 123, then loop and read abc
    (which obviously it would consider an error).

    If you want to avoid this problem, then you must read as a string and then
    convert to an integer.

    john
     
    John Harrison, Sep 12, 2004
    #6
  7. "JR" <> schrieb im Newsbeitrag
    news:...
    > Hey all,
    >
    > I have read part seven of the FAQ and searched for an answer but can
    > not seem to find one.
    >
    > I am trying to do the all too common verify the data type with CIN.
    > The code from the FAQ looks like this:
    >
    > #include <iostream>
    >
    > int main()
    > {
    > std::cout << "Enter a number, or -1 to quit: ";
    > int i = 0;
    > while (std::cin >> i) { // GOOD FORM
    > if (i == -1) break;
    > std::cout << "You entered " << i << '\n';
    > }
    > }
    >
    >
    > This works well except that I do not want to exit the loop unless a
    > valid input is entered. So if I enter an 'a' I want to stay in the
    > loop to allow for another chance at input not exit the loop. Can
    > someone please provide a modified version of this code that will allow
    > this?
    >
    >
    > Thanks,
    >
    > James


    I would do it like this:

    #include <iostream>

    using namespace std;

    //clears an error in an input stream object like cin
    //and makes it usable again by clearing the associated stream buffer
    int ClearError(istream& isIn) // Clears istream object
    {
    streambuf* sbpThis;
    char szTempBuf[20];
    int nCount, nRet = isIn.rdstate();

    if (nRet) // Any errors?
    {
    isIn.clear(); // Clear error flags
    sbpThis = isIn.rdbuf(); // Get streambuf pointer
    nCount = sbpThis->in_avail(); // Number of characters in buffer

    while (nCount) // Extract them to szTempBuf
    {
    if (nCount > 20)
    {
    sbpThis->sgetn(szTempBuf, 20);
    nCount -= 20;
    }
    else
    {
    sbpThis->sgetn(szTempBuf, nCount);
    nCount = 0;
    }
    }
    }

    return nRet;
    }


    int main()
    {
    int pri = 0;
    cout << "Enter a number: " << endl;
    do
    {
    ClearError(cin);
    cin >> pri;
    } while (!cin);
    return 0;
    }
     
    Friedrich Neurauter, Sep 12, 2004
    #7
  8. JR

    JR Guest

    "John Harrison" <> wrote in message news:<>...
    > "JR" <> wrote in message
    > news:...
    > > (Jon Bell) wrote in message
    > > news:<chvsup$hql$>...
    > > <snip>>
    > >
    > > First, let's just do the error checking for a single input, and not
    > > worry
    > >> about the "-1 to quit" yet:
    > >>
    > >> int i;
    > >> cout << "Please enter an integer, and press ENTER: ";
    > >> while (! (cin >> i))
    > >> {
    > >> cin.clear(); // reset stream status flags
    > >> cin.ignore(1000,'\n'); // skip past next newline (ENTER), or
    > >> 1000
    > >> // chars, whichever comes first
    > >> cout << "Hey dummy, I said enter an integer! Try again: ";
    > >> }
    > >>
    > >> If you want to input repeatedly until the user enters -1, wrap this in
    > >> another loop that tests for end of data:
    > >>
    > >> int i = 0;
    > >> while (i != -1)
    > >> {
    > >> cout << "Please enter an integer, and press ENTER: ";
    > >> while (! (cin >> i))
    > >> {
    > >> cin.clear();
    > >> cin.ignore(1000,'\n');
    > >> cout << "Hey dummy, I said enter an integer! Try again: ";
    > >> }
    > >> if (i != -1)
    > >> {
    > >> // process i normally
    > >> }
    > >> }
    > >>
    > >> Or you can make the real processing-code a bit cleaner by writing a
    > >> function to do the input and error-checking:
    > >>
    > >> bool GetNumber (int& num)
    > >> {
    > >> cout << "Please enter an integer, and press ENTER: ";
    > >> while (! (cin >> num))
    > >> {
    > >> cin.clear();
    > >> cin.ignore(1000,'\n');
    > >> cout << "Hey dummy, I said enter an integer! Try again: ";
    > >> }
    > >> return (num != -1); // returns true if not at end of input yet
    > >> }
    > >>
    > >> // the real processing-code
    > >>
    > >> int i;
    > >> while (GetNumber(i))
    > >> {
    > >> // process i normally
    > >> }

    > >
    > > Thanks All,
    > >
    > > Jon I really like your solution. I came across is a couple hours
    > > after I posted in this post .
    > >

    >
    > It has a weakness. Most people would consider 123abc to be erroneous input.
    > But the code above will read this as the integer 123, then loop and read abc
    > (which obviously it would consider an error).
    >
    > If you want to avoid this problem, then you must read as a string and then
    > convert to an integer.
    >
    > john



    That is a good point. It also has the weakness of if 100,000 is
    entered then only 100 is taken. It does seem that overall the input
    as a string makes the most sense.

    James
     
    JR, Sep 13, 2004
    #8
    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. andreas

    verifying valid Pointer

    andreas, Jan 18, 2005, in forum: C++
    Replies:
    16
    Views:
    6,210
    Richard Herring
    Jan 26, 2005
  2. Replies:
    1
    Views:
    480
    Steve W. Jackson
    Dec 22, 2006
  3. Hulo
    Replies:
    7
    Views:
    463
    Dave Thompson
    Feb 13, 2006
  4. たか
    Replies:
    2
    Views:
    602
    たか
    May 29, 2008
  5. Isaac Won
    Replies:
    9
    Views:
    452
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page