Thread: Why won't this simple statement work?

  1. #1
    Registered User
    Join Date
    Dec 2009
    Posts
    120

    Why won't this simple statement work?

    Why in the world will it not let me cin "a" if cin is not an int? It displays the cout statement in the if statement but any cin statement will not work in there?? I made a random number guessing game a long time ago and if your guess was not equal to the random number I had the user enter a new number. And I put the cin statement in the if statement and it worked fine...Why won't it work now??

    If I put a cout statement after the second cin it will display it. So it's running the whole thing.

    Code:
    int a;
    
    
    cout << "Enter number\n";
    cin >> a;
    
    if(!cin.good())
    {
    cout << "number only\n";
    cin >> a;
    
    }
    I am way past this in my c++ knowledge and I am aware of exception handling and everything but I'm just wondering why this specific code won't work?

  2. #2
    Registered User Swarvy's Avatar
    Join Date
    Apr 2008
    Location
    United Kingdom
    Posts
    195
    Why in the world will it not let me cin "a" if cin is not an int?
    This is just a wild stab in the dark, but maybe it has something to do with the fact that you declared 'a' as an int.

  3. #3
    Registered User
    Join Date
    Dec 2009
    Posts
    120
    Quote Originally Posted by Swarvy View Post
    This is just a wild stab in the dark, but maybe it has something to do with the fact that you declared 'a' as an int.
    So am I not using cin.good() in the proper way? I am just wondering why when the program runs, it does not give me an opportunity to input anything else if the first input is anything other than a number?

  4. #4
    Registered User Swarvy's Avatar
    Join Date
    Apr 2008
    Location
    United Kingdom
    Posts
    195
    If you look up the documentation with respect to the cin.good() and you'll find that the method tests to see if the cin input stream can take input.

    cin.good() returns a boolean, which in this case is true (basically saying that you are able to use the stream to provide input into your program), but the '!' in your if statement reverses that. Your if statement basically says 'Take another value of input if the input stream is not good'. Now do you see why the second 'cin' statement is not being executed?

    Edit: look at this as a reference: http://www.cplusplus.com/reference/iostream/ios/good/

    Note that the good() method returns false if any of the error state bits are set and true otherwise.

    I think you think that the good() method tests to see if your previous input was valid or not, and that is not what that method is for. As such, it should not be used in that capacity.
    Last edited by Swarvy; 10-18-2010 at 08:36 PM.

  5. #5
    Registered User
    Join Date
    Dec 2009
    Posts
    120
    Thanks. So what would be the most simple/beginner way to not allow a character? Without using try catch or anything.

    I tried using something like
    Code:
    bool valid = true;
    if(isalpha(a)) valid = false;
    
    while(!valid)
    {
       cout << enter a num\n";
       cin >> a;
    }
    That won't work either. It gives me a crazy runtime error.

    The only reason i'm doing this is because someone who just started learning c++ asked me about this. It seemed really simple at first, but after playing around with the most basic ways I can think of, I cannot get it to work! What is the most simple way to handle a ?

  6. #6
    Registered User
    Join Date
    Dec 2009
    Posts
    120
    Here is another approach. Again, it still will not allow me to cin anything after I enter a letter. No matter if I put the cin inside the if statement or I put it below the if statement, it will only cout "no" and it will not let me cin anything. I can't understand why it just ignores the cin statement ??

    Code:
    #include <iostream>
    using namespace std;
    
    int main()
    
    {
        int a;
    	
    	
    	cout << "Enter number\n";
    	cin >> a;
    	
    	
    	
    
    	if(a < 0){
    		cout << "no\n";
    		cin >> a;
    	}
    		
    
    	
    	
    
    	system("pause");
    
    	return 0;
    }

  7. #7
    Banal internet user
    Join Date
    Aug 2002
    Posts
    1,380
    Code:
    #include <iostream>
    #include <limits>
    using namespace std;
    
    
    
    int main()
    {
        int a;
        cout << "Enter number\n";
    
        while (!(cin >> a))
        {
            cout << "number only\n";
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(),'\n');
        }
    }
    If the stream formatter can't make the necessary type conversion then the stream goes into the fail state and the data in the buffer remains, thus to "start over" you have to clear() the fail state, then empty out the buffer, which you can do by calling ignore(), it ignores the maximum stream size number of characters or until it reaches the delimiter (EOL in this case)
    Last edited by BMJ; 10-18-2010 at 09:38 PM.

  8. #8
    Registered User Swarvy's Avatar
    Join Date
    Apr 2008
    Location
    United Kingdom
    Posts
    195
    I haven't tried this code so there are no guarantees, but on the face of it, this seems like a simple way of doing it. Although I wonder how it would hold up if you put in '>', '#', ';' or basically any other type of unusual symbol.

    Code:
    char a[BUFF_SIZE];
    int a_num;
    
    do
    {
           cout << enter a num\n";
           cin >> a;
    } while( isalpha(a) );
    
    a_num = (int)atof(a);
    Edit: BMJ's method is much cleaner. Use his. lol.

  9. #9
    Registered User
    Join Date
    Dec 2009
    Posts
    120
    Thanks BMJ but I have never seen a lot of that code before :/. Could you explain this:

    while (!(cin >> a))

    and

    cin.ignore(numeric_limits<streamsize>::max(),'\n') ;

  10. #10
    Banal internet user
    Join Date
    Aug 2002
    Posts
    1,380
    The extraction ">>" and inserter "<<" operators both return references to their respective stream objects, meaning that the expression "cin >> a" evaluates into a reference to "cin"

    It's done this way so that you can chain the operators together like this:
    Code:
    cin >> a >> b >> c; // "cin >> a" becomes "cin >> b" becomes "cin >> c"
    cout << a << b << c; // etc
    The extraction/inserter operators implement formatters as well, which can be used to convert the data being extracted/inserted to a different type. In your code the expression "cin >> a" will attempt to take any data sitting in the stream buffer and convert it into an int, if it fails, the stream object sets its fail bit and it's no longer in a valid state. Once it's failed, cin.good() will return false. The stream objects also happen to overload the boolean ! operator which also indicates the status of the stream object.

    Whew, OK, so what does that all mean? It means:
    "cin >> a" will try to extract from the input buffer and convert the data to an int and copy that value to "a" and when it's done (either having succeeded or failed) the expression returns the "cin" object itself which then can be have the boolean ! operator applied to it to test whether or not the stream is in the fail state, which would mean the extraction failed, and that the input was not an integer.

    Got it? Read from cin, try to convert, test cin to see if it failed, repeat.

    cin.ignore() pulls data off of the input buffer and discards it. It pulls off as many characters as you specify until it reaches the delimiter (the second parameter).

    "cin.ignore(numeric_limits<streamsize>::max(), '\n');" says to discard all of the data in the stream buffer up to the maximum stream buffer size or until it reaches a newline character. You would want to do this in case you receive a buffer full of junk (or for instance if the user enters a long string of nonsense rather than a single character). If you're curious you can change that line to simply "cin.ignore();" then run the program and enter a long string, you'll see how it repeats "number only" a bunch of times as it discards characters from the buffer one at a time and retries the extraction.

    Back to your original question: if the "cin >> a" extraction fails, then the data in the buffer remains unchanged. In order to "start over" you have to clear the fail state with cin.clear() then empty out anything that might still be in the stream buffer, then just go back up to the top and try the extraction again.

    Yeah I know, I hate C++ streams too (not really )
    Last edited by BMJ; 10-18-2010 at 10:59 PM.

  11. #11
    Banal internet user
    Join Date
    Aug 2002
    Posts
    1,380
    Maybe this is less confusing; It does the same thing:
    Code:
    #include <iostream>
    #include <limits>
    using namespace std;
    
    int main()
    {
        int a;
    
        cout << "Enter a number: ";
        cin >> a;
    
        while (cin.fail())
        {
            cout << "Not a number!\n";
    
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
    
            cout << "Enter a number: ";
            cin >> a;
        }
    
        cout << "Number is: " << a << endl;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How properly inherit from template?
    By 6tr6tr in forum C++ Programming
    Replies: 118
    Last Post: 04-25-2008, 04:30 AM
  2. Simple program won't work on a friend's comp
    By Ouendanation in forum C++ Programming
    Replies: 6
    Last Post: 01-25-2008, 08:03 PM
  3. simple fread doesn't work
    By ronenk in forum C Programming
    Replies: 3
    Last Post: 10-15-2004, 05:08 AM
  4. string & if statement
    By Curacao in forum C++ Programming
    Replies: 4
    Last Post: 05-02-2003, 09:56 PM
  5. Replies: 1
    Last Post: 04-02-2003, 07:50 PM