为什么STD :: getline()在格式提取后跳过输入?

发布于 2025-02-04 07:51:12 字数 569 浏览 5 评论 0原文

我有以下代码,这些代码提示用户的猫的年龄和名称:

#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;
    }
}

我发现年龄已成功阅读,但没有名字。这是输入和输出:

 输入:

“ 10”
“晶须先生”

输出:

“我的猫已经10岁了,他们的名字就是”
 

为什么从输出中省略了名称?我给出了适当的输入,但是代码以某种方式忽略了它。为什么会发生这种情况?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

方圜几里 2025-02-11 07:51:12

为什么会发生这种情况?

这与您自己提供的输入无关,而与默认行为std :: getline()具有。当您提供年龄的输入(std :: cin&gt; age)时,您不仅提交了以下字符,而且在输入输入:

 “ 10 \ n”
 

从终端提交时,当您选择 enter 返回时,始终将newline附加到您的输入中。它也用于文件中,用于朝着下一行移动。提取到age之前,新线将留在缓冲区中,直到下一个I/O操作被丢弃或读取为止。当控件流达到std :: getline()时,它将看到“ \nmr。whiskers”,并且开始时的newline将被丢弃,但是输入操作会立即停止。之所以发生的原因是因为std :: getline()的作业是尝试读取字符并在找到新线时停止。因此,其余的输入将留在缓冲区未读。

解决方案

cin.ignore()

要解决此问题,一个选项是在执行std :: getline()之前跳过newline。您可以通过调用std :: cin.ignore()在第一个输入操作后来执行此操作。它将丢弃下一个字符(newline字符),以便不再妨碍它。

std::cin >> age;
std::cin.ignore();
std::getline(std::cin, name);

assert(std::cin); 
// Success!

std :: ws

丢弃空格的另一种方法是使用std :: WS函数,该功能是一种操纵器,旨在从输入开始时提取和丢弃领先的空格流:

std::cin >> age;
std::getline(std::cin >> std::ws, name);

assert(std::cin);
// Success!

std :: cin&gt;&gt; std :: ws表达式在std :: getline()呼叫之前(以及std :: cin&gt;&gt; egt; age呼叫)删除了新线字符。

不同之处在于ignore()仅放弃1个字符(或给出参数时n个字符),而std :: WS继续忽略空格,直到找到一个非 - 空格角色。因此,如果您不知道在接下来的标记之前将要考虑使用该空间有多少,则应考虑使用此问题。

匹配操作

时,当您遇到这样的问题时,通常是因为您将格式化的输入操作与未进行输入操作相结合。格式的输入操作是您进行输入并为某种类型的格式格式化时。这就是操作员&gt;&gt;()是为了。除std :: getline()std :: cin.read()std :: cin.get( )等。这些功能不在乎输入的格式,而仅处理原始文本。

如果您坚持使用单一类型的格式,则可以避免此烦人的问题:

// Unformatted I/O
std::string age, name;
std::getline(std::cin, age);
std::getline(std::cin, name);

或者,

// Formatted I/O
int age;
std::string firstName, lastName;
std::cin >> age >> firstName >> lastName;

如果选择使用未形式的操作读取所有内容作为字符串,则可以将其转换为适当的类型。

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.

鹿! 2025-02-11 07:51:12

如果您以以下方式更改初始代码,一切都会好的:

if ((cin >> name).get() && std::getline(cin, state))

Everything will be OK if you change your initial code in the following way:

if ((cin >> name).get() && std::getline(cin, state))
贩梦商人 2025-02-11 07:51:12

