C输入输出缓存
创始人
2024-06-01 20:10:57
0

探究printf的现象

我们分别在windows系统和linux系统上使用代码做以下操作:
输出"HelloWorld"十次,每次输出后暂停500毫秒。

windows系统上的代码

#include 
#include 
int main()
{for (int i = 0; i < 10; i++) {printf("Hello World %d\n", i);Sleep(500);}return 0;
}

使用windows.h头文件中提供的Sleep函数,每次输出后休眠500毫秒。

表现

windows系统上打印出一个HelloWorld后,休眠500毫秒,再打印下一个。

linux系统上的代码

#include 
#include 
int main()
{for (int i = 0; i < 10; i++) {printf("Hello World %d\n", i);usleep(1000*500);}return 0;
}

在linux系统上,我们使用unistd.h头文件中提供的usleep函数,每次输出后休眠500毫秒。usleep的单位为1微秒,1000微秒为1毫秒。代码中给usleep传入1000 * 500,表示500毫秒。

表现

linux系统上,休眠5000毫秒,打印出所有HelloWorld

输入输出缓存区

输出缓存区

在向控制台打印字符时,程序会先将需要打印的字符串放在输出缓存区中,到特定时刻,再一起显示到控制台。
在计算机中,需要将显示在屏幕上的数据发送至显卡,再由显卡进行显示。显然,累积一串字符再批量处理发送,比起单个单个发送更有效率。

何时刷新输出缓存

我们将缓存中的数据发送至目的地并清空缓存,这一行为称之为刷新缓存

  • 在windows系统下,使用printf后,数据被写入到输出缓存区。随后,立即刷新缓存区。
  • 在linux系统下,使用printf后,数据被写入到输出缓存区。后续的printf会在缓存区中累积数据。直到程序结束才刷新缓存区。

行(háng)缓存的刷新时机

输入输出缓存属于行缓存,即一行结束后必须刷新缓存。
还有一种缓存形式为完全缓存,这种缓存的形式需要等到整个缓存区被填满,才会刷新缓存。
对于行缓存,如果要刷新缓存,只要将一行结束即可。也就是\n
在windows系统中似乎不那么在乎一行字符是否结束。但是在linux下却严格遵循一行字符结束才刷新缓存。

注意

输出缓存是一个系统特性,而不是函数特性。所有输出函数,包括printf,putchar等,均存在输出缓存。

输入缓存区

类似于输出函数(如printf,putchar)存在输出缓存,输入函数(如scanf,getchar)也存在输入缓存。
并且这些输入函数属于阻塞函数,当输入缓存区没有内容时。程序将阻塞在输入函数中,等待用户从键盘键入字符,并按回车确认。
当我们按下了回车键(即换行,存储为\n),输入的字符串将进入输入缓存区
接下来,输入函数将从输入缓存区获取字符,删除缓存区中已获取的字符,并解除阻塞状态继续执行代码。

输入缓存区仍有数据getchar不阻塞

使用getchar读取输入字符串

#include 
int main()
{char str[20];int i = 0;while (i < 19) {char c = getchar();str[i++] = c;if (c == '\n') {break;}}str[i] = '\0';printf(str);printf("\n--------------\n");scanf("%s", str);printf(str);return 0;
}

输出结果

HelloWorldHelloWorld
HelloWorldHelloWorl
--------------
d

超过19个字符后,循环将退出且还剩"d\n"两个字符未读取。
此时,由于输入缓存区内仍有数据,我们将观察到scanf不进入阻塞状态,直接从缓存区中读取数据到str中。先将’d’放到字符数组str中,其后遇到了’\n’,scanf认为一行结束了,便将’\0’附到字符数组中的’d’后。最后,str被printf打印在控制台上,内容为"d"。

不带缓存的输入函数

不带缓存的输入函数,只要按下键盘,程序就立即能获取到输入的字符。

getchgetche需要包含头文件conio.h才可以被使用

conio.h不是一个标准头文件,在windows下默认可以使用。近些年,为了区别平台实现函数与C语言标准函数。平台实现函数前会加上下划线。getch,getche这些平台实现函数,被更名为_getch_getche

