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.
Related
How do I make cin.good work on strings too?
[this is not a link]
while (1)
{
cin.clear();
cin.sync();
cout << "\n" << "Enter the state you are from" << endl;
cin >> s;
if (!cin.good())
{
cout << "\n" << "Please the enter the correct form of your state :)" << endl;
}
else
{
break;
}
}
Even if I input a number instead of string, it still does not work.
Problem is in the if condition.
cin.good() returns 0 if it has a problem reading from the file, file not existing, etc
As said in the comments under your post, entering 1234 as integer would still be considered as "1234". I think the best way would be to iterate through each character to check if they are digit and if it reaches the end, then it is a number.
string::const_iterator it = str.begin();
while(it != str.end() && isdigit(*it))
{
it++;
}
if (!str.empty() && it == str.end())
cout << "not a string";
else
cout << "valid";
Here is the link to the working example of the above code.
Even if I input a number instead of string, it still does not work
There is no such thing as "input a number instead of string". The user doesn't have any control over the datatype, the code reads a string.
In case the user inputs a string which is a representation of a number, that is still a valid string, and cin will still be in a good state.
You could use (for example) strtoi on the string to see if it is a number. But that is still very weak validation logic. "C*7" is not a number, but probably you don't want to accept it as a state/province name either. Apply some rules on what makes a valid name, and numeric inputs will be blocked along with all the other garbage.
The job of cin is to get data. If it can't it will set flags like .good(), .fail(), .eof. You can check them, when needed. In this case it got a string. It doesn't matter if you like the string, or not.
It is up to the programmer to use other code to validate that the string is useful, for example by checking if the string matches a valid state. It is not up to cin to decide anything about the data after it is provided successfully. It is like blaming the phone for who the caller is.
If all the states are placed in an associative container: set/unordered_set/map/unordered_map, then the code could look something like the following:
string msg="Enter the state you are from";
while (cin.good()) // make sure there is more to do.
{
cout << "\n" << msg << endl;
string s;
cin >> s;
if (valid_states.contains(s)) {
break;
} else {
msg="Please the enter the correct form of your state :)" << endl;
}
}
It is the container that is being used to check if the state is valid.
I am reading "C++ primer plus/Stephen Prata"
Here is the code from this book
while (!(cin >> golf[i])) {
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
The code above is easy to understand.
But the context from this book mentions
"...the program uses cin.get() in a while loop to read the remaining input through the end of the line.This gets rid of the bad input, along with anything else on the line.
Another approach is to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time.
Finally, the program tells the user to enter a number."
I wonder what the another approach is?
I try to express the code in different way and I know it's not correct.
while (!(cin >> golf[i])) {
cin.clear(); // resset input
char word[20];
while (cin >> word)
continue; // get rid of bad input
cout << "Please enter a number: ";
}
How do I code to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time?
thank you for your reading.
Let's start by looking at the existing code:
while (cin.get() != '\n')
continue;
This is what reads up to the new-line. We read a character, compare it to the new-line, and if it's not equal, we read another character. So, it reads characters, and stops reading when it gets to a new-line.
If we want to read to a space character instead, we just change the value we compare to:
while (cin.get() != ' ')
continue;
If we want to stop reading at any white-space, we could use a function to tell us whether a character is white space or not. That function would look something like this:
bool is_white_space(char ch) {
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v';
}
But this is a common enough task that the standard library already has an isspace function, so we don't have to write our own. We just have to use it:
while (!isspace(cin.get())
continue;
Personally, I'd at least consider putting this into a function by itself, and giving it a readable name like skip_to_whitespace, so our outer loop would look something like:
void skip_to_space(std::istream &in) {
in.clear();
while (!isspace(in.get()))
continue;
}
// ...
while (!(cin >> golf[i])) {
skip_to_space(cin);
cout << "Please enter a number: ";
}
At least to me, this seems to make the intent of the code considerably more apparent--we don't have to read through the content of the loop to figure out what it's supposed to do--that's obvious from the name of the function.
There is one last thing I'd change though. A while loop should normally have no effect if its condition is false. This one, however, always reads at least one character from its input, regardless of what that character might be. To make that fact more apparent, I'd prefer to use a do loop, to correctly reflect the intent that the loop always executes at least once:
void skip_to_space(std::istream &in) {
in.clear();
char ch;
do {
ch = in.get();
} while (!isspace(ch));
}
Now it's obvious that the cin.get() always happens at least once, and continues to happen until we reach a white-space character.
To throw out words until you reach a number do this:
string word;
cout << "Please enter a number: ";
while(!(cin >> golf[i])){
cin.clear();
cin >> word;
if(cin.rdbuf()->in_avail() == 1){
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Please enter a number: ";
}
}
One method of throwing out an entire line would be to use ignore.
while (!(cin >> golf[i])) {
cin.clear(); // resset input
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // get rid of bad input
cout << "Please enter a number: ";
}
So I am trying to allow a user to make a selection but Im having issue. the following lines
cout << "\nWhat would you like to do? " << endl
<< "(1) Display the entire List" << endl
<< "(2) to exit" << endl;
getline(cin,answer);
answerint=stoi(answer);
switch (answerint) {
case 1:
showLIST(myLIst);
break;
case 2:
return;
default:
cout << "\nPlease choose from the list";
}
So this works fine if the user chooses a integer, but it barfs if a character is received. How can I make this less breakable?
It seems you want something like this:
if (std::cin >> answerint) {
switch (answerint) {
// ...
}
}
Converting the integer directly from the stream puts the stream into failure state in case something different than an int is entered. You may want to add a manipulator to make sure there are no non-space characters on the end of the line.
std::string answer;
int answerint;
while (std::getline(std::cin, answer))
{
std::istringstream iss(answer);
char c; // seek non-whitespace after the number?
if (!(iss >> answerint) || (iss >> c))
answerint = 0;
switch (answerint)
{
...as you had...
}
}
The code above uses getline to ensure a complete line of text is parsed into answer, after which it creates a distinct std::istringstream from that single line. That way, we can use >> knowing it won't skip over newlines are consume or wait for further input.
if (!(iss >> answerint) || (iss >> c)) checks whether there isn't a number to parse into answerint, or after having parsed a number an additional non-whitespace character appears on the line. For example, the line typed might have been 2r - we'll consider that an error and reprompt for a selection, assigning 0 to answerint to ensure we reach the default label in the switch, thereby printing cout << "\nPlease choose from the list"; which seems as appropriate for 2r as for 99 or whatever....
Using getline and a separate istringstream this way, you can reliably attempt parsing of the next line of input from a known state.
When it comes to creating a program based on a set of instructions, I do pretty well in designing the pseudo-code, implementing the actual code. What I feel like I lack is checking for users' input (whether it's valid or invalid). As I practiced programming, I created my own way for checking for validating users' input. But the code is lengthy and I feel like it's insufficient (I'll explain why). I wanted to know if there is a better way to check for users' input. And how do other programmers implement their code.
This is how I validate users' input:
if(cin.fail()) {
cout << "Invalid Input" << endl;
cout << "Now Exiting..." << endl;
return;
}
// I didn't know how to skip a line while in code
while(input < 0) {
cout << "Invalid Input" << endl;
cout << "Enter radius: " << endl;
cin >> input;
if(cin.fail()) {
cout << "Error: Invalid Input" << endl;
cout << "Now Exiting..." << endl;
return;
}
}
The reason why I exit out when cin fails to store the value into the variable separately (line 1 - 5, line 11 -15) is because if I add the cin.fail() to the while condition and attempt to input a letter, it begins a infinite loop. I did a little research and I saw you have to cin.sync(), then cin.clear(). But I still get the infinite loop.
Here is the code:
do {
cin.sync()
cin.clear();
cout << "Enter radius: ";
cin >> input;
} while(input < 0 || cin.fail());
If I'm doing something wrong, it would very helpful to see better ways to validate user's input.
I would not recommend using std::cin, since it leaves all remaining user input after the first found instance of whitespace in the input buffer. This will create problems unless you remove the remaining characters using cin.ignore(). It is generally seen as better practice to use getline(), which will get all the characters up to the newline character. If you do choose to use std::cin, you will need to use cin.ignore() to remove the remaining characters, and cin.clear() to reset cin's fail bit so the while conditional will work properly the next time through the loop.
Below is how I would solve the problem. It uses getline() to get all the characters, and a stringstream to convert the string to an int. Notice you need to clear the stringstream's fail bit just like with cin to make sure the conditional works correctly when you do ss >> result in the while conditional.
std::cout << "Enter radius: ";
getline(std::cin, input);
std::stringstream ss(input);
while(!(ss >> result)) {
std::cout << "Invalid Input" << std::endl;
std::cout << "Enter radius: ";
getline(std::cin, input);
ss.clear();
ss << input;
}
Below I'll also include some code to solve the problem using std:cin. I still recommend using getline() though. Note: std::numeric_limits::max() is used to specify how many characters to remove from the input buffer. Using this instead of your own arbitrary number is a better practice, since you can't know for certain how many characters the user will enter. cin.ignore() will remove all the characters up to the given number or until it reaches an instance of the character provided as its second parameter, which in this case is newline ('\n').
std::cout << "Enter radius: ";
std::cin >> result;
while(std::cin.fail()) {
std::cout << "Invalid Input" << std::endl;
std::cout << "Enter radius: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin >> result;
}
The problem of input validation is an easy form of parsing.
There are language-classes (in the field of formal language theory) that express the complexity of your input. Those classes are called regular, context-free, and turing-complete.
You have to consider all your possible inputs, that your program might receive and decide whether your program should accept them or not. The language classes help you to decide what kind of input validation you need.
if the language is regular (as it is in your case) you can use regular expressions to validate the input.
A context-free language for example would be a math-formula. You cannot count the number of parentheses with a regular expression. Therefore it is impossible to check ((a+b) * (c+d)) has the right amount of parentheses with a regular expression.
Up to now these are hints on what you should be doing, when programming comes more naturally to you.
For the sake of simplicity well do a very constrained regular expression like parsing by hand.
what you actually want to do in pseudo code:
do {
std::cout << "Please enter radius: ";
line = read_a_line_from(std::cin) // separated by '\n' the newline
if (false == really_read_a_line(line)) {
/* error handling for std::cin, dealing with i.e.: the fail bit */
break; /* exit the loop */
}
if (line == "exit") { // give the user an explicit exit, to quit gracefully
exit(SUCCESS); /* exit the program */
}
if (false == is_a_number(line)) {
/* we read something that isn't a number */
/* we should tell the user he should do as we asked */
continue; /* jump back to the beginning of the loop */
}
unsigned num = convert_number(line);
unsigned area = calculate_area(num); /* do something with your input */
} while (true);
exit(FAILURE);
The code here is not too specific on purpose that you see what you could be doing in places, still leaving out the actual implementation (for your exercise). Please note that a simple way of checking whether a line is actually a number is by converting. However not all things to parse should be checked for validity and processed at the same time.
See Also (especially the examples):
http://en.cppreference.com/w/cpp/string/basic_string/getline
http://en.cppreference.com/w/cpp/string/basic_string/stol
how to check if given c++ string or char* contains only digits?
do {
cin.sync()
cin.clear();
cout << "Enter radius: ";
cin >> input;
} while(input < 0 && cin.fail());
I am trying to determine if the user enters something other than a character, and specifically, that they only enter m or s. See code below.
Note:
filingStatus is a char
do
{
cout << "Please enter your filing status (s for single, m for married)" << '\n';
cin >> filingStatus;
if (cin.fail())
{
cin.clear();
dataTest = 1;
cout << "Error, please enter a valid input!" << '\n';
double dummyDouble;
cin >> dummyDouble;
if (cin.fail())
{
cin.clear();
cin >> dummyString;
}
}
else
{
if (filingStatus == 'm' || filingStatus == 's')
{
dataTest = 0;
}
else
{
cout << "Error, please enter either m or s!" << '\n';
dataTest = 1;
}
}
} while (dataTest == 1);
Here is the problem, if I enter 1000 for example, the input doesn't fail. It instead stores the 1 in the char, and since 1 is neither m or S, it loops again, then it puts the 0, loops again, puts another 0, etc.
My understanding was it would fail when it sees that a integer is being stored in a char, but obviously it isn't failing.
My question is:
Why isn't the input failing? How can I change it so if someone enters a string, or number that it fails?
The input isn't failing, because '1' is a character. Digits are a subset of characters.
Read into a std::string. Then test whether that string consists of a single character from your desired range.
Note however, that reading into a string using >> stops at the first white space. To prevent this and read the whole line instead, read using std::getline().
I am assuming that fillingStatus is of char type.
Now even if you enter a numeral say '1' or '0', it is read as a char. Hence cin does not fail. It just keeps on looping as per your code.
Also, while reading an invalid char, you should be careful of clearing the input buffer because the return character '\n' stays along with other characters in the input buffer.
I would do it something like the following:
while ( !(cin >> fillingStatus) || (filingStatus != 'm' && filingStatus != 's') ) {
cout << "Error, please enter either m or s!" << '\n'; // error message
cin.clear(); // clear the error flag
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // ignore all invalid previous input
}
One way could be to change the fillingStatus to string and get only the first character of that string and see if it fails or not.
Alternatively, there used to be a method for getting a character input, getche() I think (it has been many years since I worked in C++ so don't exactly recall)...you maybe able to use that too.
Thanks
Since you are only reading the input one character at a time, your are essentially unable to tell that the user has input more and it is being held until you read more from the input stream.
Using a string to read a line of data at a time and having the program react to that string as a whole will solve your problem.
std::string filingStatus ;
while(!(cin >> filingStatus ) || ( filingStatus != "m" && filingStatus != "f") )
{
cin.clear();
std::cout << "Error, please enter either m or s!" << '\n';
};