文章目录
铺垫
回车换行
回车和换行是两个独立的动作
回车是将光标移动到当前行的最开始(最左侧)
换行是竖直向下平移一行
在C语言中,\n
是同时进行了回车换行,\r
实现了回车操作
缓冲区
概述
先来看一个小现象:
实例代码:
shell
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello gwj,hello Linux...\n");
sleep(3);
return 0;
}
运行mytest.exe
执行程序,会输出hello gwj,hello Linux...
,紧接着调用sleep
函数,休眠三秒
如果将printf
函数中\n
删掉,会出现什么结果呢??
现象:先休眠三秒,在最后结束的狮虎打印出内容
这这种场景中,sleep
函数和printf
函数,哪一个先运行的呢??
答案是printf
先运行,在休眠的这三秒时间里,printf
已经执行完了,字符串被保存在缓冲区
缓冲区的概念需要在操作系统层面上理解,单纯在语言基础上是很难理解的
缓冲区是一个内存空间,当休眠的时候,字符串在缓冲区里,当程序结束return 0
时,,强制冲刷缓冲区,再打印出字符串。
强制冲刷缓冲区
任何一个C语言程序都会默认打开三个流:
- stdin:标准输入流
- stdout:标准输出流
- stderr比爱准错错误
可以通过fflush
函数来刷新缓冲区
示例代码:
powershell
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello gwj,hello Linux...");
fflush(stdout);
sleep(3);
return 0;
}
现象:
简单实现倒计时功能
示例代码:
powershell
1 #include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 int cnt=9;
6 while(cnt>=0)
7 {
8 printf("%d\r",cnt);
9 fflush(stdout);
10 cnt--;
11 sleep(1);
12 }
13 return 0;
14 }
效果展示:
代码解读:
倒计时使用新数字去覆盖老数字,并且都出一同一位置,因此在printf
函数里不能使用\n
,使用换行会让新数字在老数字下面。
正确做法是在printf
函数后面使用\r
回车符号,每打印一个数字,让光标回到这一行最开始的位置,这样打印出来的新数字就会覆盖旧数字。
但是\r
不会冲刷缓冲区,因此每打印完一个数字调用 fflush(stdout)
来冲刷缓冲区。
进度条小程序
版本一
实例代码
Processbar.h
文件:
powershell
#pragma once
#include<stdio.h>
void ProcBar();
powershell
#include"Processbar.h"
#include<string.h>
#include<unistd.h>
#define Length 101
#define Style '#'
const char *lable="|/-\\";
//version1:
void ProcBar()
{
char bar[Length];
memset(bar,'\0',sizeof(bar));
int len=strlen(lable);
int cnt=0;
while(cnt<=100)
{
printf("[%-100s][%3d%%][%c]\r",bar,cnt,lable[cnt%len]);
fflush(stdout);
bar[cnt]=Style;
cnt++;
usleep(20000);
}
printf("\n");
}
效果展示
分析
该进度条的原理是一次比一次多打印一点内容、
定义一个bar
数组,通过循环,每次多打印一个字符,视觉上就会形成进度条是从右向左走
由于进度条每次打印是在同一行上,因此需要\r
符号,让光标回到最开始的位置
版本二
Processbar.h
文件:
powershell
#pragma once
#include <stdio.h>
typedef void(*callback_t)(double, double);
void ProcBar(double total, double current);
Main.c
文件:
powershell
void download(double filesize,callback_t cb)
{
double current = 0.0;
printf("download begin, current: %lf\n", current);
while(current <= filesize)
{
cb(filesize, current);
//从网络中获取数据
usleep(100000);
current += bandwidth;
}
printf("\ndownload done, filesize: %lf\n",filesize);
}
int main()
{
download(100*1024*1024,ProcBar);
download(2*1024*1024,ProcBar);
return 0;
}
Processbar.c
文件:
powershell
#include"Processbar.h"
#include<string.h>
#include<unistd.h>
#define Length 101
#define Style '#'
//version 2
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;
while(cnt <= loop_count)
{
bar[cnt++] = Style;
usleep(20000);
}
printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt%len]);
fflush(stdout);
}
效果展示: