Reputation: 543
I'm getting an infinite loop whenever I enter something that can't be converted to integer. Any suggestions?
cout << "Selection: ";
cin >> choice;
while((choice < 0)||(choice > 6)||(cin.fail())) {
cout << "That isn't a number." << endl;
cin.clear();
cout << "Selection: ";
cin >> choice;
}
Upvotes: 0
Views: 473
Reputation: 8494
Just clear
ing is not enough: cin
will read that character again and again.
You need to ignore
it.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
is a common way to achieve that.
Another way is to read the whole line as string and then parse it (like C#/Java ecc.). In terms of code it could be:
string s;
getline(cin, s);
int n = std::stoi(s);
Notice that std::stoi
can throw std::invalid_argument
or std::out_of_range
. With this method you don't have to ignore anything (thus easier to handle/learn) although you may need to catch possible exceptions.
Take into account that, even though used by other languages, this method is not logically correct: exceptions should be thrown only for exceptional cases (e.g. internal I/O failure). A wrong user input is something you do expect, instead.
Upvotes: 6
Reputation:
This is covered in the isocpp.org faq. It recommends using a loop in the form of while (std::cin >> i)
so that the loop terminates if extraction fails. Extraction will continue to fail because std::cin
does not extract the invalid characters from the input stream. To discard these, you need to use std::cin.ignore
. Generally, you can put an arbitrarily large number as the first argument, but it is idiomatic to use std::numeric_limits<std::streamsize>::max()
(#include <limits>
) instead.
The loop can be succinctly written as:
while(!(std::cin >> choice) || (choice < 0) || (choice > 6)) {
cout << "Invalid choice." << endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Alternatively, you can put the prompt in the loop condition:
while((std::cout << "Selection: ")
&& (!(std::cin >> choice) || (choice < 0) || (choice > 6))) {
cout << "Invalid choice." << endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
There is no need for an "invalid character" diagnostic because that is covered by !(std::cin >> choice)
. Example run:
Selection: a
Invalid choice.
Selection: b
Invalid choice.
Selection: c
Invalid choice.
Selection: d
Invalid choice.
Selection: 15
Invalid choice.
Selection: 10
Invalid choice.
Selection: 5
Upvotes: 1