嫌弃前文内容多:请直接看总结!
一,问题提出
情形一:
1,代码:利用数组循环输入 10 个数字,输出打印 10 个数字
#include <stdio.h>
int main( )
{
int i;
int c[10];
for(i=0;i<10;i++){
//c[i] = getchar();
// fflush(stdin);
scanf("%d", &c[i]);
}
for(i=0;i<10;i++){
printf("%d", c[i]);
}
return 0;
}
2,运行结果:结果显示正确
情形二:
1,代码:利用字符数组循环输入 10 个字符,输出打印 10 个字符
#include <stdio.h>
int main( )
{
int i;
//int c[10];
char c[10];
printf("输入:\n");
for(i=0;i<10;i++){
//c[i] = getchar();
// fflush(stdin);
// scanf("%d", &c[i]);
scanf("%c", &c[i]);
}
printf("\n输出:\n");
for(i=0;i<10;i++){
printf("%c", c[i]);
}
return 0;
}
2,运行结果:结果显示错误
二者情形对比结果分析:
情形一的结果是符合预期的,即输入 10 个数字,然后打印 10 个数字;
情形二的结果是不符合的,即输入 5 个字符后,就直接输出,后续的第 6 个字符,第 7 个字符无法输入。
情形二的解决办法:
1,代码:在 scanf() 函数后面增加一行代码 fflush(stdin),即
scanf("%c", &c[i]);
fflush(stdin);
2,结果:此时可以发现可以得到正确结果
问题提出:
这里就提出一个问题,为什么情形一不需要加 fflush 就可以正确运行,而情形二却需要添加这一行代码。
答案就是:缓冲区的概念。
二,问题解决
1,首先理解缓冲区概念:
定义: 缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。
类型: 缓冲区分为三种:
- 全缓冲:例如文件读写,即缓冲区满了才写入文件
- 行缓冲:例如本题的 scanf 标准输入输出操作,当按下 Enter 时候就输出
- 不缓冲:这里 stderr 出错信息,直接输出。
2,本题解释:
本题情形二中,
第一次输入: 当输入一个字符,比如 ’a’,
缓存情况:只有一个字符 ‘a’
a |
第二次输入: 要想进行输入 ‘b’ ,由于是行缓存的类型,所以必须按下 Enter 键才可以进行下一次输入 ’b’,
按下 ‘Enter’ 缓存情况:字符 ’a’ 出缓存,Enter 继续保留在缓存中
\n |
第三次输入: 这时才轮到输入 ‘b’,
缓存情况:这时有上一次缓冲区保留的 Enter,还有本次输入的 ‘b’
\n b |
此时要想输入 ‘c’,也就回到了第二次的输入情况
总结
情形二的数组元素的输入情况是:
地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
内容 | a | \n | b | \n | c | \n | d | \n | e | \n |
而用了flush之后就直接清理了了缓存, \n 被清除。注意是这里是清除,而不是输出。二者的区别在于清除指的是: \n 消失了,输出指的是:\n 被输出到数组中去。用了 flush 之后便有了正确的情况:
地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
内容 | a | b | c | d | e |
补充:
如果你要想知道为什么情形一是正确的,那么可以告诉你的是,因为情形一是数字数组,不会读取 \n 字符。