【Linux】文件操作|文件描述符|重定向

news2024/11/15 5:23:09

文章目录

  • 1.文件操作系统调用的几个基本接口
    • open
    • write
    • read
    • lseek
    • write read close lseek ,对比C文件相关接口
  • 2.如何理解文件操作?
  • 3.文件描述符fd
    • 文件描述符的分配规则
    • 重定向
    • 使用 dup2 系统调用进行重定向
  • 4.在自己的shell中添加重定向功能:

1.文件操作系统调用的几个基本接口

这是C语言文件操作的博客博客链接。
操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问:


open

函数原型:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
文件已经存在推荐使用它打开
int open(const char *pathname, int flags, mode_t mode);
文件不存在推荐使用它打开,以便于设置文件权限。

参数:
pathname: 要打开或创建的目标文件,若没有指明路径,默认在进程的当前路径创建文件。

flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个选项进行“或”运算,构成flags。
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
O_TRUNC:清空文件原有内容

mode:设置新建文件的访问权限

umask 功能:查看或修改文件掩码 新建文件夹默认权限是0666、新建目录默认权限是0777 但实际上你所创建的文件和目录,看到的权限往往不是上面这个值。原因就是创建文件或目录的时候还要受到umask的影响。假设默认权限是mask,则实际创建的出来的文件权限是:
默认权限 & (~umask)
说明:将现有的存取权限减去权限掩码后,即可产生建立文件时预设权限。超级用户默认掩码值为0022,普通用户默认为0002。

我们设置mode的时候也要受umask的影响,如果设置位0666,则在普通用户下最后文件的权限就是0664。
open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。

返回值:
RETURN VALUE
open() and creat() return the new file descriptor, or -1 if an error occurred
(in which case, errno is set appropriately).
成功:返回新打开的文件描述符(后面会有介绍是一个int类型的整数)
失败:-1

write

函数原型:

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

返回值:
成功:返回写入的字节数,0表示什么都没写入
失败:返回-1,并设置全局变量errno

read

函数原型:

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

返回值:
成功:返回读取的字节数,如果在调read之前已到达文件末尾,则这次read返回0
失败:返回-1并设置errno。

lseek

所有打开的文件都有一个当前文件偏移量(current file offset),以下简称为 cfo。cfo 通常是一个非负整数,用于表明文件开始处到文件当前位置的字节数。读写操作通常开始于 cfo,并且使 cfo 增大,增量为读写的字节数。文件被打开时,cfo 会被初始化为 0,除非使用了O_APPEND 。
使用 lseek 函数可以改变文件的 cfo 。
函数原型:

#include <unistd.h>
#include <sys/types.h>
off_t lseek(int filedes, off_t offset, int whence);

返回值:
成功:新的偏移量,
失败:返回-1并设置errno。
参数:
参数 offset 的含义取决于参数 whence:

  1. 如果 whence 是 SEEK_SET,文件偏移量将被设置为 offset。
  2. 如果 whence 是 SEEK_CUR,文件偏移量将被设置为 cfo 加上 offset,offset 可以为正也可以为负。
  3. 如果 whence 是 SEEK_END,文件偏移量将被设置为文件长度加上 offset,offset 可以为正也可以为负。

上面几个函数的应用代码:有一些比较重要的细节。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int main()
{
    umask(0);
    //创建不存在的文件,然后清空文件里的内容
    int fd = open("log.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
    //创建不存在的文件,然后追加文件
    //  int fd = open("log.txt", O_WRONLY  | O_CREAT | O_APPEND, 0666);
    //  int fd = open("log.txt", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return 1;    
    }    
    
    //以\0为结尾,作为字符串结束标志是C语言规定的,
    //跟文件没有关系,所以往文件里写字符串的时候不需要考虑结尾加\0。    
    const char *msg= "I like Linux!";    
    write(fd , msg, strlen(msg));    
   
    lseek(fd,0,SEEK_SET );//重新定位
    char arr[64];    
    read(fd,arr,strlen(msg));
	arr[strlen(msg)+1]=0;

    printf("%s",arr);

    // fflush(stdout);
    close(fd);
    return 0;
}

write read close lseek ,对比C文件相关接口

先来认识一下两个概念: 系统调用 和 库函数。
上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。而open close read write lseek 都属于系统提供的接口,称之为系统调用接口。
来看下面的一张图:
在这里插入图片描述
系统调用接口和库函数的关系一目了然。可以认为,C语言文件操作的函数,都是对系统调用的封装,方便二次开发,系统调用更接近底层。同样,其他语言只要是在Linux系统上跑的话,就可以统一使用系统调用来进行文件操作。减少了我们的学习成本。

