【Linux】基础IO——文件系统|软硬链接|动静态库

news2024/10/7 9:28:37

文章目录

  • 一、磁盘
    • 1. 物理结构
    • 2. 存储结构
    • 3. 逻辑抽象结构
  • 二、文件系统
    • 1. 文件系统的结构
    • 2. 查看文件
    • 3. 删除文件
  • 三、软硬链接
    • 1. 软链接
    • 2. 硬链接
    • 3. ACM 时间
  • 四、动静态库
    • 1. 动静态库的介绍
    • 2. 静态库的制作
    • 3. 动态库的制作
    • 4. 动态库的加载


一、磁盘

基于上篇博客所写到的文件各种操作都是基于被打开文件所进行操作的,那么如果一个文件没有被打开它存在哪里呢?这个答案毫无疑问肯定是存在于磁盘上的。那么,对于一个没有打开的文件(也就是磁盘文件)我们应该如何理解呢?

1. 物理结构

在这里插入图片描述

这里我们所要讲的磁盘是机械硬盘、即传统的普通硬盘,主要由:盘片,磁头,盘片转轴及控制电机,磁头控制器,数据转换器,接口,缓存等几个部分组成。

磁头可沿盘片的半径方向运动,加上盘片每分钟几千转的高速旋转,磁头就可以定位在盘片的指定位置上进行数据的读写操作。信息通过离磁性表面很近的磁头,由电磁流来改变极性方式被电磁流写到磁盘上,信息可以通过相反的方式读取。硬盘作为精密设备,尘埃是其大敌,所以进入硬盘的空气必须过滤。

💕这里我们需要注意的是: 一片盘片有两面,两面都能够读写数据,每一面都有一个磁头,磁头是悬浮在盘片上。磁盘的盘面是充满磁的,其上面存在着许多非常细小的 N、S级,磁盘是通过 N、S级来表示 0 和 1。通过充磁和消磁技术,来调转 N、S 级,从而达到 0 和 1 的写入,那么就可以表示数据了。


2. 存储结构

在这里插入图片描述

3. 逻辑抽象结构

在这里插入图片描述

类比磁带,我们可以将磁盘盘片想象成线性结构,将一摞磁盘沿磁道“拉直”,就抽象成了线性结构。那么整个磁盘可以看做一个sector arr[N]数组,对磁盘数据的管理就变成了对数组的管理。只要知道了扇区的下标,就可以定位扇区。这个下标在操作系统内部称为LBA地址。根据LBA地址可以转化为CHS地址,从而找到对应扇区。

计算机常用的访问方式是:起始地址+偏移量的方式,所以我们只需要知道数据块的起始地址(第一个扇区的起始地址)+ 4KB(块的类型),所以块的地址,本质就是数组的下标,所以我们可以直接使用下标的方式来定位任意一个块。

磁盘的最小单位512字节(扇区的大小)。但是大部分操作系统的文件系统读取数据时会以4KB为基本单位读取至内存。这个特点也印证了顺序表缓存命中率高的特点。因此,当以4KB为基本单位进行IO时,有时4KB数据并不能完全被利用,但这并不代表着浪费。根据局部性原理,当计算机访问某些数据时,它附近的数据也有非常大的概率被访问到,加载4KB有助于提高IO效率,同时增大缓存命中率。本质上就是一种数据预加载,以空间换时间的做法。因此,操作系统中内存被划分成了一块块4KB大小的空间,每个空间被称为页框

操作系统知道任意一个CHS的地址,就能访问到任意一个扇区,但是OS内部却不是直接访问CHS地址,原因如下:

  • OS是软件,CHS是硬件,硬件定位一个地址,但是如果OS直接使用了这个地址,万一硬件变了,OS也要跟着变化,因此操作系统OS要和硬件做好解耦工作。
  • 即便是扇区,也仅仅有512个字节,单位IO的基本数据量也是很小的,OS实际进行IO的基本单位是4KB。磁盘是一个块设备,OS需要有一套新的地址,来进行块级别的访问。

二、文件系统

1. 文件系统的结构

