scanf在读取输入数据后是否清空缓冲区?(使用C语言)

3
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char buf[1024];
    int a,b;
    int i;
    
    setbuf(stdin, buf);
    scanf("%d %d", &a, &b);
    
    for(i=0; buf[i]!='\n'; i++){
        putchar(buf[i]);  
    }
    
    putchar('\n');

    return 0;
}

当我输入值1 2时,我使用了setbuf来确定在读取值后缓冲区是否真的被清除。 然而,当我打印出buf时,输入的值仍保持不变。也就是说,输出结果是1 2
为什么会发生这种情况?如果您能回答,我将不胜感激。

3
“清零”状态会是什么样子? - Eugene Sh.
3
分配 char buf[1024] 是不正确的。应该使用 char buf[BUFSIZ] - Steve Summit
3
标题中问题的答案是“不”。stdin缓冲区在读取时不会被清除。stdio函数通常维护一个指针指向缓冲区,跟踪下一个要读取的字符的位置。只有当缓冲区中的所有字符都被使用完后,才会读入另一批输入数据到缓冲区,覆盖先前存在的内容。(我描述的是“典型”实现,但再次强调,几乎没有任何保证。) - Steve Summit
1
@SteveSummit: char buf[BUFSIZ]; 也不正确。应该是 static char buf[BUFSIZ];,因为缓冲区的生命周期必须至少与流的生命周期一样长。请参见 ISO C11 标准的 脚注 273cppreference.com 上的文档 也指出了这一点。 - Andreas Wenzel
1
@DanielWalker 不,但如果你想的话,随意。 - Steve Summit
显示剩余3条评论
2个回答

3

这里是C标准中对于函数setbuf的说明:

7.21.5.5 The setbuf function

Synopsis

#include <stdio.h>
void setbuf(FILE * restrict stream,
            char * restrict buf);

Description

Except that it returns no value, the setbuf function is equivalent to the setvbuf function invoked with the values _IOFBF for mode and BUFSIZ for size, or (if buf is a null pointer), with the value _IONBF for mode.

Returns
The setbuf function returns no value.

7.21.5.6 The setvbuf function

Synopsis

#include <stdio.h>
int setvbuf(FILE * restrict stream,
            char * restrict buf,
            int mode, size_t size);

Description

The setvbuf function may be used only after the stream pointed to by stream has been associated with an open file and before any other operation (other than an unsuccessful call to setvbuf) is performed on the stream. The argument mode determines how stream will be buffered, as follows: _IOFBF causes input/output to be fully buffered; _IOLBF causes input/output to be line buffered; _IONBF causes input/output to be unbuffered. If buf is not a null pointer, the array it points to may be used instead of a buffer allocated by the setvbuf function277) and the argument size specifies the size of the array; otherwise, size may determine the size of a buffer allocated by the setvbuf function. The contents of the array at any time are indeterminate.

Returns

The setvbuf function returns zero on success, or nonzero if an invalid value is given for mode or if the request cannot be honored.


277) 缓冲区的生命周期必须至少与打开的流一样长,因此在自动存储期缓冲区在块退出时被释放之前应关闭流。

由此得出结论:

  • 您代码中的数组buf应具有BUFSIZ长度,这可能不同于1024
  • 这个数组不应该有自动存储类,因为stdin在函数main返回之前没有关闭。它应该定义为static char buf[BUFSIZ];
  • 缓冲区可以或者不可以被流处理函数使用。
  • 在任何时候,数组的内容都是不确定的,因此不能对缓冲区内容做出任何预期:您观察到用户输入存在,但这并不保证。大多数实现在FILE结构中具有指针或偏移量,以跟踪缓冲区的使用和可用部分。
  • 流处理函数很可能不会在读取字节后清除缓冲区内容,因为在回溯到先前内容的情况下需要从文件重新加载缓冲区,但是这也不能保证。

setbuf是一种具有有限用途的旧函数,setvbuf是选择缓冲模式和缓冲区大小的首选方法,在极少数情况下可能会有用。


2
整理评论中的内容,不能保证libc实现会清除stdin缓冲区。FILE结构体可能只是在缓冲区内保留一个指针,指向当前位置。
另外,需要将缓冲区大小更改为BUFSIZ,并使其生命周期延续到程序的其余部分。根据C11标准:
“缓冲区的生命周期必须至少与打开的流一样长,因此在自动存储期间具有缓冲区的流应该在块退出时关闭。”
可以通过将缓冲区声明为全局变量或使用static关键字来实现这一点。
static char buf[BUFSIZ];

1
值得注意的是,如果使用setvbuf而不是setbuf,则缓冲区的大小也可以更改。 - Andreas Wenzel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接