2012-12-21 68 views
19

我们知道stdin默认情况下是一个缓冲输入;那证明是在任何的stdin说:“离开数据”机制的使用,如scanf()有没有办法查看stdin缓冲区?

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,而不仅仅是一个换行符。

+1

您可以在偷看后'ungetc()'。够好了? –

+0

@DanielFischer - 我想这不坏...如果还有一大堆字符呢?我可以知道stdin上的数据长度吗?或者我可以'ungetc()'多于一个字符? – Mike

+0

“一个字符的后退是有保证的,如果'ungetc'函数在同一个数据流上调用次数太多而没有对该数据流进行中间读取或文件定位操作,操作可能会失败。通常情况下,您可以“多个”取消选中,但只能保证一个。 –

回答

11

可移植的,你可以用getchar()得到输入流中的下一个字符,然后用ungetc()将它推回来,这样会产生一个状态,就好像字符没有从流中移除一样。

ungetc功能推动通过c(转换为unsigned char)指定的字符返回到输入流由流指向。后续读取的字符将按照推送的相反顺序返回。

只有一个字符的回推是由标准保证的,但通常你可以推回更多。

正如其他答案中所提到的,还有的意见,在实践中,你几乎可以肯定在缓冲区偷看,如果你提供setvbuf您自己的缓冲区,尽管这并非没有问题:

如果buf是不是一个空指针,它指向数组可能会被用来代替setvbuf函数所分配的缓冲区

这会导致所提供的缓冲区根本无法使用。

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

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

但是,实际上主要的问题是要找出缓冲区中尚未消耗的部分在缓冲区中的哪个部分开始以及结束的地方。

+1

当输入缓冲区为空时,不会执行'getchar'直到有什么需要读取的地方为止? –

+0

确实如此。然而,我不知道用一种可移植的方法来检查缓冲区是否为空。 –

5

你可以在stdin上用setvbuf设置你自己的缓冲区,并随时随地偷看。

+0

这将如何与'ungetc'进行交互?我认为'ungetc'ed字符存储在其他一些变量。另外,你怎么知道缓冲区的哪一部分被读取,剩下什么? – Shahbaz

+0

'setvbuf()函数对stdout,stdin或stderr没有任何影响。“是我读过的。你有一个运作的例子吗? – Mike

+0

@Mike它似乎在Windows上工作。 'ungetc'按预期工作。不完全确定如何跟踪读取/离开位置。但是如果buff是新内线的话,那很容易。 – nullpotent

3

如果你想看看stdin缓冲而不改变它,你可以告诉它使用一个又一个缓冲带setbuf,使用数组,您可以访问:

char buffer[BUFSIZ]; 

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

getchar(); 

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

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

其实这是合法的,但不正确的标准,从它引述有关setvbufsetbuf具有相同的行为):

阵列的任何时候的内容是不确定的。

因此,如果您正在寻找完整的可移植性和标准遵从性,那么这不是您所需要的,但我无法想象为什么缓冲区不应包含预期内容。但是,它似乎在我的电脑上工作。

请注意,您必须提供至少BUFSIZ个字符的数组,以便setbuf,并且您不得对其之前的数据流执行任何I/O操作。如果您需要更多灵活性,请参阅setvbuf

相关问题