发生这种情况是因为隐式线feed也称为newline字符\ n被附加到终端中的所有用户输入上,因为它告诉流开始新行。您可以使用 std :: getline 检查多行用户输入时。 std :: getline的默认行为将从输入流对象(std :: cin 在这种情况下。

#include <iostream>
#include <string>

int main()
{
    std::string name;
    std::string state;

    if (std::getline(std::cin, name) && std::getline(std::cin, state))
    {
        std::cout << "Your name is " << name << " and you live in " << state;
    }
    return 0;
}
 输入:

“约翰”
“新罕布什尔”

输出:

“你的名字叫约翰,你住在新罕布什尔州”
 

This happens because an implicit line feed also known as newline character \n is appended to all user input from a terminal as it's telling the stream to start a new line. You can safely account for this by using std::getline when checking for multiple lines of user input. The default behavior of std::getline will read everything up to and including the newline character \n from the input stream object which is std::cin in this case.

#include <iostream>
#include <string>

int main()
{
    std::string name;
    std::string state;

    if (std::getline(std::cin, name) && std::getline(std::cin, state))
    {
        std::cout << "Your name is " << name << " and you live in " << state;
    }
    return 0;
}
Input:

"John"
"New Hampshire"

Output:

"Your name is John and you live in New Hampshire"
转角预定愛 2025-02-11 07:51:12

我真的很想知道。 C ++具有专门的功能,可以吃掉任何剩余的或任何白色空间。称为 std :: ws 。然后,您可以简单地使用

std::getline(std::cin >> std::ws, name);

它应该是IDOMANT方法。对于应使用的格式化到未格式化的输入之间的每个跨源。

如果我们不是在谈论白色空间,而是输入预期数字的字母,那么我们应该遵循CPP参考并使用

.ignore(std :: Numeric_limits&lt; std :: streamSize&gt; :: max() ,'\ n');消除错误的东西。

请阅读在这里

I am really wondering. C++ has a dedicated function for eating up any remaining or whatever white spaces. It is called std::ws. And then, you can simply use

std::getline(std::cin >> std::ws, name);

That should be the idomatic approach. For each transistion between formatted to unformatted input that should be used.

If we are not talking about white spaces, but entering for example letters where a number is expected, then we should follow the CPP reference and use

.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); to eliminate the wrong stuff.

Please read here

娇纵 2025-02-11 07:51:12

由于上面的每个人都回答了输入10 \ nmr晶须\ n的问题,因此我想回答另一种方法。上面的所有解决方案都发布了代码,以便如果缓冲区像10 \ nmr晶须\ n。但是,如果我们不知道用户在给出输入方面的行为怎么办。用户可以键入10 \ n \ nmr。 Whisker \ n10 \ n \ n先生Whisker \ n误认为。在这种情况下,上面的代码可能行不通。因此,我使用以下功能进行字符串输入来解决问题。

string StringInput()  //returns null-terminated string
{
    string input;
    getline(cin, input);
    while(input.length()==0)//keep taking input as long as valid string is taken
    {
        getline(cin, input);
    }
    return input.c_str();
}

因此,答案将是:

#include <iostream>
#include <string>

int main()
{
    int age;
    std::string name;

    std::cin >> age;
    name = StringInput();
    
    std::cout << "My cat is " << age << " years old and it's name is " << name << std::endl;
    
}

额外:

如果用户输入a \ n10 \ n \ nmr。威士忌;
要检查int输入是否有效,可以使用此功能检查int输入(如果给出char,程序将具有不确定的行为作为输入而不是int):


//instead of "std::cin>>age;" use "get_untill_int(&age);" in main function.
void get_Untill_Int(int* pInput)//keep taking input until input is `int or float`
{
    cin>> *pInput;
    /*-----------check input validity----------------*/
    while (!cin) 
    {
        cin.clear();
        cin.ignore(100, '\n');
        cout<<"Invalid Input Type.\nEnter again: ";
        cin >>*pInput;
    }
    /*-----------checked input validity-------------*/
}

Since everyone above has answered the problem for input 10\nMr Whisker\n, I would like to answer a different approach. All the solution above published the code for if the buffer is like 10\nMr Whisker\n. But what if we don't know how user will behave in giving input. The user might type 10\n\nMr. Whisker\n or 10 \n\n Mr. whisker\n by mistake. In that case, codes above may not work. So, I use the function below to take string input to address the problem.

string StringInput()  //returns null-terminated string
{
    string input;
    getline(cin, input);
    while(input.length()==0)//keep taking input as long as valid string is taken
    {
        getline(cin, input);
    }
    return input.c_str();
}

So, the answer would be:

#include <iostream>
#include <string>

int main()
{
    int age;
    std::string name;

    std::cin >> age;
    name = StringInput();
    
    std::cout << "My cat is " << age << " years old and it's name is " << name << std::endl;
    
}

Extra:

If user inputs a \n10\n \nmr. whiskey;
To check whether int input is valid or not, this function can be used to check int input (program will have undefined behavior if char is given as input instead of int):


//instead of "std::cin>>age;" use "get_untill_int(&age);" in main function.
void get_Untill_Int(int* pInput)//keep taking input until input is `int or float`
{
    cin>> *pInput;
    /*-----------check input validity----------------*/
    while (!cin) 
    {
        cin.clear();
        cin.ignore(100, '\n');
        cout<<"Invalid Input Type.\nEnter again: ";
        cin >>*pInput;
    }
    /*-----------checked input validity-------------*/
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文