I have a question about the difference between these two pieces of code:
char buffer5[5];
cin.get(buffer5, 5);
cout << buffer5;
cin.get(buffer5, 5);
cout << buffer5;
and
char buffer4;
while (cin.get(buffer4))
{
cout << buffer4;
}
In the first piece of code, the code gets 5 characters and puts it in buffer5. However, because you press enter, a newline character isn't put into the stream when calling get(), so the program will terminate and will not ask you for another round of 5 characters.
In the second piece of code, cin.get() waits for input to the input stream, so the loop doesn't just terminate (I think). Lets say I input "Apple" into the input stream. This will put 5 characters into the input stream, and the loop will print all characters to the output. However, unlike the first piece of code, it does not stop, even after two inputs as I can continuously keep inputting.
Why is it that I can continuously input character sequences into the terminal in the second piece of code and not the first?
First off, "pressing enter" has no special meaning to the IOStreams beyond entering a newline character (
\n
) into the input sequence (note, when using text streams the platform specific end of line sequences are transformed into a single newline character). When entering data on a console, the data is normally line buffered by the console and only forwarded to the program when pressing enter (typically this can be turned off but the details of this are platform specific and irrelevant to this question anyway).With this out of the way lets turn our attention to the behavior of
s.get(buffer, n)
for anstd::istream s
and a pointer to an array of at leastn
charactersbuffer
. The description of what this does is quite trivial: it callss.get(buffer, n, s.widen('\n'))
. Since we are talking aboutstd::istream
and you probably haven't changed thestd::locale
we can assume thats.widen('\n')
just returns'\n'
, i.e., the call is equivalent tos.get(buffer, n, '\n')
where'\n'
is called a delimiter and the question becomes what this function does.Well, this function extracts up to
m = 0 < n? n - 1: 0
characters, stopping when eitherm
is reached or when the next character is identical to the delimiter which is left in the stream (you'd usedstd::istream::getline()
if you'd wanted the delimiter to be extracted). Any extracted character is stored in the corresponding location ofbuffer
and if0 < n
a null character is stored into locationbuffer[n - 1]
. In case, if no character is extractedstd::ios_base::failbit
is set.OK, with this we should have all ingredients to the riddle in place: When you entered at least one character but less than 5 characters the first call to
get()
succeeded and left the newline character as next character in the buffer. The next attempt toget()
more characters immediately found the delimiter, stored no character, and indicated failure by settingstd::ios_base::failbit
. It is easy to verify this theory:If you enter no character, the first call to
std::cin.get()
fails. If you enter 1 to 4 characters, the first call succeeds but the second one fails. If you enter more than 4 characters, the second call also succeeds, etc. There are several ways to deal with the potentially stuck newline character:std::istream::getline()
which behaves the same asstd::istream::get()
but also extracts the delimiter if this is why it stopped reading. This may chop one line into multiple reads, however, which may or may not be desired.std::getline()
together with anstd::string
(i.e.,std::getline(std::cin, string)
).get()
you could check if the next character is a newline usingstd::istream::peek()
andstd::istream::ignore()
it when necessary.Which of these approaches meets your needs depends on what you are trying to achieve.