磁盘采用的是分治的思想。这里我们做一个假设:将一个500G的磁盘划分成4个100G进行管理,每个125G又可以划分成多个5G的块进行管理。

在这里插入图片描述

  • Super Block:存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。在一个分区中超级块的数量不止一个,作用是备份。
  • GDT(Group Descriptor Table):块组描述表,描述所有块组属性信息;
  • Block Bitmap:每一个bit 表示datablock用0表示某位没有被使用,用1表示某位数据块已经被使用。
  • inode Bitmap:每一个bit表示一个inode是否空闲可用,用0表示某位没有被使用,用1表示某位inode已经被使用。
  • inode Table:保存了分组内部所有的可用(已使用+未使用)的inode。如果inode表中有100个inode,每个inode的大小是128字节或256字节(根据文件系统的不同Inode大小不同),inode表总大小就是100 * 128或100 * 256字节。单个inode: 存放文件中几乎所有的属性,如文件大小,所有者,最近修改时间等,唯独文件名不在inode表中存储。一个文件对应一个inode,inode是固定大小。每个分组中的inode为了区分彼此,它们都有自己的ID。
  • Data blocks: 保存的是分组内部所有文件的数据块、单个Data block:存放文件内容,大小随文件大小变化而变化。

在这里插入图片描述


2. 查看文件

想要查看一个文件,我们可以通过inode编号找到该文件的数据块数组blocks[ ],进而找到该文件的数据块,组合成整个文件。

在这里插入图片描述

当blocks[ ]指向数据块时,该数据块中保存的是其他的数据块的编号,这些块也可以存储别的数据块编号,因此,blocks[ ]表示的可以是很多个数据块,所以一个文件的数据块可以很多,文件的大小可以很大。


3. 删除文件

删除文件只需要找到 inode 在 inode Bitmap 中的比特位和 Block Bitmap 的比特位,将这两个比特位改成 0,文件就算删除了。恢复文件则与该过程相反,知道删除文件的 inode,再将 inode Bitmap 和 block Bitmap 中对应的比特位改成 1 即可恢复文件。删除文件的 inode 可以通过日志来查到。误删文件后,千万不要新建文件。以防误删文件的 inode 编号和数据块被占用,无法恢复误删文件。

但是我们平常在Linux下查看文件的时候用的是文件名,并没有使用inode来查看文件,其实文件名和inode存在一一映射的关系,目录的数据块放的就是当前目录文件名和inode的映射关系,所以在同一目录下,不可以存在同名的文件,因为文件名就是一个key值,通过该key值找到对应的inode编号,进而找到该文件!!!所以在同一个目录里创建文件,必须要有该目录的写入权限。因为要将文件名和inode的映射关系写入到目录的数据块中。


三、软硬链接

1. 软链接

ln -s 现有文件 目标文件 #将目标文件与现有文件进行软链接
unlink 文件名 #删除软链接文件

在这里插入图片描述
在这里插入图片描述

有自己独立的inode的称为软链接,即软链接是独立的文件,独立的文件有独立的inode和对应的文件内容。因此,软链接生成的文件具有独立的inode,可以被当作独立文件来看待。

💕 软链接的优势: 软链接就相当于Windows系统下的快捷方式,它能够帮助我们快速找到指定路径下的文件。

2. 硬链接

ln 现有文件 目标文件 #将目标文件与现有文件进行硬链接

在这里插入图片描述

硬链接的生成的文件没有独立的inode,也就是说,建立硬链接没有创建新的文件,其inode是原来文件的inode。所以建立硬链接并没有创建新的文件。因为没有给硬链接生成的文件分配独立的inode。既然没有创建新文件,因此硬链接生成的文件用的还是源文件的inode和内容。硬链接的本质是让inode中的引用计数count++,所以引用计数也是被称作为硬链接数。这里需要注意的是:当一个文件的硬链接数(引用计数)变成0时,该文件才能算是真正被删除。同一个inode的文件表示的就是同一个文件。

软硬链接的区别:

  • 硬链接就是相当于给原有文件取别名,硬链接生成的文件和原有文件对应的 inode 是相同的。原有文件删除,并不会影响硬链接生成的文件,只是 inode 中的引用计数减去了 1。但软链接却不同,软链接并不是使用 inode 编号来表示的,而是通过文件名来标识的。
  • 软链接生成的文件有独立的 inode,也就有自己的数据块,其数据块中保存了原有文件的路径。如果删除了原有文件,那么软链接就失效了。但是如果在新建相同名字的文件,软链接会再次生效。但文件的内容肯定是不一样的,这相当于偷梁换柱。

💕 理解创建普通文件和目录文件的默认链接数

创建一个普通文件的默认链接数是1,这是因为一个普通文件,自身就和该普通文件的iode建立了一个人映射关系,所以创建一个普通文件的默认链接数就是1了。

创建一个目录文件的默认链接数是2,这是因为当前路径的目录文件的inode编号和目录文件中的当前目录.的inode编号是相同的。所以,创建一个目录文件的默认链接数就是2了,如果在当前目录下创建一个新的目录Test,那么Test中的上级目录..的inode和当前目录是相同的,所以引用计数就变成3了。

Linux 不允许普通用户给目录建立硬链接。原因是引入了对目录的硬连接就有可能在目录中引入循环,在目录遍历的时候系统就会陷入无限循环当中,这样导致无法定位到访问目录。Linux 的目录结构是一棵以 “/” 为根节点的树,如果允许自定义硬连接,则很有可能会破坏这个结构,甚至形成循环;而一旦形成循环,对于需要遍历目录树的命令,是致命的。所以为了避免对目录树结构的破坏,Linux 不允许用户自定义硬连接在目录上。

但是可以为目录建立软链接,因为软链接生成的文件会有独立的 inode 且该文件的类型为l。注:... 是操作系统给目录建立的硬链接。


3. ACM 时间

  • A(Access):最后一次访问文件的时间。这个时间并不是访问一次就会更新,而是达到一定的访问次数或者最近两次访问时间的间隔比较长才会更新该时间。因为访问文件的概率比修改文件的概率要大得多,所以如果该时间被频繁更改会降低 Linux 系统的效率。
  • C(Change):最后一次修改文件属性的时间。一般文件内容被修改,文件属性的修改时间也会更新,因为文件的大小也会方式变化。
  • M(Modify):最后一次修改文件内容的时间。
  • touch指令可以将以上三个时间全部更新为当前时间。
  • 细节:所有文件的属性和位图结构需要先被加载到内存中,才能进行更改数据的更改。更改完后,才能将数据写回到磁盘中。

四、动静态库

1. 动静态库的介绍

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)。
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。

2. 静态库的制作

在制作静态库之前,我们先来回顾一下以前我们在学习C语言的时候,多文件的分离编译的写法:

//add.h
#pragma once
#include<stdio.h>
extern int Add(int a,int b);

//add.c
#include"add.h"
int Add(int a,int b)
{
  return a + b;
}

//sub.h
#pragma once 
#include<stdio.h>
extern int Sub(int a,int b);

//sub.c
#include<stdio.h>

int Sub(int a,int b)
{
  return a - b;
}

#include"add.h"
#include"sub.h"

int main()
{

   int x = 100;
   int y = 34;
   printf("%d + %d = %d\n", x, y, Add(x, y));
   printf("%d - %d = %d\n", x, y, Sub(x, y));
   return 0;
}

当我们编译这三个文件时,需要输入指令:

gcc add.c main.c sub.c

在这里插入图片描述

现在这种情况还算好,因为需要编译的.c文件并不是很多,但如果有一天我们需要编译的目标文件非常多的情况下,写起来就会非常的麻烦。而且在传输的过程中很有可能会出现目标文件丢失的情况。那么为了避免这种情况的发生,这里我们可以使用库来将目标文件打包,形成的包就是我们今天所要讲解的动静态库了。下面,我们先来看一下静态库的制作:

ar -rc libSResult.a add.o sub.o
//ar是GNU中的归档工具,archive——归档
//-r 替换
//-c 创建
//lib——库的前缀,.a——静态库的后缀,两者之间的内容就是静态库的名称了

