初识Linux —— 第一个程序(进度条)

初识Linux —— 第一个程序(进度条)

前言

已经学习了linux下基本工具的使用,现在来实践练习一下。

1.回车和换行

Windows下,我们认为回车换行是一个概念;但事实上,换行就是换到下一行的当前位置,而回车是回到当前行的开头位置。

我们之所以会认为回车和换行是一个概念,那是因为在我们使用\n的时候,它做了回车和换行两个操作。

现在来看linux下这样两段代码

#include<stdio.h>intmain(){printf("迟来的grown\n");return0;}
#include<stdio.h>intmain(){printf("迟来的grown\r");return0;}
在这里插入图片描述

可以看到\n\r的不同,但运行结果就不一样,其中\r就是表示回车;

那为什么\r回车就没有显示出来结果呢?

这里就要了解缓冲区这个东西了。

缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。

我们可以大致理解为在输入输出时,并不是一个一个字符来进行的(部分特殊除外),这里是行缓冲区。

行缓冲:当输入和输出时,遇到换行符,才执行真正的I/O操作。这时我们输入的字符就会先存放在缓冲区,当按下回车键才进行实际的I/O操作。典型的就是stdinstdout

行缓冲,输出时要遇到换行符才执行真正的输出;所以\r回车,输出的内容就存放在了缓冲区,在程序结束时才清空缓冲区。

这里看两段代码
#include<stdio.h>intmain(){printf("迟来的grown\n");sleep(3);return0;}
intmain(){printf("迟来的grown");sleep(3);return0;}

这里运行结果:(看到的)

第一段代码先输出了迟来的grown,然后再休眠了3秒第二段代码休眠了3秒,在程序结束时才输出了迟来的grown

这两段代码的差别就是\n,这也证明行缓冲区,遇到换行刷新缓冲区的内容。(在程序结束时,也会刷新缓冲区内容)

看到这里可能有疑问,既然程序结束后也会刷新缓冲区的内容,那为什么使用\r在程序结束后也没有输出结果啊?

这是因为linux中它要输出命令行信息,在程序执行完之后,光标是在行开头的,命令行信息就覆盖了要输出的内容。

那我们能不能进行一些操作来看到要输出的内容呢?

当然是有的,我们可以使用fflush来刷新缓冲区(stdout)的内容。

intmain(){printf("迟来的grown");fflush(stdout);sleep(3);return0;}

以上代码运行结果

输出了迟来的grown,再休眠了3秒,最后程序结束;命令行信息将输出内容覆盖了。

2.倒计时程序

了解了回车换行,现在我们来简单些一个倒计时程序。
#include<stdio.h>intmain(){int count =10;while(count){printf("%-2d\r",count);fflush(stdout); count--;sleep(1);}}

代码如上,这里可能出现的一些问题

输出时只覆盖了第一个数字:使用%2d/%-2d,我们要让数字占两个数字(字符)的位置。程序运行不显示倒计时:使用fflush刷新缓冲区内容。

3.进度条程序

在进行编写第一个linux程序——进度条之前,我们先重温一下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 *.cSRC:.c=.o,将SRC中所以的.c后缀改为.o$@$^$@是获取依赖文件列表,$^获取目标文件。$<,是将依赖文件列表拿出来逐个执行。

更加详细的make/makefile深入了解Linux —— make和makefile自动化构建工具_linux makeself-ZEEKLOG博客

好现在,我们正式开始写linux下的第一个程序——进度条

先来看一下我们要实现的进度条是什么样的:

进度条程序

在这里插入图片描述

我们想要看到的进度条是,进度一直在增加,百分比一直在上涨,最后的方框内一直在转圈。

那该如何实现呢?

首先先来看一下需要写哪些文件

在这里插入图片描述
这里呢,写了四个文件makefile文件code.c:程序主函数main所在的文件progress.c:进度条程序的代码源文件progress.h:进度条程序的代码头文件

了解了这些,现在来看我们如何实现呢?

这里虽然我们看起来是进度条连续增加的,但是事实上就是一次一次输出的结果。

不知道你是否还记得在实现贪吃蛇小游戏的时候,我们就是一次次输出,来实现蛇的移动;这里也同理,我们依然一次次打印来达到我们预期的效果。

某一时刻进度条的输出

我们先来看某一时刻进度条是如何输出的;

假设现在我们正在下载一个软件,软件大小1024.00MB ,我们当前下载了512.00MB,那如何打印这一时刻的进度条呢?

