目录
一、缓冲区
C/C++语言,会针对标准输出,给我们提供默认的缓冲区,这里主要讲输出缓冲区,那么它在哪里呢?
在C语言中,输出缓冲区通常与标准I/O流(如stdout、stderr等)相关联。这些流在C标准库中通过FILE结构体来表示,而FILE结构体内部封装了文件描述符和缓冲区等信息。因此,当使用printf()等函数进行输出时,实际上是将数据写入到了与stdout流相关联的缓冲区中。
那么需要怎么证明呢?
当我们没有使用fflush刷新缓冲区时,printf()函数早已运行了,但是数据却没有立马显示出来,而是暂停了两秒钟才显示出来,因为printf()函数输出的数据在缓冲区中,所以没有立马显示出来,当暂停两秒钟后,程序结束,强制刷新缓冲区,才将缓冲区的内容输出。
那么有人也会问了,当我们使用 printf()函数输出数据时添加
\n
,也能立马输出数据这是为什么?
因为
/n
也是一种刷新策略,
/n
也叫做行刷新。
二、回车换行的概念
在这里向大家提一个问题,大家是否认为回车和换行是一个东西,其实不然,回车和换行是两个不同的概念,回车是将光标移回当前行的第一个位置,换行是将光标的位置移动到下一行,但光标的位置并不会移回行的第一个位置。
在老式键盘中的回车换行也是比较形象的体现了回车和换行的特征。
那么我们在敲代码使用的
/r
和
/n
分别是什么呢?
- /r 是回车,光标仅仅回到当前行的第一个位置。
- /n 是回车换行,光标即移回行的第一个位置,又移动到下一行。
那么下面写一份代码,除
/r
和
/n
不同外其他部分全部相同,来看看程序的结果分别是什么。
我们通过上面的图片可以看到使用
/n
时,每一秒钟在下一行输出一个数字
而使用
/r
时,每一秒钟在当前行输出一个数字,并且覆盖上一个字符,最终被命令行覆盖,但是当循环时强制刷新缓冲区就可以把最后一个数字留下来,通过/r的这个特性,那么我们就可以设计倒计时,进度等。
三、进度条的设计
3.1 版本1(没有配合场景)
进度条效果图
// process.c#include"process.h"constchar rotate[]={"|/-\\"};voidprocess(){char arr[SIZE]={0};int rate =0;int len =strlen(rotate);while(rate <= MAX_RATE){printf("[%-100s][%3d%%][%c]\r",arr,rate,rotate[rate%len]);usleep(STIME);
arr[rate++]=STYLE;}printf("\n");}
// process.h#include<stdio.h>#include<unistd.h>#include<string.h>#defineSTYLE'#'// 进度条的风格#defineMAX_RATE100// 进度的最大值#defineSIZE101// 数组需要开多大 #defineSTIME1000*50// 暂停的时间voidprocess();
// main.c#include"process.h"intmain(){process();return0;}
// Makefile
cc=gcc
src=main.c process.c
target=myprocess
$(target):$(src)
$(cc) $^-o $@
.PHONY:clean
clean:
rm -f $(target)
3.2 版本2(配合场景)
无论任何进度条,一定和某种任务关联,那么这个版本的进度条不是在函数内部循环打印,而是通过回调的方式来进行某种任务的通知,动态进行更新进度条。
// process.c#include"process.h"constchar rotate[]={"|/-\\"};voidprocess2(int rate){staticchar arr[SIZE]={0};int len =strlen(rotate);if(rate <= MAX_RATE && rate >=0){printf("[%-100s][%3d%%][%c]\r",arr,rate,rotate[rate%len]);fflush(stdout);
arr[rate]=STYLE;}}
// main.c#include"process.h"#defineTOTAL_SIZE1024*1024// 程序大小 #defineDSIZE1024*10// 下载速度 voiddownload(){int target = TOTAL_SIZE;int sum =0;// 当前下载总大小 while(sum <= TOTAL_SIZE){int rate = sum*100/target;process2(rate);
sum += DSIZE;usleep(STIME);}process2(MAX_RATE);printf("\n");}intmain(){download();return0;}
// process.h#include<stdio.h>#include<unistd.h>#include<string.h>#defineSTYLE'#'// 进度条的风格 #defineMAX_RATE100// 进度的最大值 #defineSIZE101// 数组需要开多大 #defineSTIME1000*50// 暂停的时间 typedefvoid(*callback_t)(int);voidprocess1();voidprocess2(int);
3.3 版本3(美化进度条)
上面两个版本进度条中的旋转光标会受到进度的影响,在生活中下载软件、游戏等应用的时候可能在某个进度的时候突然卡住了,如果旋转光标会受到进度的影响的话,就不能知道软件是否在下载,所以当前版本对当前问题进行了优化,使旋转光标不再受到进度的影响。并且将进度的显示修改为小数。
进度条效果图
#include"process.h"constchar rotate[]={"|/-\\"};voidprocess3(double rate){staticint rotate_cnt =0;staticchar arr[SIZE]={0};int len =strlen(rotate);
rotate_cnt =++rotate_cnt % len;if(rate < MAX_RATE && rate >0){
arr[(int)rate-1]=STYLE_BODY;
arr[(int)rate]=STYLE_HEAD;}elseif(rate == MAX_RATE){
arr[(int)rate]='\0';
arr[(int)rate-1]=STYLE_BODY;}printf("[%-100s][%6.2lf%%][%c]\r",arr,rate,rotate[rotate_cnt%len]);fflush(stdout);}
// main.c#include"process.h"#defineTOTAL_SIZE1024*1024// 程序大小 #defineDSIZE1024*10// 下载速度 voiddownload(callback_t cb){int target = TOTAL_SIZE;int sum =0;// 当前下载总大小 while(sum <= TOTAL_SIZE){double rate = sum*100.0/target;cb(rate);
sum += DSIZE;usleep(STIME);}cb(MAX_RATE);printf("\n");}intmain(){download(process3);return0;}
// process.h#include<stdio.h>#include<unistd.h>#include<string.h>#defineSTYLE'#'// 进度条的风格 #defineMAX_RATE100// 进度的最大值 #defineSIZE101// 数组需要开多大 #defineSTIME1000*50// 暂停的时间 #defineSTYLE_HEAD'>'#defineSTYLE_BODY'='// typedef void(*callback_t)(int); typedefvoid(*callback_t)(double);voidprocess1();voidprocess2(int);voidprocess3(double);
结尾
如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹
版权归原作者 是阿建吖! 所有, 如有侵权,请联系我们删除。