Linux基本工具的使用

什么是工具?

在Linux中,工具的本质也是指令,只是因为这些指令与我们的开发的关系不是很大,所以就被称为工具

1 软件包管理器yum

在我们的Windows上如果想要安装软件,第一件事就是要先下载软件安装包,然后再安装到相应的目录下。我们要下载软件一般是在电脑的应用商店或者浏览器上搜索去下载软件包,在浏览器搜索下载软件包相当于寻找指定的链接,通过这个链接到远端的服务器上下载软件包,这些服务器一般是由软件提供者或者企业来维护的。而对于我们的应用商店,应用商店其实就相当于一个远端服务器的链接,打开应用商店之后,罗列出的一系列软件其实就是服务器中的软件包的链接,当我们搜索某个软件时,就相当于再服务器的连接清单中进行搜索筛选从而找到我们想要的软件包的链接。这就是软件包的下载过程。这个过程同样适用于我们的手机端。  那么对于Linux而言,是不是这样的呢? 我们知道,Linux是开源的操作系统,但是在网上我们是能找到Linux的各种讨论社区的,这些社区的作用就是让使用Linux的人找到Linux的组织,同时还可以通过社区来进行募捐,而募捐到的资金就用于社区的维护以及租用服务器。而我们要下载软件包也是需要找到对应的服务器然后通过找到软件链接下载的。那么我们下载的时候是如何找到对应的服务器的呢?在我们的操作系统中,一般都会有一个yum源配置文件,这个配置文件中有对应的服务器链接。当我们需要使用vim去下载某些软件时,操作系统会通过yum源文件的链接去找到远端的服务器,然后在服务器中去筛选我们所要下载的软件包。而Linux社区的服务器一般都是部署在国外的,我们在国内的访问请求有时候会被拦截,这时候,就有一些高校或者企业就将国外的软件服务器镜像了一份过来,镜像的意思差不多就是将其复制了一份到我们国内自己的服务器上,比如清华,腾讯,阿里等。但是,将软件包复制过来还不够,我们还要修改我们的系统中的yum源文件才能找到我们国内的服务器,不过我们一般不用担心这个,就比如我们自己购买的云服务器比如腾讯云等,其中Linux系统的yum源文件一般已经帮我们配置成了国内的服务器链接。同时,如果我们想要修改我们的yum源也是可以的,找到相关的配置文件,将其连接修改为我们想要的服务器链接就可以了。以上就是软件包的下载的过程,而Linux的yum其实就相当于一个应用商店的作用。而下载软件包之后还需要安装安装的过程其实就是一个拷贝的过程,将需要的配置文件拷贝到对应的目录中就是安装。

yum源文件是 /etc/yum.repos.d/epel.reps

yum的使用

三板斧:查找,安装,卸载

查找

我们想要通过名字查找对应的软件就需要用到yum list 命令

但是yum list是直接将镜像服务器中的所有的软件包的都罗列了出来,如果我们想要搜索或者筛选这些软件包,就可以使用管道和 grep 指令。

这里会显示出软件的体系结构、版本、硬件平台等诸多信息

安装

安装需要用到 yum 的 install 指令,比如我们要安装一个名字为 sl 的软件

yum install sl

或者我们也可以

yum install -y sl

-y就是直接同意安装,没有 -y 的话安装软件之前会有一次询问

卸载

卸载用到的指令就是  yum  remove

后面直接加软件名就🆗了

安装和卸载软件一般需要我们以root 的权限进行,因为安装的目录可能会有权限的限制。

2.vim

之前我们写代码,编译链接代码和运行代码都是在vs 上完成的,vs这种环境叫做集成开发环境。而在Linux中不编辑代码和调试代码和运行代码是在不同的软件上完成的,编辑代码所要用到的就是我们的vim工具,vim工具是一个十分强大的、多模式的编辑器。在我们操作系统上的vim最初始的没有进行配置的vim其实就相当于Windows上的记事本。

我们说vim是一个多模式的编辑器,那么它有哪些模式呢?

我们最常用的其实就是三种模式,插入模式,命令模式和底行模式。

当我们用vim打开一个文件时,初始就是命令模式

我们要切换其他模式都只能通过命令模式来切换

比如我们输入 i ,就能进入插入模式

这时候我们就能像记事本一样进行编辑了。

当我们完成编辑后,通过按下 Esc 键回到命令模式。

