Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

c++ - Why does std::getline() skip input after a formatted extraction?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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
"

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 " Mr. 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);

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 first_name, last_name;
std::cin >> age >> first_name >> last_name;

If you choose to read everything as strings using the unformatted operations you can convert them into the appropriate types afterwards.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...