2.如何理解文件操作?

Linux下一切皆文件!
文件操作的本质:进程被打开文件 的关系。
进程可以打开多个文件,系统中一定会存在大量的被打开的文件。被打开的文件需要被OS管理起来。
一说到管理那么就是先描述,再组织
操作系统为了管理对应打开的文件,必定要为文件创建对应的内核数据结构(struct file { })来标识文件。它内部包含了文件的大部分属性。

任何一个进程删除该文件时,另外一个进程会立即出现读写失败这句话是错误的。
删除文件实际上只是删除文件的目录项,文件的数据以及inode并不会立即被删除,因此若进程已经打开文件,文件被删除时,并不会影响进程的操作,因为进程已经具备文件的描述信息。

3.文件描述符fd

  • 通过对open函数的介绍,我们知道文件描述符就是一个小整数
  • Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
  • 0,1,2对应的物理设备一般是:键盘,显示器,显示器

在这里插入图片描述

文件描述符是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了files_struct结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程文件关联起来。
每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!
本质上,文件描述符就是该数组的下标。只要拿着文件描述符,就可以找到对应的文件。
所以输入输出还可以采用如下方式:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
	char buf[1024];
	ssize_t s = read(0, buf, sizeof(buf));
	if(s > 0){
	buf[s] = 0;
	write(1, buf, strlen(buf));
	write(2, buf, strlen(buf));
	}
	return 0;
}

文件描述符的分配规则

直接看代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
	int fd = open("myfile", O_RDONLY);
	if(fd < 0){
	perror("open");
	return 1;
	}
	printf("fd: %d\n", fd);
	close(fd);
	return 0;
}

运行结果是 fd: 3,关闭0或者2,再看

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
	close(0);
	//close(2);
	int fd = open("myfile", O_RDONLY);
	if(fd < 0){
	perror("open");
	return 1;
	}
	printf("fd: %d\n", fd);
	close(fd);
	return 0;
}

发现是结果是: fd: 0 或者 fd:2
可见,文件描述符的分配规则:在files_struct数组当中,从小到大按照顺序寻找最小的且没有被占用的fd,作为新的文件描述符。

重定向

推荐阅读
如果关闭1呢?看代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
	close(1);
	int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
	if(fd < 0){
	perror("open");
	return 1;
	}
	printf("fd: %d\n", fd);
	fflush(stdout);
	close(fd);
	exit(0);
}

执行结果:fd:1
此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这种现象叫做输出重定向。

常见的重定向有:>(输出重定向), >>(追加重定向), <(输入重定向)

类型符号用途备注
标准覆盖输出重定向1>将命令执行的正确结果默认输出的位置,修改为指定的文件或者终端(覆盖原有内容)通常’>'即可,1可以不写,默认就是1
标准追加输出重定向>>将命令执行的正确结果,输出到指定文件的末尾(不覆盖原有内容)-
错误覆盖输出重定向2>将命令执行的错误结果默认输出的位置,修改为指定的文件或者终端(覆盖原有内容)-
错误追加输出重定向2>>将命令执行的错误结果,输出到指定文件的末尾(不覆盖原有内容)-
标准输入重定向0<将命令中接收输入内容由默认的键盘,改为命令或者文件通常’<'即可0可以写也可以不写,默认0
标准输入追加重定向0<<将命令中接收输入内容由默认的键盘,改为命令或者文件-

在这里插入图片描述

那重定向的本质是什么呢?
重定向的本质是:上层用的fd不变,在内核中更改fd对应的struct file*的地址,改变它指针的指向。

每个文件描述符都是一个内核中文件描述信息数组的下标,对应有一个文件的描述信息用于操作文件,而重定向就是在不改变所操作的文件描述符的情况下,通过改变描述符对应的文件描述信息进而实现改变所操作的文件.
在这里插入图片描述

使用 dup2 系统调用进行重定向

函数原型如下:

#include <unistd.h>
int dup2(int oldfd, int newfd);

dup2,dup是英文 duplicate拷贝 的缩写,拷贝的是当前调用dup2的进程所对应的,文件描述符下标里面的内容(file*所对应的值,也就是地址)。
Linux里对其功能的描述如下:

makes newfd be the copy of oldfd, closing newfd first if necessary