要进入底行模式,我们可以再命令模式下输入 :(Shift + ;) 。在底行模式输入wq就是保存并退出。 w是写入(write),q是退出(quit)。  

当我们想要回到命令模式只要无脑按 Esc 就行了

我们前面进入的插入模式其实编辑起来并不是很方便,光标移动很麻烦,同时没有换行自动对齐吗,自动根据语境与其代码等功能,这些功能需要我们自己去配置。

vim的命令模式有很多的命令能够提高我们的编辑效率

首先就是光标定位的命令

shift + 4($) ,将光标定位到当前所在行的 行右

shift + 6(^),将光标定位到当前行的行左

shift + g(G),将光标定位到最后一行的行左

gg   ,将光标定位到第一行的行左

n + shift + g(n+G,n是行号),将光标定位到第n行的行左

h j k l(左、下、上、右),与上下左右键一样,控制光标的移动

w 、b  按单词(字)进行移动,w是向后移动,b是向前移动,也支持 n+w/n+b来进行多个字的移动

文本复制相关的命令

yy    复制当前行,也支持 n+yy ,复制当前行开始的 n 行

p      粘贴一次复制的内容带光标的位置,粘贴的时候会在光标位置新开一行粘贴,也支持 n +p,粘贴n次

dd    剪切(删除)光标所在行,dd也支持 n + dd,剪切(删除)当前行开始的n行 。dd如果单独使用就相当于删除,如果配合 p 使用就相当于剪切。

文本编辑修改命令

