【Linux系统】Linux入门系统程序−进度条


一、铺垫知识

1.回车符 和 换行符的区别

回车符’\r’ 的效果(让光标回到当前行开头) 和 换行符’\n’ 理论上的效果(把光标移动到下一行同一位置):
在这里插入图片描述
但实际上单纯的换行作用意义不大,所以在语言层面上,当你单独使用 ‘\n’ 时,它会同时执行回车 + 换行的效果。结论,在语言层面上,使用 ‘\n’ 或 "\r\n"的效果一模一样。
在这里插入图片描述

2.用户缓冲区问题

  1. 执行以下代码观察现象:
#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello world");
    sleep(2);
    return 0; 
}

现象:大约2s后,“hello world” 才被打印到屏幕上。
为什么会出现这种奇怪的现象,代码不是按顺序执行的吗?不应该是先执行printf函数打印,再执行sleep函数休眠吗?

分析:代码肯定是按顺序执行的,出现这种现象实际与用户缓冲区有关。在打印函数与显示器文件之间有一个缓冲区,叫用户缓冲区,printf函数实际上也并不什么打印函数,更确切的说它应该是一种拷贝函数,它会把字符串内容拷贝到用户缓冲区,而当用户缓冲区刷新的时候,用户缓冲区中的内容才会被拷贝到显示器文件(内容被拷贝到显示器文件,用户就能看到内容被打印到显示器的效果)。

用户缓冲区的刷新策略(一般来说是按照行刷新):
(1)遇到 ‘\n’,就会把 ‘\n’ 前的所以内容刷新到显示器文件
(2) 程序结束时,会把用户缓冲区的所有内容刷新到显示器文件

现象解释:printf函数把 “hello world” 拷贝到用户缓冲区中,接着执行sleep函数休眠2s后程序结束,程序结束时用户缓冲区中的所有内容会被刷新到显示器文件。

补充:
sleep函数:让程序休眠指定秒数再向后执行

在这里插入图片描述

  1. 验证第一种用户缓冲区刷新策略:
#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello world\n"); // 在结尾加上'\n'换行符
    sleep(2);
    return 0; 
}

现象:“hello world\n” 瞬间被打印到屏幕上,大约等待2s后程序结束。

结论:字符串结尾加上’\n’之后,字符串内容瞬间就刷新到显示器文件,而不是等待2s程序结束时才刷新,这证明了第一种刷新策略是正确有效的。

  1. 实际上除了前面两种用户缓冲区的刷新策略之外,系统还为用户提供了一种强制刷新缓冲区的函数:
    在这里插入图片描述

fflush函数可以强制将用户缓冲区中的内容刷新到显示器文件,
使用方法:fflush(stdout)

C程序在启动的时候,默认打开了3个流:
• stdin - 标准输入流,指键盘文件
• stdout - 标准输出流,指显示器文件
• stderr - 标准错误流

代码验证:

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello world"); // 字符串结尾没加 '\n'
    fflush(stdout);
    sleep(2);
    return 0; 
}

现象:“hello world\n” 瞬间被打印到屏幕上,大约等待2s后程序结束。

结论:字符串结尾没加’\n’,字符串内容还是能瞬间就刷新到显示器文件,这证明fflush函数可以强制将用户缓冲区中的内容刷新到显示器文件。

二、进度条程序初版(含视频演示效果)

main.c:

#include "progress.h"

int main()
{
    progress();
    return 0;
}

progress.h:

#pragma once
#include <stdio.h>
#include <unistd.h>

void progress();

progress.c(进度条函数实现):

#include "progress.h"

void progress()
{
    char bar[101] = {'\0'};
    const char* cnt = "|/-\\"; // '\\'是一个转义字符,⽤于表示⼀个反斜杠,防止它被解释为⼀个转义序列符
    int count = 0;
    while(count<=100)
    {
        printf("[%-100s][%-3d%%][%c]\r",bar,count,cnt[count%4]);
        fflush(stdout);
        usleep(50000);
        bar[count] = '#';
        count++;
    }
    printf("\n");
}

视频演示进度条程序初版代码运行效果(链接: 进度条初版

补充:
usleep函数:让程序休眠指定微秒数再向后执行
这里是引用

三、进度条程序(加入使用场景)

main.c(模拟下载软件的使用场景:下载函数):

#include "progress.h"

void download(double total,double speed) // total:软件总大小;speed:下载速度
{
    double current_total = 0.0;
    while(current_total<=total)
    {
        progress(current_total,total);
        usleep(10000); // 每隔10000微秒进行一次下载
        current_total += speed; // 每次下载,进度增加一个下载速度
    }
    printf("\n");
}

int main()
{
    printf("程序下载中:\n");
    download(1024.0,2.0);
    return 0;
}

progress.h:

#pragma once
#include <stdio.h>
#include <unistd.h>

void progress(double,double);

progress.c(进度条函数:进度条不会一次性走完,每次调用进度条函数会打印出当前下载进度):

#include "progress.h"

void progress(double current,double total) 
{
    double cur_progress = current/total*100; // 计算出当前进度
    char bar[101] = {'\0'};
    int bar_count = (int)cur_progress;
    for(int i = 0;i < bar_count;i++)
        bar[i] = '#';
    const char* cnt = "|/-\\";
    static int count = 0;
    printf("[%-100s][%.1lf%%][%c]\r",bar,cur_progress,cnt[count%4]);
    fflush(stdout);
    count++;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值