checking C++ string for an int: revised: clearing cin [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to validate numeric input C++
How do you do the following:
while (iNumberOfPlayers <2 || iNumberOfPlayers >5)
{
cout << "Enter number of players (1-4): ";
cin >> iNumberOfPlayers;
cin.clear();
std::string s;
cin >> s;
}
After looking at the loop I'm thrown in, it looks like cin isn't getting reset (if I put in x) cin reads X again as long as I'm in the while loop. Guessing this is a buffer issue, any way to clear it?
I then tried:
while (iNumberOfPlayers <2 || iNumberOfPlayers >5)
{
cout << "Enter number of players (1-4): ";
cin >> iNumberOfPlayers;
cin.clear();
cin.ignore();
}
which works except it reads everything 1 at a time. If I put in "xyz" then the loop goes through 3 times before it stops to ask again.

If the input is not valid, the fail bit is set on the stream. The ! operator used on a stream reads the fail bit (You could also use (cin >> a).fail() or (cin >> a), cin.fail()).
Then you just have to clear the fail bit before trying again.
while (!(cin >> a)) {
// if (cin.eof()) exit(EXIT_FAILURE);
cin.clear();
std::string dummy;
cin >> dummy; // throw away garbage.
cout << "entered value is not a number";
}
Please note that if you're reading from non-interactive input, this would become an infinite loop. So use some variation on the commented error-detection code.

The tricky thing is that you need to consume any invalid input as failure to read doesn't consume the input. The simplest solution to this is to move the call to operator >> into the loop condition and then read up to the \n if it didn't mange to read an int:
#include <iostream>
#include <limits>
int main() {
int a;
while (!(std::cin >> a) || (a < 2 || a > 5)) {
std::cout << "Not an int, or wrong size, try again" << std::endl;
std::cin.clear(); // Reset error and retry
// Eat leftovers:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}

Related

C++ How do I prevent the program from endlessly repeating input when a char is received instead of an int? [duplicate]

This question already has answers here:
How do I prevent a runaway input loop when I request a number but the user enters a non-number?
(6 answers)
Closed 4 years ago.
In the below code, if anything that is not a number is entered, the program seems to continuously enter that input automatically. It translates the input to "0" since n is an int, but it does not act the same way if "0" is actually entered.
I have looked up and down and there does not seem to be a reliable way to say something like
if (n != int){cout << "invalid";}
I guess my last resort would be to just allow 0 to be a valid input, but I was hoping there's another way.
int n;
cout << " \nPlease enter a number 1 to 99,999: ";
cin >> n;
while (n < 1 || n> 99999)
{
cout << "\nThat is an invalid entry!"
<< "\nPlease enter a number 1 to 99,999: ";
cin >> n;
}
When you try to extract a value from an std::istream like std::cin and extraction fails, all data remains in the stream for the next input operation. If the same extraction is then tried again, it will again get garbage and fail. And so on.
To repeat trying to extract an int from a stream if extraction fails, you should remove all garbage before you try again:
#inlcude <limits>
#include <iostream>
// ...
int n;
while(!(std::cin >> n)) { // extraction failed
std::cin.clear(); // clear error flags
// ignore everything left in the stream up to a newline:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Combining that with limiting the value to a number between 1 and 99999:
#include <limits>
#include <iostream>
int main()
{
int n;
std::cout << "Please enter a number 1 to 99999: ";
while (!(std::cin >> n) || n < 1 || 99999 < n) {
std::cerr << "Input Error!\n\n";
std::cin.clear(); // clear error flags
// ignore everything left in the stream up to a newline:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}

How to reject char inputs in cin and define minimum and maximum int values?

I have a program which has the ability to reject user input if a char is entered instead of an int, and this works almost perfectly - anything entered that isn't a number is being rejected.
However, all of these cins need to accept any value between a minimum and a maximum, but I can't get it to work. The code below shows my efforts so far, but there's a slight bug. If a char is entered, followed by an int that is out of range, and another char is entered (I like to test rigorously - I mean, who knows what could happen if an actual end user came across the problem) the program throws the final value of mortgageTerm out as 0.
Could anyone tell me where I'm going wrong and give me any pointers to help me fix it? Thanks in advance to anyone who's able to help me solve my problem!
int mortgageTerm;
string line;
cout << "Mortgage term (1 - 40 years) : ";
while (!(cin >> mortgageTerm))
{
cout << "That's not a valid choice! Try again : ";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
while (getline(cin, line))
{
stringstream linestream;
if (!linestream >> mortgageTerm)
{
cout << "Input was not a number! Try again : ";
cin >> mortgageTerm;
continue;
}
if ((mortgageTerm <= 0 || mortgageTerm > 40))
{
cout << "Input out of range. Try again : ";
cin >> mortgageTerm;
continue;
}
char errorTest;
if (linestream >> errorTest)
{
cout << "Invalid input. Try again : ";
cin >> mortgageTerm;
continue;
}
break;
}
cout << mortgageTerm;
You're almost there. Your first issue is your first while loop is not needed at all. Then we just need to tweak the second loop to make sure that all the input read was used in the value you get. We can also simplify it by using a single error statement, Making those changes gives you
int mortgageTerm;
string line;
cout << "Mortgage term (1 - 40 years) : ";
while (getline(cin, line)) // consume all input given
{
stringstream linestream(line); // you have to construct the stream from the string here
linestream >> mortgageTerm; // try and read the data
if (!linestream.eof() || mortgageTerm <= 0 || mortgageTerm > 40)
{
// either there is input left in linestream or the value is not in range
cout << "Invalid input. Try again : ";
}
}
Just check for the minimum and maximum in the same condition where you check if it was able to be converted into an int, using ||, in a condition the expressions are checked left to right in order, so the first did its work already when you evaluate the second and mortageTerm will have the value.
Edited to address comments.
int mortgageTerm;
cout << "Mortgage term (1 - 40 years) : ";
while (!(cin >> mortgageTerm) ||
mortageTerm < 1 ||
mortgageTerm > 40 )
{
cout << "That's not a valid choice! Try again : ";
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
}
// If you are concerned about extra input after the number and want to clear the input stream
// cin.ignore(std::numeric_limits<streamsize>::max(), '\n');

Validating input with cin

#include<iostream>
#include<limits>
int main()
{
int m;
std::cin >> m;
while (std::cin.fail() || m <= 0) {
std::cin.clear();
std::cin >> m;
}
return 0;
}
The above code is supposed to prompt for an input until a positive integer is entered. But even after entering a positive integer it keeps prompting for an input.
For example, lets say I have the input as
abc
c4
-3
1
2
.
.
So in principle the moment I enter 1, the execution should be transferred out of the loop. But it keeps prompting for an input and looks like an infinite loop.
After looking around for a while, I modified it as
cin >> m;
while (cin.fail() || m <= 0) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cin >> m;
}
As desired, entering a positive number terminates the loop.
I didn't get it. Why the new line character is stuck in the input buffer?
Suppose I have this
int a , b;
cin >> a;
cin >> b;
When my input is
1
2
It correctly sets a to 1 and b to 2, instead of setting b to \n.
Why is the behaviour different in the two cases?
It's not that there's a stray newline, but that the entire input is still in the stream.
cin >> m fails immediately if it can't extract an integer.
It does not read the next "word" and see if it's an integer, and then stop after that "word" if it wasn't - the "read pointer" is left at the point of initial failure.
The ignore skips ahead to the end of the line and ignores everything up to that point.
To illustrate the difference, this program tries to read the input first as int and if that fails, reads the same input again as a std::string for use in the error message:
int main() {
int n = 0;
string s;
while (!(cin >> n))
{
cin.clear();
cin >> s;
cout << "That wasn't an int, it was " << s << endl;
}
cout << "This is an int: " << n << endl;
}
The solution you found with ignore is pretty much the "standard" solution.
The newline will be eaten up when extraction succeeds (whether the extracted integer is positive or not).
It won't be eaten up when extraction fails.

While keeps repeating on letters but not on #'s

I have a while loop here that only takes in 1 and 2 as the number, if i insert and number that is not these my else statement will keep asking for the correct one, which works correctly. But if i insert a letter my else statement loops forever. How can i fix this?
#include <iostream>
using namespace std;
int main()
{
int myChoice;
cin >> myChoice;
while ( myChoice >= 2 || myChoice <= 1)
{
if (myChoice == 1)
{
cout <<"food1";
break;
}
else if (myChoice == 2)
{
cout <<"food2";
break;
}
else
{
cout << " " << endl;
cout << "Please select the proper choices" << endl;
cout << "Try again: ";
cin >> myChoice;
}
}
return 0;
}
If you enter a non-number, then cin >> myChoice fails. That means that it leaves the input intact in the input buffer and when you get there again it tries to parse it and fails, and so on... You must clear the error state and ignore the non-digits. The simplest way is something like this:
cout << "Try again: ";
cin.clear(); // clear error state
cin.ignore(std::numeric_limits<streamsize>::max(), '\n'); // ignore till the end of line
cin >> myChoice;
The problem here is that the cin >> operator expects to receive an int input and receives a char input.
The istream module, of which cin is an instance, is using buffered I/O. This means that the user input is first stored in a buffer, and then read from that buffer when the user program accesses the >> operator. Ordinarily, if the >> operator succeeds in reading and parsing the user input, the read data is extracted from the buffer and the next invocation of the >> operator would continue where the last call left off. In you case, however, the >> operator attempts to parse the user input as a number and fails since it contains illegal chars which are not digits. The >> operator doesn't extract the read data from the buffer in this case and this same data is being referred to over and over again in the following calls to the >> operator.
You should empty the buffer on failure, the way ybungalobill suggested, for instance.
Your while condition is always true, then you use break to exit the loop. You could simplify things a bit like this:
#include <iostream>
using namespace std;
int main()
{
int myChoice;
cin >> myChoice;
while( myChoice != 1 || myChoice != 2 ) {
cout << endl;
cout << "Please select the proper choices" << endl;
cout << "Try again: ";
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
cin >> myChoice;
}
// At this point myChoice is 1 or 2
if (myChoice == 1)
cout << "food1";
else if (myChoice == 2)
cout << "food2";
}

How do I prevent a runaway input loop when I request a number but the user enters a non-number?

I need to know how to make my cin statement not appear to 'remove' itself if you input the wrong type. The code is here:
int mathOperator()
{
using namespace std;
int Input;
do
{
cout << "Choose: ";
el();
cout << "1) Addition";
el();
cout << "2) Subtraction";
el();
cout << "3) Multiplication";
el();
cout << "4) Division";
el();
el();
cin >> Input;
}
while (Input != 1 && Input != 2 && Input!=3 && Input!=4);
return Input;
}
Execute, enter, for example, a character, and it loops nonstop acting as though the cin statement isn't there.
You must check that input succeeded and handle when it doesn't:
int mathOperator() {
using namespace std;
int Input;
do {
cout << "Choose: ";
el();
cout << "1) Addition";
el();
cout << "2) Subtraction";
el();
cout << "3) Multiplication";
el();
cout << "4) Division";
el();
el();
while (!(cin >> Input)) { // failed to extract
if (cin.eof()) { // testing eof() *after* failure detected
throw std::runtime_error("unexpected EOF on stdin");
}
cin.clear(); // clear stream state
cin.ignore(INT_MAX, '\n'); // ignore rest of line
cout << "Input error. Try again!\n";
}
} while (Input != 1 && Input != 2 && Input!=3 && Input!=4);
return Input;
}
If you don't check that extraction succeeded, then cin is left in a failed state (cin.fail()). Once in a failed state, later extractions will immediately return instead of trying to read from the stream, effectively making them no-ops – leading to your infinite loop.
Unless you're quite certain about the input being in the proper format, you rarely want to use operator>> directly from the input stream.
It's usually easier to read a line with std::getline, put that into a std::istringstream, and read from there. If that fails, you print/log an error message, throw away the remainder of the line and (possibly) go on to the next line.
After reading in a bad value, cin is in a "failed" state. You have to reset this.
You must both clear the error flag and empty the buffer. thus:
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
The second call "flushes" the input buffer of any data that might be there, to get you ready for the next "cin" call.
If you find yourself writing these 2 lines "all over your code" you could write a simple inline function to replace it.
inline void reset( std::istream & is )
{
is.clear();
is.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
}
Although I have made this function take any istream, most of the time it would only be used for cin where a user is entering and enters something invalid. If it's an invalid file or stringstream input, there is no way to fix it and you would do best to just throw an exception.
don't read int, read char so cin will pass any invalid character
char Input;
do
{
// same code
}
while (Input != '1' && Input != '2' && Input != '3' && Input!='4');
return Input;
[EDIT]
If you want convert char to int you can use this piece of code
int i = (Input - 48);
I agree that a char is just as handy, since you can always cast to int, to answer your question as to why this is happening, when a cin input is exected as an int but a char is entered, the input is kept in the input stream for the duration of the loop, which is why it seems to "disappear."
For more information: see the post from Narue at http://www.daniweb.com/forums/thread11505.html