9

This is related to: cin and getline skipping input But they don't answer the why it happens just the how to fix it.

Why does cin leaves a '\n' in the buffer but just cin.getline takes it?

for example:

cin >> foo;
cin >> bar;//No problem
cin >> baz;//No problem.

But with cin.getline

cin >> foo;
cin.getline(bar,100);//will take the '\n'

So why it doesn't happen with cin but it does with cin.getline?

shinzou
  • 5,850
  • 10
  • 60
  • 124
  • What are the type of `foo`, `bar` and `baz` ? Have you tried to play with `skipws` ? – dkg Jan 23 '15 at 12:25
  • `cin` is not a command. It's an object of type `std::ostream`. In contrast, `>>` is `std::ostream::operator>>`, i. e. an operator (still not a "command"). It leaves the newline in the buffer because the C++ standard says that this operator has to leave the newline in the buffer. `std::getline()` doesn't leave it in the buffer because the spec says that it must consume the newline. That's why. – The Paramagnetic Croissant Jan 23 '15 at 12:32
  • 1
    Everybody knows the names of the guys that contributed STL to the C++ standard library. Nobody knows who created iostream. And if I were Jerry Schwarz then I'd prefer to keep it that way too :) – Hans Passant Jan 23 '15 at 12:50
  • @HansPassant lol are you serious? – shinzou Jan 23 '15 at 12:57
  • Well, going for the lolz, but there's a kernel of truth. I don't think any C++ programmer is terribly impressed how iostream turned out. There are surely reasons for that, Schwartz had to work with earlier designs that dated from an era where the world still spoke C and C++ did not have exceptions and multiple inheritance yet. Hard to guess what kind of constraints he had to avoid breaking a lot of existing code. Which is the problem with your question, only Schwartz could ever answer it accurately. – Hans Passant Jan 23 '15 at 13:34
  • @TheParamagneticCroissant Best name on SO by a mile. I've never eaten one of those, where can I get one? :) – Paul Sanders Jun 17 '18 at 05:43

2 Answers2

11

Because, when you say getline you say you want to get a line... A line is string that ends with \n, the ending is integral part of it.

When you say cin >> something, you want to get precisely something, nothing more. End-line marker is not part of it, so it's not consumed. Unless you would have a special type for line, but there is no such thing in standard library.

While without citations from standard this might be taken as opinion, but this is logic behind it. They have different semantics. There is also another difference getline works as unformatted input, and operator>> works as formatted input. I strongly suggest reading of those links to get the differences. This also says that they are semantically different.

Another answer, better or not is debatable, would be to quote standard, that I am sure says, how getline behaves, and how operator>> behaves for different types, and say, it works like this, because standard says so. This would be good, because the standard absolutely defines how things work and it can do so arbitrarily... And it rarely does explain motivation and logic behind the design.

luk32
  • 15,812
  • 38
  • 62
  • So `cin` let the `'\n'` stay in the buffer? Can there be several `'\n'` characters in the buffer after several `cin`s? – shinzou Jan 23 '15 at 12:26
  • I am not sure if I follow. Do you ask this: If stdin buffer is "foo\n\n\nbar\n" and will do `cin >> text;` and then `cin >> text2;` what will you get? – luk32 Jan 23 '15 at 12:29
  • @rubenvb Oh, yeah it's a function, I tried to be too clever, I am not sure what you get when you do `getline` on windows with windows endings. – luk32 Jan 23 '15 at 12:31
  • Well written explanation. The logic is the important thing to understand here. – Joseph Mansfield Jan 23 '15 at 13:34
6

You are not comparing cin to cin.getline, but rather cin.operator>> and cin.getline, and that is exactly what these functions are defined to do. The answer to the question "why" is "by definition". If you want rationale, I can't give it to you.

cin.getline reads and consumes until a newline \n is entered. cin.operator>> does not consume this newline. The latter performs formatted input, skipping leading whitespace, until the end of the object it was reading (in your case whatever foo is) "stops" (in case foo is an int, when the character isn't a number). A newline is what remains when the number is consumed from the input line. cin.getline reads a line, and consumes the newline by definition.

Make sure to always check for error on each stream operation:

if(cin >> foo)

or

if(std::getline(cin, some_string))

Note I used std::getline instead of the stream's member because this way there's no need for any magic numbers (the 100 in your code).

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • Why is placing them in an `if()` check for errors? How could it be 0 or 1? – shinzou Jan 23 '15 at 12:41
  • @kuhaku that's an implicit (or explicit, in C++11) conversion to bool of the result of the `operator>>` (which returns a reference to the stream object). See for example [here](http://www.parashift.com/c++-faq-lite/istream-and-while.html) – rubenvb Jan 23 '15 at 12:49
  • I see, quite nice and useful too. – shinzou Jan 23 '15 at 12:56