假如int fd=open("./log", O_CREAT | O_RDWR); dup2(fd,1),那么就是把fd里的内容拷贝到1里,让1也指向fd,那么最后本来要输入到1对应的文件里的内容,最后就输入到了fd对应的文件里。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
	int fd = open("./log", O_CREAT | O_RDWR);
	if (fd < 0) {
		perror("open");
		return 1;
	}
	close(1);
	dup2(fd, 1);
	for (;;) {
		char buf[1024] = { 0 };
		ssize_t read_size = read(0, buf, sizeof(buf) - 1);
		if (read_size < 0) {
			perror("read");
			break;
		}
		printf("%s", buf);
		fflush(stdout);
	}
	return 0;
}

4.在自己的shell中添加重定向功能:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>

#define NUM 1024
#define OPT_NUM 64

#define NONE_REDIR   0
#define INPUT_REDIR  1
#define OUTPUT_REDIR 2
#define APPEND_REDIR  3

#define trimSpace(start) do{\
            while(isspace(*start)) ++start;\
        }while(0)

char lineCommand[NUM];
char *myargv[OPT_NUM]; //指针数组
int  lastCode = 0;
int  lastSig = 0;

int redirType = NONE_REDIR;
char *redirFile = NULL;

// "ls -a -l -i > myfile.txt" -> "ls -a -l -i" "myfile.txt" ->
void commandCheck(char *commands)
{
    assert(commands);
    char *start = commands;
    char *end = commands + strlen(commands);

    while(start < end)
    {
        if(*start == '>')
        {
            *start = '\0';
            start++;
            if(*start == '>')
            {
                // "ls -a >> file.log"
                redirType = APPEND_REDIR;
                start++;
            }
            else
            {
                // "ls -a >    file.log"
                redirType = OUTPUT_REDIR;
            }
            trimSpace(start);
            redirFile = start;
            break;
        }
        else if(*start == '<')
        {
            //"cat <      file.txt"
            *start = '\0';
            start++;
            trimSpace(start);
            // 填写重定向信息
            redirType = INPUT_REDIR;
            redirFile = start;
            break;
        }
        else
        {
            start++;
        }
    }
}


int main()
{
    while(1)
    {
        redirType = NONE_REDIR;
        redirFile = NULL;
        errno = 0;

        // 输出提示符
        printf("用户名@主机名 当前路径# ");
        fflush(stdout);

        // 获取用户输入, 输入的时候,输入\n
        char *s = fgets(lineCommand, sizeof(lineCommand)-1, stdin);
        assert(s != NULL);
        (void)s;
        // 清除最后一个\n , abcd\n
        lineCommand[strlen(lineCommand)-1] = 0; // ?
        //printf("test : %s\n", lineCommand);
        
        // "ls -a -l -i" -> "ls" "-a" "-l" "-i" -> 1->n
        // "ls -a -l -i > myfile.txt" -> "ls -a -l -i" "myfile.txt" ->
        // "ls -a -l -i >> myfile.txt" -> "ls -a -l -i" "myfile.txt" ->
        // "cat < myfile.txt" -> "cat" "myfile.txt" ->
        commandCheck(lineCommand);
        // 字符串切割
        myargv[0] = strtok(lineCommand, " ");
        int i = 1;
        if(myargv[0] != NULL && strcmp(myargv[0], "ls") == 0)
        {
            myargv[i++] = (char*)"--color=auto";
        }

        // 如果没有子串了,strtok->NULL, myargv[end] = NULL
        while(myargv[i++] = strtok(NULL, " "));

        // 如果是cd命令,不需要创建子进程,让shell自己执行对应的命令,本质就是执行系统接口
        // 像这种不需要让我们的子进程来执行,而是让shell自己执行的命令 --- 内建/内置命令
        if(myargv[0] != NULL && strcmp(myargv[0], "cd") == 0)
        {
            if(myargv[1] != NULL) chdir(myargv[1]);
            continue;
        }
        if(myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0], "echo") == 0)
        {
            if(strcmp(myargv[1], "$?") == 0)
            {
                printf("%d, %d\n", lastCode, lastSig);
            }
            else
            {
                printf("%s\n", myargv[1]);
            }
            continue;
        }
        // 测试是否成功, 条件编译
#ifdef DEBUG
        for(int i = 0 ; myargv[i]; i++)
        {
            printf("myargv[%d]: %s\n", i, myargv[i]);
        }
