So I need to get input from the user which has to be a number and I have to use cin.fail() to check if it is a number. On top of that, the number has to be either 0, 1 or 2. I'm new to C++ so haven't figured out how to do it.
Here's the part of the code. It checks if the input is a number, but I do't know how to make it check if the number is 1, 2 or 0 and if not then ask again until the input is valid.
do {
input = false;
cout << "Enter a number from the menu: ";
cin >> menu;
if (cin.fail()) {
cout << "Invalid input!" << endl;
input = true;
cin.clear();
}
cin.ignore(numeric_limits<streamsize>::max(), '\n');
} while (input);
cout << "Valid input!";
Assuming menu is an integer, witch makes sense, you can add the conditions you mentioned to your if:
if (cin.fail() || menu < 0 || menu > 2)
Live sample
Assuming the variable menu is a string ,you can take the first character of the string menu in the if statement and check if the decimal value of the character is between the decimal number of '0' to '3'.
Change your if statement to this:
if (menu[0] < '0' || menu[0] > '3' || menu.length() > 1)
{
// Error code
}
This code will run only if the decimal value of the first character is smaller than the decimal value of the char '0' or bigger than the decimal value of the char '3' and this code will run if the length of the input the user entered is bigger than 1.
Related
I'm making a program that uses a while loop in C++. Here is my code so far:
int userInput = 0;
while (userInput != 'Z')
{
cout << "Please enter the homework score: ";
cin >> userInput;
homeworkScores.push_back(userInput);
if (userInput == 'Z') {
userInput = 'Z';
}
}
The problem im having is whenever I type Z, the loop keeps printing "Please enter the homework score: " over and over without stopping. I've defined homeworkScores as a vector earlier in the code. How can I make it stop the loop once userInput == 'Z'? Thanks in advance!
The problem you are facing, is that cin is trying to read an integer, but you provide a character in the input. cin will only ask for another input, once the input is empty, you can try this by supplying more than one integer to your code:
Please enter the homework score: 2 27 12 8
will input all four numbers and print "Please enter the homework score: " 4 additional times.
If you provide it with a character, it will not remove it from the input, so whenever "cin" is reached, it will see "Z" in the input, and continue.
You can use answers like provided here How to catch invalid input in c++? for your input sanitation, but it will not make "Z" work as a stop.
The easiest way is to chose an invalid score like -1 instead of Z, end on any invalid input or try to read a string on failure to read an int.
A simple way to exit a loop is by using the break statement.
if (userInput == 'Z') {
userInput = 'Z';
break;
}
Other ways would be to set your exit condition to resolve as false, which I think is causing some issues for you.
EDIT: As #Ganea Dan Andrei noted, reading a char from cin into an integer will cause the cin::fail() to return true. This can be reset by calling cin.clear(), which will allow you to make further inputs.
userInput is an integer, and so 'Z' would have to equal the ASCII equivalent of its char value, which is 90. The way you're doing it should shouldn't work. Instead, try making userInput a char, and then convert it to an integer so you can push it back into your vector. This might look like:
char userInput = '';
while (userInput != 'Z')
{
cout << "Please enter the homework score: ";
cin >> userInput;
homeworkScores.push_back(userInput - '0'); //Are you sure you want to push a 'Z'?
if (userInput == 'Z') {
userInput = 'Z';
break;
}
userInput = ''; // Reset your input so it doesn't keep getting pushed new values
}
What happens here is userInput - '0' is subtracting the ASCII values of your chars, and leaving you with their integer value. There are other ways to do this, but this is a commonly used way.
Here are two loop structures I'm using next to each other to validate integer and character input, one after the other:
while (((std::cout << "Enter Strength stat: ") && !(std::cin >> STR)) || ((STR > 20) || (STR < 0)))
{
std::cout << inval;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
while (((std::cout << "Use characters 'Y' or 'N' to confirm. ") && !(std::cin >> confirm_Y_N)) || ((confirm_Y_N != 'Y') && (confirm_Y_N != 'N')))
{
std::cout << inval;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
It's been working fine for any sort of non-matching input until my hand slipped and I entered "1-" for the integer value.
This is the output I get when I input anything beginning with the expected datatype and then follow it with any other datatype:
Enter Strength stat: 1-
Use characters 'Y' or 'N' to confirm. Invalid value! Use characters 'Y' or 'N' to confirm. Y-
Enter Dexterity stat: Invalid value! Enter Dexterity stat:
As you can see, it's completely skipping the while loop's conditions for both integer and character input validation one after the other, essentially rendering the program broken.
Why isn't the program discarding the invalid strings as long as the requested character is given at the beginning of it? Shouldn't char only accept single character fields?
The unexpected character after the expected data stays in the input buffer.
To fix this you can clear the buffer.
Try inserting
std::cin.clear();
fflush(stdin);
between the loops. For a more C++-like approach insert
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
This method will ignore any unexpected characters after valid input.
I tested this method and it is working.
I just started learning C++ after previously coding with Java. The code below takes input from the user and validates the input. The first piece asks for the number of voters, which must be a positive number. If I enter a negative number the program behaves as I expected. It prints out the error message and asks for the input again. However, if I enter any other character, such as any alphabet letter I get an infinite loop in the console, asking for input and printing the error message. What am I doing wrong?
my code:
#include <iostream>
using namespace std;
struct dataT {
int numOfVoters = -1;
float preSpread = -1;
float votingError = -1;
};
void getUserInfo() {
dataT data;
while (data.numOfVoters == -1) {
cout << "enter the number of voters" << endl;
cin >> data.numOfVoters;
if (data.numOfVoters <= 0) {
data.numOfVoters = -1;
cout << "Invalid entry, please enter a number larger than zero." << endl;
}
}
while (data.votingError == -1) {
cout << "enter the percentage spread between candidates" << endl;
cin >> data.votingError;
if (data.votingError <= 0 || data.votingError >= 1) {
data.votingError = -1;
cout << "Invalid entry. Enter a number between 0 to 1." << endl;
}
}
while (data.preSpread == -1) {
cout << "Enter the precentage spread between the two candidates." << endl;
cin >> data.preSpread;
if (data.preSpread <= 0 || data.preSpread >= 1) {
data.preSpread = -1;
cout << "Invalid input. Enter a number between 0 and 1." << endl;
}
}
}
int main() {
getUserInfo();
return 0;
}
Console:
enter the number of voters
f
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
...
...
...
If you write cin >> integervariable but in cin there are character that cannot represent an integer, the input fails, !cin becomes true, and the character remain there until you don't reset the input state from the error and consume the wrong characters.
a proper check can be
while(integervariable has not good value)
{
cout << "prompt the user: ";
cin >> integervariable;
if(!cin) //something wrong in the input format
{
cin.clear(); //clear the error flag
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard the rubbish
cout << "prompt error message \n";
}
}
Your if statements are always true, you want something more like:
if (data.votingError < 0 || data.votingError > 1) {
...
then data.votingError can take on a value different from -1 and exit your loop.
The std::cin object will check whether or not it is in a valid state every time it reads. If you enter a char where your program expects an int, then you'll "break" the input stream. All subsequent calls to std::cin will then be effectively skipped until you manually reset the input stream. When this happens, you'll never be able to set your values to anything other than -1, and your if statement always evaluates to true, causing an infinite loop.
As an aside, you can check for failure state by including && cin in all of your tests. Input objects implicitly evaluate to true if the stream is in a valid state and to false if the stream is in a failure state instead.
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';
};
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.