Failed Input help, Int and Char, C++ - 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';
};

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.

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');

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: ";
}

"Because" to "use"; C++

I am trying to create a simple program that accepts doubles and puts them into a vector. If the value is not a double, it checks to see if the value is Q and continues to run unless it is "Q".
Here is the code:
string str = "";
while (str != "Q")
{
double n;
cin >> n;
if (cin.fail())
{
cin.clear();
cin >> str;
if (str != "Q")
cout << "'" << str << "'" << " is invalid input. Please try again!" << endl;
}
else
vec.push_back(n);
}
It seems to work perfectly. However some characters (b, e, c, a, etc.), will be skipped over when trying to output str. For instance, when I type in because, str outputs use.
I also find it really strange that when I change n from a double to an int, all characters are found (Input = because and str outputs because).
Is there something I am missing? Is this not an acceptable way to examine the output if it isn't a double?
Thanks!
When the user enters because, and you try to read it as a number with cin >> n, it tries doing so. It fails at some point, and consumed all the characters until the parse error (excluding). Only after consumption of these characters, it returns and marks the operation as failed (which you check with cin.fail()). Note that a floating point number can indeed contain hexadecimal characters, as they might be encoded in hexadecimal notation*.
Reading the number consumes some hex-digits which are part of the string you want to consume if parsing the input as a number failed. (Details see comments below question.)
A simple solution is to first try to read a 'q' and only if that fails, read a number, and if that also fails, the user entered something unexpected.
You can look at the next character without consuming it (so it's still there for parsing the number in the case it wasn't a 'q' using cin.peek().
Example:
if (cin.peek() == 'q') {
// really consume it, for the case you want to use cin later on again
cin.get();
// quit
} else if (cin >> n) {
// process input n
} else {
// handle user error; you can still get the whole line from cin
}
*) Two things are however strange and might be discussed in the comments: First, hexadecimal numbers should start with 0x, so it should fail at the very first non-digit/non-sign character. Secondly, why does int then not also show this behavior? Integers can also be hex encoded, afaik.
As comments suggested, your environment seems to be interpreting hex digits as floats, which is bizarre. What environment are you using?
I personally find iostreams' rules for when they stop reading to be very unintuitive. (For example, in GCC, your loop interprets "123abc" as "123" followed by an error.) If you want to read a line of text then process it, how about doing it explicitly?
while (str != "Q") {
getline(cin, str);
// Use stringstream to process one line of text exactly.
stringstream s(str);
double n;
s >> n;
if (str == "Q") {
break;
} else if (s.fail() || !s.eof()) {
cout << "'" << str << "'" << " is invalid input. Please try again!" << endl;
} else {
vec.push_back(n);
}
}
Boost.Lexical_Cast can make this easier.

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;
}