C++ cin weird behaviour [duplicate] - c++

This question already has answers here:
Why getline skips first line?
(3 answers)
Closed 9 years ago.
I have the following code:
int data = 0;
cout << "Enter a number: ";
cin >> data;
cout << "You entered " << data << endl;
string str;
cout << "Enter a string: ";
getline(cin,str);
cout << "Your entered " << str << endl;
After getting the first prompt, I entered a valid number 10. But as soon as I hit return, the program output:
You entered 10
Enter a string: Your entered
In other words, it didn't ask for the second string input. What happened?
Thanks

std::cin >> data;
When you input the number for data, and hit the Return key to submit your input, a new line will be inserted into the stream. A new line is the default delimiter for the input stream, and when std::getline(std::cin, str) is used, the compiler will see that a new line is already in the stream, and it will stop running. To solve this, you need to ignore the offending character with std::cin.ignore:
std::cin.ignore();
std::getline(std::cin, str);

Classic problem of mixing numbers and strings on input stream. Use getline for both and parse by using stringstream.

Check out the below. The problem is that reading an integer does not read in the terminating newline. That newline is consumed when you use getline(...) and so your program exits. You need to consume that newline first.
int data = 0;
cout << "Enter a number: ";
cin >> data;
cout << "You entered " << data << endl;
string str;
cout << "Enter a string: ";
getline(cin,str); // consume endline <------------------
getline(cin,str);
cout << "Your entered " << str << endl;

When you enter 10, you're really entering "10\n", 10 plus the new line. It can depend on the OS, but basic idea of what is happening is that cin simply reads the 10 from the input buffer, and leaves the newline character. Then when your program reaches the getline part, getline reads the "\n" off the input buffer. Since "\n" is the default terminating character for getline, getline finishes and your programs keeps going.
So, at the end of your program, str contains simply "\n".

Related

How do I terminate input without crowding cin with a value? [duplicate]