#endif
        // 内建命令 --> echo

        // 执行命令
        pid_t id = fork();
        assert(id != -1);

        if(id == 0)
        {
            // 因为命令是子进程执行的,真正重定向的工作一定要是子进程来完成
            // 如何重定向,是父进程要给子进程提供信息的
            // 这里重定向不会影响父进程,进程具有独立性
            switch(redirType)
            {
                case NONE_REDIR:
                    // 什么都不做
                    break;
                case INPUT_REDIR:
                    {
                        int fd = open(redirFile, O_RDONLY);
                        if(fd < 0){
                            perror("open");
                            exit(errno);
                        }
                        // 重定向的文件已经成功打开了
                        dup2(fd, 0);
                    }
                    break;
                case OUTPUT_REDIR:
                case APPEND_REDIR:
                    {
                        umask(0);
                        int flags = O_WRONLY | O_CREAT;
                        if(redirType == APPEND_REDIR) flags |= O_APPEND;
                        else flags |= O_TRUNC;
                        int fd = open(redirFile, flags, 0666);
                        if(fd < 0)
                        {
                            perror("open");
                            exit(errno);
                        }
                        dup2(fd, 1);
                    }
                    break;
                default:
                    printf("bug?\n");
                    break;
            }

            execvp(myargv[0], myargv); 
            // 执行程序替换的时候,不会影响曾经进程打开的重定向的文件
            exit(1);
        }
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        assert(ret > 0);
        (void)ret;
        lastCode = ((status>>8) & 0xFF);
        lastSig = (status & 0x7F);
    }
}

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

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

相关文章

唯品会api_sign分析

本次分析的案例是唯品会app,版本号:7.45.6 抓个包,请求头中有个api_sign,该字段就是本次分析的对象。 1.jadx 静态分析 直接搜索关键词:api_sign= 跟进去,来到这里。 这里用到了VCSPSecurityBasicService.apiSign()方法,双击两下,找到函数的定义地方。 这里引用到的方…

【机器学习实战】四、实现线性回归模型案例

线性回归案例 一、初始化方法 1.对数据进行预处理模块&#xff0c;调用prepare_for_training方法&#xff0c;得到返回值data_processed, features_mean, features_deviation 2.得到所有的特征个数&#xff0c;即data的特征维数的列(行shape[0]&#xff0c;列shape[1]) 3.初始…

怎么获取level2行情接口数据?

怎么获取level2行情接口数据比较方便呢&#xff1f;其实level2行情接口可以实时计算沪深所有股票数据&#xff0c;主要是可以让交易者方便引用和计算公式再进入股票池&#xff0c;就比如说一个分笔数据含有10-20个分笔数据&#xff0c;用分笔数据计算的资金流入数据不准确&…

< Linux > 进程控制

目录 1、进程创建 fork函数 fork函数返回值 写时拷贝 fork常规用法 fork调用失败的原因 2、进程终止 2.1、进程退出常见场景 2.2、进程退出码 2.3、进程常见退出方法 _exit函数 exit函数 return退出 2.4、关于终止&#xff0c;内核做了什么 3、进程等待 3.1、进程等待必要性…

解决VS2019+Qt5+Vcpkg工程无法调试但Release正常运行的问题

前言——这个问题可能比较小众&#xff0c;但是因为解决了我自己的问题&#xff0c;所以特此把解决方法分享出来&#xff0c;以给特定的人提供必要的帮助。 项目原因&#xff0c;一直使用VS2019Qt5Vcpkg&#xff0c;无奈程序一直无法进行调试&#xff0c;Release模式倒是正常运…

计算机图形学 Ray Trace 学习笔记

屏幕上的一个像素&#xff0c;是通过各种反射、折射而共同组成的&#xff0c;每个反射折射的点&#xff0c;都会考虑光源是否有直接照射到反射折射的点上&#xff0c;反射与折射之间会存在能量衰减&#xff0c;最终汇总在屏幕的像素上。 计算是哪一个三角形被射线打中&#xff…

Hive SQL 每日SQL

1、查询订单明细表&#xff08;order_detail&#xff09;中销量&#xff08;下单件数&#xff09;排名第二的商品id&#xff0c;如果不存在返回null&#xff0c;如果存在多个排名第二的商品则需要全部返回。 需要用到的表&#xff1a; 订单明细表&#xff1a;order_detail 代码…

【谷粒商城基础篇】仓储服务:仓库维护

谷粒商城笔记合集 分布式基础篇分布式高级篇高可用集群篇简介&环境搭建项目简介与分布式概念&#xff08;第一、二章&#xff09;基础环境搭建&#xff08;第三章&#xff09;整合SpringCloud整合SpringCloud、SpringCloud alibaba&#xff08;第四、五章&#xff09;前端知…

android 创建aar包

