Question
When I compile and execute the following C++ program, I find it strange that the program does not wait for the user to hit 'Enter'. What could be the possible explanation for this behaviour ? How can we solve this anamoly ?
#include <iostream>
using namespace std;
int main()
{
string key;
cout << "Enter a word\n";
cin >> key;
cout << "You entered : " [[ key [[ "\n";
cout << "Hit Enter to proceed...";
key = cin.get();
if (key == "\n")
cout << "Exit\n";
else
cout << "Error\n";
return 0;
}
The output of the program is something like this
# ./wait
Enter a word
india
You entered : india
Hit Enter to be proceed...Exit
#
Answer
Before writing the answer, it makes more sense to understand the problem. When you read input from the keyboard, the input is read through an input stream. The behaviour of this stream is to capture keyboard input and store it in an internal buffer. The stream will read from keyboard input, only after this internal buffer is empty.
When we entered the word "india" and pressed "Enter", the characters 'i','n','d','i','a','\n' were stored in the internal buffer. cin.get() only reads up to the delimiting character, viz., '\n' by default. [ More on this at :
http://www.cplusplus.com/reference/istream/istream/get/ ].
So, the initial value in the string "key" was "india", but the input buffer still contained the trailing character '\n'. When we did a cin.get(); on line 13, we expected cin to read from keyboard input. But, instead it is the trailing character in the input buffer that is read by cin. And the program never prompted for user input.
To force the program to prompt for user input, we need to clear [ or eat ] the trailing contents in the input buffer. Remember that flush() is applicable only on output streams. So, it won't solve the problem here. We have to explicitly read the trailing characters in the input buffer. Keep in mind that we do not know how many characters are still remaining in the input buffer.
If the user has only entered the "india" and pressed "Enter" [ assuming he is a very obedient user :-) ] the simplest solution is to add the following line before line 12.
string tmp = cin.get();
The new code would be :
#include <iostream>
using namespace std;
int main()
{
string key;
cout << "Enter a word\n";
cin >> key;
cout << "You entered : " [[ key [[ "\n";
string tmp = cin.get(); // This eats up the trailing '\n' still remaining in the input buffer
cout << "Hit Enter to proceed...";
key = cin.get();
if (key == "\n")
cout << "Exit\n";
else
cout << "Error\n";
return 0;
}
And the new output behaves as below :
#./wait
Enter a word
peace
You entered : peace
Hit Enter to proceed...
Exit
#./wait
Enter a word
more peace
You entered : more
Hit Enter to proceed...Error
As expected, this works only if the user enters one word. If he enters more than one word, this fails. And since we do not know what characters the user would input, and we need to program for the worst possible case, a more generic and proper fix is to bite into the entire input buffer and junk it. The complete fix would be like this one below :
#include <iostream>
using namespace std;
int main()
{
string key;
cout << "Enter a word\n";
cin >> key;
cout << "You entered : " [[ key [[ "\n";
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
cout << "Hit Enter to proceed...";
key = cin.get();
if (key == "\n")
cout << "Exit\n";
else
cout << "Error\n";
return 0;
}
The cin.clear() : only clears the internal stream's error state flags [ and not the input buffer !!! ] [ More info :
http://www.cplusplus.com/reference/ios/ios/clear/ ]
The cin.ignore() : extracts characters from the input stream and junks them till it has extracted the maximum number of input characters, or the '\n' character.
The output now is :
#./wait
Enter a word
world
You entered : world
Hit Enter to proceed...
Exit
#./wait
Enter a word
world cup
You entered : world
Hit Enter to proceed...
Exit
#./wait
Enter a word
2014 world cup
You entered : 2014
Hit Enter to proceed...
Exit
Enjoy :-)