Google Code University's C++ tutorial used to have this code:
// Description: Illustrate the use of cin to get input
// and how to recover from errors.
#include <iostream>
using namespace std;
int main()
{
int input_var = 0;
// Enter the do while loop and stay there until either
// a non-numeric is entered, or -1 is entered. Note that
// cin will accept any integer, 4, 40, 400, etc.
do {
cout << "Enter a number (-1 = quit): ";
// The following line accepts input from the keyboard into
// variable input_var.
// cin returns false if an input operation fails, that is, if
// something other than an int (the type of input_var) is entered.
if (!(cin >> input_var)) {
cout << "Please enter numbers only." << endl;
cin.clear();
cin.ignore(10000,'\n');
}
if (input_var != -1) {
cout << "You entered " << input_var << endl;
}
}
while (input_var != -1);
cout << "All done." << endl;
return 0;
}
What is the significance of cin.clear() and cin.ignore()? Why are the 10000 and \n parameters necessary?
The cin.clear() clears the error flag on cin (so that future I/O operations will work correctly), and then cin.ignore(10000, '\n') skips to the next newline (to ignore anything else on the same line as the non-number so that it does not cause another parse failure). It will only skip up to 10000 characters, so the code is assuming the user will not put in a very long, invalid line.
You enter the
if (!(cin >> input_var))
statement if an error occurs when taking the input from cin. If an error occurs then an error flag is set and future attempts to get input will fail. That's why you need
cin.clear();
to get rid of the error flag. Also, the input which failed will be sitting in what I assume is some sort of buffer. When you try to get input again, it will read the same input in the buffer and it will fail again. That's why you need
cin.ignore(10000,'\n');
It takes out 10000 characters from the buffer but stops if it encounters a newline (\n). The 10000 is just a generic large value.
Why do we use:
1) cin.ignore
2) cin.clear
?
Simply:
1) To ignore (extract and discard) values that we don't want on the stream
2) To clear the internal state of stream. After using cin.clear internal state is set again back to goodbit, which means that there are no 'errors'.
Long version:
If something is put on 'stream' (cin) then it must be taken from there. By 'taken' we mean 'used', 'removed', 'extracted' from stream. Stream has a flow. The data is flowing on cin like water on stream. You simply cannot stop the flow of water ;)
Look at the example:
string name; //line 1
cout << "Give me your name and surname:"<<endl;//line 2
cin >> name;//line 3
int age;//line 4
cout << "Give me your age:" <<endl;//line 5
cin >> age;//line 6
What happens if the user answers: "Arkadiusz Wlodarczyk" for first question?
Run the program to see for yourself.
You will see on console "Arkadiusz" but program won't ask you for 'age'. It will just finish immediately right after printing "Arkadiusz".
And "Wlodarczyk" is not shown. It seems like if it was gone (?)*
What happened? ;-)
Because there is a space between "Arkadiusz" and "Wlodarczyk".
"space" character between the name and surname is a sign for computer that there are two variables waiting to be extracted on 'input' stream.
The computer thinks that you are tying to send to input more than one variable. That "space" sign is a sign for him to interpret it that way.
So computer assigns "Arkadiusz" to 'name' (2) and because you put more than one string on stream (input) computer will try to assign value "Wlodarczyk" to variable 'age' (!). The user won't have a chance to put anything on the 'cin' in line 6 because that instruction was already executed(!). Why? Because there was still something left on stream. And as I said earlier stream is in a flow so everything must be removed from it as soon as possible. And the possibility came when computer saw instruction cin >> age;
Computer doesn't know that you created a variable that stores age of somebody (line 4). 'age' is merely a label. For computer 'age' could be as well called: 'afsfasgfsagasggas' and it would be the same. For him it's just a variable that he will try to assign "Wlodarczyk" to because you ordered/instructed computer to do so in line (6).
It's wrong to do so, but hey it's you who did it! It's your fault! Well, maybe user, but still...
All right all right. But how to fix it?!
Let's try to play with that example a bit before we fix it properly to learn a few more interesting things :-)
I prefer to make an approach where we understand things. Fixing something without knowledge how we did it doesn't give satisfaction, don't you think? :)
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate(); //new line is here :-)
After invoking above code you will notice that the state of your stream (cin) is equal to 4 (line 7). Which means its internal state is no longer equal to goodbit. Something is messed up. It's pretty obvious, isn't it? You tried to assign string type value ("Wlodarczyk") to int type variable 'age'. Types doesn't match. It's time to inform that something is wrong. And computer does it by changing internal state of stream. It's like: "You f**** up man, fix me please. I inform you 'kindly' ;-)"
You simply cannot use 'cin' (stream) anymore. It's stuck. Like if you had put big wood logs on water stream. You must fix it before you can use it. Data (water) cannot be obtained from that stream(cin) anymore because log of wood (internal state) doesn't allow you to do so.
Oh so if there is an obstacle (wood logs) we can just remove it using tools that is made to do so?
Yes!
internal state of cin set to 4 is like an alarm that is howling and making noise.
cin.clear clears the state back to normal (goodbit). It's like if you had come and silenced the alarm. You just put it off. You know something happened so you say: "It's OK to stop making noise, I know something is wrong already, shut up (clear)".
All right let's do so! Let's use cin.clear().
Invoke below code using "Arkadiusz Wlodarczyk" as first input:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl; //new line is here :-)
We can surely see after executing above code that the state is equal to goodbit.
Great so the problem is solved?
Invoke below code using "Arkadiusz Wlodarczyk" as first input:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;//new line is here :-)
Even tho the state is set to goodbit after line 9 the user is not asked for "age". The program stops.
WHY?!
Oh man... You've just put off alarm, what about the wood log inside a water?* Go back to text where we talked about "Wlodarczyk" how it supposedly was gone.
You need to remove "Wlodarczyk" that piece of wood from stream. Turning off alarms doesn't solve the problem at all. You've just silenced it and you think the problem is gone? ;)
So it's time for another tool:
cin.ignore can be compared to a special truck with ropes that comes and removes the wood logs that got the stream stuck. It clears the problem the user of your program created.
So could we use it even before making the alarm goes off?
Yes:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
The "Wlodarczyk" is gonna be removed before making the noise in line 7.
What is 10000 and '\n'?
It says remove 10000 characters (just in case) until '\n' is met (ENTER). BTW It can be done better using numeric_limits but it's not the topic of this answer.
So the main cause of problem is gone before noise was made...
Why do we need 'clear' then?
What if someone had asked for 'give me your age' question in line 6 for example: "twenty years old" instead of writing 20?
Types doesn't match again. Computer tries to assign string to int. And alarm starts. You don't have a chance to even react on situation like that. cin.ignore won't help you in case like that.
So we must use clear in case like that:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
But should you clear the state 'just in case'?
Of course not.
If something goes wrong (cin >> age;) instruction is gonna inform you about it by returning false.
So we can use conditional statement to check if the user put wrong type on the stream
int age;
if (cin >> age) //it's gonna return false if types doesn't match
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";
All right so we can fix our initial problem like for example that:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
if (cin >> age)
cout << "Your age is equal to:" << endl;
else
{
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
cout << "Give me your age name as string I dare you";
cin >> age;
}
Of course this can be improved by for example doing what you did in question using loop while.
BONUS:
You might be wondering. What about if I wanted to get name and surname in the same line from the user? Is it even possible using cin if cin interprets each value separated by "space" as different variable?
Sure, you can do it two ways:
1)
string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;
cout << "Hello, " << name << " " << surname << endl;
2) or by using getline function.
getline(cin, nameOfStringVariable);
and that's how to do it:
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
The second option might backfire you in case you use it after you use 'cin' before the getline.
Let's check it out:
a)
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
If you put "20" as age you won't be asked for nameAndSurname.
But if you do it that way:
b)
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll
everything is fine.
WHAT?!
Every time you put something on input (stream) you leave at the end white character which is ENTER ('\n') You have to somehow enter values to console. So it must happen if the data comes from user.
b) cin characteristics is that it ignores whitespace, so when you are reading in information from cin, the newline character '\n' doesn't matter. It gets ignored.
a) getline function gets the entire line up to the newline character ('\n'), and when the newline char is the first thing the getline function gets '\n', and that's all to get. You extract newline character that was left on stream by user who put "20" on stream in line 3.
So in order to fix it is to always invoke cin.ignore(); each time you use cin to get any value if you are ever going to use getline() inside your program.
So the proper code would be:
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, '\n')
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
I hope streams are more clear to you know.
Hah silence me please! :-)
use cin.ignore(1000,'\n') to clear all of chars of the previous cin.get() in the buffer and it will choose to stop when it meet '\n' or 1000 chars first.

