前言:
? ? ? ? 在前面的文章中我們學習了LInux的基礎指令
? ? ? 【Linux】初見,基礎指令-CSDN博客【Linux】初見,基礎指令(續)-CSDN博客
? ? ? ? 學習了vim編輯器【Linux】vim編輯器_linux vim insert-CSDN博客
? ? ? ? 學習了gcc/g++【Linux】編譯器gcc/g++及其庫的詳細介紹-CSDN博客
? ? ? ? 以及make/makefile【Linux】自動化構建-Make/Makefile-CSDN博客
有了以上知識的鋪墊,我們終于可以開始在Linux上編寫運行我們的代碼,于是我們來到了Linux下的第一個程序:進度條
1.回車換行符?
? ? ? ?大多數人可能覺得"回車換行"這一詞指的是同一個東西。但其實回車是回車、換行是換行,這兩個有本質區別。
????????我們日常使用的回車鍵合成了"回車"和"換行"功能,這就導致了大家覺得這是一個東西。
回車的符號為:\n
回車的功能是將光標重置到最開始位置
換行的符號為:\r?
換行的功能是將光標下移一行
2.緩沖區問題
什么是緩沖區?
????????緩沖區是系統預留的內存區域,其作用是暫時存放輸入或輸出的數據。引入緩沖區主要是為了平衡高速的 CPU 與低速的 I/O 設備之間的速度差異,進而提升系統的整體性能。
刷新緩沖區?
????????通常情況下,數據會先被存儲在緩沖區中,只有當緩沖區滿、遇到特定的控制字符,或者程序運行結束時,才會將數據真正寫入目標設備。不過,在某些特定場景下,可能需要手動刷新緩沖區,以確保數據能及時輸出。
舉例:
//代碼1
#include<stdio.h>
#include<unistd.h>
int main()
{printf("hello\n"); sleep(3);
}//代碼2
#include<stdio.h>
#include<unistd.h>
int main()
{ printf("hello");sleep(3);
}
運行代碼1:我們可以看到顯示屏上馬上顯示出"hello",然后停滯3秒結束程序
運行代碼2:我們看到是恰恰相反,先停滯3秒后打印出"hello",然后結束程序
這個就是緩沖區的問題:"\n"可以馬上刷新緩沖區,所以代碼1可以馬上顯示。而沒有"\n",就無法馬上刷新緩沖區,當整個程序結束后系統自動刷新,顯示"hello"
那如何使其馬上刷新?
fflush(stdout)
3.預備代碼
先創建文件夾,并在文件夾中創建相應的.c .h文件
hyc@hcss-ecs-4ce7:~$ mkdir progress
hyc@hcss-ecs-4ce7:~$ cd progress
hyc@hcss-ecs-4ce7:~/progress$ touch p.c p.h main.c
編寫代碼,與makefile。進度條只會在一行打印,所以我們不能使用 \n,而是使用 \r,在同一行打印
但是當我們運行代碼時,發現并沒有顯示結果。這是因為當前數據還在緩沖區沒有刷新出來,我們使用ffulsh(stdout)使其馬上刷新
這時我們可以看到結果:在同一位置上顯示
4.進度條代碼
4.1首先先看看我們想實現一個什么樣子的進度條
4.2代碼實現?
我們一步一步來,先實現左側部分
1.考慮使用字符數組來表示遞增的進度條。先將字符數組初始化為 ‘\0’,通過%s打印時遇到 ‘\0’就會停止。
2.通過計數器計數,來計算輸出多少符號
3.通過fflush(stdout)立馬刷新緩沖區,讓我們看到結果
4.通過sleep讓我們看到其過程
5.最后為了避免命令行覆蓋我們輸出的內容,進行換行操作
最后添加一下左右中括號,修改一下細節問題:
打印進度條使用%-100s占位符
sleep有點太慢了,我們可以使用usleep
#include"p.h"
#include<unistd.h>
#include<string.h>void progress_v1()
{char arr[101];memset(arr,'\0',sizeof(arr));int num=0;for(int i=0;i<=101;i++){ arr[num]='X';printf("[%-100s]\r",arr);fflush(stdout);usleep(10000);num++;} printf("\n");
}
效果:
接下來我們就可以來考慮一下百分比和旋轉光標了
1.百分比直接去計算就好了,沒什么好說的。
2.旋轉光標:我們不要去想復雜了,動態的本質其實就是一幀一幀的靜態圖像,我們只需要寫一個字符數組x,然后不斷的打印字符,就可以實現旋轉光標了。?
#include<stdio.h>
#include<unistd.h>
#include<string.h>void progress_v1()
{char arr[101];char x[]={'/','-','\\','\0'};memset(arr,'\0',sizeof(arr));int num=0;for(int i=0;i<=101;i++){ arr[num]='X';printf("[%-100s][%.2f][%c]\r",arr,num*1.0/sizeof(arr)*100,x[num%3]);fflush(stdout);usleep(10000);num++;} printf("\n");
}
效果演示:
5.模擬真實環境
一個真正的進度條不可能就我們上面寫的代碼一樣自顧自的打印。應該是根據實際情況,一邊下載(或其他操作),一邊打印進度條。
于是我們實現一個download函數模擬實時下載環境:?
total:表示一共想要下載的量
speed:表示單次下載的速度
每下載一次就更新一次進度條
通過實時的下載量來計算進度條中需要打印的個數,以及百分比。?
代碼匯總:?
//p.h#include<stdio.h>
void progress_v1();
void progress_v2(double cur,double total); //p.c#include"p.h"
#include<unistd.h>
#include<string.h>void progress_v1()
{char arr[101];char x[]={'/','-','\\','\0'};memset(arr,'\0',sizeof(arr));int num=0;for(int i=0;i<=101;i++){arr[num]='X';printf("[%-100s][%.2f][%c]\r",arr,num*1.0/sizeof(arr)*100,x[num%3]);fflush(stdout);usleep(10000);num++;} printf("\n");
}void progress_v2(double cur,double total)
{char arr[101];char x[]={'/','-','\\','\0'};memset(arr,'\0',sizeof(arr));//get the numberint num=(int)(cur*100/total);for(int i=0;i<num;i++){ arr[i]='X';} printf("[%-100s][%.2f][%c]\r",arr,cur*100/total,x[num%3]);fflush(stdout);
}//main.c#include <stdio.h>
int main()
{printf("Hello world\n");return 0;
}