0%

1.什么是const

const是C/C++中的关键字,一般用来定义一个常量,所以const修饰的变量不能修改它的值

image-20240508220803581

2.什么是#define

#define是一条预编译指令,编译器在编译阶段会将所有使用到#define的地方进行替换

1
2
3
4
5
#define a 1
//编译前
int num=a;
//编译后进行替换,用1替换a
int num=1;

3.const和#define的区别

1.在主题里把分类选项打开

打开文件\themes\next\_config.yml,搜索menu,找到如下代码段

image-20240508214604038

去掉categories: /categories/ || fa fa-th行的注释

2.创建分类目录文件

在博客文件夹下打开git bash,输入以下命令

1
hexo new page categories

成功后:image-20240508214818388

3.打开生成的index.md文件

打开后内容如下

image-20240508215002707

加上 type: "categories"

image-20240508215029274

4.给文章设置分类属性

添加以下内容就设置好分类了

注意:”-“跟类别名之间有一个空格

image-20240508215850772

如果需要二级分类:

image-20240508215842702

文件系统

文件系统的组成

文件系统的概念
  • 文件系统是操作系统中负责把用户的文件存到磁盘硬件中

    • 负责管理持久数据的子系统
  • 基本数据单位:文件

    • 目的:对磁盘上的文件进行组织管理
  • “万物皆文件”

    • 普通的文件和目录、管道、块设备、socket都是统一由文件系统管理
原理
  • 为每个文件分配两个数据结构

    • 索引节点inode

      • 记录:文件的元信息

        • inode编号、文件大小、访问权限、创建/修改时间

        • 数据在磁盘中的位置

      • 索引节点是文件的唯一标识

        • 跟文件一一对应
          • 同样存储在硬盘中
    • 目录项dentry

      • 记录:文件的名字、索引节点指针、与其他目录项的层级关联关系

        • 不只是表示目录

        • 也可以表示文件

      • 目录项是由内核维护的一个数据结构

        • 存放在内存中
      • 目录也是文件

        • 普通文件保存文件数据

        • 目录文件保存子目录或者文件

      • 目录项vs目录

        • 区别

          • 目录是文件,存放在硬盘里

          • 目录项是内核的一个数据结构,缓存在内存中

        • 关系

          • 查询目录频繁从磁盘读,效率低

          • 内核把读过的目录用目录项这个数据结构缓存在内存中

            • 下次读到相同目录,直接从内存读
    • 关系

      • 目录项和索引节点是多对一的关系

        • 一个文件可以有多个别字
      • 区别

        • 索引节点存放在硬盘

        • 目录项存放在内存

  • 文件数据如何存储在磁盘

    • 逻辑块/数据块

      • 磁盘读写的最小单位是扇区(512B),读写效率低

      • 文件系统把多个扇区组成了一个数据块

        • 每次读写的最小单位就是逻辑块

        • linux中逻辑块大小为4KB(一次性读写8个扇区)

          • 提高读写效率
    • 加速文件访问:把索引节点加载到内存

      • 磁盘格式化后的存储区域

        • 超级块

          • 存储文件系统的详细信息
            • 块个数、块大小、空闲块等
        • 索引节点区

          • 存储索引节点
        • 数据块区

          • 存储文件或者目录数据
      • 加载策略:只有需要的时候加载进内存

        • 超级块:文件系统挂载时加载进内存

        • 索引节点区:当文件被访问时加载进内存

虚拟文件系统

文件的使用

文件的存储

文件系统的结构

目录的存储

软链接和硬链接

文件I/O

腾讯音乐4.29 客户端开发面经

面试流程:
  1. 面试官介绍部门情况
  2. 自我介绍(面试官要求介绍项目什么的)
  3. 问答环节
问题:
tcp建立连接是3次握手,断开连接是4次挥手,为什么会有这个差异?

