赞
踩
回车(Carriage Return,CR):
- 在早期的机械打字机中,回车指的是将打字机的打印头移回到行首的操作,这样打印头就可以开始新的一行的打印。
- 在ASCII编码中,回车用控制字符CR表示,其编码为
\r
(即十进制的13)。换行(Line Feed,LF):
- 换行是指将打印头向下移动到下一行的操作。
- 在ASCII编码中,换行用控制字符LF表示,其编码为
\n
(即十进制的10)。即:回车,回到当前行的行首,不会切换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖;
换行,换到当前位置的下一行,而不会回到行首。
在Windows系统中,文本文件的换行符通常是回车加换行(CR+LF,即\r\n
)。而在Unix/Linux系统中,换行符仅仅是LF(\n
)(Unix/Linux下这个\n
就就包括了回车和换行)。
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world!");
sleep(3);
return 0;
}
在linux下编译运行以上代码,发现在前三秒"hello world!"并未被打印到屏幕上,三秒之后被打印到屏幕上。那么此前三秒,它被储存到了那里呢?
答案是缓冲区,缓冲区(Buffer)主要应用于提高系统性能和效率。缓冲区通常指的是内存中的一段连续区域,用于临时存储数据,减少CPU、内存和外部设备(如硬盘、网络等)之间的交互次数。当应用程序向文件或设备进行读写操作时,数据会首先被存储到缓冲区中,然后再由缓冲区根据特定的刷新策略将数据写入磁盘或设备中。
缓冲区被刷新到显示器上的几种方式:
- 程序结束的时候,一般要自动冲刷缓冲区
\n
- 缓冲区满了,自动刷新
fflush()
函数强制刷新
此文件夹下新建一个makefile
文件:
processbar: Main.c Processbar.c
gcc -o $@ $^ //选项 -o $@ 指定输出文件名,其中 $@ 是一个自动变量,代表当前规则的目标(在这里即为processbar)。而 $^ 是另一个自动变量,表示所有依赖文件的集合(即Main.c和Processbar.c)
.PHONY: clean
clean:
rm -f processbar
这是一个用于将Main.c
和Processbar.c
源文件编译并链接成名为processbar
的可执行文件的简单Makefile
。
这个Makefile
提供了两种操作:
1.运行make processbar
以编译并链接Main.c
和Processbar.c
源文件,生成processbar
可执行文件。
2.运行make clean
以删除processbar可执行文件,清理项目构建产物。
进度条代码版本一:(仅仅是进度条的模拟)
#include <string.h> #include <unistd.h> #include<stdio.h> #define Length 101 #define Style '#' //进度条填充样式为'#'字符 const char* lable="|/-\\"; //在进度条前方显示动画效果 void ProcBar(); ////version 1 void ProcBar() { char bar[Length]; //进度条的显示长度 memset(bar,'\0',sizeof(bar)); //先初始化为'\0'填充清零 int len=strlen(lable); int cnt=0; while(cnt<=100) //使用循环结构,从0迭代到100,每次迭代表示进度的1% { printf("[%-100s][%-3d%%][%c]\r",bar,cnt,lable[cnt%len]); //用回车并不是换行,每次打印进度条都从当前行头部开始打印 fflush(stdout); //强制刷新标准输出缓冲区,确保进度条立刻显示在屏幕上 bar[cnt++]=Style; //进度条数组bar的相应位置添加进度样式字符 usleep(200000); //用于休眠一段时间,模拟任务执行过程。(休眠单位为微秒) } printf("\n"); } int main() { ProcBar(); return 0; }
这段C语言代码实现了一个简单的进度条功能,用于模拟某个长时间运行的任务(如文件下载、处理任务等)的进度展示。
效果演示:
进度条代码版本二:(模拟一个下载任务,根据下载任务的进度打印进度条)
#include <string.h> #include <unistd.h> #include<stdio.h> #define Length 101 #define Style '#' //进度条填充样式为'#'字符 const char* lable="|/-\\"; //在进度条前方显示动画效果 void ProcBar(); ////version 2 ////配合场景使用 //进度条每执行一次循环就刷新一次,会出现闪烁(我还挺喜欢这个的) void ProcBar(double total, double current) //total代表总任务量(即文件大小),current代表当前已完成的任务量(即已下载的数据量) { char bar[Length]; memset(bar, '\0', sizeof(bar)); int len = strlen(lable); int cnt = 0; double rate = (current * 100.0) / total; int loop_count = (int)rate; //计算进度百分比rate和对应的循环次数loop_count while (cnt <= loop_count) { printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt % len]); fflush(stdout); bar[cnt++] = Style; //usleep(200000); //这个也不需要了,在另一个调它的函数download()中有 } //printf("\n"); } //模拟下载单个文件 void download() { double filesize = 100 * 1024 * 1024 * 1.0; // 文件大小100兆 double current = 0.0; // 当前下载量 double bandwidth = 1024 * 1024 * 1.0; // 网络带宽1兆 printf("download begin, current: %lf\n", current); while (current <= filesize) //使用一个循环来模拟下载过程,每次迭代都更新current的值,并调用ProcBar函数来更新和显示进度条。 { // 打印进度条 ProcBar(filesize, current); // 从网络获取数据 current += bandwidth; usleep(10000); //模拟网络下载的速度 } printf("\ndownload complete! filesize:%lf\n", filesize); } int main() { // 下载测试(模拟单个文件下载) // download(); return 0; }
这段代码实现了一个简单的进度条功能(ProcBar())和一个模拟单个文件下载的函数(download())。实际使用时,只需将download()中的相关参数替换为实际的下载信息,并调用此函数即可在控制台显示下载进度。
效果演示:
进度条代码版本三:(模拟多个下载任务,根据下载任务的进度打印进度条)
#include <string.h> #include <unistd.h> #include<stdio.h> #define Length 101 #define Style '#' //进度条填充样式为'#'字符 const char* lable="|/-\\"; //在进度条前方显示动画效果 typedef void(*callback_t)(double,double); //函数指针 void ProcBar(); //闪烁版 //void ProcBar(double total, double current) //total代表总任务量(即文件大小),current代表当前已完成的任务量(即已下载的数据量) //{ // char bar[Length]; // memset(bar, '\0', sizeof(bar)); // int len = strlen(lable); // // int cnt = 0; // double rate = (current * 100.0) / total; // int loop_count = (int)rate; //计算进度百分比rate和对应的循环次数loop_count // // while (cnt <= loop_count) // { // printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt % len]); // fflush(stdout); // bar[cnt++] = Style; // //usleep(200000); //这个也不需要了,在另一个调它的函数download()中有 // } // // //printf("\n"); //} // version 3 // 配合场景使用 // 每次调用函数时直接将bar拼接起来,循环执行完后再刷新,这样就不会出现闪烁 void ProcBar(double total, double current) { char bar[Length]; memset(bar, '\0', sizeof(bar)); int len = strlen(lable); int cnt = 0; double rate = (current * 100.0) / total; int loop_count = (int)rate; //计算进度百分比rate和对应的循环次数loop_count while (cnt <= loop_count) { bar[cnt++] = Style; } // 填充完成后,一次性打印出完整的进度条,并刷新输出,避免了闪烁现象 printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt % len]); fflush(stdout); } //此版本进度条与之前版本不同的是,它在循环中先将进度条字符逐个拼接到bar数组中,待循环完成后一次性刷新输出,从而避免了进度条的闪烁现象。 // 模拟下载多个文件 double bandwidth = 1024 * 1024 * 1.0; // 网络带宽1兆 void download(double filesize, callback_t cb) // 此处用函数指针也很方便 { double current = 0.0; // 当前下载量 printf("download begin, current: %lf\n", current); while (current <= filesize) //使用一个循环来模拟下载过程,每次迭代都更新当前下载量current,并调用回调函数cb来更新和显示进度条 { cb(filesize, current); // 从网络获取数据 current += bandwidth; usleep(10000); //模拟下载速度时,每次迭代都增加bandwidth(网络带宽)的值到current,并使用usleep函数来模拟网络延迟 } printf("\ndownload complete! filesize:%lf\n", filesize); } int main() { // 多个文件下载测试 download(200 * 1024 * 1024, ProcBar); download(400 * 1024 * 1024, ProcBar); download(50 * 1024 * 1024, ProcBar); download(10 * 1024 * 1024, ProcBar); return 0; }
这段C代码通过定义一个进度条更新函数ProcBar和一个模拟下载函数download,实现了在控制台中展示动态进度条的功能,并模拟了多个文件的下载过程。通过回调函数的使用,使得download函数可以灵活地与不同的进度条更新函数配合使用。
效果演示:
闪烁版演示效果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。