istream和cin.get()

时间:2012-08-28 18:17:59

标签: c++ cin istream

我对这两段代码之间的区别有疑问:

char buffer5[5];
cin.get(buffer5, 5);
cout << buffer5;

cin.get(buffer5, 5);
cout << buffer5;

char buffer4;
while (cin.get(buffer4))
{
    cout << buffer4;
}

在第一段代码中,代码获得5个字符并将其放入buffer5中。但是,由于您按Enter键,因此在调用get()时不会将换行符放入流中,因此程序将终止,并且不会要求您再拨打5个字符。

在第二段代码中,cin.get()等待输入流的输入,因此循环不会终止(我认为)。假设我在输入流中输入“Apple”。这将在输入流中放入5个字符,循环将所有字符打印到输出。但是,与第一段代码不同,即使在两次输入之后它也不会停止,因为我可以继续输入。

为什么我可以在第二段代码中连续输入字符序列而不是第一段呢?

1 个答案:

答案 0 :(得分:5)

首先,“输入”对IOStreams没有特别的意义,除了在输入序列中输入换行符(\n)之外(注意,当使用文本流时,平台特定的行序列末尾被转换为单个换行符)。在控制台上输入数据时,数据通常由控制台进行行缓冲,并且只有在按Enter键时才会转发到程序(通常可以关闭此项,但具体情况是平台特定且与此问题无关)。

通过此方法,我们可以将注意力转移到s.get(buffer, n)的{​​{1}}行为和指向至少std::istream s个字符n数组的指针。这样做的描述非常简单:它调用buffer。由于我们讨论的是s.get(buffer, n, s.widen('\n')),您可能没有更改std::istream,我们可以假设std::locale只返回s.widen('\n'),即调用等同于{{1}其中'\n'被称为分隔符,问题就变成了这个函数的作用。

好吧,这个函数最多可以提取s.get(buffer, n, '\n')个字符,当到达'\n'或者下一个字符与流中剩余的分隔符相同时停止(你使用了{{ 1}}如果你想要提取分隔符)。任何提取的字符都存储在m = 0 < n? n - 1: 0的相应位置,如果m,则将空字符存储到位置std::istream::getline()中。如果没有提取字符,则设置buffer

好吧,有了这个,我们应该把所有成分都放到谜语中:当你输入至少一个但少于5个字符时,对0 < n的第一次调用成功,并将换行符留在下一个字符中缓冲。下一次buffer[n - 1]个字符的尝试立即找到了分隔符,没有存储任何字符,并通过设置std::ios_base::failbit表示失败。很容易验证这个理论:

get()

如果您未输入任何字符,则对get()的第一次调用将失败。如果输入1到4个字符,则第一个调用成功,但第二个调用失败。如果您输入的字符数超过4个,则第二个调用也会成功,等等。有几种方法可以处理可能卡住的换行符:

  1. 只需使用与std::ios_base::failbit行为相同的#include <iostream> int main() { char buffer[5]; for (int count(0); std::cin; ++count) { if (std::cin.get(buffer, 5)) { std::cout << "get[" << count << "]='" << buffer << "'\n"; } else { std::cout << "get[" << count << "] failed\n"; } } } ,但如果这就是它停止阅读的原因,也会提取分隔符。这可能会将一行切成多个读取,但这可能是也可能不是。
  2. 为避免限制固定行长,您可以将std::cin.get()std::istream::getline()一起使用(即std::istream::get())。
  3. 成功std::getline()后,您可以在必要时使用std::stringstd::getline(std::cin, string)检查下一个字符是否为换行符。
  4. 这些方法中的哪一种符合您的需求取决于您要实现的目标。