cin.fail not working when numbers and letters entered - c++

I am working on a simple data validation as part of inputting numbers to an array. Right now it is working for the most part with the exception of one case - when I enter a number followed by a letter, the error message that I created it thrown, but the number is still entered into the array. Further confusing me is that it is functioning as intended when I compile the program in Xcode, but the issue I'm describing only shows up when I compile the program with g++. Any thoughts would be very appreciated. Here is my function which I think is giving me the issue.
float getInput()
{
float input;
std::cin >> input;
if (std::cin.fail())
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "type char/str not allowed, enter int" << '\n';
return getInput();
}
else
return input;
}

Got it sorted out. Basically, this is not the time to be using recursion. I put the if statement in a while loop, added a second cin to the end of the loop, and moved the return out of the loop. That took care of it. Thanks for the suggestion to use a loop instead.

Related

C++ infinite loop on wrong input [duplicate]

In the following loop, if we type characters as the cin input instead of numbers which are expected, then it goes into infinite loop. Could anyone please explain to me why this occurs?
When we use cin, if the input is not a number, then are there ways to detect this to avoid abovementioned problems?
unsigned long ul_x1, ul_x2;
while (1)
{
cin >> ul_x1 >> ul_x2;
cout << "ux_x1 is " << ul_x1 << endl << "ul_x2 is " << ul_x2 << endl;
}
Well you always will have an infinite loop, but I know what you really want to know is why cin doesn't keep prompting for input on each loop iteration causing your infinite loop to freerun.
The reason is because cin fails in the situation you describe and won't read any more input into those variables. By giving cin bad input, cin gets in the fail state and stops prompting the command line for input causing the loop to free run.
For simple validation, you can try to use cin to validate your inputs by checking whether cin is in the fail state. When fail occurs clear the fail state and force the stream to throw away the bad input. This returns cin to normal operation so you can prompt for more input.
if (cin.fail())
{
cout << "ERROR -- You did not enter an integer";
// get rid of failure state
cin.clear();
// From Eric's answer (thanks Eric)
// discard 'bad' character(s)
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
For more sophisticated validation, you may wish to read into a string first and do more sophisticated checks on the string to make sure it matches what you expect.
Attention
Please pay attention to the following solution. It is not complete yet to clear the error in your case. You will still get an infinite loop!
if (cin.fail())
{
cout << "Please enter an integer";
cin.clear();
}
Complete Solution
The reason is you need clear the failed state of stream, as well as discard unprocessed characters. Otherwise, the bad character is still there and you still get infinite loops.
You can simply can std::cin.ignore() to achieve this. For example,
if (cin.fail())
{
cout << "Please enter an integer";
// clear error state
cin.clear();
// discard 'bad' character(s)
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Another Solution
You can also use getline and stringstream to achieve. Here is a brief example.
string input;
while (1)
{
getline(cin, input);
stringstream(input) >> x;
cout << x << endl;
}
Perhaps, it's because,
cin is a streaming function. When a
non-numeric is entered instead of
numbers, it is ignored. And you are
prompted for re-entry.
Even if you did give numeric inputs,
you will be prompted for more inputs since you're on an infinite loop.
You can solve this problem like this:
1. Create a function to take in a string input.
2. return it as numeric after conversion. Use strtod() for conversion.
Hope this helps :)
Another alternative is operator! ,it is equivalent to member function fail()
//from Doug's answer
if ( !cin )
{
cout << "ERROR -- You did not enter an integer";
// get rid of failure state
cin.clear();
// From Eric's answer (thanks Eric)
// discard 'bad' character(s)
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Menu malfunction in simple c++ calculator [duplicate]

In the following loop, if we type characters as the cin input instead of numbers which are expected, then it goes into infinite loop. Could anyone please explain to me why this occurs?
When we use cin, if the input is not a number, then are there ways to detect this to avoid abovementioned problems?
unsigned long ul_x1, ul_x2;
while (1)
{
cin >> ul_x1 >> ul_x2;
cout << "ux_x1 is " << ul_x1 << endl << "ul_x2 is " << ul_x2 << endl;
}
Well you always will have an infinite loop, but I know what you really want to know is why cin doesn't keep prompting for input on each loop iteration causing your infinite loop to freerun.
The reason is because cin fails in the situation you describe and won't read any more input into those variables. By giving cin bad input, cin gets in the fail state and stops prompting the command line for input causing the loop to free run.
For simple validation, you can try to use cin to validate your inputs by checking whether cin is in the fail state. When fail occurs clear the fail state and force the stream to throw away the bad input. This returns cin to normal operation so you can prompt for more input.
if (cin.fail())
{
cout << "ERROR -- You did not enter an integer";
// get rid of failure state
cin.clear();
// From Eric's answer (thanks Eric)
// discard 'bad' character(s)
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
For more sophisticated validation, you may wish to read into a string first and do more sophisticated checks on the string to make sure it matches what you expect.
Attention
Please pay attention to the following solution. It is not complete yet to clear the error in your case. You will still get an infinite loop!
if (cin.fail())
{
cout << "Please enter an integer";
cin.clear();
}
Complete Solution
The reason is you need clear the failed state of stream, as well as discard unprocessed characters. Otherwise, the bad character is still there and you still get infinite loops.
You can simply can std::cin.ignore() to achieve this. For example,
if (cin.fail())
{
cout << "Please enter an integer";
// clear error state
cin.clear();
// discard 'bad' character(s)
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Another Solution
You can also use getline and stringstream to achieve. Here is a brief example.
string input;
while (1)
{
getline(cin, input);
stringstream(input) >> x;
cout << x << endl;
}
Perhaps, it's because,
cin is a streaming function. When a
non-numeric is entered instead of
numbers, it is ignored. And you are
prompted for re-entry.
Even if you did give numeric inputs,
you will be prompted for more inputs since you're on an infinite loop.
You can solve this problem like this:
1. Create a function to take in a string input.
2. return it as numeric after conversion. Use strtod() for conversion.
Hope this helps :)
Another alternative is operator! ,it is equivalent to member function fail()
//from Doug's answer
if ( !cin )
{
cout << "ERROR -- You did not enter an integer";
// get rid of failure state
cin.clear();
// From Eric's answer (thanks Eric)
// discard 'bad' character(s)
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Loop repeats indefinitely after break (c++)

My problem here is when the loop is broken after the user indicates they're done, the program then begins to print the last input infinitely. What's going on here? I've tried using break, return 0, setting loop = a, all results in the same thing. On a program earlier I used a for loop (used break) and it terminated just fine.
Note: This post is NOT up for syntax corrections, this is just a fragment, and the code runs fine until I terminate the loop. I'm wanting to know what's causing this to happen with a while-loop specifically.
Edit: Nevermind, figured out what was going on. When attempting to end the loop there was a datatype error (as you can see, we only receive input for two variables, both of which are ints), which caused the loop to the start repeating the last valid datatype entered. So my question is why does this happen with a data type error?
`
while (loop != "a")
{
cout << "Enter the first number: ";
cin >> input1;
cout << "\nEnter the second number: ";
cin >> input2;
cout << input1 << '\t' << input2 << '\n';
if (loop == "|")
{
break;
}
}`
Change the value of loop with in the block of while loop according to your condition if loop=="a" or loop =="|" then while loop will be terminated.
In the given code of you the value of loop is not changing therefore while loop will run infinite.
I hope you can understand.
It might be because you entered a wrong data type into 'cin'. This makes cin fail and it repeats the last acceptable value in the command prompt. Nothing to do with the loop. If you try it outside of the loop you'll see the same thing happen.
It's good practice to do the following:
while (!(cin >> input))
{
cin.clear();
cin.ignore(256, '\n');
cout << "Bad input. Try again: ";
}
so if cin fails - it will clear the fail status, ignore the last input and ask the user to enter his input again.
Hope this helps

Why is this code exiting at this point?

I'm new to C++. I stumbled upon one tutorial problem, and I thought I'd use the few things I have learnt to solve it. I have written the code to an extent but the code exits at a point, and I really can't figure out why. I do not want to go into details about the tutorial question because I actually wish to continue with it based on how I understood it from the start, and I know prospective answerers might want to change that. The code is explanatory, I have just written few lines.
Here comes the code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
double average_each_student() {
cout << "\n>Enter your scores seperated by spaces and terminated with a period\n"
<< ">Note: scores after total number of six will be truncated.\n"
<< endl;
double sum = 0, average = 0;
int user_input, counter = 0;
const double no_of_exams = 6;
while(cin >> user_input) {
++counter;
if(counter < 5) sum += 0.15 * user_input;
else if(counter > 4 && counter < 7) sum += 0.20 * user_input;
}
return sum / no_of_exams;
}
int reg_number() {
cout << "Enter your registration number: " << endl;
int reg_numb;
cin >> reg_numb;
return reg_numb;
}
int main() {
vector<int> reg_num_list;
vector<double> student_average;
reg_num_list.push_back(reg_number());
student_average.push_back(average_each_student());
string answer;
cout << "\n\nIs that all??" << endl;
//everything ends at this point.
//process returns 0
cin >> answer;
cout << answer;
}
The code exits at cout << "\n\nIs that all??" << endl;. The rest part after that is not what I intend doing, but I'm just using that part to understand what's happening around there.
PS: I know there are other ways to improve the whole thing, but I'm writing the code based on my present knowledge and I wish to maintain the idea I'm currently implementing. I would appreciate if that doesn't change for now. I only need to know what I'm not doing right that is making the code end at that point.
The loop inside average_each_student() runs until further input for data fails and std::cin gets into failure state (i.e., it gets std::ios_base::failbit set).
As a result, input in main() immediately fails and the output of what was input just prints the unchanged string. That is, your perception of the program existing prior to the input is actually wrong: it just doesn't wait for input on a stream in fail state. Since your output doesn't add anything recognizable the output appears to do nothing although it actually prints an empty string. You can easily verify this claim by adding something, e.g.
std::cout << "read '" << answer << "'\n";
Whether it is possible to recover from the fail state on the input stream depends on how it failed. If you enter number until you indicate stream termination (using Ctrl-D or Ctrl-Z on the terminal depending on what kind of system you are using), there isn't any way to recover. If you terminate the input entering a non-number, you can use
std::cin.clear();
To clear the stream's failure stated. You might want to ignore entered characters using
std::cin.ignore(); // ignore the next character
or
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// ignore everything up to the end of the line
use cin.clear(); before cin >> answer; That will fix the problem. But you are not controlling the input. it just runs out to cin..

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