I know this question has been asked before, but the answers have not solved my problem thus I ask this question
I have a simple program to find the greatest of three numbers which should accept only floating numbers. In case a character or string is entered an error needs to be displayed and the user needs to enter again.
I have a function to take a valid floating input
float validInput()
{
float x;
cout<< flush;
cin >> x;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cout << "Not a numeric value please enter again\n";
cin >> x;
}
return x;
}
so I take input in the main function using validInput like
int main()
{
float x = validInput();
float y = validInput();
float z = validInput();
findGreatest(x,y,z);
return 0;
}
This method works for most inputs. It fails when I enter a number followed by a character the validInput function fails weirdly. On giving such an input it displays the error message "Not a numeric value please enter again" but does not take another input instead it considers the numeric value before the characters as the input and stores it. My requirement is to ignore the entire input and ask for a fresh input
From my understanding
cin.ignore(numeric_limits<streamsize>::max(),'\n');
does not ignore the numbers that are entered in the beginning of the input but only clears out the characters from the stream even though cin.fail() was true.
Is there any way to fix this? it probably needs different parameters for cin.ignore not sure though.
Thanks in advance
sources:
https://stackoverflow.com/a/16934374/5236575
PS: I can't use any special libraries like boost. The code is for implementing test cases for software testing so it needs to handle any type of input correctly.
You might want to look at what actually happens because the behavior isn't weird at all: when you enter a floating point number followed by a non-number on one line, the floating point value is extracted just OK. The failure case of your validInput() function is not hit - with that call! However, since there is something which can't be parsed as a floating point number when the function is called again the second call triggers the failure!
You can see that this is indeed the behavior by adding output between your validInput() calls. This way you can tell which of the calls actually produced the error. Storing the value when there is no error is the expected behavior!
You can make sure that a line doesn't contain invalid input by reading a line and verifying that you can read from the line and that there is nothing but space following on this line. For example:
float validInput()
{
float x;
// cout<< flush; There is *NO* reason to flush cout: it is flushed when using cin
for (std::string line; std::getline(std::cin, line); ) {
std::istringstream lin(line);
if (lin >> x && (lin >> std::ws).eof()) {
break;
}
cout << "Not a numeric value please enter again\n";
}
throw std::runtime_error("reached end of input before getting a valid value!");
return x;
}
The use of lin >> std::ws skips all potential trailing whitespace (the newline is already removed by std::getline()) on this line. After that the stream should be consumed and the eof() flag is set if there is, indeed, no further input (it is one of the few valid uses of eof()...).
std::cin will read sequentially from the stream, so if the first chars represent a valid number, it thinks it's OK. If you want to make sure what you read is indeed just a number (not followed by some additional chars), one option is to read using std::getline into a std::string, then convert the string to a float using std::stof (C++11). The latter takes as the second argument a pointer to the location of the first character that cannot be converted. If that location is smaller than the length of the string, then your line contains more than just the number, so the input is invalid.
Example:
#include <iostream>
int main()
{
float x;
std::size_t pos;
std::string str;
while (std::getline(std::cin, str))
{
try
{
x = std::stof(str, &pos);
}
catch(...)
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
if(pos != str.length())
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
break;
}
std::cout << x;
}
Related
I am currently trying to write a program at school involving a random number generator for rolling a dice. I have written the code successfully, but I am trying to improve it so that the size of the dice and the number the user is trying to roll can be chosen by the user.
I have written code that does this, and I have also added code that repeats the request for input if the wrong value (ie not one of the dice sizes offered or trying to roll a number outside the range of the dice) or input type (ie var instead of int) is entered. However, if a floating point number is entered, and the number to the left of the floating point is in the correct range of values, it is using that number.
For example:
int size = 0;
cout << "Please choose the size of the dice to roll (6, 12 or 20): ";
cin >> size;
while (size != 6 && size != 12 && size != 20 || !cin)
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Invalid number entered. Choose the size of the dice to roll (6, 12 or 20): ";
cin >> size;
}
This will correctly ask to repeat the input if any letters or any numbers that aren't 6, 12 or 20 are entered, but if 20.125 (or any floating point number that is 6.- 12.- or 20.-) is entered it will take the number and move on to the next bit of code. This also happens if I enter a valid number followed by letters (ie 6f).
I tried modifying the condition of the while loop to:
while (size != 6 && size != 12 && size != 20 || !(cin >> size))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Invalid number entered. Choose the size of the dice to roll (6, 12 or 20): ";
cin >> size;
}
And that fixes the problem, and it asks me for another input if I enter 12.5 or 20R etc, but then when I enter a correct input (6, 12 or 20) it just takes me to a new line in the debugger without moving to the next line of code. If I then enter a correct input again, it reads it at takes me to the next line of code.
I don't quite understand why one works 99% how I want it to with one error, and the other fixes that error but then gives me another one.
Thanks in advance, any advice guidance is much appreciated!
The way cin >> some_int_variable will interpret the input is character by character, until it stops making sense as an int. For instance, when it encounters . or f, cin is done reading that int.
If you want a different behavior, you will have to implement it yourself. Specifically, how do you stop processing one input, and starts processing the next?
cin >> some_int_variable will stop when it is no longer a valid it, cin >> some_std_string_variable will stop when it encounters an white-space character (new lines included). How about your problem? How do you want to separate one input from the next?
If white-space is a sensible approach, you can do so:
std::string word;
std::cin >> word;
int value;
bool error = false;
try {
size_t pos;
value = std::stoi(word, &pos);
// Was the full string used to build the int?
if(pos != word.size()) error = true;
} catch(std::logic_error&) {
error = true;
}
if(error) { /* something went wrong */ }
See the docs for std::stoi().
You could read a float, assign it to an integer variable and then compare the two. Something along these lines:
int integerSize;
float floatSize;
cin >> floatSize;
integerSize = floatSize; //Your program will perform a cast from float to integer, it will essentially truncate whatever appears after the floating point.
if (integerSize != floatSize) //Your program will now perform a cast from integer to float in order to compare the two, but if floatSize was not a whole number, this comparison should return false.
{
//code to ask for another value
}
That being said, floats (and doubles and long doubles) do experience rounding errors, so as another user suggested, the safest bet is to read a string and parse it yourself, or using a built-in function like std::stoi() (only for integers) and std::stof() (for floats).
template<typename T>
T typed_read_line(const std::string& prompt)
{
T result{};
std::string l;
std::cout << prompt << ":";
while (std::getline(std::cin, l)) {
std::istringstream line{l};
line >> result >> std::ws;
if (line.eof()) break;
//line contains more then expected
std::cout << "Again: " << prompt << ":";
}
return result;
}
https://godbolt.org/z/dfYKe3
Or version with extra validation or v3.
Now, before this question gets marked for duplicate. I have already gone through most of the questions and their relative answers of C++. These are the links that I have tried and none of them work for me. It maybe because they are using an older version of C++, and I have the latest version of C++. Here are the links that I have tried:
Detecting ENTER key in C++
https://www.sololearn.com/Discuss/1863352/how-can-i-check-that-user-press-enter-key-in-c
http://www.cplusplus.com/forum/beginner/2624/
https://www.dreamincode.net/forums/topic/398680-detect-enter-key/
Now, with the duplicates out of the way. I am making an expression calculator. So, for example if the user input is: 2+2*6*9/9, then the output should be 14.
The code where I suspect that the problem lies is in:
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::string;
using std::vector;
void clear();
void error(string message);
int main() {
cout << "Enter an expression: ";
double l_Value = 0, r_Value = 0, result = 0, count = 0, previous_number;
char op;
while (cin >> l_Value) { // 1+2*3+6-4/2+3
if (!cin) {
error("Invalid operand entered!");
}
else {
bool is_Error = 0; // false
vector<double> numbers;
numbers.push_back(l_Value);
previous_number = l_Value;
while (cin >> op) {
if (op == '\0') {
break;
}
cin >> r_Value;
switch (op)
{
case '+':
numbers.push_back(r_Value);
previous_number = r_Value;
break;
case '-':
numbers.push_back((-1 * r_Value));
previous_number = (-1 * r_Value);
break;
case '*':
numbers.pop_back(); // take out the number
r_Value *= previous_number;
numbers.push_back(r_Value);
previous_number = r_Value;
break;
case '/':
if (r_Value == 0) {
error("Sorry, division by zero has occured. Please re-evaluate your expression!\n");
is_Error = 1; // true
break;
}
else {
numbers.pop_back(); // take out the number
previous_number /= r_Value;
numbers.push_back(previous_number);
break;
}
}
}
if (!is_Error) {
for (int i = 0; i < numbers.size(); i++) {
result += numbers[i];
}
cout << result << '\n';
}
numbers.clear();
result = 0;
l_Value = 0;
r_Value = 0;
}
cout << "Enter an expression: ";
}
clear();
return 0;
}
None of the links above seemed to work for me.
When I press the Enter key, it expects me to give another input, and that is not supposed to happen. So when I used cin.get() == 'n' or cin.get() == (int)'\n', it expects for another input. But, when I have an 'x' at the end of the expression, it works perfectly fine. So, I need the "cin" operator to help me detect an Enter character at the end of the expression and then terminate the program.
Here, is a sample run of a program with 'x':
[![running as x-terminator][1]][1]
[1]: https://i.stack.imgur.com/ORPQa.png
When I try the above solution such as "cin.get() == '\n':
Then, I thought that maybe it is reading the null character and so, I tried if (op == '\0'):
For the enter key and null character I had to press Ctrl+Z to terminate the program. Please help!
As, mentioned by user #idclev, I already have a string program that works, but I am trying to avoid using string to calculate any expressions! So, if I could detect an enter key pressed using a character datatype that would be great!
I avoided strings to avoid parsing through the text
That argument is moot. What you can read from cin you can also read from a std::string, no difference whatsoever. You just need to add one step:
#include <iostream>
#include <string>
#include <sstream>
int main( ){
std::string x;
std::cin >> x;
if (x == "") {
std::cout << "user pressed enter (and nothing else)";
} else {
double y;
std::stringstream ss{x};
ss >> y;
std::cout << y;
}
}
This will read one std::string. If user only hit enter then the string will be empty. If the user entered something the else branch will be taken and you can extract the number from the string in the same way you did extract the number from cin (via using a std::stringstream).
If you have more than one number in the input you need to use getline to read the string, because cin will (by default) only read till the next whitespace.
Again...
If I used a string, I would have a tough time in extracting single-digit and two-digit or n-number of digits in a string. The double data type does that for me
You can read single-digit or any number of digits from a stringstream in exactly the same way as you read them from cin.
I already made a program with string in it. I was trying to avoid string to see how much faster would it be without string.
It won't be any faster. Constructing the string and the stringstream is maybe in the order of microseconds. A user entering input is in the order of seconds, maybe milliseconds when they are typing very fast.
Your approach cannot work because hitting enter is not considered as a character. Trying to read a character when there is none in the stream will fail. It will not set the character to \n or \r.
On the outer loop, you are trying to read a double, but you keep pressing enter. There is no input to evaluate, so it keeps trying to read a double. You can get out of it by ending the input stream with ^Z, or you can give it any actual content to read, and it will try to make it into a double (which is what your code explicitly told it to wait for).
Basically, when you press enter, it's ignoring it because
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
Extracts as many characters as possible from the stream and inserts them into the output sequence controlled by the stream buffer object pointed by sb (if any), until either the input sequence is exhausted or the function fails to insert into the object pointed by sb.
Try experimenting with this to see what is happening.
#include <iostream>
#include <vector>
#include <string>
int main() {
double x;
std::cin >> x;
std::cout << "read this value: " << x << std::endl;
// this is what while or if will look at
bool success = !std::cin.fail();
if (success)
std::cout << "success" << std::endl;
else
std::cout << "failure, loop will exit" << std::endl;
return 0;
}
What you should want (in my opinion) is a function that takes the expression as a string, and returns the result, so you can write unit tests, and make sure the function works. You can use this function with any expression that you can put in a string. It doesn't HAVE to be typed in by a user.
If you want the user to type in the experession, it's a lot easier to just use getline() then pass the string to your function. The big problem with using cin on each variable and character is that the user has no idea which datetype is expected right then. Granted, it's not hard to guess with an expression, but you wrote it and debugged it and still didn't know which cin you were failing to get the right datatype to. (this is normal, btw -- been there, which is why I getline and parse separately)
I wrote a method to get user input from std::cin and return it and it's worked for all of my tests so far except for a float or double followed by the letter 'e'.
This is the method:
template <typename Arg>
Arg getInput(string message = "")
{
if (!is_fundamental<Arg>::value && typeid(string) != typeid(Arg))
{
return Arg();
}
if (!message.empty())
{
print(message);
}
Arg out;
cin >> out;
while (cin.fail())
{
cin.clear();
cin.ignore();
cin >> out;
}
cin.ignore(INT_MAX, '\n');
return out;
}
This is the method call:
getInput<double>("Please Enter a Double: ");
The method returns the correct value for everything I've tried so far but std::cin fails when the value is trailed by an 'e'.
For example: 12.34 is read as 12.34, ae1.23f1 is read as 1.23, but std::cin fails on 1.2ef and 12E because the numbers are immediately followed by and 'e'
As a note, when the return type of the method is changed to float, it still produces the same problem that double does. This doesn't make any sense to me because it's the only thing that I've found to cause the program to not work so my guess is that it's the way std::cin is handling the input.
Disclaimer: I am new to c++ from java so my code probably has some other minor errors like return Arg(); won't work if the class doesn't have a default constructor so I have to fix that.
If you enter a number followed by an e (or E) then cin expects a number to be entered in scientific notation. If there's no integral number (negative or otherwise) after e, then that's not valid scientific notation and cin will fail to read that as a floating point float or double.
The error is similar to your inputting something like 3...
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.
I have a question about input validation in C++. Here is my code I am having trouble with:
#include <iostream>
using namespace std;
int main()
{
int in;
while(true)
{
if(cin >> in)
{
if(in < 0 || in > 2)
{
cout << "Invalid input. Number needs to be 0, 1, or 2.";
cin.clear();
while(cin.get() != '\n');
cin.ignore();
}
else
{
cout << "Output: " << in;
break;
}
}
else
{
cout << "Invalid input. Please enter a number.";
cin.clear();
while(cin.get() != '\n');
cin.ignore();
}
}
}
This code works fine unless two invalid entries are made in a row with the second input of the form '12hfhd'. Then it accepts this as input and I can't figure out why. I have searched on SO and have found a bunch of questions regarding input validation but can't seem to find any about their code accepting certain input.
The main problem is that, when requesting an int from std::cin using the >> operator, a sequence of numeric chars from the beginning of the input will be converted. Examples:
2 will convert to 2
75$ will convert to 75
12asdfgh will convert to 12
hello,world will convert to 0, because the first char is already not a number
The best thing to do is to use some char operations:
int getNumber() {
char input;
std::cin >> input;
if(input > '2' || input < '0') { // yes, chars act like ASCII numbers
// handle this problem
return -1; //error
} else {
return int(input - '0'); // input's code - '0''s code = number
}
}
I'd use the following approach when dealing with user input:
string l;
if(!getline(cin, l))
/* handle error that no input could be read at all */
try
{
int const res = boost::lexical_cast<int>(l);
/* numerically validate input here */
return res;
}
catch(exception const&)
{
/* handle parsing error here */
}
In words, read a line and then parse and validate it using Boost's lexical_cast() function template. Note that the first error, that getline() fails, happens if someone reads input from a file (e.g. via shell redirect), but this can also be achieved with certain keypresses, depending on the shell. This state can't be recovered from, so prompting for a different answer will result in an endless loop.
If you look at the documentation of the >> extraction operator, for example here:
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
you will notice the following quote:
(1) arithmetic types
Extracts and parses characters sequentially from the stream to interpret them as the representation of a value of the proper type,
which is stored as the value of val.
This essentially means that the program will try to treat all the data you pass as formatted in the format specified by the rvalue, in your case int. Simpler: in your case it will try to make ints of what you're passing into the stream and make the data as 'integerish' as it gets.