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.
Related
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)
int readUntilValidBaseRead( int &base )
{
base = 0;
while ( base > 9 || base < 2)
{
cout << "Enter Base: " << endl;
cin >> base;
if (base > 1 && base < 10)
{
return base;
}
else
{
cout << "a valid base number is in the range of 2 to 9 inclusively" << endl;
base = 0;
}
}
}
For an assignment I'm doing, I need to use a function to get a base, and this is what I wrote. If any number is input, the code works fine. If I input f, then the code gets stuck repeating
a valid base number is in the range of 2 to 9 inclusively
Enter Base:
You need to check the result or status of this statement:
cin >> base;
It will fail if the input is not a number. The value of base when the input fails is undefined.
Try this:
if (cin >> base)
{
// User input a valid number
}
Inputting a letter causes the cin object to get stuck in an error state, failing to read to base regardless of what you feed it afterwards.
You have two options for solving this.
You could either check & clear the error after it occurs, like so:
if(!std::cin) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
Or you could read entire lines at once, and parse the lines for numbers:
std::string line;
std::getline(std::cin, line);
int value = std::stoi(line);
It's because if you don't enter input that can be parsed as an integer, then the input will not be extracted and will stay in the input buffer so the next iteration of the loop you will read the exact same input as previous iteration and have the same problem all over again.
This is the reason I recommend you use std::getline to read the whole line into a string, and then use std::istringstream to try and extract/parse the data.
You also need to remember that most input (and output for that matter) operations return a reference to the stream, and that it can be used as a boolean expression, so you can use something like
std::istringstream is(someString);
if (is >> base)
{
// Successfully read and parsed an integer
}
else
{
// Some error occurred
}
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;
}
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'm admittedly not the most experienced with C++, but am surprised to be having issues with getting such a simple function to work properly. All I'm wanting is a function to get a user's input and ensure it obtains an integer(without crashing due to unexpected input) and then return that value to the calling function. It should not accept any special characters or spaces whatsoever. Essentially, I want it to be just like the Java equivalent that I'll post below:
public static int getInt()
{
boolean isNum = false; //test variable
String str; //to hold input
do
{
str = keyboard.nextLine();
if (!(isNum = str.matches("\\d+")))
{
System.out.println("Enter a valid whole number, try again.");
}
} while(!isNum);
return Integer.parseInt(str);
}
You just try to read an int with cin >> [int variable], and make sure it succeeded. If not, wash, rinse, and repeat:
int i;
while (!(cin >> i)) {
cout << "Enter a valid integer, try again: ";
cin.clear();
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
return i;
That will work, but will return 12 when given input like
12 a
because it will read the 12 and stop at a. If you do not want to just "get as much as you can" and want to read the whole line (which is what the Java snippet apparently does) then you can use std::getline and try to convert the resulting string into an integer with std::stoi:
string line;
int integer = 0;
while (std::getline(cin, line))
try {
integer = std::stoi(line);
break;
} catch (...) {
cout << "Enter an integer, try again: ";
}
return integer;
That way will not return on input like
143 bbc
because it will try to convert the entire line 143 bbc to an integer and tell the user to try again because bbc can't be converted to an integer. It will only return when the entire line is integer input.
You can actually accomplish this by using regexen like the Java example does, but I think it's a waste to pull out regexes for this simple task.
Edit:
If you want to reject decimal input instead of truncating it, you can convert the input to a double and check to make sure it doesn't have a decimal part:
string line;
double d = 0;
while (std::getline(cin, line))
try {
d = std::stod(line);
if (std::fmod(d, 1) != 0)
throw 0;
break;
} catch (...) {
cout << "Enter an integer, try again: ";
}
return d;