断开连接为什么要4次,而不是3次?

  • TCP连接为什么要三次握手
    1. 原因:
      1. 客户端发出SYN,并收到ACK,这就是两次网络传输了。
      2. 同样服务器端也发出SYN,且等待对方回复,这也是两次网络传输。
      3. 加起来难道不是四次吗?实际上服务器端将对客户端 SYN(1) 的回复和自己 SYN(1) 的请求合并了,所以建立一个 TCP 连接最少只需要经过三次网络传输
    2. 举例:已失效的连接请求报文
  • TCP断开连接为什么需要四次挥手?
    1. 原因:
      1. 发起断开方发出FIN,并收到ACK,这就是两次网络传输了。
      2. 同样被断开方也发出FIN,且等待对方回复,这也是两次网络传输。
      3. 为什么服务端返回ACK的时候不一起发送FIN?因为在收到FIN时,服务端可能还有数据要发送,等到数据传输完时再发送FIN
ping命令使用过吗?traceroute跟它其实差不多,但是那个traceroute为什么能够探索到服务器的各个节点。

traceroute是linux/unix系统中用于分析本地到目标网络地址间的路由转发路径的工具,也常用于诊断网络链路不通或异常的发生位置。windows下命令为tracert www.baidu.com

image-20240502142938707

  1. 每一跳的IP和时延信息是怎么得到的?
  2. 为什么每一跳有3个时延信息,有时还会显示2个或者3个IP地址?
  3. 为什么有些跳数显示的结果是请求超时?为什么有节点请求超时了还能到达后续的节点?

traceroute/tracert的原理

  1. 向目标IP发送3个TTL=n(n起始值为1)的ICMP ping request报文,等待回应
  2. 如果收到ICMP ping response报文,则说明路由成功,通过n跳可以到达目标IP,traceroute工作完成。request和response的时间间隔就是时延,由于发送了3个request,因此有3个时延信息。
  3. 如果收到ICMP TTL exceeded报文,则说明第n跳路由到达了这个报文的发送节点。IP报文的TTL字段每经过一次路由转发就会减1,当减到0时当前的转发节点就会向报文的源IP发送一个ICMP TTL exceeded报文,因此发送了这个报文的节点就是第n跳的路由节点。由于发送了3个request,因此会返回3个报文和对应的时延信息。由于到目标IP的路由路径不一定是唯一的,因此报文在第n跳时到达的节点不一定是同一个,就有可能会输出多个第n跳节点地址。
  4. 如果在request发出3秒(默认超时时间)后仍然没有收到任何回应,则这轮检测超时。但这并不意味着目标IP不可达,而很可能是因为第n跳到达的节点不允许发送TTL exceeded报文。因此traceroute会继续后面的探测过程。
  5. 将TTL加1,回到第1步继续探测。
为什么https比http更安全?答:因为https在http的基础上使用了tls协议进行加密。
  • 讲一讲整个加密过程
  • 所以密钥本身是对称加密的,还是那个非对称加密?
tcp三次握手成功以后,比方说给对方发1k的数据,对方会有什么下一步的动作?
tcp报文头多少字节 20~60B

udp报文头部为8B

stl的vector是线程安全的吗?

是,所有操作加了同步锁,不支持多线程操作

vector特点:

1.动态分配空间,当空间不足时,会执行分配新空间——复制元素——释放原空间;

2.在末端插入和删除执行效率高,在其他位置插入和删除效率低(为保持原有相对次序,插入和删除点之后的元素需要整体后移);

3.删除数据并不会释放已分配的空间,因此vector的capacity(容量)大于vector的size(元素个数);

4.支持随机访问,且执行效率高;

5.vector是线程安全的,所有操作加了同步锁,不支持多线程操作

#vector跟数组的差别

区别
1.大小固定 vs 大小可变:

数组是一个具有固定大小的连续内存块,一旦定义后,其大小无法改变。
vector是一个动态数组,它使用了自动扩容机制,可以根据需要动态调整大小。可以通过添加或删除元素来改变vector的大小。
2.初始化:

数组的大小在定义时必须确定,并且可以使用初始化列表或循环初始化等方式进行初始化。
vector的大小可以在定义时指定,也可以在后续使用push_back()、emplace_back()等函数插入元素进行初始化。
3.访问元素:

