breaking out of while loop using cin.fail - c++

I am having difficulty figuring out how to get my loop to end, when an incorrect input is given. Every combination I could think of, to end the loop hasn't worked. What could be the next step to figure this out. The code is attached below. The next step, when the correct input is given, is to increment the number.
int main(){
int startingNumber;
int endingNumber;
int incriment;
cout<<"Enter a starting number\n";
cout<<"**";
while(!(cin>>startingNumber))
{
cout<<"Error: invalid entry\n";
cin.clear();
cin.ignore (500 ,'\n');
break;
return 0;
}
cout<<"Enter a ending number\n";
cout<<"**";
while(!(cin>>endingNumber))
{
cout<<"Error: invalid entry\n";
cin.clear();
cin.ignore (500 ,'\n');
}
}

First, good job on looking to validate the stream-state after input and before making use of the variable filled. Far too many questions simply ignore validation.
It looks like what you are trying to do is to require valid input from the user, and if a non-integer value is entered resulting in failbit being set, you want to clear the error bit, ignore the offending character and require the user to try again. That is a proper approach.
Where your logic breaks down is thinking you need to break if failbit is set. Just the opposite. To handle and recover from an invalid input, you want to loop-continually and break only when valid input is received. That way you validate the input, and if you have what you need, you break the read-loop, otherwise you handle the error and require the user to try again.
Ignoring increment for now, it looks like you wanted to:
#include <iostream>
#include <limits> /* for numeric limits */
int main(){
int startingNumber;
int endingNumber;
while (true) { /* loop continually until valid input received */
std::cout << "Enter a starting number\n** "; /* prompt */
if (std::cin >> startingNumber) { /* validate */
break; /* break on good */
}
/* handle error */
std::cerr << " Error: invalid entry\n";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
}
while (true) { /* ditto */
std::cout << "Enter a ending number\n** ";
if (std::cin >> endingNumber) {
/* add any additional needed criteria */
if (endingNumber == startingNumber) {
std::cerr << " Error: must not be startingNumber.\n";
}
else {
break;
}
}
else { /* condition cin.fail error since == check added */
std::cerr << " Error: invalid entry\n";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
}
}
std::cout << "startingNumber : " << startingNumber <<
"\nendingNumber : " << endingNumber << '\n';
}
(note: you would also want to check for eofbit and exit gracefully if the user enter a manual EOF with Ctrl + d (Ctrl + z on windows). Canceling input is a valid act by the user. Consider also checking for badbit in the off-chance there was a terminal error that was unrecoverable -- not likely -- up to you)
Note also the additional condition in the second input routine that checks if startingNumber == endingNumber. This is by way of example, presuming you don't want a zero increment later. The point being you can tailor your input routine to handle as many contingent cases as your code needs. You would much rather over-validate than let a corner-case that tanks your code slip through.
One additional consideration is calling std::cin.ignore() after the good input is received to deal with any trailing characters. (e.g. "20 more fleas" would be valid input but leave " more fleas" in the input buffer. In the event there is nothing to ignore, std::ignore() will return eofbit that you will need to .clear(). See: std::basic_istream::ignore This would be another simple addition that would strengthen your input routine.
Example Use/Output
Exercising the code you could do:
$ ./bin/startendno
Enter a starting number
** my dog has 10 fleas
Error: invalid entry
Enter a starting number
** 10
Enter a ending number
** 10
Error: must not be startingNumber.
Enter a ending number
** foo
Error: invalid entry
Enter a ending number
** 20
startingNumber : 10
endingNumber : 20
Look things over and let me know if you have further questions.

Related

C++ cin.fail() executes and moves to next line even though input is of another data type

I am using get.fail() to check if there's any char in the input, and if there is I would like to give the user a chance to re-enter. However, the program seems to still accept the user input whenever there's an integer in front of the input no matter the case. Say w1 and 1w, the program will tell the user that the it only accepts integers while the latter one accepts the input and moves over to the next line which then causes another problem.
void userChoice(int input){
switch(input)
{
case 1:
insert();
break;
case 2:
display();
break;
case 3:
update_data();
break;
case 4:
delete_position();
break;
case 5:
cout<<"Thank you for using the program\n";
exit(0);
break;
case 6:
tellSize();
break;
default:
cout<<"Not an option\n";
cin>>input;
while(cin.fail())
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cin>>input;
break;
}
userChoice(input);
}
}
Referring to the code above, say I give the input 1w. The program will still execute case 1 as if there's nothing wrong, and then w is somehow passed into the insert() function which is not what I want. I would like the program to let the user re-enter the input no matter if it's 1w or w1, in short I do not want the program to move over to the next line if there's a char in an integer input.
tl;dr:
Why does the code below still execute when the cin is 1w, shouldn't it print "Enter number only" since there's a character in there?
Edit: Here's a quick program I made, to reproduce the error I am facing, I first enter 1h and here's the first bug I'm facing, why is the program still executing when there's a char h in the input? Afterwards in the second input, I enter 2w and the program prints out 2, shouldn't the program loop the while loop since there's a char w in the input?
#include<iostream>
#include<iomanip>
#include<limits>
using namespace std;
void option_1()
{
int amount_input;
cout<<"Enter the amount of cake"<<endl;
cin>>amount_input;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"Enter number only\n";
cin>>amount_input;
}
cout<<amount_input;
}
void options(int input)
{
bool fail;
switch(input)
{
case 1:
option_1();
break;
default:
cout<<"Not an option"<<endl;
cin>>input;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin>>input;
break;
}
options(input);
}
}
void menu(){
int user_input;
cout<<"Enter 1 to print something\n";
cin>>user_input;
options(user_input);
}
int main(){
menu();
}
From your comments, it appears you want integer input exclusively and do not want to allow input of additional character after the integer like 1w, even though 1 would be converted to an int while leaving w unread to be removed by .ignore(...) after your call to .clear(). (as mentioned above, your use of .clear() and .ignore(...) are now correct.
If this is your intent, you need a way to check if there is anything else following the integer input by the user. To do that in a non-blocking way if nothing actually exists, you have a couple of options. (e.g. you can .peek() at the next character -- but you only get one, or you can use a line-oriented input approach) The line-oriented approach allows you to read the entire line of user input into a string and then extract the integer value and check whether there is anything else contained in the line of input.
The most straight forward way is to create a std::basic_stringstream from the line of data read with getline(). This approach, consumes the entire line of user input and provides you with all the tools you need to extract whatever information you may want from the line. It also does this in a way that does not effect any of your subsequent user inputs.
While I would recommend you combine your void menu() and void options(int input) functions so you simply have one function to handle input processing for your menu -- there is nothing wrong with breaking it in two other than the possibility of a few lines of code being duplicated. The following is just a suggestion on how to handle your menu() function to only allow integer input. You can adapt it to the remainder of your code.
You will need a couple of additional includes:
#include <sstream>
#include <string>
I would also #define the first and last acceptable menu entries so you have those constants available in your code in a place that can be easily changed as you add to your menu, e.g.
#define MENUFIRST 1 /* first valid entry */
#define MENULAST 1 /* last valid entry */
(note: that will allow only 1 be entered as a valid menu entry)
To limit you menu() function using the approach outlined above, you could do:
void menu(){
int user_input = 0;
string line, unwanted;
for (;;) { /* loop continually until valid input received */
cout << "\nEnter 1 to print something: ";
if (!getline (cin, line)) { /* read an entire line at a time */
cerr << "(user canceled or unrecoverable stream error)\n";
return;
}
stringstream ss (line); /* create a stringstream from line */
if (!(ss >> user_input)) { /* test if valid integer read */
/* test eof() or bad() */
if (ss.eof() || ss.bad()) /* if not, did user cancel or err */
cerr << "(empty-input or unreconverable error)\n";
else if (ss.fail()) /* if failbit - wasn't an int */
cerr << "error: invalid integer input.\n";
}
else if (ss >> unwanted) { /* are there unwanted chars? */
cerr << "error: additional characters following user_input.\n";
user_input = 0; /* reset user_input zero */
} /* was int outside MENUFIRST-to-MENULAST? */
else if (user_input < MENUFIRST || MENULAST < user_input)
cerr << "error: integer not a valid menu selection.\n";
else /* valid input!, break read loop */
break;
}
options(user_input);
}
The comments should be self-explanatory given the discussion above, but let me know if you have questions. Using the function with the rest of your code (and commenting the unused // bool fail;), you can test whether it meets your requirements, e.g.
Example Use/Output
$ ./bin/menu_int
Enter 1 to print something: w1
error: invalid integer input.
Enter 1 to print something: $#%&^#&$ (cat steps on keyboard) !#$%%^%*()
error: invalid integer input.
Enter 1 to print something: 1w
error: additional characters following user_input.
Enter 1 to print something: -1
error: integer not a valid menu selection.
Enter 1 to print something: 24
error: integer not a valid menu selection.
Enter 1 to print something: 1
Enter the amount of cake
3
3
Also note, your menu() funciton will now properly trap a manual EOF generated by the user pressing Ctrl+d (or Ctrl+z on windows) to cancel input and exit gracefully.

cin input (input is an int) when I input a letter, instead of printing back incorrect once, it prints correct once then inc for the rest of the loop

I'm making a multiplication practice program. As my title says, if I enter a letter into the console instead of a number, it will run off saying correct on the first one, but incorrect on the rest. Even if you're not touching the keyboard, it'll still spit out incorrect.
ans = table * i;
std::cout << table << " * " << i << " =" << std::endl;
std::cin >> input;
if(input == ans)
{
std::cout << "Correct! " << ans << std::endl;
}
else
{
std::cout << "Incorrect, the answer was " << ans << std::endl;
input = 0;
ans = 0;
}
}
Hopefully that gives you a view of what's happening in the code. Here's the output.
Enter the table you'd like to learn.
5
Enter the amount of multiples
3
5 * 0 =
s
Correct! 0
5 * 1 =
Incorrect, the answer was 5
5 * 2 =
Incorrect, the answer was 10
5 * 3 =
Incorrect, the answer was 15
What could I do to fix this problem? Thanks for your input.
There are a number of ways to structure the various test, but when taking input with cin (or generally with any input function), you must account for any characters in the input buffer that remain unread. With cin, you have three conditions you must validate:
.eof() (eofbit) is set. Either the end of input was reached, or the user manually generated an EOF by pressing Ctrl+d (or Ctrl+z on windoze, but see: CTRL+Z does not generate EOF in Windows 10);
.bad() (badbit) is set. An unrecoverable stream error occurred; and
.fail() (failbit) is set. A matching, or other recoverable, failure occurred. When the failure occurs input stops and no further characters are extracted from the input buffer.
(you can combine 1 & 2 into a single test as input is over at that point)
With failbit, you must do two things. (1) you must clear the stream error state by calling cin.clear(), and (2) you must handle any characters that remain unread in the input buffer. Generally this is handled by including <limits> and calling:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
(which will clear up to INT_MAX characters from the input buffer, stopping when the delimiter ('\n' here) is encountered)
A short example that loops until a valid integer is input by the user could be:
#include <iostream>
#include <limits>
using namespace std;
int main (void) {
int x = 0;
while (1) /* loop continually until valid input received */
{
cout << "\nenter an integer: ";
if (! (cin >> x) ) { /* check stream state */
/* if eof() or bad() break read loop */
if (cin.eof() || cin.bad()) {
cerr << "(user canceled or unreconverable error)\n";
return 1;
}
else if (cin.fail()) { /* if failbit */
cerr << "error: invalid input.\n";
cin.clear(); /* clear failbit */
/* extract any characters that remain unread */
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
else { /* on succesful read of int */
/* extract any characters that remain unread */
cin.ignore(numeric_limits<streamsize>::max(), '\n');
break; /* then break read loop */
}
}
cout << "integer: " << x << '\n';
}
(as mentioned at the beginning, you can structure the tests many different ways, as long as you cover all three conditions.)
Additionally, you can check the stream bit explicitly by calling rdstate() instead of testing with .fail(), etc..., e.g.
if (std::cin.rdstate() == std::ios_base::failbit)
Example Use/Output
$ ./bin/cin_validate_int
enter an integer: no
error: invalid input.
enter an integer: "an integer"
error: invalid input.
enter an integer: abc 123
error: invalid input.
enter an integer: 123
integer: 123
Look things over and let me know if you have further questions.
When you do cin >> input and it can't parse the input as a number, it sets cin's failbit, and when failbit is set it doesn't actually read any more data until you clear it.
You should check for errors by calling cin.good(), and try to clear them with cin.clear(), but you shouldn't try to clear some errors (like EOF) and instead should quit on them.

Stopping the user from entering letters? C++

Hi i'm newish to C++ but i have a little problem which is i have to stop the user entering letters in a number section. I have made an attempt which works but its dodgy, because it will allow the user to continue then will tell them they have got something wrong and to restart the application. How do i validate it to bring up an error message telling them thats not a number and let them re enter a number?
Here is the code:
double Rheight;
do
{
cout << "Enter height of the room. " << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4);
cout << "WARNING: If you enter a letter the program will exit." << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
cin >> Rheight;
}
while (Rheight > 20 || Rheight == 0);
Ask if you need to see more code.
There are basically two components to the answer:
Detecting that the input failed.
Cleaning up after a failed input.
The first part is rather trivial: you should always test after input that the stream is in a good state before using the input. For example:
if (std::cin >> value) {
// use value
}
else {
// deal with the input error
}
How to deal with the input error depends on your needs. When reading a file you'd probably abort reading the entire file. When reading from standard input you can ignore just the next character, the entire line, etc. Most like you'd want to ignore the entire line. Before doing so you'll need to put the stream back into a good state:
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
The first line clears the stream's error flags and the second line is a magic incantation ignoring as many characters as necessary until a newline got ignored.
To check if the input was valid you can use
if(!(cin >> Rheight))
{
cout << "Please input a valid number!" << endl;
continue;
}

Catch ios::failure keeps looping

The code below should check every input once and display "Not a number" whenever the input is not a number.
int input;
while (1 == 1){
cout << "Enter a number: ";
try{
cin.exceptions(istream::failbit);
cin >> input;
}catch(ios::failure){
cout << "Not a number\n";
input = 0;
}
}
The problem is that when the catch is called (when it is not a number) it displays "Invalid number" endlessly like if the while() loop was executed several times but without asking for any new input.
while(true) or while(1) [or for(;;)] are customary ways to make a "forever loop".
You need to "clean up" the input that isn't acceptable within the cin stream.
The typical approach is to call cin.ignore(1000, '\n'); which will ignore all input until the next newline [up to 1000 characters - you can choose a bigger number, but usually a 1000 is "enough to get to a newline].
You will almost certainly also (thanks Potatoswatter) need to call cin.clear(); on the input, to remove the failed state, so that next input can succeed. [And cin.ignore() is further input, so it needs to go before that - just to be clear].
Though you failed to extract characters from the stream into an int, those characters remain in the stream so that you can attempt to extract them as something else, instead.
To skip them entirely, run std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); inside your catch block.
Then, whatever the user enters next will be the first thing in the stream. And perhaps that'll be a number, so your next attempt to extract into an int succeeds.
Well yeah. Your try-catch statement is inside the loop. So you try something, it fails and throws an exception, then you catch the exception, and you never exit or return from the loop so you do the same thing all over again.
But since your input wasn't processed the first time (throwing an exception instead), it's not going to be processed the second time, or the third time, or any time.
To advance, handle the exception by ignoring the input until the next space:
int input;
while (1 == 1){
cout << "Enter a number: ";
try{
cin.exceptions(istream::failbit);
cin >> input;
}catch(ios::failure){
cout << "Not a number\n";
input = 0;
//the line below ignores all characters in cin until the space (' ')
//(up to 256 characters are ignored, make this number as large as necessary
cin.ignore(256, ' ');
}
}
By the way, as a general rule: exceptions should be for something that is truly exceptional, particularly since there is overhead for handling the exception. There is debate about whether invalid user input is exceptional.
As an alternative, you can make a much more compact, equally correct loop without exceptions like the following:
int input;
while (true){ //outer while loop that repeats forever. Same as "while(1 == 1)"
cout << "Enter a number: ";
//The following loop just keeps repeating until a valid value is entered.
//The condition (cin >> input) is false if e.g. the value is a character,
//or it is too long to fit inside an int.
while(!(cin >> input)) {
cout << "Not a number" << endl;
input = 0;
}
}

While loop with try catch fails at bad cin input

I can't seem to figure out why this falls into a loop after getting non-int input. I've tried cin.flush(), which doesn't seem to exist, cin.clear(), which seems like it should work, even cin.sync() after reading someone else post about it working, but didn't seem to make much sense. Also tried cin.bad().
Thank you very much for any help
Please enter the first number: f
Sorry, I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?Sorry,
you d on't get any more tries. Press
any key to continue . . .
#include <iostream>
using namespace std;
int main(){
int entry;
int attempts = 1;
int result;
while(attempts <= 5) {
try {
cout << "\n\nPlease enter the first number: ";
cin >> entry;
if (cin.fail())
throw "Sorry, I don't think that's a number?";
if (entry < 0)
throw "Sorry, no negative numbers. Try something else? ";
cout << "\nNow the second number: ";
cin >> entry;
cin.clear();
cin.get();
}
catch (char* error) {
cout << error;
attempts++;
}
}
if (attempts > 5)
cout << "Sorry, you don\'t get any more tries.\n";
system("pause");
return 0;
}
You should think carefully what you want to do if user gives invalid input in this case. Usually in these cases the best solution is to read one line from the input and throw it away.
Try putting cin.clear() and std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n'); in your catch clause. cin.clear() clears the failure state in cin, and cin.ignore() throws away rest of the line waiting in the input buffer.
(And yes, you probably should rethink your use of exceptions).
The most straight-forward (but not usually the easiest nor the fastest) way of dealing with validation of line-based input is to always read it line at a time. This way no extra whitespace (such as linefeed characters) is left unread in the buffer in any case, and discarding erroneous input is also quite automatic.
// Infinite loop for retrying until successful
while (true) {
// Ask the user something
std::cout << prompt;
// Read the answer (one full line)
std::string line;
if (!std::getline(std::cin, line))
throw std::runtime_error("End of input while expecting a value");
// Put the line read into iss for further parsing
std::istringstream iss(line);
int val;
// Read val from iss and verify that reading was successful and
// that all input was consumed
if (iss >> val && iss.get() == EOF) return val;
std::cout << "Invalid input, try again!\n";
}
It is fun to make a BASIC style input function out of this:
template <typename Val> void input(std::string const& prompt, Val& val) {
// (the above code goes here, slightly adjusted)
}
int main() {
int w;
double l;
input("Enter weight in kg: ", w);
input("Enter length in m: ", l);
std::cout << "BMI: " << w / (l * l) << std::endl;
}
Notes for the pedantics who were going to downvote me:
function input should be specialized for std::string
exceptions thrown by the input function should be caught in main
My Problem was to block char input to a cin >> number
This error caused an 'infinite' loop showing my prompt cout << prompt
with no way of exit but kill the process ...
The following shows what worked for me!
========================================
double fi_trap_d() // function to return a valid range double catching errors
{
double fi_game_sec;
//-------------------------------------------
do
{
fi_game_sec = -1;
cout << fi_game_sec_c;
//------------------------------
cin.ignore(); // (1)
//------------------------------
try
{ cin >> fi_game_sec; cin.clear(); } // (2)
catch (...) //out_of_range)
{
fi_game_sec = -1;
cout << " Dis am an error!\n";
// just loop back as we asked for a number
}
} while (fi_game_sec < 1);
//-------------------------------------------
return fi_game_sec;
}
========================================
Despite trying the " Dis am an error! " has NEVER shown up.
The key was (1) & (2) !
Exceptions should be used to handle exceptional, unexpected situations. Incorrect input from a user is neither unexpected nor exceptional -- it's more or less the norm. Personally, I tend to just ignore most bad input completely (when it can't be prevented). When (and only when) they enter something unusable repeatedly is it even worth pointing it out to them. As such, I'd tend to write the code something like:
char ch;
int attempts = 0;
std::cout << "Please enter the first number: ";
do {
cin >> ch;
attempts++;
if (attempts > 5)
std::cerr << "The only allowable inputs are '0' through '9'\n";
} while (cin.good() && !isdigit(ch));
int first_number = ch - '0';
This reads the input as a character, so it's always removed from the input stream. Then it attempts to validate the input, and if it fails, attempts to read again. Of course, you might want/need to get a little more elaborate, such as reading an entire line, attempting to convert it to a number, and reading another line if that fails.
Why are you doing this with exceptions? You're not going to kill the program on input, so you shouldn't throw an exception.
Just print out your error message and attempt to read in again.
It looks like you would be better off with iostream's native exceptions. Enable with
cin.exceptions( ios::failbit );
try {
…
} catch( ios_base::failure & ) {
cin.clear();
…
}
Never, ever throw an an object not derived from std::exception, and especially not a native type like char*.