1. 背景 由于新入职公司在做硬件接入的项目&#xff0c;需要接入多款硬件&#xff0c;而且&#xff0c;几个app的功能不太一样。于是&#xff0c;需要模块化开发&#xff0c;并且许多东西都是可以复用的&#xff08;像网络框架、log、shareprefrence、权限申请等&#xff09;。…

嵌入式HLS 案例开发步骤分享——Zynq-7010/20工业开发板(1)

目 录 前 言 3 1 HLS 开发流程说明 5 1.1 HLS 工程导入 5 1.2 编译与仿真 6 1.3 综合 8 1.4 IP 核封装 10 1.5 IP 核测试 14 前 言 本文主要介绍 HLS 案例的使用说明,适用开发环境: Windows 7/10 64bit、Xilinx Vivado 2017.4 、Xilinx Vivado HLS 2017.4 、Xilinx…

数据结构|排序算法详解

​​​​​​​目录 一.插入类 1.直接插入排序 2.希尔排序 二.选择类&#xff0c;排一次选出一个最值 1.选择排序 2.堆排序 三.交换类&#xff0c;通过一直交换一次确定数字的位置 1.冒泡排序 2.快速排序 2.1 hoare版本 2.2挖坑法 2.3前后指针法 四.归并类 1.归并…

Go第 5 章:程序流程控制

第五章程序流程控制 5.1程序流程控制介绍 在程序中&#xff0c;程序运行的流程控制决定程序是如何执行的&#xff0c;是我们必须掌握的&#xff0c;主要有三大流程控 制语句。 1)顺序控制 2)分支控制 3)循环控制 5.2 顺序控制 程序从上到下逐行地执行&#xff0c;中间没有任…

C++标准库的智能指针:shared_ptr、weak_ptr和unique_ptr

文章目录智能指针shared_ptr模版类week_ptr模版类unique_ptrC中是没有内存回收机制的&#xff0c;我在之前的一篇文章中提到使用指针的一些基本方法。C在std标准库中也提供了三种封装过的指针模版类&#xff0c;称作为智能指针&#xff1a;shared_ptrunique_ptrweek_ptr 我这里…

JVM性能调优详解

前面我们学习了整个JVM系列&#xff0c;最终目标的不仅仅是了解JVM的基础知识&#xff0c;也是为了进行JVM性能调优做准备。这篇文章带领大家学习JVM性能调优的知识。 性能调优 性能调优包含多个层次&#xff0c;比如&#xff1a;架构调优、代码调优、JVM调优、数据库调优、操…

最优二叉树(哈夫曼树)

一、最优二叉树 1、定义 官方定义&#xff1a;在权值为w1&#xff0c;w2&#xff0c;…&#xff0c;wn的 n个叶子所构成的所有二叉树中&#xff0c;带权路径长度最小(即代价最小)的二叉树称为最优二叉树或哈夫曼树。 通俗来讲&#xff0c;就是给定N个权值作为N个叶子结点&…

仿牛客论坛项目总结

一.数据库中每一张表有哪些字段 user表 用户表 &#xff08;1&#xff09;id 用户的id &#xff08;2&#xff09; username 用户名 &#xff08;3&#xff09;password 密码 &#xff08;4&#xff09;salt 盐 &#xff08;5&#xff09;emai邮箱 &#xff08;6&…

PAT甲级1008 Elevator C++/C语言

1008 Elevator 分数 20 作者 CHEN, Yue 单位 浙江大学 The highest building in our city has only one elevator. A request list is made up with N positive numbers. The numbers denote at which floors the elevator will stop, in specified order. It costs 6 seconds …

联邦学习将如何影响您的日常生活?

人工智能 (AI) 被认为是下一次工业革命的最大创新之一&#xff0c;其中包括机器学习。另一方面&#xff0c;随着原油和电力成为现代工业的基础资源&#xff0c;数据成为人工智能和机器学习的关键要素。 数据隐私与需求之间的冲突 训练的数据样本的大小决定了可用于增强 AI 性能…

CPT203-Software Engineering(2)

文章目录5. Scrum Framework5.1 Scrum Roles5.2 Scrum Activities and Artifacts6. Requirements Engineering6.1 User requirements and system requirements6.2 Functional & Non-functional requirements6.2.1 Functional requirements6.2.2 Non-functional requirement…

第一章:C++算法基础之基础算法

系列文章目录 文章目录系列文章目录前言一、排序&#xff08;1&#xff09;快速排序核心思想思路分析模板&#xff08;2&#xff09;归并排序核心思想思路分析模板稳定性时间复杂度二分查找&#xff08;1&#xff09;整数二分核心思想思路分析模板&#xff08;2&#xff09;浮点…