~ (shift +` ) ,将光标所在的字母转换成进行大小写转换,如果长按则会依次往后转换,直到行尾

如果光标指向的字母是小写,就转换为大小,如果是大写就转换为小写

文本的替换命令

shift +r(R),能够直接进入替换模式,替换模式下就是将光标指向的内容替换,每替换一个光标就往后移一位。

r   替换光标指向的一个字符,先输入 r 再输入替换后的字符,也支持 n+r 替换光标开始的n个字符,都替换为我们接下来输入的那个字符

文本删除命令

x 和 shift + x(X)  删除光标指向一个字符,他们的不同点是,x是向后删除, shift x是向前删除,就是删除一个字符后光标是向前移动还是不动的区别。 同时也都支持 n +x /n+shift+x 删除n个字符

cw  删除光标指向的一个单词(字  word),同时进入插入模式。同时也支持 c+n+w或者n+cw进行多个单词删除,但是删除后都会进入插入模式。

撤销命令

u   撤销

ctrl +r 取消撤销(回退到撤销前) 

进入插入模式的命令有很多个,比如 a ,a进入插入模式之后光标会往后移一个字符,比如 o ,o进入插入模式会新开一行进行插入

底行模式的命令 

set nu  :显示行号

set nonu  :取消行号

q :直接退出,不保存

!:强制

q!  :强制退出

w :写入

w!:强制写入

wq:保存退出

vs + 文件名,分屏操作,可以同时编辑多个文件,如果文件名不存在,就会在当前目录下创建一个该文件。但是我们要知道,光标只有一个,所以我们同一时间只能操作一个文件,这样只是更方便我们在多个文件之间来回切换编辑。 

那么如何将光标从一个文件切换到另一个文件呢?在命令行模式下输入 ctrl ww进行光标的文件切换

同时,我们也可以在底行模式下执行Linux的指令,不过要在指令前面加上 ! ,比如我们要对文件进行编译,可以在底行模式先保存,然后!gcc 文件名。

编译完成后会出现这个指令,!加Linux指令相当于暂时切换到文件外进行操作,操作完之后会切回文件编辑界面。

底行模式还支持替换操作。

语法为 %s/原内容/替换后的内容/g(g表示全局)

会将文本全局范围内的匹配上的内容都替换。

vim的基本配置

我们现在使用的插入模式进行编辑的时候,用起来十分难受,这是因为我们的vim还没有进行任何的配置。 关于vim配置要注意的是,vim的配置时一人一份的,每个普通用户只能配置自己的vim,不影响别人的使用。配置文件时家目录下的 .vimrc ,这是一个隐藏文件,我们找到之后就可以在文件中进行编辑配置。但是更建议直接在网上找一些配置好的配置文件来使用,因为自己手动配置太过费时费力。

sudoers

我们前面讲的sudo提权需要白名单,我们可以切换到root用户之后找到 /etc/sudoers ,然后使用vim进行编辑,编辑之前首先要将该文件的 w 权限加上,因为这个文件默认是不可写的,有了写权限之后使用vim打开编辑,将 100 行的内容复制粘贴,将粘贴出来的一行的root改为指定的用户,然后保存退出,改完之后记得把写权限去掉。

3.gcc/g++

gcc和g++就是我们的Linux下的编译链接软件,我们回忆一遍程序的翻译过程

1.预处理 :展开头文件(从系统中所在的路径拷贝过来),删注释,宏替换,条件编译等

我们可以使用 -E 选项,让源文件编译到预处理完就停下来

gcc -E test.c  -o  test.i 

-o选项是指明形成的临时文件名称

要注意的是,在使用这些选项的时候,比如使用 -o 选项,后面就要接形成的文件名,-E 后面就要接要编译的源文件 ,顺序没有要求

这里已经把头文件展开了。

2.编译:将C语言翻译为汇编代码

-S 选项:从当前状态开始编译到汇编完成就停下来

gcc -o test.s  -S test.i

3.汇编:汇编是将汇编指令转换为二进制指令

对应的选项是 -c :从当前状态开始编译到汇编完停下来

gcc -o test.o -c test.s

4.链接:符号表汇总,将你写的代码和C标准库中的代码合并到一起形成可执行程序。

链接没有选项,直接gcc就会链接完

链接完之后还是二进制指令。

之后我们用 ./ 来执行我们生成的可执行程序就行了

在这其中,链接有两种链接方式:动态链接和静态链接

动态链接:对于我们程序中使用的标准库中的接口、模板等代码,不将对应代码直接与我们的可执行程序绑定在一起,而是在内存中用一个共享动态库,链接的时候将我们的使用的标准库的内容与内存中的动态共享库进行链接,程序共用一个动态库。而在我们程序运行时需要调用库函数时,会跳转到动态库中执行。

静态链接:在进行链接的时候,直接将一个静态库的中用到的部分代码拷贝与我们的可执行程序链接在一起,相当于将库函数的实现也拷贝了过来,而在程序运行时调用库函数的时候就直接在程序内部解决。

动静态链接的优缺点:

动态链接的缺点就是程序收动态库的删除和升级的影响,会导致我们的程序无法运行,跳转的过程也耗费时间 。优点就是形成的可执行程序体积小,占用磁盘资源少,同时别人在下载的时候下载的软件包小,节省网络资源,程序运行时加载到内存中时占用内存也小,节省资源。

静态链接的优势就是在生成可执行程序之后就不再受库的升级和删除的影响。缺点就是可执行程序的体积太大。同时,不同的程序内部都有一份独立的静态库,当同时加载到内存是就会出现多个相同的代码内容,导致代码冗余,而且占用资源大。

如何查看我们形成的可执行程序时动态链接还是静态链接呢?

比如我们上面写成的test.exe程序 。 我们可以用 file  指令看来查看程序的信息

 我们可以看到上面的程序是使用共享库的,也就是动态链接。

如果要详细看程序使用的动态库可以用 ldd 命令来查看

我们就能看到程序使用的都是 .so 后缀的动态库,使用的C标准库是 libc.so.6。

我们可以对这个库执行 ll 指令查看他链接的库的版本

我们能发现,gcc编译默认使用动态链接的方式(前提是你有动态库),Linux系统我们知道他是使用C语言来写的,他的指令实际上也就是一些C语言的函数接口,而这些接口使用的也都是动态链接,所以Linux基本都是默认会配置动态库的,否则影响基础功能的使用。

如果我们要使用静态链接,就需要在gcc编译的时候使用 -static 选项。 同时,我们的Linux系统一般是不会自动配置静态库的,我们想要下载C标准静态库可以用 yum install -y glibc-static ,静态库的后缀是 .a 后缀

g++的使用与gcc的使用是一样的。

4.自动化构建工具 make/makefile

makefile是一个文件,我们也可以写成Makefile。

使用这个工具的时候,首先我们要在我们的源代码的路径下创建一个makefile文件,然后将源文件的依赖关系和依赖方法都写在文件中。将makefile写完之后,我们只需要在命令行输入make就能执行里面的依赖方法,而不用每一次都写很长一行的 gcc ... ... .. 了。同时,make最重要的还是在多文件的项目中使用,会很方便。

makefile的原理: makefile中两个核心的东西,依赖关系和依赖方法。makefile存在的意义就是为了按照我们想要的方法构建项目。如上图 ,第一行的 test.txt:test.c ,表明了依赖关系, : 左边是目的文件或者我们的可执行程序,冒号右边是被依赖的文件,也就是生成目标文件所需要的文件,依赖关系必须在行首开始写,前面不能有空格。而第二行则表明了依赖方法,也就是如何使用被依赖文件生成目标文件。依赖方法需要在依赖关系的下一行,使用 tab 开头。在makefile中,以tab开头的都是依赖方法。写好上面的makefile之后,我们可以在当前目录下直接make一下,就能使用test.c生成一个test.exe

当我们使用make后,就自动执行了依赖方法。我们这里的makefile中只有生成可执行程序的方法,而没有清理不用的程序的方法,为此我们可以再补充一条clean关系

clean清理文件是不需要依赖文件的,所以冒号后面我们不用接文件。他的方法就是删除生成的可执行程序。到这里我们就会有一个疑惑,当我们make的时候会不会将两个方法都执行了,这样一来刚生成的test.exe不是马上就被清理了吗? 我们可以试一下

这时候我们发现make报提示了,提示test.exe已经是最新的了,我们刚刚没有对test.c进行修改。而在make的策略中,如果我们的源文件没有被修改,这就代表着生成的可执行程序也跟上次的一摸一样,这时候,make执行gcc编译这个方法是就不会去重新编译生成一个没有任何改变的可执行程序。这时候就又有了一个新的问题,如果我们想要一个依赖方法每次make的时候都要执行,就比如上面的编译,我们想要每一次make的时候他都重新编译生成一次,不按照他的策略来,我们应该怎么做呢? 

.PHONY:关键字,我们可以在目标文件前面加上 .PHONY:关键字修饰,这个关键字修饰的对象是为伪目标,该目标总是会被执行,而不受依赖方法的影响。比如我们在上面的可执行程序前面加上该关键字修饰。使用的时候是要在依赖关系的前一行用 .PHONY:修饰目标对象。

当然,在我们实际使用时是不会对这一个依赖关系用.PHONY:修饰的,因为重新生成浪费了我们的时间。这时候我们再去make一下,而我们的clean一般是用该关键字修饰的。我们看一下能否执行clean的方法将test.exe删除

我们可以发现,确实重新执行了编译的指令,可是并没有执行 clean ,这是为什么呢?

makefile从上往下扫描时,如果扫描到的第一个方法执行不了,或者说第一个方法的被依赖文件还不存在,这时候他就会先把这个方法放一边,继续往下扫描,直到有一条方法能够执行,执行完这一条方法之后,就会逐级往回退,执行前面未执行的方法 这个推导过程与栈的先进后出类似。当栈为空时就退出makefile了。比如我们使用makefile将编译链接的的全过程都生成一遍,但是我们将顺序搞反,可以看一下他是否会执行到后面的方法。

我们可以看到他确实是先执行了后面的方法,直到前面的依赖关系的被依赖文件存在之后再执行前面的方法。那么如果我们把前面的某一个过程删除了呢

这时候就会报错。 总之我们日常也不会这么写,一般编译链接形成可执行程序就行了。 

问题是如果我们想要执行后面的clean该如何做?

很简单,make 后面加对应的目标就行了

回到我们前面的问题,gcc是怎么直到我们的源文件内容没有更新,然后不重新生成可执行程序的呢?

我们前面学过三个文件时间 Access ,Modify ,Change 。Access是最近访问时间,但是由于这个时间并不是那么重要,同时如果每一次访问都实时更新Access时间的话会增加系统的负担,所以Access并不一定是实时更新的。 gcc是通过test.exe 和test.c 的Modify时间来决定是否重新编译的,当我们的源文件的Modify时间比test.exe的Modify时间要晚,这说明可执行程序生成(文件被创建的的时候三个时间都是被创建的时间,同时我们一般也不会去修改可执行程序的内容,所以可执行程序的修改时间其实就是他的被创建时间或者被重写覆盖的时间)之后我们对源文件进行了修改,这时候就需要重新编译链接生成新的可执行程序。这就是make中gcc的策略。

5. git常用操作

首先我们要在gitee上创建初始化一个仓库,

然后找到仓库的下载链接

将这个指令复制下来,直接粘贴到Linux上运行

这时候就将远端的仓库克隆到了本地,并形成了一个本地目录,这个本地目录就是我们的本地从仓库,仓库的本质就是一个目录。进入目录查看一下里面的文件

我们发现初始化的一个文件 ,gitignore我们看不到,这是因为这是一个隐藏文件,我们用-a选项来查看

我们发现除了一个.gitignore还有一个隐藏目录 .git ,这个就是我们的本地仓库的配置文件和对象数据,我们不能删,如果删了就无法正常使用git的功能了。进入这个目录就能看到一些初始化的文件,我们也可以将这个目录看成是否为本地仓库的标志

同时我们打开刚刚的.gitignore文件,发现里面都是一些文件的后缀

这个文件的作用就是将我们上传的一些文件,如果后缀是这个文件里有的,就会拦截下来不上传。这有什么意义呢?我们有时候写一个项目,里面很多文件是一些临时文件,比如.i ,.o 或者是一些其他的与我们源文件无关的文件,我们需要上传的可能就只有 .c .h 和 .cpp文件,所以将这些没用的文件拦截下来能够更好的管理我们的git仓库,让仓库中的内容更加简洁专业。

当我们想要将某个文件上传到 gitee上的时候,第一件事首先要把这个文件复制到我们上面克隆的目录下来,也就是我们上面的 test-for-git目录下。

然后就是我们使用git的三板斧

第一步是 git add .  ,后面的 . 必须带上,这一步是将我们新添加到本地仓库的文件先添加到一个临时区域,当然我们也可以 git add+文件名的形式来添加一个文件到临时区域,但是这样操作不如上面的方便。 

第二步是 git commit  -m  "日志信息"    。commit是提交的意思,这个指令就是将我们临时区域的文件合并到本地仓库。这里的日志信息我们最好要写成有意义的东西,以便别人或者我们自己以后来查找相应的文件或代码。

第三部就是 git push 提交到远端仓库。将我们本地仓库的新内容提交到远端仓库,这样一来依次git提交就完成了

这里的中间的信息我们不用管。提交的时候会需要我们输入gitee的用户名和密码。

这时候就完成了上传的过程

有的时候我们在gitee修改了一些文件并提交之后

我们要在Linux的本地仓库中使用 git pull 将远端仓库的修改同步到本地,如果不进行同步,我们将无法进行 git push 上传到远端,所以当我们使用 git push 上传时候报错的时候,就要注意是否是我们的本地仓库没有跟远端仓库同步,要先同步之后才能再次提交新内容。

其他常用命令:

git status:查看仓库的状态,会显示那些修改与远端不同步。

如果我们要删除远端的文件,我们可以在Linux中 首先 git rm 文件名  ,先将本地仓库的文件移到临时区域中,再使用 git commit -m “日志信息” 将该文件从本地仓库删除 ,最后 git push 将删除文件的操作提交到远端,让远端仓库同步删除

git log :显示我们的提交记录和提交日志

如果你的Linux上没有git ,可以使用 sudo install -y git 下载,首次安装git会要求配置你的gitee用户名和邮箱。

6.gdb

gdb是一个Linux上的命令行调试工具。有的Linux系统上可能没有自带gdb,使用

  yum install -y gdb 下载

gdb调试和我们在Windows下的vs里面调试的思路是一样的,只是在vs中是使用图形化界面进行调试,而在Linux中是使用命令行来操作。

首先 gdb +可执行程序  打开gdb进行调试了 ,q是退出调试

    进入调试之后,我们就是这样一个界面,看不到代码,只是单纯的命令行。 

l(list) :显示代码   但是一般不是从第0行开始显示,我们也可以指定从第n行开始显示 , l n

这时候我们发现前面就已经报错了,程序没有调试信息,我们在学习C语言的时候就讲过了,只有debug版本才支持调试,才会包含调试信息,而release是发布版,对程序进行了优化,没有调试信息,无法调试。 

gcc默认编译生成的是release版本,想要生成debug版本就需要 -g 选项

这样就能正常调试了。 如果我们想要继续往下翻,我们可以继续按回车,gdb会记录上一次的指令,如果我们单独回车就会默认执行上一条指令,而在这里的显示代码的时候,会记录上一次显示的结尾,下一次就从下一行开始。

打断点:b/break + 行数   ,b是breakpoint的缩写,b+行数就是在指定行打上断点,成功打上断点之后会显示一行信息

这一行的信息分别表示断点的编号,断点所在文件,断点所在行数。断点的编号我们后面会经常用

打上多个断点之后,如果我们想要查看我们的所有断点的信息,可以使用 info b

info b

删除断点 :d / delete  +  断点编号

同时我们可以发现,断点删除之后,后续再增加新的断点不会使用已经用过的编号,而是一直往后递增。

上面三个指令是断点的增加和删除,但是我们还没有将程序跑起来,

r/run :开始运行并调试,他会运行到第一个断点处停下来,如果没有断点就直接跑完,有点像 f5 ,但是他只能使程序开始运行起来跳到第一个断点,运行起来之后如果再使用 r/run的话,就会重新开始调试,还是会在第一个断点处停下来

如果要直接运行到下一个断点,我们就要使用 c(continue) 指令


 

如果后面没有断点就直接运行完

这时候我们再查看断点信息的时候就会发现他们发生了一些变化

这表示在上一次运行中断点命中了几次,也就是断点所在行共运行了几次,我们可以在循环中打断点试一下。

断点的使能操作:禁用断点: disable +断点编号

                             启用断点:enable +断点编号

对应上面断点信息的 End 字段

除了跳到断点位置,我们调试还需要逐过程和逐语句的调试

n/next :逐过程,逐行运行,遇到函数不会进去,相当于 f10

s/step :逐语句,每一条语句都会进去,如果有函数就会跳到函数里执行,相当于f11

有时候我们还需要查看调用堆栈,来查看函数的调用或者递归的深度

bt : 查看调用堆栈

如果我们进去一个函数之后,想直接跑完这个函数,而不是逐步或者依靠断点

finish:跑完当前函数

直接跑到返回

调试时我们还需要查看变量的值和地址等信息,可以用下面两条指令

p/print + 变量  :打印变量的值,我们也可以打印变量的地址 ,p &i

但是p只是将变量在我们使用指令的地方打印出来,不会跟着我们代码的往下执行而更新

而我们大多数情况是需要变量长显示

display + 变量 :长显示变量,也可以打印地址,会跟着我们的代码的往下执行更新显示,对应监视功能在设置长显示的时候也会显示长显示的编号,同时,除了返回值当变量出作用于之后就不会显示了

如果想去掉长显示,我们可以用undisplay + 长显示编号来取消某个长显示

跳转到某一行 :until + 行号

until这个指令用的比较少,因为他不是很准确,不一定调到指定的行号,如果这一行是没有意义的一行比如右花括号和空行等。或者收到程序中循环的影响。

显示当前局部域的临时变量: info locas

学习了基本工具的使用,我们再来学习一个倒计时器和进度条的小应用

在写这两个程序之前,我们首先要了解一点缓冲区的知识,我们可以对比一下下面的两段代码

第一个printf函数在sleep(2)之前就会将内容打印到显示器上。而第二个printf函数则是在程序结束时才打印,这是为什么呢?我们知道,显示器默认是采用行缓冲的,也就是输出的字符首先会在缓冲区内,直到能够打印满显示器的一行才一次性将这一行都打印到显示器上,否则就是主动刷新缓冲区或者程序结束才能将缓冲区的内容全部输入到显示器上。 而 \n 这个换行符有刷新缓冲区的功能,所以第一个printf函数执行的时候,数据放到缓冲区之后就直接刷新打印到了显示器上。而对于第二个printf函数,则是没有刷新缓冲区也没有达到行缓冲的条件,所以他只能在程序结束时刷新缓冲区才会将缓冲区的数据输出到显示器上。

有了这一些关于缓冲区的知识,我们就能试着写一个计时器的程序了,首先计时器是要显示在屏幕的同一个地方,也就是不能用换行刷新,那么我们可以使用C语言的一个fflush函数来主动刷新缓冲区。

我们可以运行一下看是否有问题

我们发现,这根本就不是一个计时器,时间并不是打印在同一个地方,这是为什么呢?

我们可以理解为在显示器上也是有一个光标的,默认是打印一个字符,光标向后移一个位置

而我们想要的效果确是每一次都打印在第一个位置上,我们怎么控制光标在这一行的行首呢?

回车(\r):回车并不是我们现在电脑上的回车,以前的回车是将光标移动到当前行的行首,而现在电脑上的回车则是换行加回车了。 而我们现在使用的 \n 其实也相当于是换行加回车了。而\r则是单纯的回车,也就是将光标移回到当前行的行首,当我们再次在显示器第一个位置打印字符时,就相当于覆盖了之前的第一个位置的字符了,也就达到了我们的倒计时器的功能。

进度条程序

进度条程序我们则是要控制打印的格式,

我们可以将前面的一块地方用来打印进度条的增长,左侧的总长度是固定的,然后再后面加一个百分比进度,再在最后加一个旋转的万花筒 ,也就是 \  -  /  - 这样子循环显示,在视觉上就是再转圈圈。

如此一来,我们假设进度条要使用100个字符来表示,那么我们就需要一个 char [102]的字符数组来存储这些字符,初始化全部为 \0 ,而每一次循环都使进度条增长一个字符,每一次都将整个数组打印出来,要控制这块空间不变,我们可以用 %101s 来控制格式。 最后的交替的斜杠和横线我们也可以用一个字符数组来循环打印。同时我们要注意打印%的时候要用两个%,因为%也是一个特殊字符,与\一样需要两个才能表示%的字面值、

我们这里为了演示所以循环之间间隔的时间很长,我们可以将sleep函数换成 usleep函数,sleep函数休眠的时间单位是 秒 ,而usleep函数休眠的时间单位是微秒,也就是百万分之一秒,我们可以100毫秒更新一次,也就是 usleep(100000);

这样进度条就很快了。效果也还行。

如果想把进度条做得更好看还可以设置printf 打印的颜色,我们可以在网上找printf函数设置字体寒色和背景颜色的格式

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

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

相关文章

VUE之旅—day2

文章目录 Vue生命周期和生命周期的四个阶段created应用—新闻列表渲染mounted应用—进入页面搜索框就获得焦点账单统计(Echarts可视化图表渲染) Vue生命周期和生命周期的四个阶段 思考: 什么时候可以发送初始化渲染请求?&#xff…

Spring 各版本发布时间与区别

版本版本特性Spring Framework 1.01. 所有代码都在一个项目中 2. 支持核心功能IoC、AOP 3. 内置支持Hibernate、iBatis等第三方框架 4. 对第三方技术简单封装。如:JDBC、Mail、事务等 5. 只支持XML配置方式。6.主要通过 XML 配置文件来管理对象和依赖关系&#xff0…

首次曝光!我喂了半年主食冻干,喵状态真滴顶~

科学养猫理念的推广,使得主食冻干喂养越来越受到养猫者的欢迎。主食冻干不仅符合猫咪的自然饮食习惯,还能提供丰富的营养,有助于保持猫咪的口腔和消化系统健康。我家喂了半年主食冻干,猫咪的状态是真的不一样了! 然而…

P9748 [CSP-J 2023] 小苹果 / P7071 [CSP-J2020] 优秀的拆分:做题笔记

目录 P9748 [CSP-J 2023] 小苹果 思路 代码 P7071 [CSP-J2020] 优秀的拆分 思路 代码 P9748 [CSP-J 2023] 小苹果 P9748 [CSP-J 2023] 小苹果 思路 先写几个看看规律 题意我们能看出来是三个三个一组的,然后每次取走的都是三个里面的第一个。我们应该很容易…

23.HashMap的put方法流程

一、put方法的流程图 二、put方法的执行步骤 首先,根据key值计算哈希值。然后判断table数组是否为空或者数组长度是否为0,是的话则要扩容,resize()。接着,根据哈希值计算数组下标。如果这个下标位置为空&a…

Linux平台和Windows平台互传文件

rz和sz的出发对象都是从Linux出发的,例如sz发送(Send)从Linux->发送到Windows。 rz 从Windows文件发送到Linux中 先创立一个新文本文件 之后将hello Windows输入到该文本文件中 在显示器上显示里面是否有hello Windows内容 sz发送Lin…

【SpringBoot】SpringBoot整合jasypt进行重要数据加密

📝个人主页:哈__ 期待您的关注 目录 📕jasypt简介 🔥SpringBoot使用jasypt 📂创建我需要的数据库文件 📕引入依赖 🔓配置数据库文件(先不进行加密) 🌙创…

暴利 选品大课:选品决定成败,教你多种大爆款选品方法(12节课)

课程目录 001.第一讲:选品决定成败.mp4 002.第二讲:选品也有生辰八字,mp4 003.第三讲:高热度选品底层逻辑,mp4 004,第四讲:高动销选品底层逻辑,mp4 005,第五讲:高点击选品底层逻辑,mp4 006.第六讲:高转化选品底层逻辑.mp4 007.第七讲:低付费选品底层逻辑.mp4 008,第八讲…

kubernetes多master集群架构

一、完成master02节点的初始化操作 master02环境准备,详细过程参考上一期博客环境准备 #添加主机映射 vim /etc/hosts 192.168.88.3 master01 192.168.88.8 master02 192.168.88.4 node01 192.168.88.5 node021、准备master02节点需要的文件 从 master01 节点上拷…

USB-OTG:1、OTG原理介绍

目录 🍅点击这里查看所有博文 随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记…

2024042002-计算机网络 - 应用层

计算机网络 - 应用层 计算机网络 - 应用层 域名系统文件传送协议动态主机配置协议远程登录协议电子邮件协议 1. SMTP2. POP33. IMAP 常用端口Web 页面请求过程 1. DHCP 配置主机信息2. ARP 解析 MAC 地址3. DNS 解析域名4. HTTP 请求页面 域名系统 DNS 是一个分布式数据库&…

GPT-4o 炸裂发布!你竟然还没用上?(附详细教程)

今天AI界的爆炸新闻非chatgpt-4o莫属,从早上到现在随处可见的文章推送,视频推送。 大家或多或少都有耳闻了,今天主要讲一讲我们普通人到底怎么用?如果不氪金行不行?我就想体验一下可不可以?带着问题往下看 …

应用层之 HTTP 协议

HTTP 协议 HTTP (全称为 "超文本传输协议") 是一种应用非常广泛的 应用层协议。所谓 "超文本" 的含义, 就是传输的内容不仅仅是文本(比如 html, css 这个就是文本), 还可以是一些 其他的资源, 比如图片, 视频, 音频等二进制的数据。浏览器获取到网页&#…

618洗地机如何选?洗地机哪个牌子好?洗地机详解

快节奏的生活方式使得清洁工作成为许多人难以应付的任务。不过,洗地机的出现为这个问题提供了完美的解决方案。洗地机以其强劲的吸力和高效的清洁功能,能够快速清理地面的污渍和灰尘,极大地提升了清洁效率。不仅如此,洗地机的操作…

C语言/数据结构——栈的实现

一.前言 今天我们讲解新的领域——栈。 二.正文 1.栈 1.1栈的概念及结构 栈:一种特殊的线性表,其允许在固定的一段进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#…

详解绝对路径和相对路径的区别

绝对路径和相对路径是用于描述文件或目录在文件系统中位置的两种不同方式。 绝对路径(Absolute Path)是从文件系统的根目录开始的完整路径,可以唯一地确定一个文件或目录的位置。在不同的操作系统中,根目录的表示方式可能略有不同…

浅析扩散模型与图像生成【应用篇】(二十五)——Plug-and-Play

25. Plug-and-Play: Diffusion Features for Text-Driven Image-to-Image Translation 该文提出一种文本驱动的图像转换方法,输入一张图像和一个目标文本描述,按照文本描述对输入图像进行转换,得到目标图像。图像转换任务其实本质上属于图像编…

大模型日报2024-05-15

大模型日报 2024-05-15 大模型资讯 OpenAI推出全新AI模型GPT-4o,具备文本、图像和音频处理能力 摘要: OpenAI公司继ChatGPT后,最新推出了名为GPT-4o的AI模型。这一模型不仅能够理解和生成文本,还新增了图像和音频的解释及生成功能。GPT-4o作为…

字节跳动后端青训营笔记:Go语言进阶

1.语言进阶&依赖管理 1.1 语言进阶 从并发编程的视角了解Go高性能的本质。 1.1.1 并发&并行 在单核CPU下,线程实际还是串行执行的。操作系统中有一个组件叫做任务调度器,它将CPU的时间片(window下最小约为15毫秒)分给不同的程序使用&#xff0…

第十四届蓝桥杯大赛软件赛国赛C/C++ 大学 B 组 拼数字

//bfs只能过40%。 #include<bits/stdc.h> using namespace std; #define int long long int a,b,c,dp[2028]; struct s {int x,y,z;string m; }; map<vector<int>,int>k; signed main() {ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>a…