前言:
本文目录
(一)理解 \r && \n
1、可显字符 和 控制字符
2、代码演示
(二)缓冲区的理解
1、什么是缓冲区
2、为什么要引入缓冲区
3、代码演示,引出现象
4、深入理解,解答现象
①缓冲区的类型
②缓冲区的刷新
(三)倒计时功能的实现
1、9以内的倒计时
2、10以内的倒计时实现
a)修改版
(四)进度条小程序( )
1、进度条样式说明
2、多文件实现
3、主体架构实现
4、进度的实现
5、缓冲功能的实现
(五)总结
在我们正式的写进度条之间,我先给大家理清一下这两个概念,带大家看看到底什么是
\r \n
在我们之前学习的 C语言中,有很多的字符。但是在宏观上大概可以分为两类字符,它们分别是:
不知道大家发现没有,不管是在我们日常敲代码又或者像我此时写文章的时候,当我们写完一行后若是没有 自动换行功能 此时就需要敲下键盘中的【Enter
】键以此来达到换行的效果。可是对于这个按键,大家可能都认为就是简单的敲一下键盘上的一个键,但是实际上在计算机内部是做了两件事的,即 —— 【换行】+【回车】。具体如下:
此时可能就有点小伙伴会有疑惑,说不对呀!我之前写 C语言的时候就是 printf打印 \n 之后就可以了呀,你这里怎么说是有两部呢?
现在我们知道了进行“换行操作” 其实是经历过两步的。其实很早之前在我们的老式键盘上就已经体现出来了,不知道各位小伙伴有没有仔细观察过呢?
当我们知道现象后,接下来我们就需要去验证一下,看我所说的是否是真的。接下来,我写几行代码给大家演示一下
a)首先,我们的代码是先写出基础的【Makefile】,我们在创建一个【test.c】文件用来写代码
b)紧接着我们先写【Makefile】,同时在【test.c】文件中写入两行代码。具体如下:
c)最后,我们可以执行这个程序,看最后的结果是如何的
现象解释:
到此,具体的现象我就带大家看到了,原因我也给大家分析了。
因此,接下来我们将要学习的便是关于缓冲区的基本知识了!!!
那么当我们有了关于缓冲区的概念之后,此时我们就会想为什么会引入 “缓冲区” 这个概念呢?
举个简单的例子:
有了上述的基本认识之后,接下来我们通过简单的代码观察其中的现象,让大家有直观的感受,进而我们在深入探讨
sleep() 函数:——>睡眠
中fflush()函数 ——> 刷新流
int fflush(FILE *stream);
还是以上述验证字符的代码为例,我给几段代码以及输出现象,大家先感受一下
a)代码
1 #include
2 #include
3 int main()
4 {
5 printf("hello world");
6
7 sleep(2);
8
9 return 0 ;
10 }
运行结果
现象描述:
b)代码
1 #include
2 #include
3 int main()
4 {
5 printf("hello world\n");
7 sleep(2);
8
9 return 0 ;
10 }
运行结果
现象描述:
sleep()
函数,相当于在打印输出完之后让程序 “延迟” 2秒,然后才会显示【命令提示符】c)代码
1 #include
2 #include
3 int main()
4 {
5 printf("hello world");
6 fflush(stdout);
7 sleep(2);
8
9 return 0 ;
10 }
运行结果
现象描述:
fflush()
这个函数,将其放在 sleep()
函数之前,也就相当于是优先刷新了一下缓冲流,此时就可以看到【hello world】立马先被打印了出来,等上2秒后才显示的【命令提示符】d)代码
1 #include
2 #include
3 int main()
4 {
5 printf("hello world\r");
6
7 sleep(2);
8
9 return 0 ;
10 }
运行结果
现象描述:
\r 时
,当开始执行后程序便开始睡眠, 然后在2秒睡眠后便直接打印出了【命令提示符】(注意:问题又来了哟!!!)e)代码
1 #include
2 #include
3 int main()
4 {
5 printf("hello world\r");
6 fflush(stdout);
7 sleep(2);
8
9 return 0 ;
10 }
运行结果
现象描述:
fflush()
刷新流,我们提前显示了一下需要打印的数据,此时就可以清晰的观察到,其实我们原本要打印的数据是在的,结果被【命令提示符】覆盖掉了从上述的代码展示以及最后的结果我们提出了以下几个问题,分别是:
\n
时为何是先睡眠再打印?加上 \n
后数据会立刻显示出来,完成睡眠后才显示提示符?\r
后观察不到我们输出的数据。然而刷新一下就有了? 接下来,我会一一为大家解答上述疑惑!!!
缓冲区可以分为三种类型:全缓冲、行缓冲和不带缓冲
1、全缓冲
2、行缓冲
3、不带缓冲
当发生以下情况后,缓冲区将会执行刷新操作:
可见,缓冲区满或关闭文件时都会刷新缓冲区,进行真正的I/O操作。
另外,我们可以使用 fflush 函数来刷新缓冲区(执行I/O操作并清空缓冲区)
接下来,我就来回答一下上述我们提出的几个问题吧!
①不加换行符 \n
时为何是先睡眠再打印?
sleep()
函数的缘故,导致这个缓冲区没有被刷新而已,所以它并没有丢失②加上\n
后数据会立刻显示出来,完成睡眠后才显示提示符?
\n
,数据都会被保存在缓冲区里。③加上回车 \r
后观察不到我们输出的数据。然而刷新一下就有了?
当我们领悟到上述所讲的知识之后,接下来我们先简单的实现一个——倒计时。
sleep(1)
代码如下:
1 #include
2 #include
3 int main()
4 {
5 int i=9;
6 for(;i>=0; i--)
7 {
8 printf("%d\n",i);
9 sleep(1);
10 }
11
12 return 0 ;
13 }
运行结果如下:
上述就是最简单的倒计时实现了。但是这跟我们想象的似乎不一样啊是不是:
接下来我就带大家看看怎么实现:
代码如下:
1 #include
2 #include
3 int main()
4 {
5 int i=9;
6 for(;i>=0; i--)
7 {
8 printf("%d\r",i); //注意这里变为了\r
9 fflush(stdout);
10 sleep(1);
11 }
12
13 return 0 ;
14 }
此时我们再去查看最终的结果:
不知道大家觉得【0-9】和【0-10】这二者实现倒计时是否一样呢?其实是不一样的哟!!
结论:
00
那么我们要如何修改才会和上述的一样呢?
putc()
这个函数将字符一一地打印在显示器上我们可以像如下一样进行修改,即可实现我们上述的效果。
代码如下:
1 #include
2 #include
3 int main()
4 {
5 int i=10;
6 for(;i>=0; i--)
7 {
8 printf("%2d\r",i); //改为%2d
9 fflush(stdout);
10 sleep(1);
11 }
12 return 0 ;
13 }
运行结果:
到此,在这里就简单的实现出来了一个倒计时的“小玩具”。
有了以上的知识铺垫,接下来就到了实现 ——>进度条小程序的实现过程了!
首先,就是给大家先说明一下本次进度条我们最终呈现出来的样式是什么样的。
因为,Linux下不是图形化的,因此我们这里实现的进度条就不是大家所熟知的网上看见的那种形状。
首先,我先给出我们的进度条的大概样式,最后呈现出来的就是以下这种现象:
说明:
1.主体部分大概就是用个【】来进行概括,中间用 ## 这样的符号来表示我们的进度条的进度样式;
2.后一个【】则表示相应的进度情况;
3.因为我们是在Linux环境下,无法做到这种图形化界面。最后就是用旋转字符的样式来代替我们在 Windows下的缓冲的样式
在这里我们给出的是多文件这样的实现方案。因此在正式的上手之前,我们需要创建相应的文件来表示相应的代码。
先直接给出程序的大概框架,让大家先见见:
此时,可能好多小伙伴就会有疑惑,在创建的文件列表【Makefile】中只有 main.c和 proc.c 而没有头文件 proc.h 文件
gcc
】的时候我大概提到过关于这个知识点。.c
源文件中进行展开,因此加不加结果都是一样的。第一步:
#define SIZE 101
解释说明:
第二步:
memset(bar, '\0', sizeof(bar));
解释说明:
代码如下:
1 #include"proc.h"
2
3 #define SIZE 101
4
5 void process()
6 {
7 char bar[SIZE];
8
9 memset(bar,'\0',sizeof(bar));
10
11 int i=0;
12 while(i<+100)
13 {
14 printf("[%s]\n",bar);
15 bar[i++]='#';
16 sleep(1);
17 }
18 }
但是此时我们可以发现,这是不断的换行实现的,但是在我们的认知中进度条就是在 “一行 ”上实现的呀。因此,此时显然不符合我们的预期
当我们完成上述要求之后,紧接着来编译代码看最终的结果是不是我们期望的那样,具体如下:
1 #include"proc.h"
2
3 #define SIZE 101
4
5 void process()
6 {
7 char bar[SIZE];
8
9 memset(bar,'\0',sizeof(bar));
10
11 int i=0;
12 while(i<+100)
13 {
14 printf("[%s]\r",bar); //此时变为\r
15 bar[i++]='#';
16 sleep(1);
17 }
18 }
此时,出现了一个 “小坑” ,我们可以发现并没有显示出任何东西大家知道什么吗?
fflush(stdout);
不过此时有点小伙伴就会有这样一个问题,是什么呢?
答案是有的,此时有需要另外一个库函数了,那就是 【usleep】函数。
1 #include"proc.h"
2
3 #define SIZE 101
4 #define ARP '>'
5
6 void process()
7 {
8 char bar[SIZE];
9
10 memset(bar,'\0',sizeof(bar));
11
12 int i=0;
13 while(i<+100)
14 {
15 printf("[%s]\r",bar);
16 fflush(stdout);
17 bar[i++]='#';
18 usleep(100000); //变为usleep
19 }
20 }
主体的进度条预留出了一个100的空间,好呈现进度条从0 ~ 100的推进,就可以上面说到过的格式化占位符
printf("[%100s]\r", bar);
我们可以发现怎么是从反方向走的,这也不是符合我们的需求啊!
printf("[%-100s]\r", bar);
当然我们还可以实现更多的样式,例如假设我们要实现【===>】这样的,我们可以怎么操作呢?
1 #include"proc.h"
2
3 #define SIZE 102 //记住,此时当你加入的符号过多时,空间也应该随之变大
4 #define ARP '>'
5 #define STYLE '=' //我们在这里用宏定义样式,便于我们修改
6
7 void process()
8 {
9 char bar[SIZE];
10
11 memset(bar,'\0',sizeof(bar));
12
13 int i=0;
14 while(i<+100)
15 {
16 printf("[%-100s]\r",bar);
17 fflush(stdout);
18 bar[i++]= STYLE;
19 bar[i]=ARP;
20
21 usleep(100000);
22 }
23 }
实现完主体的框架之后,紧接着我们需要去实现一下百分比递增
1 #include"proc.h"
2
3 #define SIZE 102
4 #define ARP '>'
5 #define STYLE '='
6
7 void process()
8 {
9 char bar[SIZE];
10
11 memset(bar,'\0',sizeof(bar));
12
13 int i=0;
14 while(i<+100)
15 {
16 printf("[%-100s][%d]\r",bar,i); //我们只需在最后加上输出的值即可
17 fflush(stdout);
18 bar[i++]= STYLE;
19 if(i != 100) bar[i]=ARP;
20
21 usleep(100000);
22 }
23 }
但是此时我们可以发现,输出只是数字,并不是百分数啊!
到此,关于进度的实现便完成了。接下来就是关于缓冲功能了!!!
终于到了最后。马上就要揭开我们进度条的了 ”庐山真面目“了。
const
】来修饰。const char* label = "|/-\\";
printf("[%-100s][%d%%][%c]\r", bar, i , label[i % 4]);
运行如下:
到此,我们就实现了一个进度条小程序的设计。最终代码如下:
1 #include"proc.h"
2
3 #define SIZE 102
4 #define ARP '>'
5 #define STYLE '='
6
7 void process()
8 {
9 const char* label = "|/-\\";
10 char bar[SIZE];
11
12 memset(bar,'\0',sizeof(bar));
13
14 int i=0;
15 while(i<+100)
16 {
17 printf("[%-100s][%d%%][%c]\r", bar, i , label[i % 4]);
18 fflush(stdout);
19 bar[i++]= STYLE;
20 if(i != 100 )bar[i]=ARP;
21
22 usleep(100000);
23 }
24 }
到此,关于进度条小程序的所有知识便讲解完毕了!接下来,我们一起回顾一下
\n
】与【\r
】,知道了这两者的作用及功能;以上就是本文的所有知识,感谢各位的支持!!!