Hello everyone, I was trying to use the getline for the first time and this weird thing happend.
Here’s the Code on Gist.
So there’s two calls for user input with cin to demonstrate the cin problem of geting two values at once by mistake and one input done with getline().
I made a third input because the code was looking terrible and I wanted to just get it done and compare it as it went, the problem is that as long as both cin calls were in the code, the getline would not work, it would just be skiped and the program would end as if the getline got an empty value out of it. As soon as I deleted both cin (lines 18 - 35), the code worked perfectly.
I don’t get it, why is the cin input getting in the way of getline? What did I do wrong?
Even if I input single words on both cin, the getline is skipped.
If I delete one cin, the problem continues as well.
If I clear out the Guess string to " " before getline, it still doesn’t work.
Is getline looking the return value of the cin itself after it was used, instead of calling it again?
I feel like I am missing out on some detail about the use of getline, that might come back to haunt me.
I took a while to figure this out because I thought I was using wrong syntax or something, so I decided to post this here.
All the best, thanks for reading.
Hi @emberfox,
What you have to understand is that cin is not a function. It is a special variable called an input stream. When you input data in the terminal, it somehow has to “travel” to your program, that’s where an input stream comes into play, it is the medium your computer uses to move data from the terminal to your program. Also notice that input streams have an internal index of where the next character your program will read is located.
Now think on the first parameter of getline, you are passing the input stream cin. What getline does is that it reads an input stream until it reaches a newline or delimiter character. In the other hand, take a look at the documentation of the “>>” operator: http://www.cplusplus.com/reference/istream/istream/operator-free/
Extracts characters from is and stores them in s as a c-string, stopping as soon as either a whitespace character is encountered or (width()-1) characters have been extracted (if width is not zero).
A null character (charT()) is automatically appended to the written sequence.
The function then resets width to zero.
So, having in mind that, here’s what’s happening on your attached code, let’s say I input hello in the first prompt and world in the second:
- First call to
cin >> guess
: You type:: hello\n and >> appends an extra null character - Second call: the input string now looks something like this: hello\n[null_character]world\n[null_character]
- getline: Remember I said input streams have an internal index of where to read next? Well, you are passing cin to the getline function, and cin is not empty and the internal index is not pointing to the end of the stream, so getline WILL read whatever’s on that input stream, which in this case is the null characters appended by the “>>” operator.
- Now the
Guess
variable value is the [null_character], which literally is nothing, so nothing is printed.
So I hope that clears things up. In general, don’t combine cin with getline, or if you do, try to ignore or skip (those are functions of the input streams) the null characters before passing it to getline. I reccommend doing the exercise of writing down what happens when you enter a word with space while using the >> operator and read the documentation, that is very important:
- http://www.cplusplus.com/reference/string/string/getline/
- http://www.cplusplus.com/reference/istream/istream/operator-free/
Here’s a stackoverflow post that might give you more insight: http://stackoverflow.com/questions/5739937/using-getlinecin-s-after-cin
I realize that you posted this 15 days ago, but if you have any questions do let me know.
Wow! That was so clarifying! Thank you so much! Sorry I didn’t answer this before, I went through a surgery and have been away for a while! I love this! This is perfect!
The answer by mretana gives the right idea, but it is not really correct. The >> operator does not append a null character to the input stream, it appends a null character to the C string that is receiving the extracted content (because that is the C way of identifying the end of a string). When used with std::string from C++, the need to append a null character only exists from C++11.
Here is what the >> operator does in the example at hand:
- discards any leading whitespace from the input stream
- extracts non-whitespace contents of the input stream…
- stops when it encounters another whitespace, but does not consume it
- fills up the supplied string with the extracted contents, plus a null character (’\0’)
Here is what the getline() function does in the example:
- (does not discard any leading whitespace)
- extracts all contents from the input stream…
- stops when it encounters a new line, and discards it
- fills up the supplied string with the extracted contents, minus the new line character, plus a null character (’\0’)
And here is something the standard input stream itself does:
- if the stream contents are exhausted while being consumed, asks the user for more input, then allow it to keep being consumed
So, let’s follow what happens:
cin >> Guess; // (first time)
// Input stream is empty, asks the user for input.
// Input stream after user input: “hello\n”.
// Operator >> extracts “hello”, input stream keeps ‘\n’
cin >> Guess; // (second time)
// Operator >> consumes the ‘\n’ whitespace, then needs more input.
// Input stream has become empty, asks the user for input.
// Input stream after user input: “world\n”.
// Operator >> extracts “world”, input stream keeps ‘\n’.
getline(cin, Guess);
// Reads input stream, immediately finds ‘\n’, discards it and stops.
// Fills Guess with the empty content if found before ‘\n’.
// (since getline() stopped consuming from the input stream, it does not ask the user for more input)
Hope this helps clarify even more.