Using cin.good for strings - c++

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.

Related

While loop isn't working when user inputs letters instead of integers? [duplicate]

In C++, how do you handle wrong inputs? Like, if the program asks for an integer, when you type a character it should be able to do something and then loop to repeat the input but the loop goes infinite when you input a character when an integer is need and vice versa.
The reason the program goes into an infinite loop is because std::cin's bad input flag is set due to the input failing. The thing to do is to clear that flag and discard the bad input from the input buffer.
//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
std::cin.clear(); //clear bad input flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
std::cout << "Invalid input; please re-enter.\n";
}
See the C++ FAQ for this, and other examples, including adding a minimum and/or maximum into the condition.
Another way would be to get the input as a string and convert it to an integer with std::stoi or some other method that allows checking the conversion.
The top voted answer covers the solution really well.
In addition to that answer, this may help visualize what's going on a little better:
int main()
int input = 1;//set to 1 for illustrative purposes
bool cinState = false;
string test = "\0";
while(input != -1){//enter -1 to exit
cout << "Please input (a) character(s): ";//input a character here as a test
cin >> input; //attempting to input a character to an int variable will cause cin to fail
cout << "input: " << input << endl;//input has changed from 1 to 0
cinState = cin;//cin is in bad state, returns false
cout << "cinState: " << cinState << endl;
cin.clear();//bad state flag cleared
cinState = cin;//cin now returns true and will input to a variable
cout << "cinState: " << cinState << endl;
cout << "Please enter character(s): ";
cin >> test;//remaining text in buffer is dumped here. cin will not pause if there is any text left in the buffer.
cout << "test: " << test << endl;
}
return 0;
}
Dumping the text in the buffer to a variable isn't particularly useful, however it helps visualize why cin.ignore() is necessary.
I noted the change to the input variable as well because if you're using an input variable in your condition for a while loop, or a switch statement it may go into deadlock, or it may fulfill a condition you weren't expecting, which can be more confusing to debug.
Test the input to see whether or not it is what your program expects. If it is not, alert the user that the input they provided is unacceptable.
You can check it through the ASCII value if the ascii value s between 65 t0 90 or 97 to 122 the it would be character.

I am trying to end my C++ program when the user presses 'Ctrl-D'

my program has read in a large file of words (a dictionary) and inserted them all into a hash table. I am prompting the user to lookup a word and I want them to be able to terminate the program by pressing Ctrl-D. This is what I have tried but when I press Ctrl-D it just gets stuck in a loop printing out what I have in the else statement. I am using Unix. I have attempted looking this up on this website and nothing was working that I was trying hence why I am asking my own question. Any thoughts? PS. The transform is to make the user input all uppercase to match the file I am reading from.
void query(){
bool done = false;
string lookupWord;
while(!done){
cout << "Type a word to lookup or type ctrl-D to quit: ";
cin >> lookupWord;
if(atoi(lookupWord.c_str()) == EOF)
done = true;
else{
transform(lookupWord.begin(), lookupWord.end(), lookupWord.begin(), ::toupper);
cout << endl << "Word: " << lookupWord << endl;
cout << endl << "Definition: " << myDict.lookup(lookupWord) << endl << endl;
}
}
}
atoi(lookupWord.c_str()) == EOF
This doesn't do what you think it does. This checks the return value of atoi() and compares it to EOF. EOF is typically defined as -1. So, the code ends up setting done only when -1 is typed in. Which is not what you want.
std::istream has a convenient operator bool that tests whether the file stream is in a good state. So, all that really needs to be done is:
if (cin >> lookupWord)
{
// Your existing code is here
}
else
{
done=true;
}

"Because" to "use"; C++

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.

How To Check If User's Input Is Valid? (C++)

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());

Try and catch with while loop: jumps to catch block even after the input is correct only if the first input was incorrect - C++

I'm trying to check if the user has entered their name correctly, with or without space i.e. Joe Bloggs. They cannot have special characters or numbers in their name or it will pop up with an error message i.e. Jo3_Bl0ggs. What I'm trying to do is if they enter their name in the wrong format, an error message will be alerted and the program will ask the user to enter their name again, until they enter it correctly.
I'm using a while loop to do this so if it's correct, I change the value of the flag and break out of the loop, if not I'll rerun the setName() function which asks for their name.
However the problem I'm having is that if they enter for the first time and it's incorrect, it asks them to enter their name again and if the second input is correct a message will say "Welcome Joe Bloggs", but the loop will continue and ask them to enter their name in again.
The only way I can avoid this problem is if the first input is correct, but that kind of defeats the whole point of the try and catch block.
Below is the two functions I'm concerned with. If someone can point me in the right direction, then that would be great. I'm new to c++ which is why I'm a bit confused about this.
inputclass::inputclass(){//empty constructor}
void inputclass::validateName(string name){
int flag = 1;
while ( flag == 1){
try{
for (int i=0; i < name.length(); i++){
if (name[i] != ' '){
if (!isalpha(name[i])){
cout << "You have entered incorrectly. Please try again. " << endl;
cin.clear(); //I'm trying to clear input buffer but still doesn't work
cin.ignore(256, '\n');
setName();
throw 0; //do i need this?
break; //do i need breaks?
}else if(i == name.length()-1){
cout << "Welcome to the program " << name << endl;
flag = 2; //break out of while loop
break; //not sure if this does anything
}
}
}
}catch (int e){
cout << "There's been an error" << endl;
setName(); //until input is correct, this will ask the user for their name.
}
}
}
void inputclass::setName(){
string name;
cout << "Please enter your name: " << endl;
getline(cin, name);
validateName(name);
}
My honest opinion is that your algorithm logic itself is wrong. Validation should be done as a consequence of input. The input itself should be the decision point of recycling on validation failure
1. Write a simple validation function
This is easier than you may think, in particular since the standard library provides some neat algorithms for doing much of the iteration work for you.
2. Integrate your validation function exclusively in setName(); not the opposite.
Your input mechanics should take said-input, validate, and if invalid, loop on the input. The validator should exclusively be returning yea or nay. Leave the input mechanics to the input function, and don't trigger them from the validator. A validator is for just that; validating, not cycling input loops.
The first of these is fairly simple since the standard library provides you with most of the algorithms you need. The sample below uses a functor to do this, but C++11 could easily do this with a lambda instead:
struct is_not_space_or_alpha
{
bool operator()(char c) const
{
return c != ' ' && !std::isalpha(static_cast<unsigned char>(c));
}
};
static bool is_valid_name(const std::string& name)
{
return !name.empty() &&
name.end() != std::find_if(name.begin(), name.end(), is_not_space_or_alpha());
}
With that, your setName() becomes the location where validation is a consequence of input; the validation doesn't internally trigger more input. That is left to the caller (setName()) to decide:
std::string name;
while (true)
{
std::cout << "Please enter your name: ";
std::flush(std::cout);
if (std::getline(std::cin, name) && is_valid_name(name))
{
std::cout << "Welcome to the program " << name << "!\n";
break;
}
std::cout << "You have entered incorrectly. Please try again. \n";
std::cin.clear();
}
Sample Output
Please enter your name: Monkey777
You have entered incorrectly. Please try again.
Please enter your name: Wiley Coyote
Welcome to the program Wiley Coyote!
The Bottom Line: Don't trigger input from validation. Instead, trigger validation from input and act accordingly.