缓冲区(Buffer)又称为缓存(Cache)
缓冲区是内存空间的一部分。也就是说,计算机在内存中预留了一定的存储空间,用来暂时保存输入或输出的数据,这部分预留的空间就叫做缓冲区(缓存)。
缓冲区的优点:加快了程序的运行速度,减少了硬件的读写次数,让整个计算机变得流畅起来。
全缓冲
当缓冲区被填满时才刷新缓冲区。(通常出现在文件输入中)
行缓冲
在出现换行符是时刷新缓冲区。(键盘输入通常是行缓冲,在按下Enter键后才刷新缓冲区)
无缓冲
某些环境下,我们希望程序能够立即响应用户按键(玩游戏,输入处理越快越好)
如何控制输入与输出缓冲区
-
为什么使用scanf()函数时经常会发生一些莫名其妙的错误?原来这与缓冲区有关。
当遇到 scanf() 函数时,程序会先检查输入缓冲区中是否有数据:
1.如果没有,就等待用户输入。用户从键盘输入的每个字符都会暂时保存到缓冲区,直到按下回车键,产生换行符\n,输入结束,scanf() 再从缓冲区中读取数据,赋值给变量。
2.如果有数据,那就看是否符合控制字符串的规则:
1>如果能够匹配整个控制字符串,那最好了,直接从缓冲区中读取就可以了,就不用等待用户输入了。
2>如果缓冲区中剩余的所有数据只能匹配前半部分控制字符串,那就等待用户输入剩下的数据。
如果不符合,scanf() 还会尝试忽略一些空白符,例如空格、制表符、换行符等:
a.如果这种尝试成功(可以忽略一些空白符),那么再重复以上的匹配过程。
b.如果这种尝试失败(不能忽略空白符),那么只有一种结果,就是读取失败。 -
输入缓冲
scanf(),不管用户输入多少内容,只要不按下回车键,就不进行真正的读取。这是因为 scanf() 是带有行缓冲的,用户输入的内容会先放入缓冲区,直到用户按下回车键,产生换行符\n,才会刷新缓冲区,进行真正的读取。
getche()、getch() 就不带缓冲区,输入一个字符后立即就执行了,根本不用按下回车键。 -
清空输入缓冲区
- 使用 getchar() 清空缓冲区
while((c = getchar()) != '\n' && c != EOF);
getchar() 是带有缓冲区的,并且一切字符通吃,或者说一切字符都会读取,不会忽略。不过这种方案有个缺点,就是要额外定义一个变量 c,对于有强迫症的读者来说可能有点难受。 - 使用 scanf() 清空缓冲区
scanf("%*[^\n]"); scanf("%*c");scanf("%*[^\n]");
第一个 scanf() 将逐个读取缓冲区中\n之前的其它字符,% 后面的 * 表示将读取的这些字符丢弃,遇到\n字符时便停止读取。此时,缓冲区中尚有一个\n遗留,第二个 scanf() 再将这个\n读取并丢弃,这里的星号和第一个 scanf() 的星号作用相同。由于所有从键盘的输入都是以回车结束的,而回车会产生一个\n字符,所以将\n连同它之前的字符全部读取并丢弃之后,也就相当于清除了输入缓冲区。
看不懂scanf用法的人可以看我上一篇博客《C语言复习——输入输出》
-
输出缓冲
\n会使得缓冲区刷新,将缓冲区中的所有内容都输出到显示器上。 -
清空输出缓冲区
fflush() 是一个专门用来清空缓冲区的函数。但是通用性非常差,不建议使用。 -
缓冲区刷新的原则
a.不管是行缓冲还是全缓冲,缓冲区满时会自动刷新;
b.行缓冲遇到换行符\n时会刷新;
c.关闭文件时会刷新缓冲区;
程序关闭时一般也会刷新缓冲区。 -
消除缓冲区的负面影响
对于输出操作,清空缓冲区会使得缓冲区中的所有数据立即显示到屏幕上。很明显,这些数据没有地方存放了,只能输出了。
对于输入操作,清空缓冲区就是丢弃残留字符,让程序直接等待用户输入,避免引发奇怪的行为。