前言
已经学习了
linux
下基本工具的使用,现在来实践练习一下。
1.回车和换行
在Windows
下,我们认为回车换行是一个概念;但事实上,换行就是换到下一行的当前位置,而回车是回到当前行的开头位置。
我们之所以会认为回车和换行是一个概念,那是因为在我们使用\n
的时候,它做了回车和换行两个操作。
现在来看linux
下这样两段代码
cpp
#include<stdio.h>
int main()
{
printf("迟来的grown\n");
return 0;
}
cpp
#include<stdio.h>
int main()
{
printf("迟来的grown\n");
return 0;
}

可以看到\n
和\r
的不同,但运行结果就不一样,其中\r
就是表示回车;
那为什么\r
回车就没有显示出来结果呢?
这里就要了解缓冲区这个东西了。
缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。
我们可以大致理解为在输入输出时,并不是一个一个字符来进行的(部分特殊除外),这里是行缓冲区。
行缓冲:当输入和输出时,遇到换行符,才执行真正的
I/O
操作。这时我们输入的字符就会先存放在缓冲区,当按下回车键才进行实际的I/O
操作。典型的就是stdin
和stdout
。
行缓冲,输出时要遇到换行符才执行真正的输出;所以\r
回车,输出的内容就存放在了缓冲区,在程序结束时才清空缓冲区。
这里看两段代码
cpp
#include<stdio.h>
int main()
{
printf("迟来的grown\n");
sleep(3);
return 0;
}
cpp
int main()
{
printf("迟来的grown");
sleep(3);
return 0;
}
这里运行结果:(看到的)
- 第一段代码先输出了
迟来的grown
,然后再休眠了3
秒- 第二段代码休眠了
3
秒,在程序结束时才输出了迟来的grown
这两段代码的差别就是\n
,这也证明行缓冲区,遇到换行刷新缓冲区的内容。(在程序结束时,也会刷新缓冲区内容)
看到这里可能有疑问,既然程序结束后也会刷新缓冲区的内容,那为什么使用
\r
在程序结束后也没有输出结果啊?
这是因为linux
中它要输出命令行信息,在程序执行完之后,光标是在行开头的,命令行信息就覆盖了要输出的内容。
那我们能不能进行一些操作来看到要输出的内容呢?
当然是有的,我们可以使用fflush
来刷新缓冲区(stdout
)的内容。
cpp
int main()
{
printf("迟来的grown");
fflush(stdout);
sleep(3);
return 0;
}
以上代码运行结果
输出了迟来的grown
,再休眠了3
秒,最后程序结束;命令行信息将输出内容覆盖了。
2.倒计时程序
了解了
回车
和换行
,现在我们来简单些一个倒计时程序。
cpp
#include<stdio.h>
int main()
{
int count =10;
while(count)
{
printf("%-2d\r",count);
fflush(stdout);
count--;
sleep(1);
}
}
代码如上,这里可能出现的一些问题
- 输出时只覆盖了第一个数字:使用
%2d
/%-2d
,我们要让数字占两个数字(字符)的位置。- 程序运行不显示倒计时:使用
fflush
刷新缓冲区内容。
3.进度条程序
在进行编写第一个linux
程序------进度条
之前,我们先重温一下makefile
makefile
BIN=progress
SRC=$(shell ls *.c)
OBJ=$(SRC:.c=.o)
CC=gcc
RM= rm -rf
$(BIN):$(OBJ)
$(CC) -o $@ $^
%.o:%.c
$(CC) -c $<
.PHONY:
clean:
$(RM) $(OBJ) $(BIN)
- 首先
shell ls *.c
,获得当前目录下所有的.c
文件,可以使用wildcard *.c
。SRC:.c=.o
,将SRC
中所以的.c
后缀改为.o
。$@
和$^
,$@
是获取依赖文件列表,$^
获取目标文件。$<
,是将依赖文件列表拿出来逐个执行。
更加详细的make
/makefile
,深入了解Linux ------ make和makefile自动化构建工具_linux makeself-CSDN博客
好现在,我们正式开始写linux
下的第一个程序------进度条
先来看一下我们要实现的进度条是什么样的:
进度条程序

