Why does std::getline() skip input after a formatted extraction?
c++, getline, input, iostream, istream
Solution
Why does this happen?
This has little to do with the input you provided yourself but rather with the default behavior `std::getline()` has. When you provided your input for the age (`std::cin >> age`), you not only submitted the following characters, but also an implicit newline was appended to the stream when you typed Enter:
"10\n"
A newline is always appended to your input when you select Enter or Return when submitting from a terminal. It is also used in files for moving toward the next line. The newline is left in the buffer after the extraction into `age` until the next I/O operation where it is either discarded or read. When the flow of control reaches `std::getline()`, it will see `"\nMr. Whiskers"` and the newline at the beginning will be discarded, but the input operation will stop immediately. The reason this happens is because the job of `std::getline()` is to attempt to read characters and stop when it finds a newline. So the rest of your input is left in the buffer unread.
Solution
`cin.ignore()`
To fix this, one option is to skip over the newline before doing `std::getline()`. You can do this by calling `std::cin.ignore()` after the first input operation. It will discard the next character (the newline character) so that it is no longer in the way.
std::cin >> age;
std::cin.ignore();
std::getline(std::cin, name);
assert(std::cin);
// Success!
`std::ws`
Another way to discard the whitespace is to use the `std::ws` function which is a manipulator designed to extract and discard leading whitespace from the beginning of an input stream:
std::cin >> age;
std::getline(std::cin >> std::ws, name);
assert(std::cin);
// Success!
The `std::cin >> std::ws` expression is executed before the `std::getline()` call (and after the `std::cin >> age` call) so that the newline character is removed.
The difference is that `ignore()` discards only 1 character (or N characters when given a parameter), and `std::ws` continues to ignore whitespace until it finds a non-whitespace character. So if you don't know how much whitespace will precede the next token you should consider using this.
Match the operations
When you run into an issue like this it's usually because you're combining formatted input operations with unformatted input operations. A formatted input operation is when you take input and format it for a certain type. That's what `operator>>()` is for. Unformatted input operations are anything other than that, like `std::getline()`, `std::cin.read()`, `std::cin.get()`, etc. Those functions don't care about the format of the input and only process raw text.
If you stick to using a single type of formatting then you can avoid this annoying issue:
// Unformatted I/O
std::string age, name;
std::getline(std::cin, age);
std::getline(std::cin, name);
or
// Formatted I/O
int age;
std::string firstName, lastName;
std::cin >> age >> firstName >> lastName;
If you choose to read everything as strings using the unformatted operations you can convert them into the appropriate types afterwards.
Problem
I have the following piece of code that prompts the user for their cat's age and name: ``` #include <iostream> #include <string> int main() { int age; std::string name; std::cin >> age; std::getline(std::cin, name); if (std::cin) { std::cout << "My cat is " << age << " years old and their name is " << name << std::endl; } } ``` What I find is that the age has been successfully read, but not the name. Here is the input and output: ``` Input: "10" "Mr. Whiskers" Output: "My cat is 10 years old and their name is " ``` Why has the name been omitted from the output? I've given the proper input, but the code somehow ignores it. Why does this happen?