33

In C++, how do you handle wrong inputs? Like, if the program asks for an integer, when you type a character it should be able to do something and then loop to repeat the input but the loop goes infinite when you input a character when an integer is need and vice versa.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Zik
  • 1,556
  • 7
  • 22
  • 31

5 Answers5

60

The reason the program goes into an infinite loop is because std::cin's bad input flag is set due to the input failing. The thing to do is to clear that flag and discard the bad input from the input buffer.

//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
    std::cin.clear(); //clear bad input flag
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
    std::cout << "Invalid input; please re-enter.\n";
}

See the C++ FAQ for this, and other examples, including adding a minimum and/or maximum into the condition.

Another way would be to get the input as a string and convert it to an integer with std::stoi or some other method that allows checking the conversion.

chris
  • 60,560
  • 13
  • 143
  • 205
  • 1
    i have done some research before asking here. I saw that they put cin.ignore(1000, '\n'); what does this do? Also !(cin >> num) returns a boolean? i didn't know that – Zik Apr 27 '12 at 11:42
  • 2
    @Marvin, `cin.ignore (1000, '\n')` ignores/discards characters in the input buffer until either 1000 have been discarded, or a newline has been encountered, whichever comes first. It's a good way to get rid of a line. You'll see in the parashift example, they use the maximum size of a stream instead of 1000 to account for a line of max length. I use `cin.sync()` because when doing this, I want to be on equal footing with the user (not read the next line yet), so I discard everything. Finally, `cin` has an `operator void *`, so it cann convert to a bool. – chris Apr 27 '12 at 11:48
  • but how does the while loop check !(cin >> num) ? – Zik Apr 27 '12 at 12:12
  • 3
    @Marvin, `cin >> num` fails if a user types, say 'a' when it was expecting an int. It provides a conversion operator to allow it to be implicitly converted to a `void *`. If `cin` is in a bad state, it will return `NULL`. If not, it will return the object. This can then be taken and converted to bool: true if not NULL, false if NULL. The loop can then use that to evaluate the bool expression it needs. – chris Apr 27 '12 at 12:15
  • @chris mind that ignore() has to be passed before clear() for this to work, the reference you have given has the correct form in it ;) – maja Mar 23 '15 at 07:17
  • @Zik It could just be XCode, but although this code works cin>>num does not return a boolean as in bool x = (cin>>num) will not compile. Anyone have any idea why? – Supamee Apr 03 '17 at 18:53
  • @Supamee, `cin >> num` returns `cin`, which is contextually-convertible to `bool`. That means `if (cin)` compiles and does what you expect, but `bool b = cin;` doesn't compile without an explicit cast. – chris Apr 03 '17 at 19:45
  • What about using std::getline() instead of std::cin and then checking for proper datatype? eg: std::getline(std::cin, input); if (input......YOUR CONDITION.... –  Nov 04 '20 at 19:40
  • 1
    @VaisakMohan, That would be fine too; it's one way to do the last paragraph. However, do be aware of whether you want to count multiple inputs on one line. It would be a shame if you read a line of valid inputs, convert the first part of it, and toss the others. `getline` works best for actual line-based input instead of token-based. You also have to be aware of whitespace, which could be handled differently in your conversion. Beyond that, reading line by line means you have to do the conversion _and_ error checking (minus discarding bad input from the stream) instead of only the latter. – chris Nov 04 '20 at 22:45
  • 1
    In addition, with `getline`, you have to be careful not to leave a stray newline in the stream before using it. If using `getline`, it's generally recommended to go all-in instead of trying to mix and match it with token-based input. – chris Nov 04 '20 at 22:46
10

The top voted answer covers the solution really well.

In addition to that answer, this may help visualize what's going on a little better:

int main()

    int input = 1;//set to 1 for illustrative purposes
    bool cinState = false;
    string test = "\0";
    while(input != -1){//enter -1 to exit
        cout << "Please input (a) character(s): ";//input a character here as a test
        cin >> input; //attempting to input a character to an int variable will cause cin to fail
        cout << "input: " << input << endl;//input has changed from 1 to 0
        cinState = cin;//cin is in bad state, returns false
        cout << "cinState: " << cinState << endl;
        cin.clear();//bad state flag cleared
        cinState = cin;//cin now returns true and will input to a variable
        cout << "cinState: " << cinState << endl;
        cout << "Please enter character(s): ";
        cin >> test;//remaining text in buffer is dumped here. cin will not pause if there is any text left in the buffer.
        cout << "test: " << test << endl;
    }
    return 0;    
}

Dumping the text in the buffer to a variable isn't particularly useful, however it helps visualize why cin.ignore() is necessary.

I noted the change to the input variable as well because if you're using an input variable in your condition for a while loop, or a switch statement it may go into deadlock, or it may fulfill a condition you weren't expecting, which can be more confusing to debug.

AWolfAtTheDoor
  • 101
  • 1
  • 2
0

Here is my approach to this matter.

Below is a C++ program that allows an end user to answer Yes or No to a simple "Yes" or "No" question.

This program will re-ask the same question, as long as the answer is neither Yes nor No.

Since C++ is case sensitive, I have also set up the program to accept both upper and lower case letters of the first letter of the allowed answers, since they both basically signify the same thing.

 #include <iostream>

 #include <string>

 using namespace std;

 int main() {
     
   string input;

   do {
       cout << "Are you interested in learning how to solve problems through coding?" <<endl;
       
       cout << "Choose Yes or No" <<endl;
       
       cin >> input;

       if ((input == "Yes") || (input == "yes"))
       
       {

        cout << "That is one of the ways of becoming a software engineer.";
        
        break;

       } 
       
       else if ((input == "No") || (input == "no"))
       
       {

        cout << "You have little possibility of becoming a computer engineer."<<endl;
        
        break;
        
       }

        } while ((input != "Yes" && input != "No") || (input != "yes" && input != "no"));

   return 0;
 }
-6

Test the input to see whether or not it is what your program expects. If it is not, alert the user that the input they provided is unacceptable.

-6

You can check it through the ASCII value if the ascii value s between 65 t0 90 or 97 to 122 the it would be character.

jiten
  • 5,128
  • 4
  • 44
  • 73