【Linux】编写第一个小程序:进度条

文章目录

  • 1. 预备知识
    • 1.1 简单认识几个函数
      • 1.1.1 sleep()
      • 1.1.2 fflush()
      • 1.1.3 usleep()
      • 1.1.4 memset()
    • 1.2 缓冲区
    • 1.3 回车与换行
  • 2. 编写入门版的进度条
    • 2.1 基本逻辑
    • 2.2 美化效果
    • 2.3 代码实现
    • 2.4 执行效果
  • 3. 编写升级版的进度条
    • 3.1 代码实现
    • 3.2 执行效果

在这里插入图片描述

1. 预备知识

1.1 简单认识几个函数

1.1.1 sleep()

unsigned int sleep(unsigned seconds);
  • 作用:让程序休眠指定秒数,如:sleep(3); //让程序休眠3秒
  • 与 Windows 上的 Sleep() 函数不同
  • 需要包含头文件<unistd.h>

1.1.2 fflush()

int fflush(FILE* stream);
  • 作用:刷新缓冲区
  • 需要传入一个流
  • 需要包含头文件<stdio.h>

1.1.3 usleep()

int usleep(useconds_t usec);
  • 作用:让程序休眠指定微秒,如:usleep(100000); //让程序休眠100000微秒(0.1秒)
  • 1秒 = 1000000微秒
  • 需要包含头文件<unistd.h>

1.1.4 memset()

void* memset(void* ptr, int value, size_t num);
  • 作用:将 ptr 指向的内存块的前 num 个字节设置为指定的 value 值
  • 返回设置后的 ptr
  • 需要包含头文件<string.h>

1.2 缓冲区

直接上代码观察现象

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

int main()
{
    printf("you can see me       ");
    sleep(3);
    return 0;
}

执行效果图

在这里插入图片描述

  • 首先要否定上面不切实际的想法,C语言是顺序执行的,所以 printf 函数一定先于 sleep 函数执行。
  • 那为什么 3 秒后才打印到屏幕上呢?当然是因为缓冲区!
  • printf 函数跑完后,输出的字符串是被保存到 C 对 IO 函数提供的一个缓冲区里了,在程序退出的时候,缓冲区中的内容才被刷新到屏幕上
  • 我们需要使用上面讲的 fflush 函数把缓冲区中的内容提前强制刷新到屏幕上,使用方法:fflush(stdout);

1.3 回车与换行

首先我要抛出一个概念:回车和换行是不一样的!

  • 回车( \r ):把光标放到当前行的开始。

在这里插入图片描述

  • 换行( \n ):把光标放到当前位置的下一行。

在这里插入图片描述

  • 所以理论上来讲,‘\n’ 和 ‘\r’ 一起用才是我们理解中的”回车“,即:把光标放到下一行最开始的位置。

2. 编写入门版的进度条

2.1 基本逻辑

  • 进度 1% 打印 1 个字符,回车到开始的位置,刷新缓冲区;
  • 进度 2% 打印 2 个字符,回车到开始的位置,刷新缓冲区;
  • 进度 100% 打印 100 个字符,回车到开始的位置,刷新缓冲区,程序终止。

在这里插入图片描述

2.2 美化效果

  • 进度条主体增加箭头显示
  • 显示进度百分比
  • 添加一个动态的旋转光标

在这里插入图片描述

2.3 代码实现

// porcessbar.h

#pragma once

#include <stdio.h>

#define NUM 103
#define Body '='
#define Head '>'

// version 1
void process();
// processbar.c

#include "processbar.h"
#include <string.h>
#include <unistd.h>

const char* lable = "|/-\\";

// version 1
void process()
{
    char buffer[NUM];
    memset(buffer, '\0', sizeof(buffer));
    int cnt = 0;
    int n = strlen(lable);
    buffer[0] = Head;
    while (cnt <= 100)
    {
        printf("[%-100s][%3d%%][%c]\r", buffer, cnt, lable[cnt % n]);
        fflush(stdout);
        buffer[cnt++] = Body;
        if (cnt < 100)
        {
            buffer[cnt] = Head;
        }
        usleep(50000);
    }
    printf("\n");
}

2.4 执行效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3. 编写升级版的进度条

  • 上面的进度条算是一个进度条吗?我们的进度条似乎在一个人玩单机呀,这样的进度条是没有意义的。
  • 进度条的进度应该是依赖于其他应用的,比如下载。
  • 下面我们模拟一个下载环境,并修改进度条,使进度条可以根据下载的进度,同步进行显示进度的工作。

3.1 代码实现

// processbar.h

#pragma once

#include <stdio.h>

