带你理解输入输出缓存区(超详解)

缓冲区是内存中用于暂存输入输出数据的部分,分为输入缓冲区和输出缓冲区。完全缓冲在数据填满后才刷新,无缓冲则不缓存直接操作,行缓冲在遇到换行时刷新。printf和scanf等函数涉及到行缓冲,scanf会吃掉回车。_getch函数则是不带缓冲的输入函数,直接读取键盘输入。
摘要由CSDN通过智能技术生成

带你理解输入输出缓冲区(超详解)

1.缓冲区的意义

缓冲区(Buffer)是内存空间的一部分。也就是说,在内存中预留了一定的存储空间,用来暂时保存输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区输出缓冲区。

举个例子,相信大家在洗衣服的时候往往不会有了一件旧衣服就马上拿去洗衣机洗了,而等多几件了之后一起洗,这还可以避免水电资源浪费。同理,计算机的缓存区也是运用了同样的思想。
简而言之,缓存区就是一块内存,用来做数据的临时存放点,在输入输出操作者起至关重要的作用

2.缓冲的分类

1.完全缓冲

就是等整个缓存区被填满,才会被刷新缓存。最典型的例子就是磁盘的文件,文件用标准IO打开,默认都是全缓存。当缓存区填满或进行flush操作时才进行磁盘操作。

比如内存中有一段存储区域,比如有64个字节大小,有一个程序会从这段存储区域中读取数据。系统把一个文件内容放入这个区域,只要64个字节都放满了,那么程序会立即来读取这64个字节的数据。只要64个字节没有放满,哪怕只放了63个字节,程序都不会来读取,这就是完全缓冲的意思。

2.无缓冲

不对输入输出操作进行缓存,对流的读写可以立即操作实际文件。标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来.

3.行缓冲

即当一行结束的时候便开始刷新缓存.想要刷新行缓存,只要使用换行符’\n’便成功,即回车键(enter),其中我们最常见的也就是输入输出缓冲(printf,scanf)就是行缓冲.(这也是我们今天的重点!!!)

补充:如果我们没有自己设置缓冲区的话,系统会默认为标准输入输出设置一个缓冲区,这个缓冲区的大小通常是 512个字节 的大小。缓冲区大小由 stdio.h 头文件中的宏 BUFSIZ 定义
在这里插入图片描述

接下来我们着重讲一下我们最常接触到的输入输出缓冲(行缓冲)

3.1输出缓冲区

在C语言中很多输出函数(如printf, putchar)便存在输出缓存. 在window系统下,使用printf()函数后,数据被写入到输出缓冲区,随后立即刷新缓冲区,所有我们在使用printf()函数时往往会很快就在控制台打印出来了(Linux操作系统略有不同,在此我们便不做演示)

3.2输入缓冲区

类似于输出函数,输入函数(scanf,getchar)也存在输入缓存,并且这些输入函数属于阻塞函数,当缓存区没有内容时,程序将阻塞在输入函数中,等待用户从键盘输入内容,并按下回车键(即换行’\n’)确认,之后,输入的字符将进入输入缓存区,输入函数便从缓存区获取字符,并且删除缓冲区中已经获得的字符,并解除阻塞状态继续执行代码

下面举例一个十分经典的C语言代码来展示输入缓存的存在

#include<stdio.h>
int main()
{
	char str[10];
	int i;
	for(i=0;i<10;i++)
		scanf("%c",&str[i]);        
	for(i=0;i<10;i++)
		printf("%c",str[i]);
	return 0;
}

上面这个程序,获取10个字符,然后打印出来,如果我们正常的输入10个字符,打印正常
在这里插入图片描述
但是如下程序,如果我们输入a,然后回车,再输入b,再回车… 结果只能输入5个字符便打印了出来程序结束,这其实就是所谓的scanf() 吃掉回车
在这里插入图片描述
分析:首先这个程序运行到第1次循环的scanf的时候,此时缓冲区为空,即发生阻塞现象,我们输入a,之后按回车,此时缓存区其实是两个字符,‘a’和’\n’,然后此时的scanf拿到了字符a,第一次循环结束(注意此时缓存区还剩一个’\n’). 开始第2次循环. 但是scanf发现缓冲区有’\n’,便不会发生阻塞,此时scanf读取这个’\n’. 然后又开始第三次循环,此时缓冲区是空的,便又发生阻塞,所以又等待键盘输入,我们输入b,再次按下回车,此时缓存区又是两个字符,‘b’和’\n’,接下来重复上面过程.综上,相当于这个循环十次的for循环在第偶数次得到的都是’\n’,这也是为什么后面打印的时候这abcde是竖着打印出来的

3.不带缓冲的输入函数

前面介绍了带缓存的输入函数,只有当按下了回车键之后,输入的字符串才能进入缓存区,等待程序读取。接下来介绍一个不带缓存的输入函数( _getch ),只要按下键盘,程序立即获得输入的字符串。_getch直接从键盘获取键值,不等待用户按回车,只要用户按一个键,_getch就立刻结束输入了,换言之,不需要将输入的字符保存在缓存区,也就是说,输入一个字符,它马上读取

#include<stdio.h>
#include<conio.h>
int main()
{
	while (1)
	{
		char c;
		c = _getch();   //输入后用putchar打印
		putchar(c);
		if ('q' == c)
			break;
	}
	return 0;
}

输入“abcq”,程序立即显示‘abcq’并退出,如下
在这里插入图片描述
这是因为_getch相当于无缓存的getchar(或者单个读取的sancf函数),程序运行到_getch函数将进入阻塞状态,并等待键盘直接输入一个字符,按下一个键后(不需要回车送入输入缓存区),getch函数就立刻能收到对应的字符(但是不会显示在控制台上),随后通过putchar打印在控制台。简而言之,这是一个不带回显的函数,即控制台abcq完全是putchar的功能,_getchar是不会显示内容的(不带回显),所以这个函数可以应用在密码中

接下来对比如果换成scanf控制台结果.

#include<stdio.h>
#include<conio.h>
int main()
{
	while (1)
	{
		char c;
		scanf("%c",&c);   //输入后用putchar打印
		putchar(c);
		if ('q' == c)
			break;
	}
	return 0;
}

打印出的结果为:
在这里插入图片描述

此时有两排,因为scanf是带回显的,第一排是键盘输入,第二排才是打印的。
相当于上面_getch打印出来的abcq是没有第一排的,只有第二排。

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kklovecode

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值