scanf缓冲区刷新问题

本文探讨了在Linux环境中使用scanf时遇到的缓冲区刷新问题。当输入字符或特殊键时,缓冲区可能不会清空,导致scanf无限读取。通过分析,发现当数据类型与格式符匹配时缓冲区会正常刷新,否则不会。解决方案包括使用while循环清空缓冲区和通过字符串格式读取字符来避免换行符问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在Linux终端写代码时,使用scanf输入一个字符,当不小心输入了一个退格键或者方向键时,程序就出现无限读取的现象,这显然是scanf的缓冲区内的字符无法刷新出去,即研究一下scanf缓冲区的刷新规则。

scanf缓冲区的刷新规则

当scanf从缓冲区读取走需要的数据之后,缓冲区应该会被清空,但在某些情况下,缓冲区并不会会清空,使用下面的代码检测一下什么情况下缓冲区不会被清空

输入数字

#include <stdio.h>

int main()
{
    int num = 0;
    while(1)
    {
    	scanf("%d", &num);
        printf("%d\n", num);
    }
    return 0;
}
[ahao@AHAOAHA test]$ ./test
1 #输入1
1 #输出1
^C
[ahao@AHAOAHA test]$ ./test
w #输入字符w
1
1
1
1
...#输出无数个1
^C
[ahao@AHAOAHA test]$ ./test
^H #输入退格键
0
0
0
0
... #输出无数个0
^C
[ahao@AHAOAHA test]$ ./test
123456787654367654323567654 #输入一个大于INT_MAX的数
-1 #输出-1
^C

通过该例,可以知道当scanf的格式符为"%d"时:

  • 输入整型数字:
    • 小于INT_MAX:缓冲区正常刷新
    • 大于INT_MAX:缓冲区正常刷新,但读取到的数据为-1
  • 输入字符:缓冲区不会刷新,则输入的字符会一直保存在缓冲区中,造成scanf不再阻塞等待输入
  • 输入退格键等:缓冲区不进行刷新,造成scanf不再阻塞等待输入

输入字符

#include <stdio.h>

int main()
{
    char ch;
    while(1)
    {
        scanf("%c", &ch);
        printf("%c\n", ch);
    }
    return 0;
}
[ahao@AHAOAHA test]$ ./test
w #输入字符
w
  #换行
  #换行
^C
[ahao@AHAOAHA test]$ ./test
  #仅输入回车键
  #换行
  #换行
^C
[ahao@AHAOAHA test]$ ./test
1 #输入数字
1
  #换行
  #换行
^C
[ahao@AHAOAHA test]$ ./test
^H #输入退格键
   #换行
   #换行
^C

则当scanf的格式符为"%c"时:

  • 输入一个字符:当从键盘输入一个字符时,需要按下回车键表明输入结束,但此时的回车键也会被写入进scanf的缓冲区内,并在下一个scanf是被读出。
  • 输入退格键等:依然会被像字符一样对待。
  • 输入数字:依然会被像字符一样对待。

经过测试,scanf在读取数据时:

  • 当数据的类型与格式符的类型相符时,scanf会读取数据,并将已经读取到的字符从缓冲区中清除
  • 当数据的类型与格式符不符时,scanf不会读取该数据,也不会将该数据从缓冲区中清除,这就容易造成scanf不阻塞等待用户输入的现象

清空输入缓冲区的方法

使用while((ChBuf = getchar()) != ‘\n’ && ChBuff != EOF)将缓冲区内的数据全部读出,当读到’\n’或EOF时退出

#include <stdio.h>

int main()
{
    char ChBuf = '\0';
    char ch;
    while(1)
    {
        scanf("%c", &ch);
        printf("%c\n", ch);
        
        //清空输出缓冲区
        while((ChBuf = getchar()) != '\n' && ChBuf != EOF);
    }
    return 0;
}

解决输入字符时连带读取换行符的方法

在读取字符的时候,使用字符串格式读取,将缓冲区的所有内容刷新到一个数组中,再将数组的第一个字符赋给目标字符

  • 缺点:
    • 如果想要连续读取字符,则字符与字符之间必须使用空格隔开
    • 无法读取换行符
#include <stdio.h>

int main()
{
    char ch;
    char buf[12];
    scanf("%s", buf);
    ch = buf[0];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值