#define NUM 103
#define Body '='
#define Head '>'

typedef void (*callback_t)(double);		// 函数指针类型

// version 2
void process_flush(double rate);
// processbar.c

#include "processbar.h"
#include <string.h>
#include <unistd.h>

const char* lable = "|/-\\";

// version 2: 进度是多少,你进度条能知道吗?另外,什么进度?依附于其他应用的,比如下载
char buffer[NUM] = {0};
void process_flush(double rate)
{
    static int cnt = 0;
    int n = strlen(lable);
    if (rate <= 1.0)
    {
        buffer[0] = Head;
    }
    printf("[%-100s][%.1f%%][%c]\r", buffer, rate, lable[cnt % n]);
    fflush(stdout);

    buffer[(int)rate] = Body;
    if ((int)rate + 1 < 100)
    {
        buffer[(int)(rate + 1)] = Head;
    }
    if (rate >= 100.0)
    {
        printf("\n");
    }

    cnt++;
    cnt %= n;
}
// main.c

#include "processbar.h"
#include <time.h>
#include <stdlib.h>
#include <unistd.h>

// 模拟文件大小
#define FILESIZE (1024 * 1024 * 1024)

// 模拟一种场景,表示一种下载任务
void download(callback_t cb)    // 回调函数的形式
{
    srand(time(NULL) ^ 1023);   // 这样写只是为了让随机数更随机
    int total = FILESIZE;
    while (total)
    {
        usleep(10000);  // 下载动作
        int one = rand() % (1024 * 1024);  // 一次下载的大小
        total -= one;
        if (total < 0)
        {
            total = 0;
        }

        // 当前的进度是多少?
        int download = FILESIZE - total;
        double rate = (download * 1.0 / FILESIZE) * 100.0;
        cb(rate);
    }
}

int main()
{
    download(process_flush);
    return 0;
}

3.2 执行效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/314306.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++每日一练(15):简单幂计算

题目描述 输入两个数a和b&#xff0c;求a的b次方。 输入 输入两个整数a&#xff0c;b&#xff08;1<a<10&#xff0c;1<b<15&#xff09;。 输出 输出一个正整数&#xff0c;该值<1000000000000。 输入样例 3 3 输出样例 27 参考答案 #include<bits/stdc.h&…

企业级iptalbes防火墙

一、IPtables介绍 Iptables是unix/linux自带的一款开源的基于包过滤(对OSI模型的四层或者是四层以下进行过滤)的防火墙工具&#xff0c;它的功能十分强大&#xff0c;可以对流入和流出服务器的数据包进行很精细的控制。 iptables其实并不是真正的防火墙&#xff0c;我们可以把…

【AI绘画】全网最强midjourney使用方法!新手必收藏!!

手把手教你入门绘图超强的AI绘画程序Midjourney&#xff0c;用户只需要输入一段图片的文字描述&#xff0c;即可生成精美的绘画。下面是Midjourney注册和使用的方法。给大家带来了全新保姆级教程资料包**&#xff08;文末可获取&#xff09;** 第一步&#xff1a; 先注册一个D…

10 sping核心技术验证(Validation) 数据绑定(Data Binding)

Validation Spring提供了一个Validator接口&#xff0c;您可以使用它来验证对象。Validator接口通过使用Errors对象来工作&#xff0c;以便在进行验证时&#xff0c;验证器可以向Errors对象报告验证失败public class Person {private String name;private int age;// the usua…

代码随想录算法训练营第三天| LeetCode203.移除链表元素、707.设计链表、206.反转链表

文章目录 一、203. 移除链表元素感受代码二、707.设计链表感受代码206.反转链表感受总结一、203. 移除链表元素 感受 我对这道题。从理论上来说太熟悉了。咸鱼讲数据结构常用的方法他都会讲。但是我没上机没写过。到后面上机还是写不出来。giao。 代码 第一次写,想说一下,…

Blazor中使用impress.js

impress.js是什么&#xff1f; 你想在浏览器中做PPT吗&#xff1f;比如在做某些类似于PPT自动翻页&#xff0c;局部放大之类&#xff0c;炫酷无比。 官方示例直接放到Blazor中是不可用的。几经尝试&#xff0c;用以下方法可以实现。 &#xff08;写文不易&#xff0c;请点赞、…

Java常用类---日期时间类

日期时间类 Date类 简介 在Java中&#xff0c;Date类用来封装当前的日期和时间。Date类提供两个构造函数来初始化对象&#xff0c;如下所示。 通过Date() 使用当前日期和时间来初始化对象。 通过Date(long millisec) 来初始化对象&#xff0c;其中的参数是从1970年1月1日起…

RS触发器