voidprocess(){double total =1024.00;//下载总量double current =512.00;//当前下载量int rate =(int)(current*100)/total;//进度条百分比,也是要打印`=`的数量constchar* str ="|-/\\";//表示最后方框内旋转的字符,最后一个\\转义字符staticint 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

为了控制方框内转动,我们定义一个静态常量,来决定应该输出哪一个字符。

具体代码如下

#include"progress.h"#include<unistd.h>#include<string.h>#defineNUM101#defineCH'='voidprocess(){char buff[NUM];memset(buff,0,sizeof(buff));constchar* 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

#include"progress.h"#definespeed1.0voidDownload(double total){double current=0;while(current<=total){Process(total,current);usleep(6000); current+=speed;}printf("\ndownload %lfMB Done\n",total);}intmain(){//process();Download(1024.00);return0;}

progress.h

#include<stdio.h>#include<unistd.h>voidProcess(double total,double current);

progress.c

voidProcess(double total,double current){char buff[NUM];memset(buff,0,sizeof(buff));constchar* str ="|/-\\";int len =strlen(str);//当前进度int num =(int)(current*100)/total;int i=0;for(i=0;i<num;i++){ buff[i]=CH;}staticint 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

Read more

Ubuntu Server 24.04.3 LTS 超详细安装教程

Ubuntu Server 24.04.3 LTS 超详细安装教程

🐧 Ubuntu Server 24.04.3 LTS 超详细安装教程 Ubuntu简介 Ubuntu 是一个基于 Debian 的免费开源 Linux 操作系统,由英国公司 Canonical Ltd. 于 2004 年首次发布。它以“人性化、易用、安全”为核心理念,提供桌面版(Desktop)、服务器版(Server) 和云/物联网版本(Core),广泛应用于个人电脑、企业服务器、云计算平台和嵌入式设备。 第一步:安装前准备 1. 下载 Ubuntu Server ISO 镜像 * 官方下载地址:https://ubuntu.com/download/server * 选择

By Ne0inhk

Flutter 三方库 serverpod_cli 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、全能、自动化的 Full-stack Dart (Serverpod) 后端与 HAP 端代码生成引擎

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 serverpod_cli 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、全能、自动化的 Full-stack Dart (Serverpod) 后端与 HAP 端代码生成引擎 在鸿蒙(OpenHarmony)系统的端云一体化应用开发中,如何通过一份模型定义(YAML),即可自动生成鸿蒙(HAP)端的强类型客户端代码、数据库迁移脚本及复杂的 RPC 接口?serverpod_cli 为开发者提供了一套工业级的“全栈 Dart”构建控制台。本文将带您深入实战其在构建鸿蒙高性能云端交互层中的应用。 前言 什么是 Serverpod CLI?它不是运行在 HAP 里的库,而是运行在鸿蒙开发环境(DevEco Studio 配套主机)中的“

By Ne0inhk
2025最新 WSL(Windows Subsystem for Linux)安装教程 (保姆级,图文讲解,带安装包)

2025最新 WSL(Windows Subsystem for Linux)安装教程 (保姆级,图文讲解,带安装包)

WSL 是微软官方推出的“Windows 下的 Linux 子系统”,允许用户在 Windows 10/11 中直接运行原生 Linux 命令行工具、程序和服务,无需虚拟机或双系统。本教程面向零基础用户,提供完整安装流程、常见问题及解决方案,并附赠离线安装包,确保在无网络或网络受限环境下也能顺利完成部署。 一、下载 WSL (一)网盘下载(推荐) 为了方便大家不用去官网下载,现提供网盘下载 网盘链接 【最后更新时间 2025/06/17】 (二)在线商店下载 下载完成后得到 wsl-install.msi 安装包。 Microsoft Store,直接搜索wsl,然后选择Linux发行版本进行下载即可 二、安装 WSL 步骤 1:启用 WSL

By Ne0inhk
【Linux指南】进程控制系列(二)进程终止 —— 退出场景、方法与退出码详解

【Linux指南】进程控制系列(二)进程终止 —— 退出场景、方法与退出码详解

文章目录 * 一、先想明白:进程终止不是 “消失”,而是 “释放资源” * 二、进程退出的三大场景:正常与异常的边界 * 场景 1:正常退出(代码执行完毕,结果正确) * 场景 2:正常退出(代码执行完毕,结果不正确) * 场景 3:异常退出(代码崩溃,被迫终止) * 三、三种进程退出方法:return、exit、_exit 的核心差异 * 3.1 方法 1:return—— 仅在 main 函数中有效 * 核心逻辑: * 3.2 方法 2:exit 函数 —— 带清理操作的库函数退出 * 核心逻辑与清理操作: * 函数原型: * 3.

By Ne0inhk