I am writing a program where I have to verify that the inputted value by the user is a valid float number. So, I've tried this method:
string test;
cin >> test;
float n;
n = atof(test.c_str());
cout << n << endl;
But it doesn't seem to do the job; when it does the conversion, the numbers after the . are lost. How can I validate that a valid floating point number is used in C++ (not 11)?
Examples:
INPUT: 32.e
OUTPUT: 32 (should be error)
INPUT: 2a.1234
OUTPUT: 2 (should be error)
When you use formatted reads combined with a check if everything is read you can determine if the [complete] value is a valid floating point number, e.g.:
int main()
{
for (std::string test; std::cin >> test; ) {
std::istringstream in(test);
double value;
if (in >> value >> std::ws && in.eof()) {
std::cout << "the string '" << test << "' is a valid floating point number\n";
}
else {
std::cout << "the string '" << test << "' is not a valid floating point number\n";
}
}
}
The test does ignore whitespace surrounding the string. If that isn't desirable, the manipulator std::noskipws can be used and the use of std::ws can be omitted. Alternatively you can use strtod() do determine if the entire value represents a floating point number.
What atof() is to simply see if the initial string of its argument is valid floating point number which is the case for the examples you quoted.
int main() {
float f;
cin >> f;
if (!cin.fail()) {
cout << f << endl;
} else {
cout << "Invalid input" << endl;
}
// your code goes here
return 0;
}
The fail() function checks the failbit and badbit on the stream. failbit signals what you want, if there was a logical error on I/O operation (example: try to read a float, but couldn't parse the token to a float) and badbit signals if there was a read/writing error on i/o operation (could not read/write token at all).
The answer really depends on whether you want an entire line of input validated. atof will work even if only the beginning of the input is a float (e.g. 3.3a, 4.72abc). If you want all of the input stream validated, then you'll have to use getline to read the string and parse it. Simply check for the existence of only digits plus a single '.'.
I credit the C++ faq lite for the basic idea.
http://www.parashift.com/c++-faq/istream-and-ignore.html
My example is in a loop so that you can more easily see what I mean.
#include <iostream>
#include <limits>
int main()
{
while(true)
{
double value = 0;
while ((std::cout << "Enter a floating point number\n ")
&& !(std::cin >> value)) {
std::cout << "\nThat's not a floating point number\n ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "You entered " << value << "\n";
}
return 0;
}
Related
I am trying to get input from the user and need to know a way to have the program recognize that the input was or was not a double/char this is what i have right now... but when you type an incorrect type of input
1) the double test one just loops infinatly
2) the char one won't stop looping even with the correct imput
int main () {
double _double = 0;
bool done = true;
while ( done ) {
cout << "Please enter a DOUBLE:\n" << endl;
cin >> _double;
if ( _double > 0 ) { done = false; }
if ( _double < 0 ) { cout << "\nthe number you entered was less than zero\nplease enter a valad number..." << endl; }
if(cin.fail()) { cin.clear(); }
}
done = false;
char _char = ' ';
while ( !done ) {
cout << "Please enter a CHAR" << "\n";
cout << "\t'y' = yes\n\t'n' = no" << endl;
cin >> _char;
if ( _char == 'y' || _char == 'n' ) { done = true; }
if ( ! (_char == 'y' || _char == 'n') ) { cout << "\nyou have entered an invald symbol... \n" << endl; }
if(cin.fail()) { cin.clear(); }
}
The best bet is always to read your input as strings. You can then use functions like std::strtod() to test and convert to doubles. Checking if streams have failed and then resetting them is error prone at best, and doesn't give you the possibility of producing good error messages.
For example:
string s;
cin >> s;
char * p;
double d = strtod( s.c_str(), & p );
if ( * p == 0 ) {
cout << "Read double: " << d << endl;
}
else {
cout << "Read string: " << s << endl;
}
The pointer 'p' will point to the first character that cannot be converted to a double. How exactly you handle that really depends on your app's logic.
The problem is that when you read something and cin sees the input can never be a double, it stops reading, leaving the stuff in the buffer that it didn't consume. It will signal failure, which you clear but you won't eat the remaining input that cin didn't eat up. So, the next time the same wrong input is tried to read again, and again...
The problem with the char one is that you have to press the return key to make it process any characters on most terminals (this does not happen if you make your program read from a file, for instance). So if you press y then it won't go out of the read call, until you hit the return key. However, then it will normally proceed and exit the loop.
As others mentioned you are better off with reading a whole line, and then decide what to do. You can also check the number with C++ streams instead of C functions:
bool checkForDouble(std::string const& s) {
std::istringstream ss(s);
double d;
return (ss >> d) && (ss >> std::ws).eof();
}
This reads any initial double number and then any remaining whitespace. If it then hit eof (end of the file/stream), it means the string contained only a double.
std::string line;
while(!getline(std::cin, line) || !checkForDouble(line))
std::cout << "Please enter a double instead" << std::endl;
For the char, you can just test for length 1
std::string line;
while(!getline(std::cin, line) || line.size() != 1)
std::cout << "Please enter a double instead" << std::endl;
If you want to read only 1 char and continue as soon as that char was typed, then you will have to use platform dependent functions (C++ won't provide them as standard functions). Look out for the conio.h file for windows for instance, which has the _getch function for this. On unix systems, ncurses provides such functionality.
cin >> _double will always get you a double, whether they typed in "42", "0" or "mary had a little lamb". You need to read the user input as a string, then test that string to see if it is a double. sscanf will return 0 if it can't convert the input string to the desired type:
cout << "Please enter a DOUBLE:\n" << endl;
string s;
cin >> s;
if( !sscanf(s.c_str(), "%lf", &_double) )
{
done = false;
cout << "Not a number, sparky. Try again." << endl;
continue;
}
Also, identifiers with leading underscores like you have are reserved by the language. Don't get in the habit of naming things like _double -- someday, they may not work.
So I figure I'll put this here since I had to traverse a lot of docs and forums to find the definitive answer. I was trying to get input from the user and check if the input was an integer using isdigit() in an if statement. If the if statement failed the program would output an error message. Although, when a nondigit character was entered the program would loop through the error message endlessly. Here's that code:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if(isdigit(guess))
{
game.guess(guess);
else
{
std::cout << "Error\n"; //this would be looped endlessly
}
}
std::cout << "You got " << game.getCorrect() << " correct" << std::endl;
return 0;
}
NOTE: Solved, only posted to include my solution. Feel free to correct if I stated anything incorrectly.
The posted way will fail sometimes and will cast the doubles to integers if any doubles are input.
Use something like the following
int getIntInput() {
try {
std::string input;
std::cout << "\nPlease Enter a valid Integer:\t";
std::cin >> input;
size_t takenChars;
int num = std::stoi(input, &takenChars);
if (takenChars == input.size()) return num;
} catch (...) {}
return getIntInput();
}
Problem: The program kept hold of the non-integer value stored in the cin buffer. This leads to the program never leaving the error message.
Solution:
Use std::cin.fail() to check if the input matches the variable data type. I.E. int was the expected input but the user entered a char. In this case std::cin.fail() would be true.
In the case of std::cin.fail(), use std::cin.clear() and std::cin.ignore(std::numeric_limits<int>::max(), 'n') std::cin.clear() will clear the error flag. The std::cin.ignore(std::numeric_limits<int>::max(), 'n') will ignore any other input that is not an integer and will skip to the new line. Effectively progressing the program.
The solution implemented in my code looks like this:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if (std::cin.fail())
{
std::cout << "Please enter a valid number\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
}
game.guess(guess);
}
Hope this helps and that it saves some people the tedious research because of never learning std::cin error handling! Note: I'm aware my implementation skips the current move, call it punishment ;)
I'm new to statically typed C++. In JavaScript, I could just check the data type first, but that seems to be very complicated, and the answers all seem to imply that you aren't "getting" the language.
here's the code I was testing out rand() with, where I came upon the issue of converting strings to integers:
int main(){
std::string input;
cout <<endl<< "What to do?"<<endl;
cin >> input;
if (input == "rand")
{
cout << "what is the max?" << endl;
cin >> input;
int number;
if (stoi(input) > 1) {
number = stoi(input);
}
else {
number = 10;
cout << "using 10"<<endl;
}
cout << rand() % stoi(input);
return main();
}
}
so in Javascript, I would just check the type of input or result, but what do people do in C++?
Not allowed to say thank you in the comments so I'm saying thank you here!
Well, let's try out what happens: https://godbolt.org/z/1zahbW
As you can see, std::stoi throws an exception if you pass it invalid input or its input is out of range.
You should, however, be aware that std::cin >> some_string; is somewhat non-obvious in that it reads in the first "word", not a line or anything like that, and that std::stoi does the same thing (again).
One way to perform the check, could be like this:
#include <string>
#include <iostream>
int main(){
std::cout << "Please give me a number: " << std::flush;
std::string input;
std::getline(std::cin, input);
try {
auto value = std::stoi(input);
std::cout << "Thanks for the " << value << " (but the string was \"" << input << "\")\n";
} catch(std::invalid_argument const&) {
std::cout << "The provided value is not an integer\n";
} catch(std::out_of_range const&) {
std::cout << "The provided value is out of range\n";
}
}
https://godbolt.org/z/rKrv8G
Note that this will parse " 42 xyz" as 42. If that is a problem for your use case, you may wish to use std::strtoi directly, or to check if your input is valid before parsing (e.g., using a regex)
Regarding to the documentation of std::stoi it throws an std::invalid_argument.
What you could do is to place your std::stoi call inside a try and then catch the std::invalid_argument, but personally i wouldn't do that.
Instead, it is (most likely) a lot better to check if the first character of your input is an int, because if it is one, it can simply be parsed by std::stoi.
You can do that by e.g. doing the following:
int max = 0;
std::string input;
std::cin >> input;
if(std::isdigit(input[0]))
max = std::stoi(input);
EDIT: Please note that this would not respect the case of a too big number, to handle that case you would need an additional check.
I have the following simple code:
#include <iostream>
int main()
{
int a;
std::cout << "enter integer a" << std::endl;
std::cin >> a ;
if (std::cin.fail())
{
std::cin.clear();
std::cout << "input is not integer, re-enter please" <<std::endl;
std::cin >>a;
std::cout << "a inside if is: " << a <<std::endl;
}
std::cout << "a is " << a <<std::endl;
std::cin.get();
return 0;
}
When I run the above code and input: 1.5, it outputs: a is 1. FYI: I compile and run the code with gcc 4.5.3.
This means that if cin expects an integer but sees a float, it will do the conversion implicitly. So does this mean that when cin sees a float number, it is not in fail() state? Why this is the case? Is it because C++ does implicit conversion on >> operator?
I also tried the following code to decide whether a given input number is integer following idea from this post: testing if given number is integer:
#include <iostream>
bool integer(float k)
{
if( k == (int) k) return true;
return false;
}
int main()
{
int a;
std::cout << "enter integer a"<< std::endl;
std::cin >> a ;
if (!integer(a))
{
std::cout << "input is not integer, re-enter please" ;
std::cin.clear();
std::cin >> a;
std::cout << "a inside if is: " << a <<std::endl;
}
std::cout << "a is " << a <<std::endl;
std::cin.get();
return 0;
}
This block of code was also not able to test whether a is integer since it simply skip the if block when I run it with float input.
So why this is the case when getting user input with cin? What if sometimes I want the input to be 189, but typed 18.9 by accident, it will result in 18 in this case, which is bad. So does this mean using cin to get user input integers is not a good idea?
thank you.
When you read an integer and you give it an input of 1.5, what it sees is the integer 1, and it stops at the period since that isn't part of the integer. The ".5" is still in the input. This is the reason that you only get the integer part and it is also the reason why it doesn't seem to wait for input the second time.
To get around this, you could read a float instead of an integer so it reads the whole value, or you could check to see if there is anything else remaining on the line after reading the integer.
When reading user input I prefer not to use operator>> as user input is usally line based and prone to errors. I find it best to read a line at a time and validate:
std::string line;
std::getline(std::cin, line);
This also makes it easy to check for different types of numbers.
std::stirngstream linestream(line);
int val;
char c;
if ((linestream >> val) && !(linestream >> c))
{
// Get in here if an integer was read.
// And there is no following (non white space) characters.
// i.e. If the user only types in an integer.
//
// If the user typed any other character after the integer (like .5)
// then this will fail.
}
Of course boost already supports this:
val = boost::lexical_cast<int>(linestream); // Will throw if linestream does
// not contain an integer or
// contains anything in addition
// to the integer.
Boost of course will convert floats as well.
I have some snippet which is kind a poor coding, but it works.
This method is pretty simple, but doesn't handle case when input value is invalid.
See more: https://en.cppreference.com/w/cpp/string/byte/atof
static float InputFloat(std::string label)
{
std::string input;
std::cout << label;
std::cin >> input;
return atof(input.c_str());
}
int main()
{
float value = InputFloat("Enter some float value: ");
std::cout << "value = " << value;
return 0;
}
I've written this piece of code that allows the user to choose input either the value 1 or 2. This is working perfectly fine aside from one minor issue:
If the user inputs something like "1asdaosd" the input is recognized only as 1.
I've tried using the isdigit function but I still didn't manage to make this work.
bool validInput;
do
{
cout << "Choose the game type: ";
cin >> gametype;
validInput = true;
if (cin.fail())
{
validInput = false;
cin.clear();
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
if (gametype<1 || gametype>2) {
validInput = false;
}
} while (!validInput);
The expected behaviour should be:
Anything other than "1" or "2" shouldn't be considered a validInput and therefore repeating the cycle. What happens is that "1asdasd" or "2aods" is considered a validInput but I want it to fail.
Below is a method based on stuff I read in one of the early chapters of Stroustrup's Programming: Principles and Practice Using C++ and an answer provided by Duoas at cplusplus.com. It defines a function, get_int_between(), that allows you to do something like this:
int my_variable;
get_int_between(my_variable, min, max, prompt, error_msg);
Which would prompt, validate, and store into my_variable.
Just for fun, I've also included a function, get_int(my_variable, prompt, error_msg), that does the same thing but allows an integer of any value.
#include <iostream>
#include <sstream> // stringstream
void get_int(int& d, std::string prompt, std::string fail);
void get_int_between(int& d, int min, int max, std::string prompt, std::string fail);
int main()
{
int my_number = 1; // initialize my_number
get_int(my_number, "Please enter an integer: ", "Sorry, that's not an integer.\n");
//Do something, e.g.
std::cout << "You entered: " << my_number << "\n";
get_int_between(my_number, 1, 2, "Choose the game type (1 or 2): ", "Sorry, that's not an integer.\n");
//Do something, e.g.:
std::cout << "Let's play Game " << my_number << "!\n";
return 0;
}
void get_int(int& d, std::string prompt, std::string fail)
{
while(1) {
std::cout << prompt;
std::string str;
std::cin >> str;
std::istringstream ss(str);
int val1;
ss >> val1;
if(!ss.eof()) {
std::cout << fail;
continue;
} else {
d = val1;
break;
}
}
}
void get_int_between(int& d, int min, int max, std::string prompt, std::string fail)
{
while(1) {
get_int(d, prompt, fail);
if(d > max || d < min) {
std::cout << "Sorry, your choice is out of range.\n";
continue;
}
break;
}
}
If you want to use strings use getline.
#include <iostream> // std::cin, std::cout
int main ()
{
char name[256], title[256];
std::cout << "Please, enter your name: ";
std::cin.getline (name,256);
std::cout << "Please, enter your favourite movie: ";
std::cin.getline (title,256);
std::cout << name << "'s favourite movie is " << title;
return 0;
}
if you make gametype as an int it will only accept 1 or 2 (of course you have to prevent other numbers to be accepted).
It's because gametype is an integer, so it's trying to read as much as would be valid for an integer. 1asdaosd is not a valid integer so it stops at the 1. If you want to read that thing in completely you'll have to make gametype a string for example, but then you won't be able to compare it to integers as you already do.
You can read it as a string if you want, and if you want to handle the case of strings and ints both, then you can use something like stoi to attempt to convert the string to an integer. Then catch the std::invalid_argument exception so you can know if the string can be converted to an integer. If it can't, then you know to keep it as a string.
It reads an int as far the input can be construed as such. Then stops. If you read into a string variable it will get it all.
Read data into a string variable.
Check that data is a valid integer.
Convert string to integer.
Tedious but it's the only way to do it
I'm guessing you want one input value on each line. You need to read this as string and then check if you got more than you asked for. If you need it as an integer you can convert the read string later.
I'm also assuming you only need to read single digit integers. More digits need the string to integer conversion in the loop and some more checks.
string gametype;
do
{
cout << "Choose the game type: ";
// read one word as string, no conversion, so will not fail (may hit eof though)
cin >> gametype;
// ignore rest of line (assuming you want next valid input on next line)
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
while ( gametype.size() != 1 || gametype.at(0) < '1' || gametype.at(0) > '2') );
// char to int conversion (single digit only)
int gametypeint = gametype.at(0) - '0';
// other way to convert string to int
istringstream iss(gametype);
iss >> gametypeint;
// yet another way (C++11)
gametypeint = stio(gametype);