1

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

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 中。但是,由于您按下回车,调用 get() 时不会将换行符放入流中,因此程序将终止并且不会再要求您输入 5 个字符。

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

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

4

1 回答 1

5

首先,除了\n在输入序列中输入换行符(在控制台上输入数据时,数据通常由控制台进行行缓冲,并且仅在按 Enter 时转发给程序(通常可以关闭此功能,但其详细信息是特定于平台的,无论如何与此问题无关)。

With this out of the way lets turn our attention to the behavior of s.get(buffer, n) for an std::istream s and a pointer to an array of at least n characters buffer. The description of what this does is quite trivial: it calls s.get(buffer, n, s.widen('\n')). Since we are talking about std::istream and you probably haven't changed the std::locale we can assume that s.widen('\n') just returns '\n', i.e., the call is equivalent to s.get(buffer, n, '\n') where '\n' is called a delimiter and the question becomes what this function does.

Well, this function extracts up to m = 0 < n? n - 1: 0 characters, stopping when either m is reached or when the next character is identical to the delimiter which is left in the stream (you'd used std::istream::getline() if you'd wanted the delimiter to be extracted). Any extracted character is stored in the corresponding location of buffer and if 0 < n a null character is stored into location buffer[n - 1]. In case, if no character is extracted std::ios_base::failbit is set.

OK, with this we should have all ingredients to the riddle in place: When you entered at least one character but less than 5 characters the first call to get() succeeded and left the newline character as next character in the buffer. The next attempt to get() more characters immediately found the delimiter, stored no character, and indicated failure by setting std::ios_base::failbit. It is easy to verify this theory:

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

If you enter no character, the first call to std::cin.get() fails. If you enter 1 to 4 characters, the first call succeeds but the second one fails. If you enter more than 4 characters, the second call also succeeds, etc. There are several ways to deal with the potentially stuck newline character:

  1. Just use std::istream::getline() which behaves the same as std::istream::get() but also extracts the delimiter if this is why it stopped reading. This may chop one line into multiple reads, however, which may or may not be desired.
  2. To avoid the limitation of a fixed line length, you could use std::getline() together with an std::string (i.e., std::getline(std::cin, string)).
  3. After a successful get() you could check if the next character is a newline using std::istream::peek() and std::istream::ignore() it when necessary.

Which of these approaches meets your needs depends on what you are trying to achieve.

于 2012-08-28T19:35:30.407 回答