Loop and Input going wrong...

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Nepomuk
    Recognized Expert Specialist
    • Aug 2007
    • 3111

    Loop and Input going wrong...

    Hi!
    I'm just learning C++ and found something weird - I have the following program:
    [code=c++]#include <iostream>

    int main()
    {
    std::cout << "Please enter a positive integer: ";
    int n;
    do
    {
    std::cin >> n;
    std::cout << "You entered " << n << ".\n";
    if(n<=0)
    std::cout << "I said, a positive integer! :-P ";

    } while(n <= 0);
    for(int i=1; i<=n; i++)
    {
    std::cout << i << ". Some text\n";
    }
    std::cout << "Oh, I almost forgot:\n" << (n+1) << ". More text\n";
    }

    [/code]Now, it works fine, as long as I enter an integer. But if I enter a letter, it always shows
    Code:
    You entered 134515049.
    or a sligtly different number.
    It's the same number for any letter, although that constant number changes sometimes after recompiling. It seems to be related to the amount of characters in my code or something like that.
    I tried the following:
    [code=c++]
    do
    {
    // the same as before
    } while(n <= 0 || n >= 134515049);
    [/code]and got an output like this:
    Code:
    You entered 134515065.
    You entered 134515065.
    You entered 134515065.
    You entered 134515065.
    You entered 134515065.
    You entered 134515065.
    ...
    My thought was, that maybe it's reading the endl symbol as well, but I've no idea, what I can do against that.
    Actually, I'd like to either avoid the user entering letters or interpret them as their ASCII-number or something like that.
    Now, why does it give me these weird numbers and how can I get it to work as it should?

    Greetings,
    Nepomuk
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    You are using the >> operator. That is the formatted input extraction operator. That means when you >> to an int, there will be an int entered.

    If not, the >> fails and the stream is put into a fail state. Now the >> operator first checks the fail state and if the state is fail, the >> operator returns without doing anything. Now it appears all of your >> operators have quit working.

    Now you have to a) clear the fail state using cin.clear() and then b) you have to remove the offending data using a means other than the >> operator.

    Any time you use cin >> there should be a check:
    [code=cpp]
    cin >> myInt;
    if (cin.fail())
    {
    //fail state is set
    //take corrective action
    //
    cin.clear(); //clear the fail state
    //
    //add logic here to remove the bad data token}
    }
    [/code]

    If you are just learning C++, don't get fancy with the input. Give th program what ot wants. Later when the program is completely working you can come back and beef up the input edits.

    Comment

    • Nepomuk
      Recognized Expert Specialist
      • Aug 2007
      • 3111

      #3
      Originally posted by weaknessforcats
      You are using the >> operator. That is the formatted input extraction operator. That means when you >> to an int, there will be an int entered.

      If not, the >> fails and the stream is put into a fail state. Now the >> operator first checks the fail state and if the state is fail, the >> operator returns without doing anything. Now it appears all of your >> operators have quit working.

      Now you have to a) clear the fail state using cin.clear() and then b) you have to remove the offending data using a means other than the >> operator.

      Any time you use cin >> there should be a check:
      [code=cpp]
      cin >> myInt;
      if (cin.fail())
      {
      //fail state is set
      //take corrective action
      //
      cin.clear(); //clear the fail state
      //
      //add logic here to remove the bad data token}
      }
      [/code]

      If you are just learning C++, don't get fancy with the input. Give th program what ot wants. Later when the program is completely working you can come back and beef up the input edits.
      OK, thank you. At least I understand, what's happening now.
      However, this program isn't supposed to do anything else (it's basically just for learning about the syntax), so it's time to "beef up the input edits"! ^^

      I tried what you said as good as I could and (with something I found in a tutorial) got this far:[code=cpp]
      do
      {
      std::cin >> n;
      std::cout << "You entered " << n << ".\n";
      if(std::cin.fai l())
      {
      std::cout << "Failed\n";
      std::cin.clear( );
      std::cin.ignore (std::cin.rdbuf ()->in_avail()); // Found this somewhere else. Hoped it was you "magic logic", but it didn't work...
      // n = -1;
      }
      if(n<=0)
      std::cout << "I said, a positive integer! :-P ";
      } while(n <= 0);
      [/code]However, no luck. That way, it does give out Failed, but then it just continues. If however I uncomment the n = -1, it repeats itself without checking the input again, so the >> must still be deactivated.

      You said, that ">>" formats the input - would I get unformated data with cin.read(...)? And does "unformated " mean, it would be a String? Or integers? Or something even weirder? :-D

      Greetings,
      Nepomuk

      Comment

      • weaknessforcats
        Recognized Expert Expert
        • Mar 2007
        • 9214

        #4
        Formatted input means you know ahead of time what type of data is coming. Like for a disc file of people you know the data is name followed by address followed by city. You may also know the name is 30 bytes, the address 50 bytes and the city is 20 bytes.

        The same applies to keyboard input.

        Therefore, if you don't know what's coming then you can't use the >> operator.

        Instead you use cin.get() and fetch the input one byte at a time and figure out what the heck it is. Or maybe cin.getline() to read an entire text record. This can take a lot of code.

        In your example, the cin.clear() does reset the fail date but the cin.ignore() is skipping a lot of bytes. Just skip one byte at a time. Also, do not display your input until it is correct:
        [code=cpp]
        do
        {
        std::cin >> n;
        if(std::cin.fai l())
        {
        std::cout << "Failed\n";
        std::cin.clear( );
        std::cin.ignore ();
        }
        else
        {
        if(n<=0)
        {
        std::cout << "I said, a positive integer! :-P ";
        }

        }
        } while(n <= 0);
        std::cout << "You entered " << n << ".\n";
        [/code]

        Comment

        • whodgson
          Contributor
          • Jan 2007
          • 542

          #5
          When I ran your program it performed as expected. When a letter was entered it translated to the integer 2 in all cases tried. When n was initialised to =1, entry of all letters was read as n=1.

          Comment

          • Nepomuk
            Recognized Expert Specialist
            • Aug 2007
            • 3111

            #6
            Originally posted by weaknessforcats
            Formatted input means you know ahead of time what type of data is coming. Like for a disc file of people you know the data is name followed by address followed by city. You may also know the name is 30 bytes, the address 50 bytes and the city is 20 bytes.

            The same applies to keyboard input.

            Therefore, if you don't know what's coming then you can't use the >> operator.

            Instead you use cin.get() and fetch the input one byte at a time and figure out what the heck it is. Or maybe cin.getline() to read an entire text record. This can take a lot of code.

            In your example, the cin.clear() does reset the fail date but the cin.ignore() is skipping a lot of bytes. Just skip one byte at a time. Also, do not display your input until it is correct:
            [code=cpp]
            do
            {
            std::cin >> n;
            if(std::cin.fai l())
            {
            std::cout << "Failed\n";
            std::cin.clear( );
            std::cin.ignore ();
            }
            else
            {
            if(n<=0)
            {
            std::cout << "I said, a positive integer! :-P ";
            }

            }
            } while(n <= 0);
            std::cout << "You entered " << n << ".\n";
            [/code]
            Thanks a lot, now I've finally got it working AND I've learnt about formatted input! :-)

            Greetings,
            Nepomuk

            Comment

            Working...