getch函数

getch函数相当于无缓存的getchar
程序运行到getch时函数将进入阻塞状态,并等待键盘直接输入一个字符,按下一个键后(不需要回车送入输入缓存区),getch函数立刻就能收到对应的字符

getche函数

getche函数相当于无缓存有回显的getchar
getche函数与getch函数类似,不过它会自己将输入的字符打印在控制台上。

无缓存函数直接从键盘输入

#include 
#include 
int main()
{char c = getchar();putchar(c);c = _getch();putchar(c);c = getchar();putchar(c);return 0;
}

运行结果

123
1A2

过程如下

第一个getchar将进入阻塞状态,等待用户输入并按下回车,将数据送到缓存区。
我们输入了字符串"123\n",第一个getchar将获取字符’1’,现在缓存区中的数据为"23\n"。
第一个getchar解除阻塞状态。随后’1’被putchar打印到控制台。
程序运行至getch,虽然输入缓存区中仍有数据,但是getch函数将阻塞等待键盘直接输入一个字符。
输入’A’后,getch解除阻塞状态。‘A’被putchar打印到控制台。
第二个getchar将不进入阻塞状态,读取缓存区中的字符’2’。随后putchar将打印’2’到控制台。

相关内容

热门资讯

求经典台词和经典旁白 求经典台词和经典旁白谁有霹雳布袋戏里的经典对白和经典旁白啊?朋友,你尝过失去的滋味吗? 很多人在即将...
小王子第二章主要内容概括 小王子第二章主要内容概括小王子第二章主要内容概括小王子第二章主要内容概括
爱情睡醒了第15集里刘小贝和项... 爱情睡醒了第15集里刘小贝和项天骐跳舞时唱的那首歌是什么谢谢开始找舞伴的时候是林俊杰的《背对背拥抱》...
世界是什么?世界是什么概念?可... 世界是什么?世界是什么概念?可以干什么?物质的和意识的 除了我们生活的地方 比方说山 河 公路 ...
全职猎人中小杰和奇牙拿一集被抓 全职猎人中小杰和奇牙拿一集被抓动画片是第五十九集,五十八集被发现,五十九被带回基地,六十逃走
“不周山”意思是什么 “不周山”意思是什么快快快快......一座山,神话里被共工撞倒了。
《揭秘》一元一分15张跑得快群... 一元一分麻将群加群主微【ab120590】【tj525555】 【mj120590】等风也等你。喜欢...
玩家必看手机正规红中麻将群@2... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
始作俑者15张跑的快群@24小... 微信一元麻将群群主微【ab120590】 【tj525555】【mj120590】一元一分群内结算,...
《重大通知》24小时一元红中麻... 加V【ab120590】【tj525555】【mj120590】红中癞子、跑得快,等等,加不上微信就...
盘点一下正规一块红中麻将群@2... 一元一分麻将群加群主微:微【ab120590】 【mj120590】【tj525555】喜欢手机上打...
(免押金)上下分一元一分麻将群... 微【ab120590】 【mj120590】【tj525555】专业麻将群三年房费全网最低,APP苹...
[解读]正规红中麻将跑的快@群... 微信一元麻将群群主微【ab120590】 【tj525555】【mj120590】一元一分群内结算,...
《普及一下》全天24小时红中... 微【ab120590】 【mj120590】【tj525555】专业麻将群三年房费全网最低,APP苹...
优酷视频一元一分正规红中麻将... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
《火爆》加入附近红中麻将群@(... 群主微【ab120590】 【mj120590】【tj525555】免带押进群,群内跑包包赔支持验证...
《字节跳动》哪里有一元一分红中... 1.进群方式-[ab120590]或者《mj120590》【tj525555】--QQ(QQ4434...
全网普及红中癞子麻将群@202... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
「独家解读」一元一分麻将群哪里... 1.进群方式《ab120590》或者《mj120590》《tj525555》--QQ(4434063...
通知24小时不熄火跑的快群@2... 1.进群方式《ab120590》或者《mj120590》《tj525555》--QQ(4434063...