前言:
- 在之前的學(xué)習(xí)中,我們已經(jīng)基本掌握了關(guān)于了 Linux 下的一些工具的使用,接下來我們運(yùn)用之前學(xué)到的知識,我將帶領(lǐng)大家寫了一個(gè)關(guān)于?進(jìn)度條 的小程序來練練手!?。?/span>
本文目錄
(一)理解 \r && \n
1、可顯字符 和 控制字符
2、代碼演示
(二)緩沖區(qū)的理解
1、什么是緩沖區(qū)
2、為什么要引入緩沖區(qū)
3、代碼演示,引出現(xiàn)象
4、深入理解,解答現(xiàn)象
①緩沖區(qū)的類型
②緩沖區(qū)的刷新
(三)倒計(jì)時(shí)功能的實(shí)現(xiàn)
1、9以內(nèi)的倒計(jì)時(shí)
2、10以內(nèi)的倒計(jì)時(shí)實(shí)現(xiàn)
a)修改版
(四)進(jìn)度條小程序(???)
1、進(jìn)度條樣式說明
2、多文件實(shí)現(xiàn)
3、主體架構(gòu)實(shí)現(xiàn)
4、進(jìn)度的實(shí)現(xiàn)
5、緩沖功能的實(shí)現(xiàn)
(五)總結(jié)
(一)理解 \r && \n
在我們正式的寫進(jìn)度條之間,我先給大家理清一下這兩個(gè)概念,帶大家看看到底什么是?
\r \n
1、可顯字符 和 控制字符
在我們之前學(xué)習(xí)的 C語言中,有很多的字符。但是在宏觀上大概可以分為兩類字符,它們分別是:
- a)可顯字符:當(dāng)我們從鍵盤上輸入這個(gè)字符時(shí),顯示器上就可以顯示這個(gè)字符,即輸入什么就顯示什么。這類字符稱為可顯示字符,如a、b、c、$、+和空格符等都是可顯示字符。
- b)控制字符:通常表示出現(xiàn)于特定的信息文本中,表示某一控制功能的字符。例如我們今天要講到的? \n \r 等字符
不知道大家發(fā)現(xiàn)沒有,不管是在我們?nèi)粘G么a又或者像我此時(shí)寫文章的時(shí)候,當(dāng)我們寫完一行后若是沒有?自動換行功能 此時(shí)就需要敲下鍵盤中的【Enter
】鍵以此來達(dá)到換行的效果??墒菍τ谶@個(gè)按鍵,大家可能都認(rèn)為就是簡單的敲一下鍵盤上的一個(gè)鍵,但是實(shí)際上在計(jì)算機(jī)內(nèi)部是做了兩件事的,即 —— 【換行】+【回車】。具體如下:
- \n:表示新起一行,此時(shí)光標(biāo)位于行末 (換行)
- \r:表示回到當(dāng)前文本行的最開始處(回車)
?
此時(shí)可能就有點(diǎn)小伙伴會有疑惑,說不對呀!我之前寫 C語言的時(shí)候就是 printf打印 \n 之后就可以了呀,你這里怎么說是有兩部呢?
- 那是因?yàn)楦魑划?dāng)前的語言范疇它呢就把 \n 就默認(rèn)成為了 回車加換行,所以呢你看到的就是這個(gè)樣子
現(xiàn)在我們知道了進(jìn)行“換行操作” 其實(shí)是經(jīng)歷過兩步的。其實(shí)很早之前在我們的老式鍵盤上就已經(jīng)體現(xiàn)出來了,不知道各位小伙伴有沒有仔細(xì)觀察過呢?
?
2、代碼演示
?當(dāng)我們知道現(xiàn)象后,接下來我們就需要去驗(yàn)證一下,看我所說的是否是真的。接下來,我寫幾行代碼給大家演示一下
- 注意:因?yàn)樵谥暗闹v解中,我們已經(jīng)知道了 【vim】【make\Makefile】以及【gcc】的基本使用,接下來我們就不解釋這些工具的使用了
a)首先,我們的代碼是先寫出基礎(chǔ)的【Makefile】,我們在創(chuàng)建一個(gè)【test.c】文件用來寫代碼
?
?b)緊接著我們先寫【Makefile】,同時(shí)在【test.c】文件中寫入兩行代碼。具體如下:
?
?c)最后,我們可以執(zhí)行這個(gè)程序,看最后的結(jié)果是如何的
?
?現(xiàn)象解釋:
- 從上我們不難發(fā)現(xiàn)一個(gè)事情。最后帶有 【\r】的一行沒有打印出來。
- 原因就是因?yàn)椤綷r】將光標(biāo)回到最開始的位置,你可以理解為本來是應(yīng)該打印 【hello hello】,但是光標(biāo)此時(shí)回到最左側(cè),最后刷新顯示的時(shí)候就什么都沒有了!
到此,具體的現(xiàn)象我就帶大家看到了,原因我也給大家分析了。
- 但是這就完了嗎?其實(shí)并沒有,我們想要充分理解,我們還要學(xué)習(xí)一下關(guān)于緩沖區(qū)的概念
因此,接下來我們將要學(xué)習(xí)的便是關(guān)于緩沖區(qū)的基本知識了?。?!
(二)緩沖區(qū)的理解
1、什么是緩沖區(qū)
- 緩沖區(qū)又稱為緩存,它是內(nèi)存空間的一部分。也就是說,在內(nèi)存空間中預(yù)留了一定的存儲空間,這些存儲空間用來緩沖輸入或輸出的數(shù)據(jù),這部分預(yù)留的空間就叫做緩沖區(qū)。
- 緩沖區(qū)根據(jù)其對應(yīng)的是輸入設(shè)備還是輸出設(shè)備,分為輸入緩沖區(qū)和輸出緩沖區(qū)。
2、為什么要引入緩沖區(qū)
那么當(dāng)我們有了關(guān)于緩沖區(qū)的概念之后,此時(shí)我們就會想為什么會引入 “緩沖區(qū)” 這個(gè)概念呢?
舉個(gè)簡單的例子:
- 當(dāng)我們從磁盤里讀取信息時(shí),我們先把讀出的數(shù)據(jù)放在緩沖區(qū),計(jì)算機(jī)再直接從緩沖區(qū)中取數(shù)據(jù),等緩沖區(qū)的數(shù)據(jù)取完后再去磁盤中讀取,這樣就可以減少磁盤的讀寫次數(shù);
- 再加上計(jì)算機(jī)對緩沖區(qū)的操作遠(yuǎn)快于對磁盤的操作,故緩沖區(qū)的使用可大大提高計(jì)算機(jī)的運(yùn)行速度。
3、代碼演示,引出現(xiàn)象
有了上述的基本認(rèn)識之后,接下來我們通過簡單的代碼觀察其中的現(xiàn)象,讓大家有直觀的感受,進(jìn)而我們在深入探討
- 在這之前先認(rèn)識兩個(gè)Linux下的庫函數(shù)
sleep() 函數(shù):——>睡眠
- 頭文件包含在
<unistd.h>
中 - 注意區(qū)分一點(diǎn):Windows中的 sleep() 單位是 毫秒;而Linxu中的sleep()單位是?秒
fflush()函數(shù) ——>?刷新流
- 該函數(shù)一般用來刷新輸出流 ->stdout
- 格式:
int fflush(FILE *stream);
還是以上述驗(yàn)證字符的代碼為例,我給幾段代碼以及輸出現(xiàn)象,大家先感受一下
a)代碼
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 printf("hello world");
6
7 sleep(2);
8
9 return 0 ;
10 }
運(yùn)行結(jié)果
現(xiàn)象描述:
- 以上代碼輸出的最后我們沒有加上【\n】,從結(jié)果我們不難看出,我們要輸出的【hello world】并沒有在第一時(shí)間打印,而是在睡眠2秒后和【命令提示符】一同進(jìn)行打印,這是為何呢?(注意,問題來了喲?。。。?/strong>
b)代碼
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 printf("hello world\n");
7 sleep(2);
8
9 return 0 ;
10 }
運(yùn)行結(jié)果
現(xiàn)象描述:
- 從上述的結(jié)果我們可以發(fā)現(xiàn):和我們平時(shí)寫的代碼幾乎沒有區(qū)別的,當(dāng)加上
sleep()
函數(shù),相當(dāng)于在打印輸出完之后讓程序 “延遲” 2秒,然后才會顯示【命令提示符】
c)代碼
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 printf("hello world");
6 fflush(stdout);
7 sleep(2);
8
9 return 0 ;
10 }
運(yùn)行結(jié)果
現(xiàn)象描述:
- 緊接著我們在下行加入了?
fflush()?
這個(gè)函數(shù),將其放在?sleep()?
函數(shù)之前,也就相當(dāng)于是優(yōu)先刷新了一下緩沖流,此時(shí)就可以看到【hello world】立馬先被打印了出來,等上2秒后才顯示的【命令提示符】
d)代碼
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 printf("hello world\r");
6
7 sleep(2);
8
9 return 0 ;
10 }
運(yùn)行結(jié)果
現(xiàn)象描述:
-
從上述我們可以觀察到:當(dāng)我們在輸出語句后加上了?
\r 時(shí)
,當(dāng)開始執(zhí)行后程序便開始睡眠, 然后在2秒睡眠后便直接打印出了【命令提示符】(注意:問題又來了喲?。。。?/strong>
e)代碼
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 printf("hello world\r");
6 fflush(stdout);
7 sleep(2);
8
9 return 0 ;
10 }
運(yùn)行結(jié)果
現(xiàn)象描述:
- 通過上述現(xiàn)象我們不難發(fā)現(xiàn):通過
fflush()
刷新流,我們提前顯示了一下需要打印的數(shù)據(jù),此時(shí)就可以清晰的觀察到,其實(shí)我們原本要打印的數(shù)據(jù)是在的,結(jié)果被【命令提示符】覆蓋掉了
4、深入理解,解答現(xiàn)象
從上述的代碼展示以及最后的結(jié)果我們提出了以下幾個(gè)問題,分別是:
- 不加換行符?
\n?
時(shí)為何是先睡眠再打?。?/strong> 加上?\n?
后數(shù)據(jù)會立刻顯示出來,完成睡眠后才顯示提示符?-
加上回車?
\r?
后觀察不到我們輸出的數(shù)據(jù)。然而刷新一下就有了??
接下來,我會一一為大家解答上述疑惑!??!
- 在解答之前,我們先來看一些需要大家了解的文字知識!
①緩沖區(qū)的類型
緩沖區(qū)可以分為三種類型:全緩沖、行緩沖和不帶緩沖
- 注意:在這里我們主要講的是關(guān)于【行緩沖】的基本知識
1、全緩沖
- 在這種情況下,當(dāng)填滿標(biāo)準(zhǔn)I/O緩存后才進(jìn)行實(shí)際I/O操作。全緩沖的典型代表是對磁盤文件的讀寫。
2、行緩沖
- 在這種情況下,當(dāng)在輸入和輸出中遇到換行符時(shí),執(zhí)行真正的I/O操作。這時(shí),我們輸入的字符先存放在緩沖區(qū),等按下回車鍵換行時(shí)才進(jìn)行實(shí)際的I/O操作。典型代表是鍵盤輸入數(shù)據(jù)。
3、不帶緩沖
- 顧名思義,也就是不進(jìn)行緩沖,標(biāo)準(zhǔn)出錯(cuò)情況 【stderr】就是典型代表,這使得出錯(cuò)信息可以直接盡快地顯示出來。
②緩沖區(qū)的刷新
當(dāng)發(fā)生以下情況后,緩沖區(qū)將會執(zhí)行刷新操作:
- 1、緩沖區(qū)滿時(shí)會自動刷新
- 2、執(zhí)行特定的函數(shù)時(shí)
- 3、行緩沖遇到換行符時(shí)也會刷新
- 4、關(guān)閉文件時(shí),也會自動刷新
可見,緩沖區(qū)滿或關(guān)閉文件時(shí)都會刷新緩沖區(qū),進(jìn)行真正的I/O操作。
另外,我們可以使用 fflush 函數(shù)來刷新緩沖區(qū)(執(zhí)行I/O操作并清空緩沖區(qū))
接下來,我就來回答一下上述我們提出的幾個(gè)問題吧!
①不加換行符?\n
時(shí)為何是先睡眠再打?。?/span>
- 對于上述的代碼而言,程序執(zhí)行時(shí)一定是順序執(zhí)行的,因此一定是先打印輸出語句中的內(nèi)容;
- 那么就有很多小伙伴好奇,我們怎么看不到這個(gè)現(xiàn)象呢?因?yàn)樗淮娣诺搅司彌_區(qū)里,由于
sleep()
函數(shù)的緣故,導(dǎo)致這個(gè)緩沖區(qū)沒有被刷新而已,所以它并沒有丟失
②加上\n
后數(shù)據(jù)會立刻顯示出來,完成睡眠后才顯示提示符?
-
首先,我們需要知道一點(diǎn)。那就是無論我們加不加
\n
,數(shù)據(jù)都會被保存在緩沖區(qū)里。 - 因?yàn)檩敵龅淖詈笠粋€(gè)字符是 \n ,并且是往顯示器里面進(jìn)行打印,此外緩沖區(qū)還有很多的刷新策略。今天我們關(guān)心的是行緩沖,即->只要碰到了換行符,這就意味著此時(shí)就會把換行符之前的所有內(nèi)容全部顯示出來
- 所以字符串是以行緩沖的方式保存在了行緩沖區(qū)里,最后當(dāng)我們要退出的時(shí)候就會顯示出來,所以此時(shí)保存在沖區(qū)里的數(shù)據(jù)就會被刷新出來
③加上回車?\r
后觀察不到我們輸出的數(shù)據(jù)。然而刷新一下就有了??
- 對于 \r 我們可以通過上述的輸出可以發(fā)現(xiàn),此時(shí)光標(biāo)會回到行首;
- 因?yàn)椋?dāng)我們打印的時(shí)候,當(dāng)遇到 \r 的時(shí)候,光標(biāo)就會回到最開始,但是這些數(shù)據(jù)并沒有在緩沖區(qū)中被移除,依舊是存在的;
- 當(dāng)我們 sleep() 的時(shí)候,光標(biāo)打印輸出的內(nèi)容時(shí)遇到 \r 就會回到最開始,但是程序執(zhí)行完之后,shell還會打印提示符,此時(shí)就會覆蓋掉程序輸出的內(nèi)容
(三)倒計(jì)時(shí)功能的實(shí)現(xiàn)
當(dāng)我們領(lǐng)悟到上述所講的知識之后,接下來我們先簡單的實(shí)現(xiàn)一個(gè)——倒計(jì)時(shí)。
1、9以內(nèi)的倒計(jì)時(shí)
- 我們先來簡單的實(shí)現(xiàn)一下9以內(nèi)的倒計(jì)時(shí),思路很簡單,就是循環(huán)輸出即可。然后在打印完每個(gè)數(shù)字之后使用
sleep(1)
代碼如下:
1 #include<stdio.h>
2 #include<unistd.h>
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 }
運(yùn)行結(jié)果如下:
上述就是最簡單的倒計(jì)時(shí)實(shí)現(xiàn)了。但是這跟我們想象的似乎不一樣啊是不是:
- 我們希望看到的是在一行實(shí)現(xiàn)相應(yīng)的功能,并且每次輸出的結(jié)果把上次輸出的結(jié)果覆蓋掉,那么我們應(yīng)該怎么做呢?
接下來我就帶大家看看怎么實(shí)現(xiàn):
代碼如下:
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 int i=9;
6 for(;i>=0; i--)
7 {
8 printf("%d\r",i); //注意這里變?yōu)榱薥r
9 fflush(stdout);
10 sleep(1);
11 }
12
13 return 0 ;
14 }
此時(shí)我們再去查看最終的結(jié)果:
2、10以內(nèi)的倒計(jì)時(shí)實(shí)現(xiàn)
不知道大家覺得【0-9】和【0-10】這二者實(shí)現(xiàn)倒計(jì)時(shí)是否一樣呢?其實(shí)是不一樣的喲?。?/strong>
- 眼見為實(shí),我們把【i】的值改為10,看最終的結(jié)果是不是我們想要的那樣。
結(jié)論:
- 通過上述我們不難發(fā)現(xiàn)一件事,當(dāng)是兩位數(shù)時(shí)只有前面的數(shù)字會被覆蓋,10后面的這個(gè)0會始終被保留下來,最后倒計(jì)時(shí)結(jié)束后便成了
00
那么我們要如何修改才會和上述的一樣呢?
- 在計(jì)算機(jī)打印時(shí),假設(shè)我們要打印的是【100】這個(gè)數(shù),那么是不是計(jì)算機(jī)就是按整數(shù)【100】的形式打印出來的呢?
- 其實(shí)不是這樣的。在計(jì)算機(jī)打印中,它會把100 當(dāng)成三個(gè)字符進(jìn)行打印,即在計(jì)算機(jī)看來 100,就是由 字符 1 0 0 組成;
- 將整型數(shù)字先轉(zhuǎn)換為字符串的形式,然后去遍歷這個(gè)字符串,用
putc()
這個(gè)函數(shù)將字符一一地打印在顯示器上
a)修改版
我們可以像如下一樣進(jìn)行修改,即可實(shí)現(xiàn)我們上述的效果。
代碼如下:
1 #include<stdio.h>
2 #include<unistd.h>
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 }
運(yùn)行結(jié)果:
到此,在這里就簡單的實(shí)現(xiàn)出來了一個(gè)倒計(jì)時(shí)的“小玩具”。
(四)進(jìn)度條小程序(???)
有了以上的知識鋪墊,接下來就到了實(shí)現(xiàn) ——>進(jìn)度條小程序的實(shí)現(xiàn)過程了!
1、進(jìn)度條樣式說明
首先,就是給大家先說明一下本次進(jìn)度條我們最終呈現(xiàn)出來的樣式是什么樣的。
因?yàn)?,Linux下不是圖形化的,因此我們這里實(shí)現(xiàn)的進(jìn)度條就不是大家所熟知的網(wǎng)上看見的那種形狀。
首先,我先給出我們的進(jìn)度條的大概樣式,最后呈現(xiàn)出來的就是以下這種現(xiàn)象:
- 【##################################>】【100%】【/】
說明:
1.主體部分大概就是用個(gè)【】來進(jìn)行概括,中間用 ## 這樣的符號來表示我們的進(jìn)度條的進(jìn)度樣式;
2.后一個(gè)【】則表示相應(yīng)的進(jìn)度情況;
3.因?yàn)槲覀兪窃贚inux環(huán)境下,無法做到這種圖形化界面。最后就是用旋轉(zhuǎn)字符的樣式來代替我們在 Windows下的緩沖的樣式
2、多文件實(shí)現(xiàn)
在這里我們給出的是多文件這樣的實(shí)現(xiàn)方案。因此在正式的上手之前,我們需要?jiǎng)?chuàng)建相應(yīng)的文件來表示相應(yīng)的代碼。
- 【proc.h】:存放頭文件的文件夾
- 【proc.c】:代表頭文件匹配的源文件,進(jìn)度條實(shí)現(xiàn)的邏輯存放在這里面
- 【mainc】:來進(jìn)行程序的調(diào)度
先直接給出程序的大概框架,讓大家先見見:
- ?接下來,我們要去編譯的話,此時(shí)我們還需要?jiǎng)?chuàng)建文件列表,即【makefile】來存放,這個(gè)在之前我們已經(jīng)詳細(xì)的講過了,這里就不多講了。直接給出,具體如下:
- ?緊接著,我們邊去測試一下程序是否可以正常的編譯運(yùn)行:
?此時(shí),可能好多小伙伴就會有疑惑,在創(chuàng)建的文件列表【Makefile】中只有 main.c和 proc.c? 而沒有頭文件 proc.h 文件
- 對于以上問題,之前在講解【
gcc
】的時(shí)候我大概提到過關(guān)于這個(gè)知識點(diǎn)。 - 我們在進(jìn)行多文件編譯時(shí)候是不需要考慮【頭文件】的,因?yàn)樵陬A(yù)處理階段頭文件就會在它被包含的?
.c
源文件中進(jìn)行展開,因此加不加結(jié)果都是一樣的。 - 一般我們是不加的
3、主體架構(gòu)實(shí)現(xiàn)
第一步:
#define SIZE 101
解釋說明:
- 因?yàn)檫M(jìn)度條嘛!進(jìn)度就是從0到100 的,將整體進(jìn)度條看作是一個(gè)字符串,因此我們設(shè)置101來存放
第二步:
memset(bar, '\0', sizeof(bar));
解釋說明:
- 因?yàn)閷?shí)現(xiàn)這個(gè)進(jìn)度條推演就是一個(gè)循環(huán)的方式,每次都去修改這個(gè)字符數(shù)組當(dāng)前位置上的字符,將其變?yōu)?“=” ,緊接著去打印的時(shí)候下一個(gè)位置就會多出來一個(gè) “=” ,從而實(shí)現(xiàn)往后慢慢推進(jìn)的過程
- 初始化時(shí)就把數(shù)組全部的位置初始化為 \0 ,緊接著隨著進(jìn)度條的推進(jìn)去修改為 “=” 即可
代碼如下:
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 }
- 此時(shí)我們編譯一下,看最終的結(jié)果是怎么樣的:
但是此時(shí)我們可以發(fā)現(xiàn),這是不斷的換行實(shí)現(xiàn)的,但是在我們的認(rèn)知中進(jìn)度條就是在 “一行 ”上實(shí)現(xiàn)的呀。因此,此時(shí)顯然不符合我們的預(yù)期
- 我們的預(yù)期是在一行上進(jìn)行不斷推進(jìn)的過程。因此,我們就不能加上【\n】這個(gè)字符;
- 我們使用【\r】,當(dāng)每次打印的時(shí)候,都從當(dāng)前行的起始位置處進(jìn)行操作。
當(dāng)我們完成上述要求之后,緊接著來編譯代碼看最終的結(jié)果是不是我們期望的那樣,具體如下:
- 代碼如下:
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); //此時(shí)變?yōu)閈r
15 bar[i++]='#';
16 sleep(1);
17 }
18 }
- 運(yùn)行結(jié)果:
此時(shí),出現(xiàn)了一個(gè) “小坑” ,我們可以發(fā)現(xiàn)并沒有顯示出任何東西大家知道什么嗎?
- 我相信聰明的小伙伴已經(jīng)知道了,即 緩沖區(qū)沒刷新!
fflush(stdout);
- 再次運(yùn)行,結(jié)果如下:
不過此時(shí)有點(diǎn)小伙伴就會有這樣一個(gè)問題,是什么呢?
- 我們可以觀察到這個(gè)進(jìn)度條推進(jìn)的速度很慢,那有沒有辦法讓它快一點(diǎn)呢?
答案是有的,此時(shí)有需要另外一個(gè)庫函數(shù)了,那就是 【usleep】函數(shù)。
- 大家可以用 【man】手冊去查一下到底什么意思,我在這里給出簡略的回答:
- ?代碼如下:
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); //變?yōu)閡sleep
19 }
20 }
- 運(yùn)行如下:
主體的進(jìn)度條預(yù)留出了一個(gè)100的空間,好呈現(xiàn)進(jìn)度條從0 ~ 100的推進(jìn),就可以上面說到過的格式化占位符
printf("[%100s]\r", bar);
- 運(yùn)行結(jié)果:
我們可以發(fā)現(xiàn)怎么是從反方向走的,這也不是符合我們的需求??!
- 別急,其實(shí)很好解決,只需在 輸出的 100前加上 【-】 即可實(shí)現(xiàn)從左開始輸出。
printf("[%-100s]\r", bar);
- 運(yùn)行結(jié)果:
當(dāng)然我們還可以實(shí)現(xiàn)更多的樣式,例如假設(shè)我們要實(shí)現(xiàn)【===>】這樣的,我們可以怎么操作呢?
- 代碼如下:
1 #include"proc.h"
2
3 #define SIZE 102 //記住,此時(shí)當(dāng)你加入的符號過多時(shí),空間也應(yīng)該隨之變大
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 }
- 運(yùn)行結(jié)果如下:
4、進(jìn)度的實(shí)現(xiàn)
實(shí)現(xiàn)完主體的框架之后,緊接著我們需要去實(shí)現(xiàn)一下百分比遞增
- 代碼如下:
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 }
- 運(yùn)行如下:
但是此時(shí)我們可以發(fā)現(xiàn),輸出只是數(shù)字,并不是百分?jǐn)?shù)?。?
- 我們只需在【%d】的后面在加上 % 即可,即——>【%d%%】
- 結(jié)果如下:
到此,關(guān)于進(jìn)度的實(shí)現(xiàn)便完成了。接下來就是關(guān)于緩沖功能了?。?!
5、緩沖功能的實(shí)現(xiàn)
終于到了最后。馬上就要揭開我們進(jìn)度條的了 ”廬山真面目“了。
- 此時(shí)我們只需要定義一個(gè)字符數(shù)組,并用【
const
】來修飾。 - 目的很簡單就是防止里面的內(nèi)容被修改。
const char* label = "|/-\\";
- 最后在打印的時(shí)候,要去實(shí)現(xiàn)一個(gè)輪回就需要用到一個(gè)取余操作,每次打印的都是【0 ~ 3】的倍數(shù),因此模上4 即可
printf("[%-100s][%d%%][%c]\r", bar, i , label[i % 4]);
運(yùn)行如下:
到此,我們就實(shí)現(xiàn)了一個(gè)進(jìn)度條小程序的設(shè)計(jì)。最終代碼如下:
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 }
(五)總結(jié)
到此,關(guān)于進(jìn)度條小程序的所有知識便講解完畢了!接下來,我們一起回顧一下
- 首先我們學(xué)習(xí)了C語言中的兩個(gè)控制字符【
\n
】與【\r
】,知道了這兩者的作用及功能; - 緊接著我們又引出了緩沖區(qū)的概念,并且通過代碼的形式給大家具體的呈現(xiàn)了出來。知道了緩沖區(qū)是需要被刷新才會被顯示出來的;
- 有了以上知識點(diǎn)的鋪墊,我們通過設(shè)計(jì)的倒計(jì)時(shí)的功能給大家變相的總結(jié)了上文,并且對上述知識進(jìn)行了運(yùn)用;
- 最后,就是總結(jié)上文,之前的一切都是在給我們即將設(shè)計(jì)的 進(jìn)度條小程序做“背景板”。通過幾個(gè)方面的講述帶領(lǐng)大家對這個(gè)小程序進(jìn)行了實(shí)現(xiàn)。
以上就是本文的所有知識,感謝各位的支持?。?!
文章來源:http://www.zghlxwxcb.cn/news/detail-429713.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-429713.html
到了這里,關(guān)于【Linux】Linux第一個(gè)小程序-進(jìn)度條的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!