目录
问题
我们先来看道题目

这道题其实并不难,但是如果我们使用下面这段代码就会出现一个问题
#include <stdio.h>
int main()
{
int n, a[10] = { 0 }, m;
char c;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
while ((c = getchar()) != '\n')
{
if (c >= '0' && c <= '9')
{
m = c - 48;
a[m]++;
}
}
}
for (int i = 0; i < 10; i++)
{
if (a[i] > 0)
printf("%d:%d\n", i, a[i]);
}
return 0;
}
那就是明明我们让n=3,但是在接下来输入数据时只能输入两个,然后回车就输出结果了,但这并不是我们想要的结果,可是按逻辑而言上面代码没啥问题,说明这个bug可能比较隐蔽、比较底层

这是因为 scanf 读取完n后,输入缓冲区中会留下换行符(\n,ASCII 码值为 10 ),导致后续 getchar 直接读取到了这个残留的换行符。
以下详细分析并给出解决办法:
1. 问题根源:输入缓冲区残留
- 当执行
scanf("%d", &n);时,假设你输入n的值(比如3)后按了 回车键,此时输入的内容是3\n(3是给n的数据,\n是回车键产生的换行符)。 scanf只会读取%d匹配的整数部分(即3),但 换行符\n会残留在输入缓冲区 中。- 进入
for循环的第一次迭代后,执行while ((c = getchar()) != '\n'),此时getchar会直接从缓冲区中读取到残留的\n(ASCII 码对应10),所以c一开始就被赋值为10。
2. 解决方法:清空缓冲区残留
在 scanf 读取 n 之后、for 循环之前,手动清空输入缓冲区,避免残留的 \n 干扰后续 getchar。常用两种方式:
方式 1:用 getchar 吃掉换行符
在 scanf("%d", &n); 后加一行:
// 吃掉 scanf 残留的换行符
getchar();
这样会单独读取并丢弃缓冲区中残留的 \n,后续 getchar 就能正常等待用户输入了。
方式 2:用循环批量清空(更彻底)
如果担心缓冲区残留多个字符(比如用户输入 abc 这类非数字内容导致 scanf 失败,缓冲区残留更多垃圾),可以用循环清空:
int ch;
// 持续读取并丢弃字符,直到遇到换行或文件结束
while ((ch = getchar()) != '\n' && ch != EOF);
这种方式会把缓冲区中 \n 之前的所有残留字符都清空,更适合复杂输入场景。
3. 完整修正
#include <stdio.h>
int main() {
int n, m;
// 假设 a 是统计数字的数组,这里简单定义长度
int a[10] = {0};
char c;
// 读取 n
scanf("%d", &n);
// 关键:清空缓冲区残留的换行符
getchar();
for (int i = 0; i < n; i++) {
// 读取一行中的字符,直到遇到换行
while ((c = getchar()) != '\n') {
if (c >= '0' && c <= '9') {
m = c - '0';
a[m]++;
}
}
}
// 输出统计结果(示例)
for (int i = 0; i < 10; i++) {
printf("数字 %d 出现 %d 次\n", i, a[i]);
}
return 0;
}
4. 总结
- 问题核心是
scanf不会自动清理缓冲区的换行符,导致getchar误读残留内容。 - 解决关键是在
scanf后手动清空缓冲区,用getchar()或循环都能实现,根据场景选其一即可。 - 修正后,
getchar就会正常等待用户输入,而非直接读取残留的\n了。

145

被折叠的 条评论
为什么被折叠?



