scanf()函数键盘缓冲区残余信息的问题!!!

本文探讨了C语言中键盘缓冲区残余信息导致的问题,包括如何解决scanf函数读取字符时遇到的换行符干扰,以及连续输入字符时出现的垃圾字符问题。
1,c-scanf键盘缓冲区残余信息问题

键盘缓冲区残余信息问题 

#include <stdio.h>
int main()
{
    int a;
    char c; 
    do
    {
        scanf("%d",&a);
        scanf("%c",&c);
        printf("a=%d     c=%c\n",a,c);
        /*printf("c=%d\n",c);*/
    }while(c!=''N'');

   scanf("%c",&c);这句不能正常接收字符,什么原因呢?我们用printf("c=%d\n",c);将C用int表示出来,启用printf("c=%d\n",c);这一句,看看scanf()函数赋给C到底是什么,结果是 c=10 ,ASCII值为10是什么?换行即\n.对了,我们每击打一下"Enter"键,向键盘缓冲区发去一个“回车”(\r),一个“换行"(\n),在这里\r被scanf()函数处理掉,而\n被scanf()函数“错误”地赋给了c. 
解决办法:可以在两个scanf()函数之后加个fflush(stdin);,还有加getch(); getchar();也可以,但是要视具体scanf()语句加那个,这里就不分析了,读者自己去摸索吧。但是加fflush(stdin);不管什么情况都可行。 

但是fflush(stdin)函数在linux下不可用!!!

方法一:可添加getchar()来吸收\n字符,这个比较简单。。

方法二:可在说明符前加上两个空格来跳过\n.



2,在C语言中,如果使用字符型变量(就是char型)时在有连续输入的情况下,很容易因为出现垃圾字符而导致程序的流程非法。
看下面,简单的一段代码:
#include "stdio.h" 
main()
{
char a,b;
printf("input a:");
scanf("%c",&a); /*或a=getchar();*/
printf("a=%c\n",a);
printf("input b:");
scanf("%c",&b); /*或b=getchar();*/
printf("b=%c\n",b); 
}
这段代码确实挺简单的,但是却隐藏着很难发现的问题。当在执行了printf("input a:");这句后要求我们做输入的时候,随便输入一个数,然后按回车,程序继续往下执行。没等我们做第二次输入的时候程序就已经结束了。把scanf()换成getchar()也一样存在问题。
为什么会有这样的问题呢?那是因为在我们做了第一次输入时,并按下回车,使程序继续执行。而那个回车也随之进入了流当中。而遇到第二个scanf()时,scanf()把回车当作是第二次输入的字符而接收。因此程序也就忽略了输入而继续执行了。这个回车就是在做输入时产生的垃圾字符了。我第一次遇到它时,是我在写循环时遇到的,由于垃圾字符的原因,使得循环提早结束,而破坏了我预期的流程(第一次见垃圾字符时郁闷死我了)。那怎么才能防止垃圾字符的破坏,或是避免它的呢?而我的解决方法只有两种.
第一种方法是多定义一个字符变量,如char c;这样。把变量c分别放到输入后面。如:
a=getchar();
c=getchar();
……
b=getchar();
c=getchar();
这样可以使垃圾字符自动进入变量c中,而不破坏我们正确的流程和输入。如果是scanf()的话,可以按照下面的方式来写:scanf(”%c%c”,&a,&c);这样的效果跟使用getchar()是一样的。
这样的方法无疑是浪费了一个内存空间,而且增加了很多的冗余代码。
第二种方法是使用getche()函数,而不使用scanf()和getchar()。这个函数也是接收字符的,但是它不等待回车的输入!而直接把字符送入流中,这样就可以避免垃圾字符的出现了。 



在 C 语言中,“清空缓冲区”通常指的是**清除输入流(如 `stdin`)中残留的字符**,比如换行符 `\n`、多余输入等。如果不及时清理,这些残留数据会影响后续的 `scanf`、`getchar` 等函数的行为。 --- ### 回答问题:如何清空输入缓冲区? C 标准库没有提供直接的 `fflush(stdin)` 来安全清空输入缓冲区(**注意:对 `stdin` 使用 `fflush` 是未定义行为**,仅某些编译器如 MSVC 支持),所以我们必须手动读取并丢弃缓冲区中的内容。 #### ✅ 正确方法:使用循环读取直到换行符或 EOF ```c #include <stdio.h> // 清空标准输入缓冲区 void flush_input_buffer() { int c; while ((c = getchar()) != '\n' && c != EOF); } ``` 这个函数会一直从输入流读取字符,直到遇到换行符 `\n` 或文件结束 `EOF`,从而清除所有残余输入。 --- ### 常见场景与示例代码 #### 场景1:`scanf` 后残留换行符影响 `getchar` ```c #include <stdio.h> void flush_input_buffer() { int c; while ((c = getchar()) != '\n' && c != EOF); } int main() { int num; char ch; printf("请输入一个整数: "); scanf("%d", &num); // 必须清空缓冲区,否则下面的 getchar 会立即返回 '\n' flush_input_buffer(); printf("请输入一个字符: "); ch = getchar(); printf("你输入的整数是: %d\n", num); printf("你输入的字符是: %c\n", ch); return 0; } ``` > ❌ 如果不调用 `flush_input_buffer()`,`getchar()` 会直接读取之前输入数字后留下的 `\n`,导致“跳过输入”。 --- #### 场景2:防止多次输入错误累积 ```c #include <stdio.h> int get_integer() { int num; while (1) { printf("请输入一个整数: "); if (scanf("%d", &num) == 1) { flush_input_buffer(); // 清除多余输入,例如用户输入了 "123abc" return num; } else { flush_input_buffer(); // 清除非法输入 printf("输入无效,请输入一个有效整数!\n"); } } } void flush_input_buffer() { int c; while ((c = getchar()) != '\n' && c != EOF); } ``` 这样即使用户输入 `"123abc"`,程序也能正确处理,只取 `123` 并清除后面的 `abc`。 --- ### 其他方式对比 | 方法 | 是否推荐 | 说明 | |------|----------|------| | `fflush(stdin)` | ❌ 不推荐(未定义行为) | 仅在部分编译器(如 MSVC)上可用,不可移植 | | `setbuf(stdin, NULL)` | ⚠️ 不解决当前问题 | 关闭缓冲,但不会清除已有内容 | | `fgets(buffer, size, stdin)` + 解析 | ✅ 推荐替代方案 | 更安全地读取整行输入 | | 循环 `getchar()` 直到 `\n` | ✅ 强烈推荐 | 标准、可移植、安全 | --- ### 高级建议:使用 `fgets` 替代 `scanf` 更安全的做法是使用 `fgets` 读取一整行,再用 `sscanf` 解析: ```c char line[100]; fgets(line, sizeof(line), stdin); sscanf(line, "%d", &num); // 安全解析 ``` 这种方式天然避免了缓冲区残留问题。 --- ### 总结解释 - **不能使用 `fflush(stdin)`** —— 对输入流调用 `fflush` 是未定义行为; - 应使用 `while((c = getchar()) != '\n' && c != EOF);` 手动清空; - 特别适用于 `scanf` 后接 `getchar` 或下一次输入前; - 最佳实践是改用 `fgets + sscanf` 组合,从根本上避免问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值