现在的位置: 首页 > 综合 > 正文

c语言scanf缓冲区问题

2019年09月30日 ⁄ 综合 ⁄ 共 1357字 ⁄ 字号 评论关闭

今天在递归调用scanf函数获取输入的字符时发现的这个问题,之前也遇到过,现提出来记录一下。

测试用例如下:

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

int main()
{
    int n = 5;
    char c[n];
    for(int i = 0; i < n; ++i) {
        scanf("%c", &c[i]);
    }

    printf("-----------\n");
    printf("%s", c);
    return 0;
}

在写这个程序之前,我们期望的是c[n]字符数组中能够存储 abcde, 于是我们依次输入a,回车,然后输入b,回车,然会输入c,在此时你就会发现程序打印出字符数组c中的内容,并且运行完毕,用gdb调试工具单步执行的话,你会发现,在输入a,回车之后,c[0]中值是a,然后++i, 继续执行scanf("%c", &c[i])语言,而在这时程序不会提示你再输入字符,此时你查看c[1]中的字符是'\n',也就是说,我们输入的回车符保存在了缓冲区,scanf函数会直接读取该值。

解决方案,在scanf语句之后加入fpurge(stdin)语句,如下所示:

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

int main()
{
    int n = 5;
    char c[n];
    for(int i = 0; i < n; ++i) {
        scanf("%c", &c[i]);
        fpurge(stdin);
    }

    printf("-----------\n");
    printf("%s", c);
    return 0;
}

查看man fpurge的文档说明如下:

int fpurge(FILE *stream);

The function fpurge() erases any input or output buffered in the given stream. For output streams this discards any unwritten output. For input
streams this discards any input read from the underlying object but 
not yet obtained via getc(3); this includes any text pushed back via ungetc(3).

也就是说,fpurge函数会直接删除当前缓冲区中的内容。

有同学可能会想使用fflush函数,这样是不行的,fflush的函数说明如下:

int fflush(FILE *stream);

The function fflush() forces a write of all buffered data for the given output or update stream via the stream's underlying write function. The open status of the stream is unaffected.

If the stream argument is NULL, fflush() flushes all open output streams.

从上面的说明可以看出,fflush是强制把缓冲区中数据输出到给定输出,在上面的例子中,在scanf函数之后调用fflush函数没有任何作用,因为此时还没有为后面的'\n'字符指定一个输出。


我的微博:http://weibo.com/caryaliu

抱歉!评论已关闭.