数组通过索引直接访问元素,可以使用下标运算符[]或指针运算符*来访问特定位置的元素。
vector也可以使用下标运算符[]访问元素,还可以使用at()函数进行边界检查。
4.自动内存管理:

数组需要手动管理内存,包括分配和释放内存。
vector自动处理内存管理,会自动增加或减少内存以适应元素的数量。
5.功能差异:

vector提供了许多方便的成员函数,如push_back()、pop_back()、insert()、erase()等,用于在尾部或指定位置添加、删除元素。
数组本身没有提供这些功能,需要手动编写代码来实现。

map底层的红黑树的实现原理
C++虚函数跟普通的函数有什么区别吗?
虚函数表是在什么阶段,可以知道它自己的指针是多少。
utf16,包括utf32,讲一下他们的差异。
  • utf8

    1. 特点:使用变长字节数

      原因:可以理解为按需分配,节省存储空间

      优势:节省空间;劣势:不利于程序内部处理

      而UTF-32这样等长码元序列(即等宽码元序列)的编码方式就比较适合程序处理,当然,缺点是比较耗费存储空间

    2. 编码方式:最短为一个字节,通过utf8首字节就能判断编码有几个字节

      1. 如果首字节以0开头,肯定是单字节编码(即单个单字节码元);
      2. 如果首字节以110开头,肯定是双字节编码(即由两个单字节码元所组成的双码元序列);
      3. 如果首字节以1110开头,肯定是三字节编码(即由三个单字节码元所组成的三码元序列),以此类推。
      • 这里的0相当于终结标志

      • 前缀码的作用:区分和标识

      • 除了单字节编码外,由多个单字节码元所组成的多字节编码其首字节以外的后续字节均以10开头(以区别于单字节编码以及多字节编码的首字节)。

  • utf16

    1. 特点:2字节或者4字节(没有办法兼容ASCII编码,ASCII编码使用1 Byte来进行存储)

    2. 字节顺序问题:如某字符为十六进制编码4E59,按两个字节拆分为4E59

      - 读取顺序 显示字符
      Windows 4E 59
      Mac 59 4E

      引入:字节顺序标记(英语:byte-order mark,BOM)来标记是大端序还是小端序。

    3. BOM:是一个有特殊含义的统一码字符,码点为U+FEFF。当以UTF-16或UTF-32来将UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其字节序。

      字符U+FEFF如果出现在字节流的开头,则用来标识该字节流的字节序,是高位在前还是低位在前。

空的class大小是多少?
  1. 空类大小=1,因为编译器需要安插进去一个 char,使得这个 class 对象得以在内存中被配置独一无二的地址。
  2. 某个类A继承该空类
    1. 如果A为空,sizeof(A)=1
    2. 如果A不为空,sizeof(A)=真实大小
  3. 如果一个类没有成员变量,但是含虚函数/虚继承别的类,则会生成一个vptrsizeof(A)=4/8

虚继承

  1. 多继承:多个直接基类中产生派生类,存在问题:多个基类相互交织

    image-20240505011615000

    假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A –>B–>D 这条路径,还是来自 A–>C–>D 这条路径。

  2. 虚继承:为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。

    目的:让某个类做出声明,承诺愿意共享它的基类。

    image-20240505011755261

    本例中的 A 就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。

计算类的大小,还要考虑字节对齐

定义一个结构体,里面可能有很多的数据类型。在不同的编译器,不同的系统下,结构体大小可能会有不同的大小。你觉得是因为什么?(字节对齐)
  1. 内存对齐(Padding):
    为了提高数据访问的效率,许多处理器和编译器会要求数据按照特定的边界对齐,不同的编译器可能会有不同的默认对齐设置或对齐策略。例如,某些处理器可能要求一个int类型的变量在4字节边界上对齐。如果结构体中的某个成员不满足这个对齐要求,编译器会在成员之间插入额外的空间(填充字节),以达到所需的对齐。这会导致结构体的大小在不同系统或编译器下有所不同。
  2. 数据类型的大小:
    虽然标准数据类型(如intlong等)在大多数系统上都有固定的大小,但在某些系统或编译器下,它们的大小可能会有所不同。
