- 博客(59)
- 收藏
- 关注
原创 http协议
在应用层http协议是一个很重要的协议,它定义了客户端和服务器之间如何通信,交换和传输超文本(超文本:可以传输图片或视频等)。我们平时说的网址就是URL,如下:前面的https是获取资源的协议,://是协议分隔符,www.gitee.com是域名,/qingsong-zzz/linux-learning是要访问资源的路径。
2025-11-24 15:51:45
792
原创 网络基础概念
简单来说协议就是约定!一般由国际知名的组织和机构来制定。最经典的就是ISO制定的OSI协议。在OSI中分为7层,设计成层状设计是为了更好的解耦和和模块化,该7层分别是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。OSI协议制定的非常完善,但在实际的操作上会话层、表示层、应用层不可能接入到操作系统中,所以在实际工程中是5层协议也就是TCP/IP协议。
2025-10-17 20:23:22
558
原创 线程的互斥与同步
它是一种线程同步原语,允许线程在某个条件不满足时挂起等待,直到其他线程改变该条件并通知它们。怎么理解呢?假设现在有一个盘子,有两个人一个人向盘子里放苹果二个人从盘子中拿苹果。对于拿苹果的人来说当盘子里有苹果时拿取,没有苹果时他需要等待(两个人会按照先后顺序排成队列,依次去拿取),当放苹果的人放好后会提醒拿苹果的人。这里盘子即临界资源,拿放苹果的人即线程,当盘子里无苹果即不满足某个条件,拿苹果的人等待即挂起等待,苹果放好即改变条件,然后通知。
2025-10-10 09:00:34
543
原创 线程的概念和控制
在讨论线程时离不开进程,进程是承担分配系统资源的基本实体,那线程呢?线程是CPU调度的基本单位。这么说还是很抽象,大家先看下图:上图相信大家都很熟悉,这是进程从虚拟到物理的映射图。进程占据着系统资源比如CPU资源、内存资源等。当我们在一个程序中同时执行多个相对独立的任务时,如果采用单进程就会造成任务逻辑耦合度高,代码的可读性和可维护性会变差;采用多进程他们之间资源共享麻烦,并且每次创建和调度开销也大。所以引入了线程!你拥有的资源,在安全情况下就是有多少个虚拟地址,虚拟地址就是资源的代表。
2025-10-01 10:34:55
1072
原创 进程间信号
最常见的就是ctrl + c它是向目标进程发送信号,相当一部分的信号的处理动作就是终止自己。“相当一部分的信号”这是什么意思?其实在信号的处理动作不仅仅只有它的默认动作,还有自定义动作或忽略。
2025-09-24 09:48:30
788
原创 进程间通信
它通过让多个进程访问同一块物理空间来实现数据交换,该区域会被映射进程的虚拟空间中,共享内存有极致的访问速度因为直接放到内存中不会像管道通信还得拷贝到管道中。但是它没有同步机制即保护机制,可以认为一个进程正在写而另一个进程进入也开始写这时就会内容就会混在一起。共享内存的生命周期和内核的一样不随进程的结束而消失。内存中有多个进程不可能只用一个共享内存来通信,所以必然在内存中会有多个共享内存,所以我们需要进行管理依然是先描述在组织。
2025-09-18 23:36:58
849
原创 库的制作与原理
start会调用动态链接器的代码来解析和加载程序中所依赖的库,并且实现符号解析和地址重定位,确保程序中的函数可以正确映射到动态库的实际地址。可以看到在main.c文件中puts(printf的实现)和func在Ndx(符号所在的节索引)中都是UND表示该符号在当前文件中未定义,在链接时链接器会拿着符号表中的信息,将未定义的符号与对应的定义进行匹配。EIP会指示 CPU下一条要执行的指令在内存中的地址,CR3会定位页表的起始地址,然后通过MMU查询页表,将虚拟地址转换为物理地址 ,然后让CPU执行。
2025-09-10 15:18:16
1026
原创 ext系列文件系统
如果当该块组的数据区已满但仍有数据需要存储,那么就会使用其他块组的数据区,因为一个分区中所有数据区里的块的编号是唯一的。如 bolck 和 inode 的总量,未使用的 block 和 inode 的数量,一个 block 和 inode 的大小,最近一次挂载的时间,最近一次写入数据的时间等。在寻找某一扇区时,会先通过移动磁臂(会带动所有磁头同步沿径向移动)找到该扇区所在的柱面,也就是找到对应的磁道,然后通过激活特定编号的磁头来找到具体盘片和该盘片的正反面,最后通过转轴来找到扇面,这种方式被称为CHS。
2025-08-05 17:07:42
912
原创 基础 IO
当打开了一个设备文件时内核会创建一个struct file结构体,该结构体的f_op成员会先在设备管理表中找到对应设备的file_operations(驱动定义的操作函数集合)结构体,然后该结构体的地址赋值给f_op,后续如果要读写直接从f_op里找到对应函数即可,该技术被称为VFS,这样在进程看来访问的就都是文件,即用户以为“一切皆文件”!要访问文件,要先打开文件,进程通过系统调用请求操作系统打开文件,因为操作系统负责管理外设的IO操作,我们对文件的操作实际上是进程对文件的操作。当然是先描述,再组织!
2025-07-19 10:07:55
746
原创 简易Shell实现
仅使用strtok函数无法完整实现命令解析功能,需要配合全局变量存储分割结果(也就是创建一张命令行参数表),命令行参数表(g_argv)用来存放分割下来的字符,变量(g_argc)表示g_argv里内容数量。例如:用户在看到命令提示符后,输入"ls -a -l",然后对该命令进行拆解(其中要判断是否存在内建命令,重定向等),然后去执行命令并反馈结果。最多写入size-1字符,自动添加'\0'。读到'\n'或已经读了size-1个字符时停止,'\n'是会被包含在字符串里的,它会自动在字符串末尾加'\0'。
2025-07-11 10:04:07
1011
原创 进程——控制
进程终止的本质是释放系统资源,就是释放进程申请的相关内核数据结构和对应的数据和代码。代码运行完毕,结果正确代码运行完毕,结果不正确代码异常终止回收子进程的资源。如果子进程退出,而父进程不管它,这时就会有僵尸进程的问题,进而发生内存泄露。获取子进程的退出信息。父进程派给子进程的任务,父进程需要知道子进程完成的怎么样。简单来说就是一个新的进程替换当前正在运行的进程。
2025-06-23 09:35:25
1067
原创 进程——环境变量及程序地址空间
有了虚拟地址之后我们就不用把所有的代码和数据给一次性都给加载到物理内存里,而是分批次加载,甚至可以不加载,让进程只有PCB和页表,这时去查页表时如果物理地址为空就会发生缺页中断,进程会停下来等页表补充完后再次执行。命令行是可以定义变量的(命令行定义),这种变量被称为本地变量(支持该操作有一点原因是要支持脚本),它不会被继承,只能在当前的进程里使用。这些参数用于控制程序的行为等。上面是运行结果是不是感觉很熟悉,其实我们平时使用的指令,它里的选项就是这样实现的,通过上面就可以实现在一个函数里有不同的子功能。
2025-06-03 09:58:06
990
原创 进程——优先级及切换
进程切换的本质:保存和恢复进程的硬件上下文数据(即CPU里的寄存器里的内容)它被称为TSS(任务状态段)以前是存储到PCB里的。其实不只有分时还有实时操作系统,简单来说对于特定的进程它会把它直接执行完后或者该进程在等待资源时才会执行其他进程。像在智能交通就会有它的身影。
2025-05-26 14:43:45
739
原创 进程——概念及状态
大多数初学者会认为进程就是从硬盘加载到内存的可执行文件(当可执行文件被加载到内存里称为程序),实际上并不是这样的,进程其实是操作系统里进程控制块(PCB)和程序。进程控制块是进程的“灵魂”。程序:它里面包含了代码和数据等进程控制块:是操作系统用于管理进程的核心数据结构。其实就是描述进程的属性。PCB是统称,在Linux中具体是叫task_struct标识符:用于其它进程区分状态:进程有运行、挂起、阻塞状态等优先级:被CPU执行的先后顺序程序计数器:程序中即将执行下一条指令的地址。
2025-05-20 19:39:43
1029
原创 进程——前言
操作系统(Operator System)它就是进行软硬件管理的软件!内核(进程管理、文件管理、内存管理、驱动管理)其它程序(函数库、shell程序)狭义上称操作系统就是内核,广义上是内核和其它程序。在后面介绍中没特别说明就是指狭义上的。
2025-05-15 14:48:17
886
原创 Linux中常见开发工具简单介绍
apt和yum都是软件包管理器,apt是Ubuntu的,yum是CentOs的。它可以主动帮我们解决包的依赖问题。它是通过内置链接来实现下载软件包的。软件包管理器就相当于是手机上的应用商店,而软件包就类似于App。vim是一个文本编辑器,vim是多模式的编辑器,其中常用的有命令模式,插入模式,底行模式。当我们打开vim时默认是命令模式。进入vim只需要vim 普通文件名即可。在打开vim时可以用:vim 文件名 +n,即可直接让光标在第n行。如果没有普通文件名会先创建一个然后在进入。
2025-05-11 12:54:26
807
原创 Linux权限
可以用chown修改拥有者,用chgrp修改所属组,也可以chown xxx:xxx来一起修改拥有者和所属组。普通用户变超级用户可以用su或su-命令,用exit退出超级用户,超级变普通也是用su或su-实现的(su或su-的区别是su会保持当前路径,su-不会)。但是在实际中会根据不用的需要来修改属性权限,一个一个改效率低下,这时候就要用到umask(权限掩码)。在上面的图片中左边的root是拥有者,右边的是所属组,他们两个之外的就是其他用户。斜杠左边的是文件类型, 1是拥有者,2是所属组,3是其他人。
2025-04-22 19:28:23
850
原创 C++11——可调用对象
lambda表达式本质上是匿名函数对象,该表达式在语法使用层是没有类型的,一般用auto或模板参数定义的对象去接收它的对象(模板参数定义的对象是当用 vector<T> 时,会根据 T 这个模板参数实例化出一个专门用于存储 T 类型数据的 vector 对象)。function的实例对象可以包装存储其他的可以调用对象,包括函数指针、仿函数、lambda 、bind等,存储的可调对象被称为目标。lambda中默认只能使用函数体里定义的变量和参数列表的变量,如果想使用作用域外的变量就要使用捕捉列表。
2025-04-21 16:33:05
983
原创 C++多态
多态简单来说就是有多种形态,就是当你传入不同对象就会完成不同的行为。相当于就是你传入一个狗对象就是“汪汪汪”,当传入一个猫对象就是“喵喵喵”。
2025-04-10 17:50:21
925
原创 Linux中基本命令
它默认从键盘文件里读取内容,然后输入到显示器文件上(在Linux里一切皆文件像键盘,显示器也是文件它们被称为设备文件,系统会自动打开该文件)。当你在命令行输入 cat 后按回车键,它会等待你从键盘输入内容,你输入的内容会立即显示在屏幕上,直到你按下 Ctrl + D (表示文件结束符)来结束输入。其实大部分命令都是可执行的文件,但有一些命令比如Shell内置命令,它没有对应的独立可执行文件,而是由Shell直接解释执行的。注意:它和cat t.c是有本质的区别的,关于为什么到后面的文章在讲述。
2025-03-21 17:35:08
1180
原创 leetcode53—最大子数组和(kadane算法)
目录题目介绍解决思路代码实现证明 kadane算法是一种用于解决最大子数组和问题的动态规划算法。 现有一个整数数组nums,找出一个最大和的连续子数组(子数组是数组中的一个连续部分,可以为一个数),并返回其最大和。 示例:nums = [ -2,1,-3,4,-1,2,1 ],输出:6(子数组[4,-1,2,1] 的和最大)。 范围:1 <= nums.length <= 1e5, -1e4 <= nums <= 1e4 题目链接:最大子数组和 暴力的解法就是
2025-02-28 16:17:18
655
原创 C++11—可变参数模板
它的写法和之前的函数模板很像就只是在class后和参数列表里加个...,具体如下:返回类型 函数名(Args… args)//函数体;上面的args是参数包,参数包是用于表示一组可变数量的模板参数。//...
2025-02-07 17:47:35
796
原创 C++11—右值引用
之前我们曾学习过引用叫左值引用,但那是C++98的,在C++11中新增了一种引用叫右值引用。右值引用主要用于支持移动语义和完美转发。从而可以更高效地管理资源,减少不必要的复制操作。
2025-02-02 18:06:50
1021
原创 关于new和delete的匹配问题
编译器为这么做是因为析构一般用于资源释放,前面的数据个数就代表析构几次(如果不加前面的4个字节编译器就不知道要析构几次)。没写析构为什么不多开这4个字节,这是因为没有写析构编译器认为这些空间没有资源可释放,它自己生成的析构函数也并不需要做什么事情然后编译器一优化就直接省略了析构,所以就arr1即使首地址这时候释放就没事。A类的大小是4个字节,我们开10个空间大小就应该是40个字节,通过上面的可以发现没加析构的大小和预期的一样,写析构的大小居然多出来了4个字节。我就直接说了那4个字节是用来存放数据的个数的。
2025-01-19 21:32:41
368
原创 二叉树的前中后序遍历(非递归)
前序遍历下面我会用示例 2 讲解。在讲非递归的实现就必须先了解递归的实现。事实上非递归实现的逻辑就是递归的底层原理。中序遍历中序遍历就不在画它的递归逻辑了,因为它和前序遍历的逻辑差不多一样,区别是访问节点里的val时机不同。后序遍历。
2024-12-16 18:23:44
1149
原创 C++继承
继承是面向对象的三大特征之一,是代码复用的重要手段。它可以让我们在原有类特性的基础上对它进行扩展。原有的类被称为基类,扩展出来的类被称为子类。子类的对象在内存中存储是先存储基类成员然后才是子类成员。class person//基类protected://名字//性别//电话class student : public person//子类private:string _id;//学号class teacher : public person//子类private://职位。
2024-11-20 10:55:47
890
原创 C++中string使用
string属于STL(Standard Template Library,标准模板库)中容器的一部分。容器是用来存储和管理数据的对象。string表示字符串的字符串类。string的出现的时间比STL还要早所以里面的有些接口就会有点冗余。要使用string的话要加上名为<string>的头文件。string,这里我就只是简单介绍一下某些接口的使用。
2024-09-13 19:08:03
884
原创 C++模板
返回类型 函数名(参数列表)//内容;typename是定义模板的关键字,class可以替换typename。<>里的内容被称为模板参数列表。//下面的举例都会用到这个函数函数模板其实是一个蓝图,它本身并不是函数,是编译器产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。在编译阶段,编译器会推导传入参数的类型然后生成该类型的函数(下面的类模板也是一样的)。class 类模板名//内容;typename也是可以被class替换。
2024-09-10 10:38:31
985
原创 关于类和对象
类是从C语言结构体的基础上发展而来的。class是定义类的关键字,后面接类的名字,然后在接一对 {} ,注意要在 } 的后面接一个分号(class可以被struct替换)。class A//...在类体中可以存在变量和函数,类的内容称为类的成员,类中的变量称为类的属性或成员变量,类中的函数称为类的方法或成员函数(类里定义的函数默认是inline)。在定义成员变量时建议加一个特殊标识,我一般在变量前加_。这么做是为了方便认出成员变量。//没加特殊标志class A。
2024-07-20 10:12:49
813
原创 初识C++
现在有一个项目分配给两个人让他们实现。他们写的都没问题但是它们一合并就出现了命名冲突的问题。在C++里就可以避免此问题的发生。C++提出了命名空间这是对标识符的名称进行本地化,以避免命名冲突。定义命名空间需要用到namespace关键字,后面接命名空间的名字,然后接一对{}即可。int a = 1;int b = 2;命名空间里面不止可以定义变量也可以定义函数和类型,注意一个命名空间就定义了一个新的作用域,命名空间里的所有内容只限于该命名空间中。
2024-07-11 10:55:25
912
原创 排序——归并排序
所以有解决这道题就要用比较快的排序,考虑到该题的特殊性用归并排序解决是最合理的。在排序时不能在原数组上进行排序,解决这个问题其实只需要开辟一个与原数组大小一样的空间,在排完一个后把该数据存入开辟的数组中,当这次序排完后把数据拷贝到原数组中即可。将已有序的子序列合并,得到完全有序的序列。上面的代码就只能对2的倍数进行排序如果不是就无法排序,下面的图片是对一个只有10个数据的序列下标访问情况。,先让一个序列不断对半拆分(递推),拆到只有一个数据的序列时(递推结束条件),开始回归排序(回归)。
2024-07-06 17:56:03
478
原创 排序——快速排序
基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排列在相应位置上为止。最后的一两层里面包含的数据并不是很多,所以我们可以写一个判断,到特定的范围内用插入排序的方式来排序(这里我写的是当数据量小于10时),这样它的深度会变小很多。先让end走遇到比基准值小的停下来,然后让begin走遇到比基准值大的停下来,之后让它们交换位置。快速排序的非递归实现是基于栈实现的。
2024-06-18 21:34:31
1020
原创 排序——希尔排序
当序列越有顺序时,插入排序的时间效率就越高。时间复杂度:O(N^2)(虽然时间复杂度是N^2,那是在逆序的序列情况下,在现实中这种情况一般不会出现)空间复杂度:O(1)gap>1:预排序,目的是让序列变得更有序。时间复杂度:O(N^1.3)空间复杂度:O(1)
2024-06-16 18:27:54
854
原创 二叉树的链式结构实现
该篇是在的基础上的。该篇会有点抽象大家要自己多画画图自己感受一下。现在我们开始吧!在学习二叉树基本操作时,我们需要先有一个现成的二叉树。来方便我们练习。因为现在我们对二叉树的理解也并不是很深入。在这里创建一个树是方便让我们理解。等我们学的差不多的时候,我们来真正的创建二叉树。下图是我创建二叉树的结构。在二叉树的介绍及堆这篇文章中的二叉树概念可以发现二叉树定义是递归式的,因此下面操作中基本都是按照该概念实现的。
2024-06-03 16:10:47
869
原创 二叉树介绍及堆
找到它的两孩子中小的那个,在让这个小的孩子与它进行比较如果孩子大于它则退出,如果小于则交换位置,重复上述操作直至循环结束或跳出循环。先建一个K个数据的小堆,然后让后面的N-K个数据跟该小堆的根结点进行比较,如果大于则进行交换,然后向下调整。先建一个大堆,然后让第一个结点的数据与最后一个结点交换,拿出最后的那个结点,然后再让根结点向下调整。大家应该注意到了哈,这次建堆的方式有点不一样,这是先找到树的最后一个根结点(画四角星的是树的最后一个根结点)4. 若规定根结点的层数为1,具有n个结点的满二叉树的深度,
2024-05-29 18:07:51
874
1
原创 时间复杂度
我们在这里就是将算法中的基本操作的执行次数,认为是算法的时间复杂度。大家可能注意到了底数为什么不写2,实际上2是最常见的可以不写,但如果是其它底数就要写。解释:假设某个算法的执行次数是F(N)=N^2+N。因为只保留最高项所以把N给删掉,即时间复杂度为O(N^2)。O(1) < O(logN) < O(N) < O(N^2) < O(2^N)(越往右越低)。解释:假设某个算法的执行次数是F(N)=2N。时间复杂度是用大O的渐进表示法来表示(大O符号:是用于描述函数渐进行为的数学符号)。
2024-05-27 11:24:26
675
原创 线性表—栈的实现
创建一个栈,只让左括号入栈,让右括号与栈里的数据匹配。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。如果top是0,就要后置了。一般来说top应该也是0,这里是-1是为了确保top是栈顶数据的。然后返回下标top对应的数据即可。将arr置为空指针,top置为-1,capacity置为0。然后只要让top--即可。如果top=-1则返回true,否则返回false。以下的内容如果你对顺序表的实现熟悉的话就很简单。栈顶和栈底并不是固定的,这是人为决定的。直接返回pst->top==-1即可。
2024-05-14 11:19:52
725
原创 leetcode.环形链表问题
当slow走到环的入口处时,假设fast与slow的距离为N。fast走两步,slow走一步,这时N会变成N-1。只要它们一直走,N一定会等于零,这时候它们相遇,即存在环。第二轮它们的距离是C-1,如果C-1是奇数那它们就永远就遇不到了。设slow走的距离为L ,fast走的距离为L+X*C+C-N(X是fast在环里转的圈数)。所以3L=L+X*C+C-N。分析:2L为偶数,将上面的不存在条件带入会发现该等式并不成立,所以走三步会遇到。快指针走两步慢指针走一步,让它们一起往后走,如果它们相等即存在环。
2024-05-14 11:13:28
473
1
原创 通讯录项目—顺序表实现
下面是通讯录要实现的功能。能够保存用户信息:名字、性别、年龄、电话、地址等。增加用户信息。删除指定用户信息。查找用户信息。修改用户信息。显示用户信息。
2024-05-08 20:33:11
1407
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