我们想要看到的进度条是,进度一直在增加,百分比一直在上涨,最后的方框内一直在转圈。
那该如何实现呢?
首先先来看一下需要写哪些文件

这里呢,写了四个文件
makefile
文件code.c
:程序主函数main
所在的文件progress.c
:进度条程序的代码源文件progress.h
:进度条程序的代码头文件
了解了这些,现在来看我们如何实现呢?
这里虽然我们看起来是进度条连续增加的,但是事实上就是一次一次输出的结果。
不知道你是否还记得在实现
贪吃蛇
小游戏的时候,我们就是一次次输出,来实现蛇的移动;这里也同理,我们依然一次次打印来达到我们预期的效果。
某一时刻进度条的输出
我们先来看某一时刻进度条是如何输出的;
假设现在我们正在下载一个软件,软件大小1024.00
MB ,我们当前下载了512.00
MB,那如何打印这一时刻的进度条呢?
cpp
void process()
{
double total = 1024.00;//下载总量
double current = 512.00;//当前下载量
int rate = (int)(current*100)/total;//进度条百分比,也是要打印`=`的数量
const char* str = "|-/\\";//表示最后方框内旋转的字符,最后一个\\转义字符
static int cnt =0;//表示当前应该那个字符,来转圈
char buff[101]={'\0'};
int i=0;
for(i=0;i<rate;i++)
{
buff[i]='=';
}
printf("[%-100s][%d%%][%c]\n",buff,rate,rate[cnt]);
}

可以看到在一时刻的进度条就已经成型了;那我们根据先已经写好的代码,来实现完整的进度条。
进度条实现
- 我们知道了这一时刻的进度条如何打印,那我们之间让
current
当前进度累加即可(这就涉及到一个速度问题)。- 还有一点,最后方框内如何让它转动起来
为了控制速度 ,我们既可以控制current
累加的值,当然也可以控制休眠时间usleep
。
为了控制方框内转动,我们定义一个静态常量,来决定应该输出哪一个字符。
具体代码如下
cpp
#include"progress.h"
#include<unistd.h>
#include<string.h>
#define NUM 101
#define CH '='
void process()
{
char buff[NUM];
memset(buff,0,sizeof(buff));
const char* str="|/-\\";
int len = strlen(str);
int cnt =0;
while(cnt<=100)
{
printf("[%-100s][%d%%][%c]\r",buff,cnt,str[cnt%len]);
fflush(stdout);
buff[cnt]=CH;
usleep(10000);
cnt++;
}
printf("\n");
}
这里curremt
增加量和usleep
休眠时间可以自行修改。
对于这个版本,感觉还是差点意思如果我们需要下载内容,大小不一,下载网速也不同,那该如何?
这个进度条我们只有修改这个函数内的数值才能控制进度条的快慢,我们还可以进行修改,通过传参来控制总量。
这里提供修改后的版本,细节就不详细讲解了。
当然这个版本也存在一些不足之处,有待提高。
code.c
cpp
#include"progress.h"
#define speed 1.0
void Download(double total)
{
double current=0;
while(current<=total)
{
Process(total,current);
usleep(6000);
current+=speed;
}
printf("\ndownload %lfMB Done\n",total);
}
int main()
{
//process();
Download(1024.00);
return 0;
}
progress.h
cpp
#include<stdio.h>
#include<unistd.h>
void Process(double total, double current);
progress.c
cpp
void Process(double total, double current)
{
char buff[NUM];
memset(buff,0,sizeof(buff));
const char* str = "|/-\\";
int len = strlen(str);
//当前进度
int num = (int)(current*100)/total;
int i=0;
for(i=0;i<num;i++)
{
buff[i]=CH;
}
static int cnt = 0;
cnt%=len;
printf("[%-100s][%d%%][%c]\r",buff,num,str[cnt]);
cnt++;
fflush(stdout);
}
*到这里本篇内容就结束了,希望对你有所帮助。
制作不易,感谢大佬的支持。
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws