24

我们知道,stdin默认情况下,这是一个缓冲输入;证明是使用任何“保留数据”的机制stdin,例如scanf()

int main()
{
    char c[10] = {'\0'};
    scanf("%9s", c);
    printf("%s, and left is: %d\n", c, getchar());
    return 0;
}

./a.out
你好
你好,左边是10

10当然是换行...

我一直很好奇,有没有什么办法可以“偷看”stdin缓冲区而不删除那里可能存在的任何东西?

编辑
一个更好的例子可能是:

scanf("%9[^.]", c);

输入“at.ct”,现在我ct\n留下了“数据”()stdin,而不仅仅是换行符。

4

3 回答 3

13

可移植地,您可以使用 获取输入流中的下一个字符,getchar()然后使用 将其推回ungetc(),这会产生一种状态,就好像该字符没有从流中删除一样。

ungetc函数将c(转换为unsigned char)指定的字符推回流指向的输入流。被推回的字符将由该流上的后续读取以与推入相反的顺序返回。

标准只保证一个回退字符,但通常可以回退更多。

正如其他答案中提到的那样。那里的评论,在实践中,如果你为自己的缓冲区提供 ,你几乎可以肯定地偷看缓冲区setvbuf,尽管这并非没有问题:

如果buf不是空指针,则可以使用它指向的数组而不是setvbuf函数分配的缓冲区

这留下了提供的缓冲区可能根本不被使用的可能性。

数组的内容在任何时候都是不确定的。

这意味着您无法保证缓冲区的内容反映实际输入(如果我们很挑剔,如果它具有自动存储持续时间,它会使用缓冲区未定义的行为)。

然而,在实践中,主要问题将是找出缓冲输入中尚未使用的部分在缓冲区中的何处开始以及在何处结束。

于 2013-01-21T17:20:45.067 回答
4

您可以在标准输入上设置自己的缓冲区setvbuf,并随时查看。

于 2012-12-21T16:36:15.063 回答
4

如果您想查看stdin缓冲区而不更改它,您可以告诉它使用另一个缓冲区setbuf,使用您可以访问的数组:

char buffer[BUFSIZ];

if (setbuf(stdin, buffer) != 0)
  // error

getchar();

printf("%15s\n", buffer);

这让你看到的不仅仅是ungetc,但我认为你不能以便携的方式走得更远。

实际上这是合法的,但对于标准来说是不正确的,引用它关于setvbuf(setbuf具有相同的行为):

数组的内容在任何时候都是不确定的。

因此,如果您正在寻找完全的可移植性和标准合规性,这不是您所需要的,但我无法想象为什么缓冲区不应该包含预期的内容。但是,它似乎可以在我的计算机上运行。

请注意,您必须向 提供一个至少包含BUFSIZ字符的数组setbuf,并且您不能对它之前的流进行任何 I/O 操作。如果您需要更大的灵活性,请查看setvbuf.

于 2012-12-21T17:26:48.447 回答