C++的加锁方式
C++子类跟基类的构造顺序和析构顺序,为什么?
局部变量在进程内存的哪一块里面

一般全局变量存放在数据区,局部变量存放在栈区,
动态变量存放在堆区,函数代码放在代码区。

函数的参数的压栈顺序:参数从右到左入栈

例:void func(int a,int b,int c),进栈顺序为:c b a.

网络的多路复用?
线程切换怎么保证切回来的时候,还能够按照原来流程继续走下去。
算法问题:运营在线上搞了两个活动,回收数据的时候,a活动收了2千万的那个qq号,b活动他回收了那个5千万的qq号。求两个活动大概都参加的用户有多少。设计一个算法求a和b的交集。
如果编写组件,提供接口定义入参和出参,为什么入参尽可能使用C的数据类型,而不是使用C++
共享屏幕做算法:解析http报文,实现传入参数key返回value
共享屏幕做算法:快排

Linux内核级安全开发基础

1.1 Linux的动态内核模块机制

1.动态内核模块机制概述

Linux内核:宏内核

缺点:系统功能扩展性差,设计之初实现了较多冗余功能,影响操作系统的运行效率和系统稳定性

解决办法:引入内核模块动态加载机制——通过内核模块的扩展和动态加载实现操作系统功能的扩充,当一些内核模块不再使用时可以卸载该模块,以保证操作系统的运行效率和系统稳定性。

Linux内核=基本内核+一系列内核模块

​ 系统启动——加载基本内核——用户按照需要动态加载系统内核模块——不需要时再从内核卸载

好处:a.让内核保持很小的尺寸,同时又非常灵活;b.可以不通过重构内核并频繁重启的方式来尝试运行新内核代码,便于新设备驱动程序的编写和调试

2.linux内核模块的加载和卸载

内核模块的加载方式有两种:

  • 使用insmod命令手工加载模块
  • 在需要时加载模块,即请求加载

符号表:所有能够被内核模块使用的资源(基本内核中定义的资源和新加载模块中定义的资源),被操作系统以内核输出符号表的形式统一管理。

内核模块加载过程:

  1. 在内核输出符号表中找到本模块用到的外部符号
    1. 找不到定义的外部符号,或者找到外部符号但是与所定义的类型不一致,系统拒绝加载该模块
  2. 加载成功——>将本模块输出的符号添加到内核输出符号表中

模块A输出的符号被模块B使用,则称模块B依赖于模块A,或者模块A被模块B引用

引用计数:新模块加载到内核过程中,内核会检查该模块使用的外部符号,增加这些外部符号所在模块的引用技术。可通过lsmod命令查看系统已加载的内核模块以及模块的引用计数。

image-20240430002656528

内核模块的卸载:通过使用rmmod命令来卸载

  • 如果要卸载的内核模块正在被其他模块引用,即引用计数不为零,linux系统会拒绝卸载该模块
  • 一旦内核模块被成功卸载
    • linux从内核符号输出表中删除在该模块中定义的外部符号
    • 检查模块曾引用的外部符号所在的模块,引用计数减1

内核模块除了可以手动卸载以外,还支持自动卸载——内核模块的自动卸载工作由后台进程kerneld完成,keneld在相应定时器到期时检查,卸载不用的模块

使用GitHub搭建个人博客

1.安装nodejs

下载地址:http://nodejs.cn/download/

  • 选择合适的包下载安装

image-20240426220019530

  • 验证是否下载成功

    在git bash里面执行下面的命令

    1
    2
    node -v
    npm -v

    image-20240426220150706

2.安装cnpm

  • 在git bash里面执行下面的命令

    1
    npm install -g cnpm --registry=http://registry.npmmirror.com

    检查是否安装成功

    1
    cnpm -v