在这里插入图片描述

我们可以给对方提供.o文件(方法的实现),同时还有提供.h(里面包含着都有哪些方法),此时对方是能用的。为了让用户更好的使用库,我们就有把所有的.o文件打成一个包,给对方提供一个库文件即可!把多个.o合并成一个文件,这个文件就是库,把包方式的不同就分为了动态库和静态库。库的本质就是.o文件的集合。

💕 使用Makefile来生成静态库:

libSResult.a:add_s.o sub_s.o
	ar -rc libSResult.a sub_s.o add_s.o
add_s.o:add.c
	gcc -c add.c -o add_s.o -std=c99
sub_s.o:sub.c
	gcc -c sub.c -o sub_s.o -std=c99
.PHONY:out
out:
	mkdir -p out/include
	mkdir -p out/lib 
	cp -rf *.h out/include
	cp -rf *.a out/lib 

.PHONY:clean
clean:
	rm -rf *.o libSResult.a out

在这里插入图片描述

将其他的文件清理之后,我们将文件只剩下静态库我们要执行的.c文件

在这里插入图片描述

将静态库拷贝到系统默认的搜索路径,头文件的默认搜索路径是:/usr/include/,库文件的默认搜索路径是:/lib64/ 或者 /usr/lib64

在这里插入图片描述

接下来我们就可以编译我们的代码了,但是因为gcc默认链接的静态库是/lib64/libc.a,因此如果我们想要让我们自己的程序链接我们自己写的静态库,需要使用如下的指令:

gcc main.c -l静态库名称
//这里我们需要注意的是,静态库的名称是我们的静态库掉前缀,去掉后面的.a

在这里插入图片描述

但是,由于我们自己写的库并没有经过可靠的验证,所以一般不建议将我们的库写入系统的默认路径。因此,最后我们需要将我们的静态库卸载掉。

在这里插入图片描述

指定头文件、库的路径和要链接的库

gcc main.c -I ./hello/include/ -L ./hello/lib/ -lhello
//-I 指明头文件所在的路径
//-L 指明库的路径
//-l 指明所要路径的库(因为库路径下可能不止一个库)

3. 动态库的制作

静态库的代码会被拷贝到可执行程序中,动态库在没有被链接前就会被编译好,当使用动态库时,并不是直接将代码拷贝到可执行程序中,而是让可执行程序与动态库产生关联。

💕 生成目标文件

gcc -fPIC -c add.c -o add_d.o -std=c99
gcc -fPIC -c sub.c -o sub_d.o -std=c99
readelf -S 目标文件名 #查查看ELF格式的文件信息

-fPIC 选项的意思是形成与位置无关的目标二进制文件。动态库形成后,可以在内存的任意位置加载。而静态库的代码是拷贝到可执行程序中,可执行程序是有自己的地址空间的,所以静态库的代码需要拷贝到地址空间的特定位置,这就是与位置有关。静态库是按照绝对编址的方式,而动态库是按照相对编址(段地址+偏移量)的方式。

💕 将目标文件打包

打包动态库使用的是gcc + -shared 选项,这里我们需要注意的是,一定要加上 -shared选项。

gcc -shared add_d.o sub_d.o -o libDResult.so

在这里插入图片描述

使用 Makefile 来生成动态库:

libDResult.so:add_d.o sub_d.o
	gcc -shared -o libDResult.so sub_d.o add_d.o
add_d.o:add.c
	gcc -c add.c -o add_d.o -std=c99
sub_d.o:sub.c
	gcc -c sub.c -o sub_d.o -std=c99
.PHONY:out
out:
	mkdir -p out/include
	mkdir -p out/lib 
	cp -rf *.h out/include
	cp -rf *.so out/lib 

.PHONY:clean
clean:
	rm -rf *.o *.so out

在这里插入图片描述

现在我们将我们生成的动态库main.c一起拷贝到一个新的文件夹demo下:

[cjl@iZ8vb3efb0tbtvz8lz3upyZ demo]$ ls
main.c  out

💕 链接动态库

gcc main.c -I out/include/ -L out/lib/ -lDResult

在这里插入图片描述
在这里插入图片描述

当我们链接动态库并生成可执行程序后,当我们执行这个可执行程序时,发现其报错原因是无法找到对应的动态库。 这是因为我们的库路径只告诉了gcc,而gcc只工作到可执行程序的形成,但是动态库是程序在运行的时候才去链接动态库中的代码的。但是操作系统和shell却不知道库文件的位置,所以我们还需要在程序运行时告诉操作系统动态库的位置。而程序运行时操作系统会去两个地方查找动态库,一个是默认的路径下(lib64),另一个就是环境变量 $LD_LIBRARY_PATH中,所以我们可以将我们的库文件添加到这两个地方。

这里我们需要注意两点:

  • 如果out/lib/路径下只有静态库时,可以生成对应的可执行程序。这是因为 gcc 默认链接的是动态库,而如果只有我们自己制作的静态库,没有自己制作的动态库,那么就只能链接该静态库了。
  • 系统的动态库还是动态链接的,只是静态链接自己制作的静态库。如果想让全部库都是静态链接的话,需要加上 -static 选项。-static 的意义就是摒弃优先使用动态库的原则,而是直接使用静态库。

那么面对操作系统找不到动态库的情况,我们应该如何解决呢?下面我们了解一下动态库的加载,这个问题就可以迎刃而解了!


4. 动态库的加载

我们知道,在静态链接中,静态库的代码会直接被拷贝到可执行程序中。因此,当执行可执行程序时,静态库的代码也会被加载到内存中。那么,对于动态库的动态链接又是怎么做的呢?对于动态链接来说,可执行程序和动态库是分批加载的,动态库的代码会被加载到进程地址空间的共享区。

在这里插入图片描述

动态库的加载过程:

操作系统将磁盘中的动态库加载到物理内存中,然后通过页表将其映射到该进程的地址空间的共享区中,然后立即确定该动态库在进程地址空间中的地址,即动态库的起始地址,然后继续执行代码。此时操作系统就可以通过库函数中存放的地址。即.o文件在动态库中的偏移量,在加上动态库的起始地址得到.o文件的地址,然后跳转到共享区中执行函数,执行完之后跳转回来继续执行代码段后面的代码。这就是完整的动态库的加载过程。

如果多个进程使用同一个静态库,内存中就会有许多份静态库的代码,这样就会造成内存的浪费。但如果多个进程使用同一个动态库,动态库也只需要加载一次——动态库被加载到物理内存中并通过页表映射到某一个进程(假设是A进程)的共享区后,操作系统会记录该动态库在A进程共享区中的位置,当其他进程也需要执行该动态库的代码时,操作系统会根据记录的地址 + 偏移量通过页表跳转到A进程的共享区中执行该函数,执行完毕后再跳转回当前进程地址空间的代码段处。所以内存中只需要有一份动态库代码就可以了。

那么,对于上面 操作系统找不到动态库的情况 我们应该怎么做呢?

  1. 将动态库导入环境变量LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/cjl/Date_4-20/out/lib/

在这里插入图片描述

  1. 新增配置文件

/etc/ld.so.conf.d/路径下创建一个.conf后缀的文件,该文件中保存动态库的路径,最后输入 sudo ldconfig 指令更新配置文件即可。

在这里插入图片描述

.conf后缀文件中需要添加的动态库的路径:

/home/cjl/Date_4-20/out/lib

删除配置文件

在这里插入图片描述

  1. 在/lib64/路径下创建一个与动态库的软链接

在这里插入图片描述

💕 库的意义

站在使用库的角度,库的存在,可以大大减少我们开发的周期,提高软件本身的质量 (健壮性等)。同时还有许多好玩的库,比如:ncurses(基于字符的界面库),搜索关键词 Centos 7 yum 安装 ncurses。 boost(C++ 的准标准库)。


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从0搭建Vue3组件库(十一): 集成项目的编程规范工具链(ESlint+Prettier+Stylelint)

欲先善其事,必先利其器。一个好的项目是必须要有一个统一的规范,比如代码规范,样式规范以及代码提交规范等。统一的代码规范旨在增强团队开发协作、提高代码质量和打造开发基石,所以每个人必须严格遵守。 本篇文章将引入 ESLintPrettierStylelint 来对代码规范化。 ESlint ES…

【计算机网络】学习笔记:第三章 数据链路层(八千字详细配图)【王道考研】

基于本人观看学习b站王道计算机网络课程所做的笔记&#xff0c;不做任何获利 仅进行交流分享 特此鸣谢王道考研 若有侵权请联系&#xff0c;立删 如果本篇笔记帮助到了你&#xff0c;还请点赞 关注 支持一下 ♡>&#x16966;<)!! 主页专栏有更多&#xff0c;如有疑问欢迎…

redhat 8.7 安装oracle 11g-11.2.0.4

redhat 8.7 安装oracle 11g-11.2.0.4 1、写在前面&#xff1a;这篇文章最后安装失败了。这是一次失败的尝试&#xff0c;仅做记录。结论是RHEL 8不支持Oracle 11g-11.2.0.4 安装&#xff0c;后续再研究怎么跑起来。1、数据库下载和安装文档1.1、查看oracle 11g 适合安装的linux…

阿里云版GPT官宣,我们问了它10个问题

4月7日&#xff0c;阿里云宣布自研大模型“通义千问”&#xff0c;目前已开始邀请用户测试体验。 阿里达摩院在NLP自然语言处理等前沿科研领域早已布局多年&#xff0c;并于2019年启动大模型研发&#xff0c;通义千问便是其最新成果&#xff0c;相当于阿里云版的“ChatGPT”。 …

让GPT成为护理专家 - 护士的工作如此简单

引子    书接上文《GPT接入企微应用 - 让工作快乐起来》&#xff0c;我把GPT接入了企微应用&#xff0c;不少同事都开始尝试起来了。有的浅尝辄止&#xff0c;有的刨根问底&#xff0c;五花八门&#xff0c;无所不有。这里摘抄几份&#xff1a; “帮我写一份表白信&#xff…

【Prompt】7 个向 chatGPT 高效提问的方法

欢迎关注【youcans的 AIGC 学习笔记】原创作品 【Prompt】7 个向 chatGPT 高效提问的方法 0. 向 chatGPT 高效提问的方法1. 提问方法&#xff1a;明确问题2. 提问方法&#xff1a;简洁清晰3. 提问方法&#xff1a;避免歧义4. 提问方法&#xff1a;提供上下文5. 提问方法&#x…

很不错的一篇文章,值得点赞收藏,带你全面了解MySQL性能调优、错误代码总结和全局参数配置(持续更新中ing)

前言 本文主要介绍当前MySQL性能优化原理实战&#xff0c;包括以下方面&#xff1a; 已更新文章目录MySQL遇到的的错误及解决方法全局参数文件配置详解。 后续希望大家提出宝贵的建议。喜欢的话点赞收藏关注走一波。如有错误的地方&#xff0c;请指出&#xff01;&#xff01;&…

C51 - 自写操作系统

最简OS 1> 版本1&#xff1a;任务建立与切换2> 版本2&#xff1a;定时器切换2.1> main.c2.2> task.c2.3> sleep.c 3> 版本3&#xff1a;加时间片轮转 在51单片机上&#xff0c;实现操作系统最简模型&#xff0c; 学习理解操作系统的基本概念&#xff1b; &am…

〖Python网络爬虫实战㉑〗- 数据存储之JSON操作

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

912. 排序数组

1.题目&#xff1a; 2.我的代码&#xff1a; C语言&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* sortArray(int* nums, int numsSize, int* returnSize) {//希尔排序int gap numsSize;//多次预排while (gap > 1) {/…

【Linux】初识Linux

