一、前提引入
🎗️下面的代码什么现象?
🎗️现象:马上打印出Hello Makefile!
🎗️下面的代码什么现象?
🎗️现象:停留三秒后打印出Hello Makefile!
现象是先sleep!但是一定是printf先执行,printf早就执行了,只不过字符串没有被显示出来罢了。所以在sleep期间,字符串在哪里?
答案:在输出缓冲区。
二、缓冲区
🎗️C/C++语言,会针对标准输出,给我们提供默认的缓冲区。
🎗️输出缓冲区在哪里呢?
在标准输出流。C/C++默认会打开三个文件流:标准输入流、标准输出流、标准错误流。
🎗️fflush(stdout) 刷新缓冲区
🎗️\n 是一种刷新的策略 行刷新
C程序是默认有输出缓冲区的,数据输出时会默认放在输出缓冲区。之所以可以立马见到数据,是因为该数据被刷新了;如果没有立马见到它,该数据没有被刷新,被暂存在输出缓冲区stdout当中。强制刷新fflsh(stdout)可使数据立马显示出来。
三、回车换行
🎗️注意
回车换行是两个动作
回车是让光标回到该行的最开始位置
换行是换到下一行
🎗️图解
🎗️老式回车键造型(意思是充当两个动作)
🎗️\r 和 \n
🎗️在C语言中,\r代表回车,\n代表换行
🎗️在Linux中,\r代表回车,\n代表回车和换行
🎗️倒计时代码
代码1
效果
形成一个9到1的倒计时效果(打印完一个数字,回车回到最开始打印,下一个数字覆盖上一个数字的打印结果)
注意:如果没有刷新缓冲区那句代码,那么什么也不会显示出来。
代码2
🎗️效果
形成一个从100的倒计时
🎗️注意点
控制两位字符的输出宽度,可达到10的倒计时效果;控制三位字符的输出宽度,可达到100的倒计时效果。控制几位字符就在%d的d前面加数字。
输出结果如果不设置对齐方式,可能会出现覆盖从而达不到预想效果。输出结果左对齐,在%后加上-
思考
🎗️我们向显示器打印的数字真的是数字吗?
答案:不是
往显示器输出123,实际上输出的是1字符,2字符,3字符。
显示器只能显示字符。
因此显示器叫做显示器字符设备。
🎗️我们从键盘上读取到的内容,是什么呢?
b比如说我们从键盘输入1234,键盘读取到的并不是一千两百三十四,而是1字符、2字符、3字符、4字符,然后由scanf将字符串转成整数,放到对应的变量里,这样才有了整数。
四、进度条
预想的进度条效果
构想代码结构
(一)简单原理版本
Makefile
process:process.c main.c gcc -o $@ $^ .PHONY:clean clean: rm -f $@
process.c
#include "process.h" #include<string.h> #include<unistd.h> #define SIZE 101 #define MAX_RATE 100 #define STYLE '#' #define STIME 1000*40 const char *str="|/-\\"; void process(){ int rate=0; char bar[SIZE]; memset(bar,'\0',sizeof(bar)); int num=strlen(str); while(rate<=MAX_RATE){ printf("[%-100s][%d%%][%c]\r",bar,rate,str[rate%num]); fflush(stdout); usleep(STIME); bar[rate++]=STYLE; } printf("\n"); }
process.h
#pragma once #include<stdio.h> void process();
main.c
#include "process.h" int main(){ process(); return 0; }
重点代码解读
进度条效果
(二)实际工程实践版本
下载逻辑
Makefile
process:process.c main.c gcc -o $@ $^ .PHONY:clean clean: rm -rf process
process.c
#include "process.h" #include<string.h> #include<unistd.h> const char *str="|/-\\"; void process_v2(int rate){ static char bar[SIZE]={0}; int num=strlen(str); if(rate<=MAX_RATE&&rate>=0){ printf("[%-100s][%d%%][%c]\r",bar,rate,str[rate%num]); fflush(stdout); bar[rate]=STYLE; } if(rate==MAX_RATE){ memset(bar,'\0',sizeof(bar)); } }
process.h
#pragma once #include<stdio.h> #include<string.h> #include<unistd.h> #define SIZE 101 #define MAX_RATE 100 #define STYLE '#' #define STIME 1000*40 void process_v2(int);
main.c
#include "process.h" #define TARGET_SIZE 1024*1024 #define DSIZE 1024*10 void download(){ int target=TARGET_SIZE; int total=0; while(total<target){ usleep(STIME); total+=DSIZE; process_v2(total*100/target); } printf("\n"); } //下载的软件 int main(){ download(); return 0; }
重点代码解读
改进
process.h
#pragma once #include<stdio.h> #include<string.h> #include<unistd.h> #define SIZE 101 #define MAX_RATE 100 #define STYLE '#' #define STIME 1000*40 typedef void(*callback_t)(int); void process_v2(int);
main.c
#include "process.h" #define TARGET_SIZE 1024*1024 #define DSIZE 1024*10 void download(callback_t cb){ int target=TARGET_SIZE; int total=0; while(total<target){ usleep(STIME); total+=DSIZE; int rate=total*100/target; cb(rate); } printf("\n"); } //下载的软件 int main(){ download(process_v2); return 0; }
🎗️回调:把一段可执行的代码像参数传递给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。
🎗️改进的版本:
这里,将更新显示的进度条的函数process_v2作为参数传递给download函数,在download函数中需要它时就调用它,调用以函数指针的形式来实现回调函数。
总结
版本2进度条不是在进度条函数内部进行循环打印的,这样有点不好,所以我们采用回调的方式,来进行某种任务的通知,动态更新进度条!(在下载任务中调用进度条)
(三)简单的美化风格
Makefile
process:process.c main.c gcc -o $@ $^ .PHONY:clean clean: rm -rf process
process.c
#include "process.h" #include<string.h> #include<unistd.h> const char *str="|/-\\"; void process_v3(double rate){ static char bar[SIZE]={0}; int num=strlen(str); if(rate<=MAX_RATE&&rate>=0){ printf("[%-100s][%.1f%%][%c]\r",bar,rate,str[(int)rate%num]); fflush(stdout); if(rate<MAX_RATE){ bar[(int)rate]=STYLE_BODY; bar[(int)rate+1]=STYLE_HEAD; }else{ bar[(int)rate]=STYLE_BODY; } } }
process.h
#pragma once #include<stdio.h> #include<string.h> #include<unistd.h> #define SIZE 101 #define MAX_RATE 100 #define STYLE '#' #define STIME 1000*40 #define STYLE_BODY '=' #define STYLE_HEAD '>' typedef void(*callback_t)(double); void process_v3(double);
main.c
#pragma once #include<stdio.h> #include<string.h> #include<unistd.h> #define SIZE 101 #define MAX_RATE 100 #define STYLE '#' #define STIME 1000*40 #define STYLE_BODY '=' #define STYLE_HEAD '>' typedef void(*callback_t)(double); void process_v3(double);
进度条效果
模拟加载中效果
版本3基础上,模拟实现进度条加载过程中不移动时,数字不改变时,(即现实中加载的资源不足以1%时),后面的光标一直旋转(显示加载中)的效果。
🎗️在process.c和main.c文件中做了修改
process.c
#include "process.h" #include<string.h> #include<unistd.h> const char *str="|/-\\"; void process_v3(double rate){ static char bar[SIZE]={0}; int num=strlen(str); static int cnt=0; if(rate<=MAX_RATE&&rate>=0){ cnt++; cnt=(cnt>=num?0:cnt); printf("[%-100s][%.1f%%][%c]\r",bar,rate,str[cnt]); fflush(stdout); if(rate<MAX_RATE){ bar[(int)rate]=STYLE_BODY; bar[(int)rate+1]=STYLE_HEAD; }else{ bar[(int)rate]=STYLE_BODY; } } }
process.h
#pragma once #include<stdio.h> #include<string.h> #include<unistd.h> #define SIZE 101 #define MAX_RATE 100 #define STYLE '#' #define STIME 1000*40 #define STYLE_BODY '=' #define STYLE_HEAD '>' typedef void(*callback_t)(double); void process_v3(double);
main.c
#include "process.h" #define TARGET_SIZE 1024*1024 #define DSIZE 1024*10 void download(callback_t cb){ int testcnt=100; int target=TARGET_SIZE; int total=0; while(total<target){ usleep(STIME); total+=DSIZE; double rate=total*100/target; if(rate>50.0&&testcnt){ total=target/2; testcnt--; } cb(rate); } cb(MAX_RATE); printf("\n"); } //下载的软件 int main(){ download(process_v3); return 0; }
Makefile
process:process.c main.c gcc -o $@ $^ .PHONY:clean clean: rm -rf process
重点代码解读
进度条效果
C语言扩展–给进度条带上颜色
C语言有具体的语法可以设置不同的颜色,具体内容大家可以自行搜索,为进度条设置自己喜爱的颜色。
本篇内容的学习就到这里啦!如果对友友们有帮助的话,可以关注后续的创作内容哦~👻