c++ object array string input is not working at console [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Using getline() in C++
(7 answers)
Closed 4 years ago.
Can anyone explain why I am having trouble with the below C++ code?
#include <iostream>
using namespace std;
class stud
{
public:
string name,adrs;
long long unsigned int mob;
};
int main()
{
stud s[10];
unsigned int num;
cout << endl << "Enter the number of students(<10): ";
cin >> num;
cout << endl;
for(int i = 0; i < num; i++)
{
cout << endl << "Enter student " << i+1 << " name(put '.' at end and press enter): ";
getline(cin, s[i].name); // this line skips some data before even they are
//entered and there is no error while compiling
}
system("CLS");
for(int i = 0; i < num; i++)
{
cout << endl << " Student " << i+1 << " name is: ";
cout << s[i].name << endl;
}
return 0;
}
When I try to input a string value for an object in the array as above, using getline() without any delimiter (which uses a new line by default), I don't get correct output since some other data is automatically being skipped.
But, when I use getline() as follows instead of above, it works fine, but it needs a delimiter at the end:
getline(cin, s[i].name, '.');
Please help me find a solution. I think the Enter key is pressed several times at one key press, and that's why the getline() skips some data. I'm not sure about this, though.
before correcting you program one thing to know is that
Actually, a newline is always appended to your input when you select Enter or Return when submitting from a terminal.
cin>> doesn't remove new lines from the buffer when the user presses Enter.
This has little to do with the input you provided yourself but rather with the default behaviour std::getline() exhibits. When you provided your input for the name (std::cin >> num;), you not only submitted the following characters, but also an implicit newline was appended to the stream, getline() mistakes this for user input along with enter.
It is recommended to use cin.ignore() to get rid of those extra characters after using cin>>(whatever) if you are going to use getline(cin,any string) later.
Edit this part of your code:
stud s[10];
unsigned int num;
cout << endl << "Enter the number of students(<10): ";
cin >> num;
cout << endl;
cin.ignore();//just add this line in your program after getting num value through cin
//fflush(stdin);
//cin.sync();
//getchar();
for(int i = 0; i < num; i++)
{
cout<<endl<< "Enter student " << i+1 << " name(put '.' at end and press enter): ";
getline(cin,s[i].name);
}
system("CLS");
you can use and may be tempted to use fflush(stdin) also but it is not recommended as it has undefined behaviour, as
According to the standard, fflush can only be used with output buffers, and obviously stdin isn't one.
about cin.sync():
using “cin.sync()” after the “cin” statement discards all that is left in buffer. Though “cin.sync()” does not work in all implementations (According to C++11 and above standards).
you can also use getchar() to get the newline caused by Enter

Using consecutive while(cin >> input) successfully [duplicate]

This question already has answers here:
std::cin loops even if I call ignore() and clear()
(2 answers)
Closed 5 years ago.
My first while loop executes, until I enter a non-number to terminate it. Then, instead of while(cin >> cel) executing, it is skipped, leading the program to terminate/finish. I have tried everything including clearing the "cin bit" as described in another similiar question with no success. What am I doing wrong?
int main() {
double fah = 0;
cout << "Enter a fahrenheit value:\n";
while (cin >> fah) { // executes until a non-number input is entered
cout << fah << "F == " << fah_to_cel(fah) << "C\n";
}
// tried cin.clear(); here
// tried cin.clear(ios_base::eofbit); here
double cel = 0;
cout << "Enter a celcius value:\n";
while(cin >> cel) { // executes until a non-number input is entered
cout << cel << "C == " << cel_to_fah(cel) << "F\n";
}
return 0;
}
You were correct to call cin.clear(). That resets the error flags of cin, which you need to do before you can perform any more input operations. But you need to do one more thing. When input fails, whatever characters cin was trying to read remain in the input buffer. So when you try to collect input again (after clearing the error), it will fail again. So you need to remove the data that was left in the buffer. You can do that like this:
std::streamsize amount_to_ignore = std::numeric_limits<std::streamsize>::max();
std::cin.ignore(amount_to_ignore, '\n');
This tells cin to discard all characters in its buffer until it finds a newline character (which should be in there from when you last pressed the enter key).
This is, in my opinion, a very clunky and error prone way to do user input. I would suggest that you exclusively use std::getline when reading from cin, which should never fail (except in the unlikely event of a memory allocation failure). And then parsing the resulting string manually, which gives you a lot more control over the form of the input.

getline(cin.name) gets skipped

I call a function from a function in C++ that has the line getline(cin,name) where name is a string. the first time through the loop, the program does not wait for input. It will on all other passes through the loop. Any ideas on why?
void getName (string& name)
{
int nameLen;
do{
cout << "Enter the last Name of the resident." << endl << endl
<< "There should not be any spaces and no more than 15"
<< " characters in the name." << endl;
getline(cin,name);
cout << endl;
nameLen = name.length();// set len to number of characters input
cout << "last" << name << endl;
}
while (nameLen < LastNameLength);
return;
}
Make sure there isn't left overs since the last time you read something from cin, like:
In an earlier point in your program:
int number;
cin >> number;
The input you give:
5
Later in the program:
getline(cin,name);
and getline will seem to not be called, but rather it collected the newline from the last time you took input because when you use cin >> it leaves new lines.
It may be because of the input stream. The getline function stops reading input after is receives the first newline char. If for example there are multiple newlines within the buffer of std::cin - the getline will return every time it encounters one.
Check the input you are expecting.
Do you have any:
cin << variableName;
lines of code? I ran into getline() skipping run-time errors when I was using:
cin << intvariable and subsequently getline(cin, variable).
This is because the cin stream object holds a buffer of input. When you enter the newline character I assume it is trunacated from the stream going to the variable asisgnment, yet is still contained within the cin object instance itself.
One workaround I used is cin.ignore(); after the cin << integer statement.
Another user mentioned parsing all input from getline into integers, floats - not root beer -, and strings. Good luck and check your code for the dual use of cin & getline().

Why would we call cin.clear() and cin.ignore() after reading input?

Google Code University's C++ tutorial used to have this code:
// Description: Illustrate the use of cin to get input
// and how to recover from errors.
#include <iostream>
using namespace std;
int main()
{
int input_var = 0;
// Enter the do while loop and stay there until either
// a non-numeric is entered, or -1 is entered. Note that
// cin will accept any integer, 4, 40, 400, etc.
do {
cout << "Enter a number (-1 = quit): ";
// The following line accepts input from the keyboard into
// variable input_var.
// cin returns false if an input operation fails, that is, if
// something other than an int (the type of input_var) is entered.
if (!(cin >> input_var)) {
cout << "Please enter numbers only." << endl;
cin.clear();
cin.ignore(10000,'\n');
}
if (input_var != -1) {
cout << "You entered " << input_var << endl;
}
}
while (input_var != -1);
cout << "All done." << endl;
return 0;
}
What is the significance of cin.clear() and cin.ignore()? Why are the 10000 and \n parameters necessary?
The cin.clear() clears the error flag on cin (so that future I/O operations will work correctly), and then cin.ignore(10000, '\n') skips to the next newline (to ignore anything else on the same line as the non-number so that it does not cause another parse failure). It will only skip up to 10000 characters, so the code is assuming the user will not put in a very long, invalid line.
You enter the
if (!(cin >> input_var))
statement if an error occurs when taking the input from cin. If an error occurs then an error flag is set and future attempts to get input will fail. That's why you need
cin.clear();
to get rid of the error flag. Also, the input which failed will be sitting in what I assume is some sort of buffer. When you try to get input again, it will read the same input in the buffer and it will fail again. That's why you need
cin.ignore(10000,'\n');
It takes out 10000 characters from the buffer but stops if it encounters a newline (\n). The 10000 is just a generic large value.
Why do we use:
1) cin.ignore
2) cin.clear
?
Simply:
1) To ignore (extract and discard) values that we don't want on the stream
2) To clear the internal state of stream. After using cin.clear internal state is set again back to goodbit, which means that there are no 'errors'.
Long version:
If something is put on 'stream' (cin) then it must be taken from there. By 'taken' we mean 'used', 'removed', 'extracted' from stream. Stream has a flow. The data is flowing on cin like water on stream. You simply cannot stop the flow of water ;)
Look at the example:
string name; //line 1
cout << "Give me your name and surname:"<<endl;//line 2
cin >> name;//line 3
int age;//line 4
cout << "Give me your age:" <<endl;//line 5
cin >> age;//line 6
What happens if the user answers: "Arkadiusz Wlodarczyk" for first question?
Run the program to see for yourself.
You will see on console "Arkadiusz" but program won't ask you for 'age'. It will just finish immediately right after printing "Arkadiusz".
And "Wlodarczyk" is not shown. It seems like if it was gone (?)*
What happened? ;-)
Because there is a space between "Arkadiusz" and "Wlodarczyk".
"space" character between the name and surname is a sign for computer that there are two variables waiting to be extracted on 'input' stream.
The computer thinks that you are tying to send to input more than one variable. That "space" sign is a sign for him to interpret it that way.
So computer assigns "Arkadiusz" to 'name' (2) and because you put more than one string on stream (input) computer will try to assign value "Wlodarczyk" to variable 'age' (!). The user won't have a chance to put anything on the 'cin' in line 6 because that instruction was already executed(!). Why? Because there was still something left on stream. And as I said earlier stream is in a flow so everything must be removed from it as soon as possible. And the possibility came when computer saw instruction cin >> age;
Computer doesn't know that you created a variable that stores age of somebody (line 4). 'age' is merely a label. For computer 'age' could be as well called: 'afsfasgfsagasggas' and it would be the same. For him it's just a variable that he will try to assign "Wlodarczyk" to because you ordered/instructed computer to do so in line (6).
It's wrong to do so, but hey it's you who did it! It's your fault! Well, maybe user, but still...
All right all right. But how to fix it?!
Let's try to play with that example a bit before we fix it properly to learn a few more interesting things :-)
I prefer to make an approach where we understand things. Fixing something without knowledge how we did it doesn't give satisfaction, don't you think? :)
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate(); //new line is here :-)
After invoking above code you will notice that the state of your stream (cin) is equal to 4 (line 7). Which means its internal state is no longer equal to goodbit. Something is messed up. It's pretty obvious, isn't it? You tried to assign string type value ("Wlodarczyk") to int type variable 'age'. Types doesn't match. It's time to inform that something is wrong. And computer does it by changing internal state of stream. It's like: "You f**** up man, fix me please. I inform you 'kindly' ;-)"
You simply cannot use 'cin' (stream) anymore. It's stuck. Like if you had put big wood logs on water stream. You must fix it before you can use it. Data (water) cannot be obtained from that stream(cin) anymore because log of wood (internal state) doesn't allow you to do so.
Oh so if there is an obstacle (wood logs) we can just remove it using tools that is made to do so?
Yes!
internal state of cin set to 4 is like an alarm that is howling and making noise.
cin.clear clears the state back to normal (goodbit). It's like if you had come and silenced the alarm. You just put it off. You know something happened so you say: "It's OK to stop making noise, I know something is wrong already, shut up (clear)".
All right let's do so! Let's use cin.clear().
Invoke below code using "Arkadiusz Wlodarczyk" as first input:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl; //new line is here :-)
We can surely see after executing above code that the state is equal to goodbit.
Great so the problem is solved?
Invoke below code using "Arkadiusz Wlodarczyk" as first input:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;//new line is here :-)
Even tho the state is set to goodbit after line 9 the user is not asked for "age". The program stops.
WHY?!
Oh man... You've just put off alarm, what about the wood log inside a water?* Go back to text where we talked about "Wlodarczyk" how it supposedly was gone.
You need to remove "Wlodarczyk" that piece of wood from stream. Turning off alarms doesn't solve the problem at all. You've just silenced it and you think the problem is gone? ;)
So it's time for another tool:
cin.ignore can be compared to a special truck with ropes that comes and removes the wood logs that got the stream stuck. It clears the problem the user of your program created.
So could we use it even before making the alarm goes off?
Yes:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
The "Wlodarczyk" is gonna be removed before making the noise in line 7.
What is 10000 and '\n'?
It says remove 10000 characters (just in case) until '\n' is met (ENTER). BTW It can be done better using numeric_limits but it's not the topic of this answer.
So the main cause of problem is gone before noise was made...
Why do we need 'clear' then?
What if someone had asked for 'give me your age' question in line 6 for example: "twenty years old" instead of writing 20?
Types doesn't match again. Computer tries to assign string to int. And alarm starts. You don't have a chance to even react on situation like that. cin.ignore won't help you in case like that.
So we must use clear in case like that:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
But should you clear the state 'just in case'?
Of course not.
If something goes wrong (cin >> age;) instruction is gonna inform you about it by returning false.
So we can use conditional statement to check if the user put wrong type on the stream
int age;
if (cin >> age) //it's gonna return false if types doesn't match
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";
All right so we can fix our initial problem like for example that:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
if (cin >> age)
cout << "Your age is equal to:" << endl;
else
{
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
cout << "Give me your age name as string I dare you";
cin >> age;
}
Of course this can be improved by for example doing what you did in question using loop while.
BONUS:
You might be wondering. What about if I wanted to get name and surname in the same line from the user? Is it even possible using cin if cin interprets each value separated by "space" as different variable?
Sure, you can do it two ways:
1)
string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;
cout << "Hello, " << name << " " << surname << endl;
2) or by using getline function.
getline(cin, nameOfStringVariable);
and that's how to do it:
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
The second option might backfire you in case you use it after you use 'cin' before the getline.
Let's check it out:
a)
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
If you put "20" as age you won't be asked for nameAndSurname.
But if you do it that way:
b)
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll
everything is fine.
WHAT?!
Every time you put something on input (stream) you leave at the end white character which is ENTER ('\n') You have to somehow enter values to console. So it must happen if the data comes from user.
b) cin characteristics is that it ignores whitespace, so when you are reading in information from cin, the newline character '\n' doesn't matter. It gets ignored.
a) getline function gets the entire line up to the newline character ('\n'), and when the newline char is the first thing the getline function gets '\n', and that's all to get. You extract newline character that was left on stream by user who put "20" on stream in line 3.
So in order to fix it is to always invoke cin.ignore(); each time you use cin to get any value if you are ever going to use getline() inside your program.
So the proper code would be:
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, '\n')
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
I hope streams are more clear to you know.
Hah silence me please! :-)
use cin.ignore(1000,'\n') to clear all of chars of the previous cin.get() in the buffer and it will choose to stop when it meet '\n' or 1000 chars first.