目录 &#x1f34e;一.Linux历史&#x1f34e; 1.UNIX发展的历史 2.Linux发展历史 &#x1f34f;二.开源&#x1f34f; &#x1f351;三.官网&#x1f351; &#x1f34a;四.企业应用现状&#x1f34a; 1.Linux在服务器领域的发展 2.Linux在桌面领域的发展 3.Linux在移…

自实现朴素贝叶斯分类器with案例:基于SMS Spam Collection数据集的广告邮件分类

目录 贝叶斯分类器何为朴素案例&#xff1a;基于SMS Spam Collection数据集的广告邮件分类SMS数据集词向量表示Laplacian平滑训练过程分类过程 完整代码 贝叶斯分类器 首先要理解贝叶斯决策的理论依据&#xff0c;引用西瓜书上的原话&#xff1a;对于分类任务&#xff0c;在所…

【小呆的力学笔记】非线性有限元的初步认识【二】

文章目录 1.2 有限元分析的数学原理1.2.1 基于最小势能原理的变分法提法1.2.1.a 弹性力学方程简化记法1.2.1.b 应变能密度和应变余能密度1.2.1.c 最小势能原理变分基础 1.2 有限元分析的数学原理 书接上回&#xff0c;我们已经回顾了线性有限元分析的理论基础——线弹性力学的…

TryHackMe-Lunizz CTF(boot2root)

Lunizz CTF 端口扫描 循例nmap Web枚举 进80&#xff0c;apache默认页面 gobuster扫一下目录 /hidden一个文件上传点, 图片上传后无权访问/hidden/uploads/ /whatever一个假的命令执行点 /instructions.txt 由 CTF_SCRIPTS_CAVE 制作&#xff08;不是真实的&#xff09;感谢…

如何看待人工智能技术的变革与未来?

人工智能是当今科技领域中最具前景的技术之一。从最初的逻辑推理到现在的深度学习&#xff0c;人工智能技术的发展已经经历了多个阶段。在本文中&#xff0c;我们将从技术的角度&#xff0c;探讨人工智能的发展历程和未来发展趋势。 一、起源和逻辑推理阶段 人工智能的起源可…

【五一创作】Java 反射

在了解反射前&#xff0c;我们先要知道一些相关知识 Class类 Class类的实例表示java应用运行时的类或接口&#xff0c;每个java类运行时都在JVM里表现为一个class对象&#xff0c;可通过类名.class、类型.getClass()、Class.forName("类名")等方法获取class对象。 …

关于 IO、存储、硬盘和文件系统

关于IO、存储、硬盘和文件系统 0.引入1.了解IO1.1.存储器IO1.2.设备IO 2.存储介质和存储类型2.1.内存2.2.硬盘2.3.固态硬盘&#xff08;SSD&#xff09;2.4.U盘 3.硬盘的工作原理3.1.磁头3.2.盘片3.3.电动机3.4.硬盘的读写操作 4.文件系统概述4.1.文件系统的类型4.2.文件系统的…

vagrant virtualbox 复制

菜鸟学习&#xff0c;记录一下 vagrant virtualbox 虚拟机复制。 目录 第一步&#xff0c;使用 virtualbox 复制虚拟机 第二步&#xff0c;复制 vagrant 文件 第三步&#xff0c;重命名相关文件夹及文件并修改配置&#xff1a; 第四步&#xff0c;注册运行复制后的虚拟机 第…

ImageJ实践——测量大小/长短(以细胞为例)

ImageJ是一款功能强大的图像处理软件。毫无疑问它在测量方面提供了十分便利的功能。下面我将以测量细胞的长短、大小&#xff08;面积&#xff09;为例&#xff0c;详细介绍ImageJ的测量操作流程。 1. ImageJ打开图像文件 在弹出的文件选择对话框中选择目标文件&#xff0c;即…

Spring Data Elasticsearch--ElasticsearchRestTemplate--使用/教程/实例

原文网址&#xff1a;Spring Data Elasticsearch--ElasticsearchRestTemplate--使用/教程/实例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文用实例来介绍如何使用Spring Data Elasticsearch的ElasticsearchRestTemplate来操作ES。包括&#xff1a;索引的增删等、文档的增删改查…