转自&#xff1a;【基础】RS触发器_两个或非门构成rs触发器-CSDN博客 RS触发器为什么能 “保持上一状态” 触发器就是在常规的门电路的基础上加入了反馈&#xff0c;这样触发器就实现了存储数据的功能。这也是上面章节 “RS触发器实验” 的 RS触发器特征表 中第3条 “保持上一…

Redis的优化

1 Redis的高可用 1.1 高可用的定义 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&…

mat数据格式转png

目的 将多个.mat数据格式转化成多个文件夹下的png图片格式 即 一个PAT.mat文件&#xff0c;生成一个PAT文件夹下的图片 方法 1 单文件处理 import scipy.io as scio from PIL import Image import numpy as npdef MatrixToImage(data):data data*255new_im Image.fromarray…

windos exe 以服务的形式运行(开机运行)

windos 品台编写的 小工具 exe 或者 批处理 .bat 经常需要开机自启动&#xff0c;可以直接把它 加在开启启动项&#xff0c;或者做成 windos服务&#xff0c;这样既可以开机自动启动而且还可以 防止误触关闭掉&#xff1b; windos 以服务启动 exe/bat 的通用方式&#xff1…

Word不同部分(分节)设置页眉和页码的使用指南——附案例操作

Word页眉和页码分节设置的使用指南 目录 Word页眉和页码分节设置的使用指南摘要1. 插入分节符2. 设置不同的页眉3. 设置不同的页码4. 调整页码的起始值5. 删除或更改分节6. 预览和调整 摘要 在撰写word文档时&#xff0c;我们经常需要在不同的部分应用不同的页眉和页码格式。在…

androj studio安装及运行源码

抖音教学视频 目录 1、 jdk安装 2、下载安装androj studio 3 、打开源码安装运行相关组件 4、 安装模拟器 1、 jdk安装 安卓项目也是java开发的&#xff0c;运行在虚拟机上&#xff0c;安装jdk及运行的时候&#xff0c;就会自动生成虚拟机&#xff0c; jdk前面已经讲过&…

宏景eHR 多处 SQL注入漏洞复现

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR view、trainplan_tree.jsp等接口处存在SQL注入漏洞,未经过身份认证的远程攻击者可利用此漏洞执行任意SQL指令,从而窃…

C++力扣题目106,105--中序和后序,前序和中序遍历构造二叉树

106.从中序与后序遍历序列构造二叉树 力扣题目链接(opens new window) 根据一棵树的中序遍历与后序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如&#xff0c;给出 中序遍历 inorder [9,3,15,20,7]后序遍历 postorder [9,15,7,20,3] 返回如下的二叉树&am…

从无到有制作docker镜像、容器详细步骤

1、编写一个Dockerfile文件&#xff0c;内容如下 # 基础镜像jdk,jdk里包含里操作系统 FROM openjdk:8u282-jdk# 工作目录&#xff0c;也就是容器里目录 WORKDIR /home/prq/# 添加ppp目录下的文件到容器/home/prq/里 ADD ./ppp /home/prq/# 暴露端口8080 EXPOSE 8080# 启动脚本…

红黑树之概述

红黑树 R-B Tree&#xff0c;全称是 Red-Black Tree&#xff0c;又称为“红黑树”&#xff0c;它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色&#xff0c;可以是红(Red)或黑(Black)。 红黑树的特性 &#xff08;1&#xff09;每个节点或者是黑色&…

从DETR到Mask2Former(1):DETR-segmentation结构全解析

网上关于DETR做的detection的解析很多&#xff0c;但是DETR做Segmentation的几乎没有&#xff0c;本文结合DETR的论文与代码&#xff0c;对DETR做一个详细的拆解。理解DETR是理解Mask2Former的基础。 首先得把DETR-segmentation给run起来。Github上DETR的repository&#xff0…

日常工作中,软件测试人员如何避免“背锅”

作为一名软件测试工程师&#xff0c;日常工作中最常打交道的肯定就是开发和产品经理。有沟通就会问题&#xff0c;有问题难免会有争执。那么你肯定听过这些话&#xff1a; “这么弱智的bug你都测不出来吗&#xff1f;” “为啥这个功能还没测完就上线了&#xff1f;” “研发…

AI生成APP工具推荐:5款让你惊艳的AI应用

在这个数字化、智能化的时代&#xff0c;人工智能(AI)已经深入到我们生活的方方面面。其中&#xff0c;AI生成APP工具更是以其强大的创意和生成能力&#xff0c;成为自媒体人和设计师们的得力助手。本文将为你介绍五款实用的AI生成APP工具&#xff0c;它们将为你的创意打开无限…