When I enter in a correct value (an integer) it is good. But when I enter in a character, I get an infinite loop. I've looked at every side of this code and could not find a problem with it. Why is this happening? I'm using g++ 4.7 on Windows.
#include <iostream>
#include <limits>
int main()
{
int n;
while (!(std::cin >> n))
{
std::cout << "Please try again.\n";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.clear();
}
}
Input: x
Output:
It's because your recover operations are in the wrong order. First clear the error then clear the buffer.
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
You have to clear the error state first, and then ignore the unparsable buffer content. Otherwise, ignore will do nothing on a stream that's not in a good state.
You will separately need to deal with reaching the end of the stream.
Related
I am learning C++, and I wrote this code:
#include <iostream>
namespace input
{
template <typename T>
T prompt_user(std::string prompt)
{
T input;
std::cout << prompt << ": ";
std::cin >> input;
if (std::cin.fail())
{
std::cin.clear();
prompt_user<T>(prompt);
}
return input;
}
} // namespace input
If the user types in an invalid value, my if statement would catch it with std::cin.fail() (I think that's how you do it) and start over. But it instead loops my code infinitely and skips cin. How can I fix this?
When you start over, you just read the same invalid value again. You have no code to figure out where the invalid value begins and ends in the input stream and remove it.
It's not clear what the fix is. What the invalid value consists of may depend on the type. Do you want to discard a line? Do you want to discard characters until you find valid input? Or what?
You need to decide what behavior you want and code it.
I had to add std::cin.ignore(std::numeric_limits<std::streamsize>, '\n') below std::cin.clear(). I am so sorry for my mess up.
I have been making some simple programs such as number guessing games, betting games, etc. One thing I am trying to do in these programs is to create a catch for inputting the wrong data type. So if I had the variable int num; and the user inputted a string, is there a way to recognize if the data entered does not match the data type of the declared variable and ask to re-input it?
Thanks.
The C++ IOstream library does that for you. by default, std::istream objects will fail if formatted extraction operations fail.
So when you have something like this.
int num;
if(!(std::cin >> num)){
//operation failed
}
If the user enters characters other than numbers. std::cin will fail. Hence all you need to do is to check the status of the stream object to know if a formatted input succeeded
is there a way to recognize if the data entered does not match the
data type of the declared variable and ask to re-input it?
You could do something like this:
#include <limits> //for std::numeric_limits
#include <ios> //for std::streamsize
......
int num;
while(!(std::cin >> num)){
std::cerr << "Please enter a valid number!\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
EDIT:
As user4581301 pointed out in the comment, there are a few corner cases to watch out for.
A slight improvement hack for ints/floats hullabalo may be:
while(!(std::cin >> num) || std::cin.get() == static_cast<int>('.') ){
std::cerr << "Please enter a valid number!\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Note, that this hack only applies to ints
Well, you can store the input of the user on a string; then use stoi or a similar function to convert it back to int (or other type). That function can thow an exception if the conversion is invalid.
I did something similar here: https://gist.github.com/illescasDaniel/40ad9811af35855132d7588d08bf672a
Here Im trying to get an integer from user, looping while the input is correct.
After entering non integer value (e.g "dsdfgsdg") cin.fail() returns true, as expected and while loop body starts executing.
Here I reset error flags of cin, using cin.clear(); and cin.fail() returns false, as expected.
But next call to cin doesn't work and sets error flags back on.
Any ideas?
#include<iostream>
using namespace std;
int main() {
int a;
cin >> a;
while (cin.fail()) {
cout << "Incorrect data. Enter new integer:\n";
cin.clear();
cin >> a;
}
}
After cin.clear(), you do this:
#include <iostream> //std::streamsize, std::cin
#include <limits> //std::numeric_limits
....
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
What the above does is that it clears the input stream of any characters that are still left there. Otherwise cin will continue trying to read the same characters and failing
As a matter of style, prefer this method:
int main()
{
int a;
while (!(std::cin >> a))
{
std::cout << "Incorrect data. Enter new integer:" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
cin.clear() does not clear the buffer; it resets the error flags. So you will still have the sting you entered in your buffer and the code will not allow you to enter new data until you clear the cin buffer. cin.Ignore() should do the trick
There is also a very easy method:
#include <iostream>
std::cin.clear() //reset stream state so that cin.fail() becomes false.
std::cin.ignore(INT_MAX,'\n'); //clear the stream from any remaining characters until the \n which is present at the end of any cin.
This will reset stream state and clear any remaining things in it. Much easier, less code, and less header files.
Hey my code is stuck on looping my while when I input numeric letters, it just floods my output with "Invalid Input, please try again." It's just a simple menu.
If you ever enter anything "invalid", such that reading from cin will cause an error, you have to call cin.clear() to be able to read further input, otherwise the stream in operator will just return immediately.
Typically, when reading user input, you check the state of cin and exit or do some error handling when it is invalid. In addition, on a failed input attempt, the characters that caused the error will still be sitting in cin, and need to be ignored (e.g., up to the next newline):
#include <iostream>
#include <limits>
int main() {
int userOption;
while(1) {
while(!(std::cin >> userOption)) {
std::cout << "Invalid input." << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << userOption << std::endl;
}
return 0;
}
The problem is with the following line of code,
cin.ignore(numeric_limits<streamsize>::max(), '\n');
When you are entering a single number, you don't have to ignore any other character. So simply remove the above line of code to correct your program.
I'd like to know how to limit an input value to signed decimals using std::cin.
double i;
//Reading the value
cin >> i;
//Numeric input validation
if(!cin.eof())
{
peeked = cin.peek();
if(peeked == 10 && cin.good())
{
//Good!
count << "i is a decimal";
}
else
{
count << "i is not a decimal";
cin.clear();
cin >> discard;
}
}
This also gives an error message with the input -1a2.0 avoiding the assignation of just -1 to i.
If the backing variable of the cin is a number, and the string provided is not a number, the return value is false, so you need a loop:
int someVal;
while(!(cin >> someVal)) {
cin.reset();
cout << "Invalid value, try again.";
}
Combining the techniques from the top answer here and this website, I get
input.h
#include <ios> // Provides ios_base::failure
#include <iostream> // Provides cin
template <typename T>
T getValidatedInput()
{
// Get input of type T
T result;
cin >> result;
// Check if the failbit has been set, meaning the beginning of the input
// was not type T. Also make sure the result is the only thing in the input
// stream, otherwise things like 2b would be a valid int.
if (cin.fail() || cin.get() != '\n')
{
// Set the error state flag back to goodbit. If you need to get the input
// again (e.g. this is in a while loop), this is essential. Otherwise, the
// failbit will stay set.
cin.clear();
// Clear the input stream using and empty while loop.
while (cin.get() != '\n')
;
// Throw an exception. Allows the caller to handle it any way you see fit
// (exit, ask for input again, etc.)
throw ios_base::failure("Invalid input.");
}
return result;
}
Usage
inputtest.cpp
#include <cstdlib> // Provides EXIT_SUCCESS
#include <iostream> // Provides cout, cerr, endl
#include "input.h" // Provides getValidatedInput<T>()
int main()
{
using namespace std;
int input;
while (true)
{
cout << "Enter an integer: ";
try
{
input = getValidatedInput<int>();
}
catch (exception e)
{
cerr << e.what() << endl;
continue;
}
break;
}
cout << "You entered: " << input << endl;
return EXIT_SUCCESS;
}
Sample run
Enter an integer: a
Invalid input.
Enter an integer: 2b
Invalid input.
Enter an integer: 3
You entered: 3.
cin's >> operator works by reading one character at a time until it hits whitespace. That will slurp the whole string -1a2.0, which is obviously not a number so the operation fails. It looks like you actually have three fields there, -1, a, and 2.0. If you separate the data by whitespace, cin will be able to read each one without problem. Just remember to read a char for the second field.
I tried many techniques for reading integer input from the user using the >> operator, but in a way or another all my experiments have failed.
Now I think that getline() function (not the method with the same name on std::istream) and the strtol() function from the include cstdlib is the only predictable consistent solution for this problem. I would appreciate if someone proved me wrong. Here is something like the one I use:
#include <iostream>
#include <cstdlib>
// #arg prompt The question to ask. Will be used again on failure.
int GetInt(const char* prompt = "? ")
{
using namespace std; // *1
while(true)
{
cout << prompt;
string s;
getline(cin,s);
char *endp = 0;
int ret = strtol(s.c_str(),&endp,10);
if(endp!=s.c_str() && !*endp)
return ret;
}
}
*1: Placing using namespace whatever; to the global scope may lead to broken "unity builds" (google!) on larger projects, so should be avoided. Practice to not use that way, even on smaller projects!
Reading integers from files is a very different matter. Raúl Roa's approach can be good for that if properly worked out. I also suggest that wrong input files should not be tolerated, but it really depends on the application.
Be warned that using >> and getline() in the same program on cin will lead to some problems. Use one of them only, or google to know how to handle the issue (not too hard).
Something like:
double a;
cin >> a;
Should read your signed "decimal" fine.
You'll need a loop and some code to make sure it handles invalid input in a sensible way.
Good luck!