image-20240426220719751

3.安装hexo和初始化博客

(1)安装hexo

在git bash里面执行下面的命令安装hexo

1
cnpm install hexo-cli -g
(2)初始化博客

新建或者选择一个文件夹,作为blog文件夹,在该文件夹下打开git bash

然后执行

1
hexo init

如果跟我一样遇到问题,可以更换淘宝镜像,再执行hexo init

当时输完命令就去吃饭了,具体不知道跑了多久

1
npm config set registry http://registry.npmmirror.com

image-20240427191601372

然后执行

1
cnpm install

接下来就可以预览博客啦

1
hexo s

结果如下,访问这段http开头的网址就可以预览了

注意:不要结束命令或者关闭终端!!!所以复制网址的时候别直接ctrl+C

image-20240427191954231

image-20240427191939029

4.更换主题

如果不喜欢默认主题的话,可以更换为next主题(适合新手)

  • 下载主题

    1
    git clone https://github.com/theme-next/hexo-theme-next.git themes/next

    image-20240427192416992

  • 修改配置文件

    在自定义的博客文件夹下找到_config.yml文件

    landscape改为next

    image-20240427192533655image-20240427192554514

  • 预览网站

    同样的执行hexo s

    image-20240427192750576

5.其他配置

注意区分两个文件,名字都为_config.yml

  1. 站点配置文件:指的是根目录下的,比如D:\blog\_config.yml
  2. 主题配置文件:指的是具体主题下的,比如D:\blog\themes\next\_config.yml
a.设置语言

更改站点配置文件D:\blog\_config.yml,将language改为zh-CN

image-20240427193621611

b.更改主题外观

更改主题配置文件D:\blog\themes\next\_config.yml

根据需求更改

image-20240427193801777

你也可以查看文档修改其他值https://hexo.io/docs/configuration.html

再执行hexo s预览网站,现在网站长这样啦!

如果没有更新的话,可以关掉刚刚git bash的窗口,重新打开就可以看到刷新了

image-20240427194518821

6.生成文章的编辑工具

比如,你想创建一个名为“如何使用github搭建个人博客”的文章

在博客根目录下执行

1
hexo new "How to build a personal blog on GitHub"

image-20240427195036268

就会生成对应的markdown文件啦

打开文件如下,在这里你可以修改文章标题,在下面输入文章内容

image-20240427195223632

同样的,执行hexo s预览网站

7.将博客部署到网站上

现在只是本地预览,将博客部署到网站上,就可以通过域名访问了

可以通过github部署,也可以通过coding部署

我用的是github

  • 创建一个仓库 Create repository

    image-20240427200514974

  • 仓库名为用户名+.github.io,勾选初始化README

    image-20240427200739418

进行其他配置,创建一个git密钥

  • 打开git bash,执行(更换为你的邮箱),一直回车
1
ssh-keygen -t rsa -C “your_email@youremail.com“

​ 然后执行cat ~/.ssh/id_rsa.pub,复制输出信息

  • 回到github,点击头像,打开Settings,打开SSH and GPG keys,点击new SSH key

    在Key那里粘贴密钥,点击Add SSH Key

  • 打开git bash,执行:ssh -T git@github.com,输入yes回车

    image-20240427201542974

  • 打开项目,点击Code—SSH,复制地址image-20240427201722320

  • 打开站点配置文件

    修改

    1
    2
    3
    4
    deploy:
    type: git
    repo: git@github.com:yhcslin/yhcslin.github.io.git //更换为你的地址
    branch: main

    image-20240427202617046

  • 在博客根目录下打开git bash,分别执行下面的命令,更换为你的名字和邮箱

    1
    2
    git config --global user.name "yourname"
    git config --global user.email "youremail"

    安装上传插件

    1
    cnpm install hexo-deployer-git --save

    然后执行下面的命令上传

    1
    hexo g -d
  • 然后打开项目,点击Settings—Pages

    出现的就是你的网址

    image-20240427202655378

    完结撒花!!!

参考链接

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment