Can you stop letters being entered for an integer? - c++

I was wondering if there was anyways of stopping letters being entered for an integer. Here is the code which I have been using in my int main.
do
{
cout << "Player 1 please enter the value of the row you would like to take ";
cin >> row;
}while (row != 0 && row != 1 && row != 2 && row != 3);
My problem with this code is that if the user enters a letter it creates a never ending loop. Any help would be much appreciated.

Standard library doesn't provide anything that would filter characters that are entered through standard input. I believe you could use libraries like curses to do that.
What you can do, though, is check whether input suceeded. operator>> for int will set the stream's state to failbit if it couldn't extract an integer (for example, when it encountered an 'a' or something like that. You can use extraction operators in boolean context, something like this:
cout << "Player 1 please enter the value of the row you would like to take ";
while (!(cin >> row) || (row < 0 || row > 3)) {
cout << "Invalid input, try again!\n";
// clear the error flags and discard the contents,
// so we can try again
cin.clear();
cin.ignore(std:numeric_limits<std::streamsize>::max(), '\n');
}
Note that if you enter for example 1abc, the read will succesfuly read 1 and leave the abc in the stream. This might not be a desired behaviour. If you wish to treat that as an error you can say
if ((cin >> std::ws).peek() != EOF) { /* there's more input waiting */ }
and act accordingly, or just unconditionaly ignore everything from the stream once you've got a value.

Get characters one at a time and only add the number characters to the string. Use
cin.get();
in a loop.

Related

While condition: How to allow comparison between non-integer/double user input and integer limits

Objective: Run a while loop that will repeat until the user inputs an integer between 1-3 (inclusive). So if an integer that is smaller than 1 or bigger than 3 is inputted or any character or string is inputted, the loop repeats.
My noob knowledge: I know how to compare user input when it is an integer, but when it is a char or string datatype input all I get is an infinite loop. Plus I declared the inputtable variable as an integer, so not sure how to go on about this.
I've done some Google searches but can't seem to find a question similar enough to mine.
Advice is highly appreciated :)
Code below:
int Decision1 = 4;
while ( Decision1 < 1 || Decision > 3)
{
std::cout << "Enter answer here: ";
std::cin >> Decision1;
std::cout << "\n\n";
}
int Decision1;
while(std::cin >> Decision1) {
if(Decision1 >= 1 && Decision1 <= 3) break;
// todo
}
You can use ASCII codes for checking number or character.
#include <iostream>
int main() {
char Decision1 = '0';
while ( (Decision1 < 49 && Decision1 >=47) || (Decision1 >51 && Decision1 <=57 ))
{
std::cout << "Enter answer here: ";
std::cin >> Decision1;
std::cout << Decision1;
std::cout << "\n";
}
}
I hope helpful for you.
Keep in mind: when you read input from std::cin you're reading text that's typed at the console. The stream extractor tries to convert that text to the target type. That is, in
int i;
std::cin >> i;
the >> operator looks for digit characters and figures out what value those characters represent. If the characters can't be converted to an integer value the extraction fails. Streams have a conversion to bool that tells you whether the stream is in a good state, or whether an attempted operation failed. So:
int i;
if (std::cin >> i)
std::cout << "got a value!\n";
To write a loop that prompts for valid input you need to reverse the test:
int i;
while (!(std::cin >> i) {
std::cout << "bad input\n":
// now clear the input stream, so it's back in a good state
}
To also check that the value is in the required range, just do it:
int i;
while (!(std::cin >> i) || i < 1 || i > 3) {
std::cout << "bad input\n":
// now clear the input stream, so it's back in a good state
}
To clear the input stream, you have to reset its internal flags. You do that with std::cin.clear();. And, depending on what you think was typed in, you probably want to get rid of any additional characters that the user typed. You do that with std::cin::ignore(std::numeric_limits<std::streamsize>::max(), '\n'). That tells the stream to discard character until it reaches a newline (press ENTER), or until it has read a huge number of characters.
Putting it all together:
int i;
while (!(std::cin >> i) || i < 1 || i > 3) {
std::cout << "bad input\n":
std::cin.clear();
std::cin::ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Yes, this clears the stream state and flushes the input when the input was a valid integer but out of range; that's harmless. It's a waste of time, but the speed of keyboard input is limited by how fast the user types, which is much slower than anything that the code in this loop does.

Input Validation Inside While Loop

I'm currently working on a small project to learn (and for fun) and need a while-loop to check if a user's input is one of the integers 1, 2, 3, 4, or 5. What is the best way to do this? Here's my basic idea in code, but it's not quite working:
std::cin >> input;
while (cin.fail() == true || input != 1 && input != 2 && input != 3 && input != 4 && input != 5){
std::cout << std::endl "The valid choices are 1, 2, 3, 4, and 5. Please choose: ";
std::cin >> input;
std::cout << std::endl;
}
This only works if it's a digit above 5, but fails if I enter a letter. How can I use cin.fail() to validate correctly?
First
#include <limits>
to get max streamsize. Then flip some of the logic around
while (!std::cin >> input || // didn't read valid input
input < 1 || // number too small
input > 5) // number too large
{
std::cout << std::endl "The valid choices are 1, 2, 3, 4, and 5. Please choose: ";
Then clear the stream error and any other crap the user typed in
std::cin.clear();
std::cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
Finally ask for a redo
std::cin >> input;
std::cout << std::endl;
}
What this won't catch:
1.23
cin will stop reading at the '.' because it's not found in an integer and happily return 1. Ooops.
1a
Same problem
1 holy bad input, Batman!
Similar problem. cin stops at the space.
What you really want to do is something that gets the whole input line from the user with std::getline and then uses std::stoi to make sure that it is all an int
Assuming that input is an integer, failures will happen when it reads in a string/char. What you need is
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
in the body of your while loop since when it fails the stream closes, so you need to clear it.
To expand a bit, the cin.clear() just clears the stream, and then the rest of the line is ignored in the cin.ignore(). It will ignore the maximum possible line size so it's the most correct, but most programs can get away with just putting some huge number in there instead.

How to get rid of bad input one word at a time instead of one line at a time?

I am reading "C++ primer plus/Stephen Prata"
Here is the code from this book
while (!(cin >> golf[i])) {
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
The code above is easy to understand.
But the context from this book mentions
"...the program uses cin.get() in a while loop to read the remaining input through the end of the line.This gets rid of the bad input, along with anything else on the line.
Another approach is to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time.
Finally, the program tells the user to enter a number."
I wonder what the another approach is?
I try to express the code in different way and I know it's not correct.
while (!(cin >> golf[i])) {
cin.clear(); // resset input
char word[20];
while (cin >> word)
continue; // get rid of bad input
cout << "Please enter a number: ";
}
How do I code to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time?
thank you for your reading.
Let's start by looking at the existing code:
while (cin.get() != '\n')
continue;
This is what reads up to the new-line. We read a character, compare it to the new-line, and if it's not equal, we read another character. So, it reads characters, and stops reading when it gets to a new-line.
If we want to read to a space character instead, we just change the value we compare to:
while (cin.get() != ' ')
continue;
If we want to stop reading at any white-space, we could use a function to tell us whether a character is white space or not. That function would look something like this:
bool is_white_space(char ch) {
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v';
}
But this is a common enough task that the standard library already has an isspace function, so we don't have to write our own. We just have to use it:
while (!isspace(cin.get())
continue;
Personally, I'd at least consider putting this into a function by itself, and giving it a readable name like skip_to_whitespace, so our outer loop would look something like:
void skip_to_space(std::istream &in) {
in.clear();
while (!isspace(in.get()))
continue;
}
// ...
while (!(cin >> golf[i])) {
skip_to_space(cin);
cout << "Please enter a number: ";
}
At least to me, this seems to make the intent of the code considerably more apparent--we don't have to read through the content of the loop to figure out what it's supposed to do--that's obvious from the name of the function.
There is one last thing I'd change though. A while loop should normally have no effect if its condition is false. This one, however, always reads at least one character from its input, regardless of what that character might be. To make that fact more apparent, I'd prefer to use a do loop, to correctly reflect the intent that the loop always executes at least once:
void skip_to_space(std::istream &in) {
in.clear();
char ch;
do {
ch = in.get();
} while (!isspace(ch));
}
Now it's obvious that the cin.get() always happens at least once, and continues to happen until we reach a white-space character.
To throw out words until you reach a number do this:
string word;
cout << "Please enter a number: ";
while(!(cin >> golf[i])){
cin.clear();
cin >> word;
if(cin.rdbuf()->in_avail() == 1){
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Please enter a number: ";
}
}
One method of throwing out an entire line would be to use ignore.
while (!(cin >> golf[i])) {
cin.clear(); // resset input
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // get rid of bad input
cout << "Please enter a number: ";
}

Failed Input help, Int and Char, C++

I am trying to determine if the user enters something other than a character, and specifically, that they only enter m or s. See code below.
Note:
filingStatus is a char
do
{
cout << "Please enter your filing status (s for single, m for married)" << '\n';
cin >> filingStatus;
if (cin.fail())
{
cin.clear();
dataTest = 1;
cout << "Error, please enter a valid input!" << '\n';
double dummyDouble;
cin >> dummyDouble;
if (cin.fail())
{
cin.clear();
cin >> dummyString;
}
}
else
{
if (filingStatus == 'm' || filingStatus == 's')
{
dataTest = 0;
}
else
{
cout << "Error, please enter either m or s!" << '\n';
dataTest = 1;
}
}
} while (dataTest == 1);
Here is the problem, if I enter 1000 for example, the input doesn't fail. It instead stores the 1 in the char, and since 1 is neither m or S, it loops again, then it puts the 0, loops again, puts another 0, etc.
My understanding was it would fail when it sees that a integer is being stored in a char, but obviously it isn't failing.
My question is:
Why isn't the input failing? How can I change it so if someone enters a string, or number that it fails?
The input isn't failing, because '1' is a character. Digits are a subset of characters.
Read into a std::string. Then test whether that string consists of a single character from your desired range.
Note however, that reading into a string using >> stops at the first white space. To prevent this and read the whole line instead, read using std::getline().
I am assuming that fillingStatus is of char type.
Now even if you enter a numeral say '1' or '0', it is read as a char. Hence cin does not fail. It just keeps on looping as per your code.
Also, while reading an invalid char, you should be careful of clearing the input buffer because the return character '\n' stays along with other characters in the input buffer.
I would do it something like the following:
while ( !(cin >> fillingStatus) || (filingStatus != 'm' && filingStatus != 's') ) {
cout << "Error, please enter either m or s!" << '\n'; // error message
cin.clear(); // clear the error flag
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // ignore all invalid previous input
}
One way could be to change the fillingStatus to string and get only the first character of that string and see if it fails or not.
Alternatively, there used to be a method for getting a character input, getche() I think (it has been many years since I worked in C++ so don't exactly recall)...you maybe able to use that too.
Thanks
Since you are only reading the input one character at a time, your are essentially unable to tell that the user has input more and it is being held until you read more from the input stream.
Using a string to read a line of data at a time and having the program react to that string as a whole will solve your problem.
std::string filingStatus ;
while(!(cin >> filingStatus ) || ( filingStatus != "m" && filingStatus != "f") )
{
cin.clear();
std::cout << "Error, please enter either m or s!" << '\n';
};

while loop to infinity when the input of a cin is a 'dot'

I am having trouble using the cin method to acquire a variable. When the input is a number there is no problem, but when it is a special character like a dot [.],
the whileloop loops into infinity.
What am I doing wrong?
cout << "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl;
cin >> *race;
while(*race<1||*race>3)
{
system("cls");
cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl;
cin >> *race;
}
I searched for the answer and i should have to flush the buffer but i don"t get how to do it. I'm rather new with c++. Thanx
Make race an char, then you will be able do to:
while (*race < '1' || *race > '3')
which is probably what you want to achieve.
Explanation:
When you cin >> into an int, it converts given ASCII string to integer value. . doesn't have an integer meaning, so it isn't read into race and failbit is set - further >>s are no-op, until you clear them. However, if you cin >> into char and compare it with other chars (well, their ASCII codes, actually), you will be able to check it without troubles.
This example exactly reproduces your problem:
#include <iostream>
int main()
{
int i = 5;
while (i < 1 || i > 3)
{
std::cin >> i;
}
}
Here's what happens: When operator>> fails to read an integer (e.g. when you type a dot and press enter), whatever you typed stays in the stream, including the newline character.
So in the next iteration of the while loop the next input is already there and since it's not a valid integer, the loop can never break.
You need to make sure that, when operator>> fails, you empty the stream and clear all the error flags that got set.
#include <iostream>
#include <limits>
int main()
{
int i = 5;
while (i < 1 || i > 3)
{
if (!(std::cin >> i))
{
// clear streams internal error flags
std::cin.clear();
// ignore what's left in the stream, up to first newline character
// or the entire content, whichever comes first
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
}
There are several problems with your code. The first is that you don't
verify that your input has succeeded; the correct condition for the
while should be:
while ( !cin || (*race < 1 || *race > 3) )
As written, if the input fails (which is what is happening when you
enter a '.', supposing that race has type int*), then *race
contains its previous value, whatever that was.
The second is that if you do get an error from cin, you don't clear
it. Once the stream is in an error state, it stays that way until you
explicitly clear it. If cin has failed, you need to execute:
cin.clear();
somewhere in the loop.
The third is that if cin fails, you don't extract the character which
made it failed, so that after clearing the error status, you need to
extract it. Given the way you've structured your dialog, you probably
want to ignore everything until the end of the line:
cin.ignore( INT_MAX, '\n' );
You may want to do this even if cin didn't fail, either in the loop
(if entered because of the *race < 1 || *race > 3 condition), or in
case of success. Alternatively, you may want to shift to reading lines,
and ensure that the line only contains whitespace after the character
you're interested in.
This last solution is the one I would adopt, since it handles pretty
much all of the above problems. So my code would look something like:
// return -1 on error in input,
// throw exception on (unexpected) end of file
int
getRace( std::istream& source )
{
std::string line;
if ( !std::getline( source, line ) ) {
throw std::ios_base::failure( "Unexpected end of file" );
}
std::istringstream tmp( line );
int results;
return tmp >> results >> std::ws && tmp.get() == EOF
? results
: -1;
}
// ...
int race = -1;
while ( race < 0 ) {
std::cout << "What is your race\n"
"1. Human\n"
"2. Troll\n"
"3. Zombie\n" << std::flush;
race = getRace( std::cout );
if ( race < 0 ) {
std::cout << "Wrong choice" << std::endl;
}
}
Note that by inputting through a line, you avoid any problems with
resetting format errors, skipping erroneous input or resynchronizing in
case of error.
The other solution besides the one accepted is to clear the cin's failbit and ignore the last input like below:
cout << "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl;
cin >> *race;
while(*race<1||*race>3)
{
// Clears the state of cin to be in good state
cin.clear();
// Ignores the last input read so that it's not read back again
cin.ignore();
system("cls");
cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl;
cin >> *race;
}