为什么 cin 和 getline 表现出不同的读取行为?
Why do cin and getline exhibit different reading behavior?
作为参考,我已经看过 Why does std::getline() skip input after a formatted extraction?
我想了解 cin 和 getline 的行为。我想象 cin 和 getline 是通过在输入缓冲区上循环来实现的,每次迭代都会增加一个游标。一旦输入缓冲区的当前元素等于某个“停止”值(cin 为“”或“\n”,getline 为“\n”),循环就会中断。
我的问题是cin和getline的读取行为的区别。对于 cin,它似乎在“\n”处停止,但它会在退出循环之前递增光标。例如,
string a, b;
cin >> a;
cin >> b;
cout << a << "-" << b << endl;
// Input: "cat\nhat"
// Output: "cat-hat"
所以在上面的代码中,第一个cin一直读到"\n"。一旦它碰到那个“\n”,它就会在中断循环之前将光标递增到下一个位置“h”。然后,下一个 cin 操作从“h”开始读取。这允许下一个 cin 实际处理字符而不是仅仅中断。
当 getline 与 cin 混合时,这不是行为。
string a, b;
cin >> a;
getline(cin, b);
cout << a << "-" << b << endl;
// Input: "cat\nhat"
// Output: "cat-"
在这个例子中,cin 读取到“\n”。但是当 getline 开始读取时,它似乎是从“\n”而不是“h”读取的。这意味着光标没有前进到“h”。所以 getline 处理了 "\n" 并将光标前进到 "h" 但实际上并没有将 getline 保存到 "b"。
所以在一个例子中,cin 似乎将光标前移到“\n”,而在另一个例子中,它没有。 getline 也表现出不同的行为。例如
string a, b;
getline(cin, a);
getline(cin, b);
cout << a << "-" << b << endl;
// Input: "cat\nhat"
// Output: "cat-hat"
现在getline实际上是将光标移到“\n”上。为什么会有不同的行为,当涉及到定界字符时,cin 与 getline 的实际实现是什么?
reading behavior of cin and getline.
cin
不“读取”任何内容。 cin
是一个输入流。 cin
正在从 读取 。 getline
从输入流中读取。格式化提取运算符 >>
从输入流中读取。读取的是 >>
和 std::getline
。 std::cin
没有自己的阅读。这是从.
读到的内容
first cin read up until the "\n". once it hit that "\n", it increments the
cursor to the next position
不,不是。第一个 >>
运算符读取到 \n
,但 没有读取它 。 \n
仍未读。
第二个 >>
运算符以换行符开始读取。 >>
运算符在提取预期值之前跳过输入流 中的所有空格 。
你缺少的细节是 >>
跳过空白(如果有的话)before 它提取来自输入流的值,而不是 after.
现在,>>
确实有可能在提取格式化值之前在输入流中找不到空格。如果 >>
的任务是提取一个 int
,并且输入流刚刚打开并且它位于文件的开头,并且文件中的第一个字符是 1
,那么, >>
根本不跳过任何空格。
最后,std::getline
不会跳过任何空格,它只是从输入流中读取直到读取 \n
(或到达输入流的末尾)。
tl;dr: 因为 std::cin
是面向行内的,而 getline 是面向行的。
历史上,在 C 的标准库中,我们有函数 scanf()
和 getline()
:
当您告诉 scanf()
期待一个字符串时,它
... stops at white space or at the maximum field width, whichever occurs first.
更一般地说,
Most conversions [e.g. readings of strings] discard initial white space characters
(来自scanf()
man page)
当你调用getline()
时,它:
reads an entire line ... the buffer containing the text ... includes the newline character, if one was found.
现在,C++ 的 std::cin
机制取代了 scanf()
用于格式化输入匹配,但具有类型安全性。 (实际上 std::cin
和 std::cout
作为替代品是很有问题的,但现在不用管它了。)作为 scanf()
的替代品,它继承了它的许多特性,包括不喜欢拾取白色space.
因此,就像 scanf()
一样,运行 std::cin >> a
对于字符串 a
将在 \n
字符之前停止,并保留该换行符供将来使用的输入流。另外,就像 scanf()
一样,std::cin
的 >> 运算符会跳过前导白色 space,所以如果您第二次使用它,\n
将被跳过,并且从下一行的第一个非白色 space 字符开始拾取下一个字符串。
使用 std::getline()
,您将获得与过去几十年完全相同的 getline()
行为。
PS - 您可以使用 std::cin
[=38 的 skipws format-flag 来控制白space-跳过行为=]
作为参考,我已经看过 Why does std::getline() skip input after a formatted extraction?
我想了解 cin 和 getline 的行为。我想象 cin 和 getline 是通过在输入缓冲区上循环来实现的,每次迭代都会增加一个游标。一旦输入缓冲区的当前元素等于某个“停止”值(cin 为“”或“\n”,getline 为“\n”),循环就会中断。
我的问题是cin和getline的读取行为的区别。对于 cin,它似乎在“\n”处停止,但它会在退出循环之前递增光标。例如,
string a, b;
cin >> a;
cin >> b;
cout << a << "-" << b << endl;
// Input: "cat\nhat"
// Output: "cat-hat"
所以在上面的代码中,第一个cin一直读到"\n"。一旦它碰到那个“\n”,它就会在中断循环之前将光标递增到下一个位置“h”。然后,下一个 cin 操作从“h”开始读取。这允许下一个 cin 实际处理字符而不是仅仅中断。
当 getline 与 cin 混合时,这不是行为。
string a, b;
cin >> a;
getline(cin, b);
cout << a << "-" << b << endl;
// Input: "cat\nhat"
// Output: "cat-"
在这个例子中,cin 读取到“\n”。但是当 getline 开始读取时,它似乎是从“\n”而不是“h”读取的。这意味着光标没有前进到“h”。所以 getline 处理了 "\n" 并将光标前进到 "h" 但实际上并没有将 getline 保存到 "b"。
所以在一个例子中,cin 似乎将光标前移到“\n”,而在另一个例子中,它没有。 getline 也表现出不同的行为。例如
string a, b;
getline(cin, a);
getline(cin, b);
cout << a << "-" << b << endl;
// Input: "cat\nhat"
// Output: "cat-hat"
现在getline实际上是将光标移到“\n”上。为什么会有不同的行为,当涉及到定界字符时,cin 与 getline 的实际实现是什么?
reading behavior of cin and getline.
cin
不“读取”任何内容。 cin
是一个输入流。 cin
正在从 读取 。 getline
从输入流中读取。格式化提取运算符 >>
从输入流中读取。读取的是 >>
和 std::getline
。 std::cin
没有自己的阅读。这是从.
first cin read up until the "\n". once it hit that "\n", it increments the cursor to the next position
不,不是。第一个 >>
运算符读取到 \n
,但 没有读取它 。 \n
仍未读。
第二个 >>
运算符以换行符开始读取。 >>
运算符在提取预期值之前跳过输入流 中的所有空格 。
你缺少的细节是 >>
跳过空白(如果有的话)before 它提取来自输入流的值,而不是 after.
现在,>>
确实有可能在提取格式化值之前在输入流中找不到空格。如果 >>
的任务是提取一个 int
,并且输入流刚刚打开并且它位于文件的开头,并且文件中的第一个字符是 1
,那么, >>
根本不跳过任何空格。
最后,std::getline
不会跳过任何空格,它只是从输入流中读取直到读取 \n
(或到达输入流的末尾)。
tl;dr: 因为 std::cin
是面向行内的,而 getline 是面向行的。
历史上,在 C 的标准库中,我们有函数 scanf()
和 getline()
:
当您告诉
scanf()
期待一个字符串时,它... stops at white space or at the maximum field width, whichever occurs first.
更一般地说,
Most conversions [e.g. readings of strings] discard initial white space characters
(来自
scanf()
man page)当你调用
getline()
时,它:reads an entire line ... the buffer containing the text ... includes the newline character, if one was found.
现在,C++ 的 std::cin
机制取代了 scanf()
用于格式化输入匹配,但具有类型安全性。 (实际上 std::cin
和 std::cout
作为替代品是很有问题的,但现在不用管它了。)作为 scanf()
的替代品,它继承了它的许多特性,包括不喜欢拾取白色space.
因此,就像 scanf()
一样,运行 std::cin >> a
对于字符串 a
将在 \n
字符之前停止,并保留该换行符供将来使用的输入流。另外,就像 scanf()
一样,std::cin
的 >> 运算符会跳过前导白色 space,所以如果您第二次使用它,\n
将被跳过,并且从下一行的第一个非白色 space 字符开始拾取下一个字符串。
使用 std::getline()
,您将获得与过去几十年完全相同的 getline()
行为。
PS - 您可以使用 std::cin
[=38 的 skipws format-flag 来控制白space-跳过行为=]