因近期在进行面试,所以想着对过程中遇到的面试题进行记录,供大家进行参考。(正确答案也在逐步更新中)
C基础
-
一个程序相关的内容都会存储到区?局部变量和全局变量存储于哪个区?
栈区:由编译器管理分配和回收,存放局部变量和函数参数。
堆区:有程序员管理,需要手动malloc
、free
进行分配和回收,空间较大,但可能出现内存泄漏和空闲碎片的情况。
全局/静态存储区:分为初始化和未初始化两个相邻区域,存储初始化和未初始化的全局变量和静态变量。
常量存储区:存储常量,一般不允许修改。
代码区:存放程序的二进制代码。 -
栈区和堆区有什么区别?
栈:由编译器管理。需要时由编译器自动分配空间,不需要时自动回收,一般保存局部变量和函数参数等。内存空间连续,从高地址向低地址扩展,栈低高地址,空间较小。
堆:由程序员管理,需要手动malloc
、free
进行分配和回收,如果未进行回收,将会造成内存泄露。不连续空间,其实系统内部由一个空闲链表。从低地址向高地址扩展,空间较大,较为灵活。 -
函数未定义会在预处理、编译、链接、执行哪个阶段发现?
在链接阶段会检查出来。 -
宏展开是在哪个阶段?
预处理 -
static、const 关键字的作用及用法?
static 控制变量的存储方式及可见性。主要作用有:修饰局部变量;修饰全局变量;修饰函数。
const 控制对象不可被修改。主要作用有:修饰基本的数据类型;修饰指针变量;修饰函数入参。 -
介绍一下
fork()
、vfork()
函数?fork()
返回值都有什么,代表什么意思?
fork()
和vfork()
是 Unix 和类 Unix 操作系统中用于创建新进程的系统调用。这两个函数的主要目的都是创建一个新的进程,但它们的实现和行为有所不同。
fork()
函数用于创建一个新的进程,该新进程被称为子进程。子进程是父进程的一个复制品,拥有自己的地址空间、文件描述符等。返回值含义如下:
子进程:fork()
在子进程中返回 0。
父进程:fork()
在父进程中返回新创建的子进程的进程 ID(PID)。
错误:如果fork()
失败,它将返回 -1,并且设置 errno 来指示错误原因。
vfork()
函数也是用于创建新进程,但它的实现方式不同。vfork()
在创建子进程时共享父进程的地址空间,直到调用exec()
或exit()
。这意味着在vfork()
创建的子进程中,任何对父进程内存的修改都会影响到父进程。 -
gdb 调试多进程,多线程命令?
set detach-on-fork on
set follow-fork-mode child
info threads # 查看所有线程
thread <id> # 切换到指定线程
info inferiors # 查看所有进程
inferior <id> # 切换到指定进程
break <function> # 在函数设置断点
continue # 继续执行
step # 单步进入函数
next # 单步执行,不进入函数
backtrace # 查看当前线程的调用栈
print <variable> # 打印变量的值
watch <variable> # 观察变量的变化
quit #退出 GDB
-
对 flag 的某一位置零、置 1 ?
置零是:flag = flag & ~(1 << n);
;置为 1:flag = flag | (1 << n);
-
内存对齐的规则是什么?为什么要内存对齐?
对齐规则:
对于结构体中的各个成员:第一个结构体成员位于偏移为 0 的位置,此后的每个结构体成员的偏移量都必须是 MIN(#pragma pack(X) , 结构体成员本身的类型长度) 的倍数(其中X的取值一般为 4 或 8 ,分别对应 32 位和 64 位操作系统)。
所有结构体成员各自对齐之后,结构体本身也要进行对齐。结构体整体长度应该是 MIN(#pragma pack(X), 结构体中长度最长的结构体成员数据类型的长度) 的倍数。
对齐原因:
内存对齐可以提升 CPU 的性能。因为 CPU 是按块去处理内存的,内存块的大小可以是 2、4、8、16 个字节,块的大小称为内存读取粒度。假设内存读取粒度为 4 ,CPU 从 0 字节开始的位置读取一个 4 字节的数据到寄存器中,那么 CPU 将会把 0 ~ 3 四个字节全部读取到寄存器中进行处理。若数据起点位置不在 0 字节呢?假设数据起始位置为 2 字节,那么读取这个数据就需要 CPU 读取两次,首先读取 0 ~ 3,接着再读取 4 ~ 7,然后再把 0、1、6、7 字节的数据去除,最后合并 2、3、4、5 字节的数据放入寄存器中。上述就是内存未对齐的场景,此场景下寄存器做了很多额外的操作,必然会影响到 CPU 的性能。可参考:内存对齐总结 -
讲讲大小端,如何确定一台机器是大端还是小端?
大端模式:数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址端。
小端模式:数据的高字节保存在内存的高地址中,而低字节保存在内存的低地址端。
检测方式:直接读取存放在内存中的十六进制数值,取低位进行值判断如下:
int a = 0x12345678;
unsigned char *a_ptr = (unsigned char *)&a;
a_ptr[0] == 0x12; // 大端模式
a_ptr[0] == 0x78; // 小端模式
- 设置地址 0x67a9 的整型变量值为 0xaa66 ?
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa66;
-
socket 通信,三次握手的第一次握手是在哪个函数接口中?
在 TCP/IP 网络协议中,三次握手(Three-Way Handshake)是建立 TCP 连接的过程。具体来说,第一次握手是通过调用socket()
和connect()
函数来实现的。
客户端调用socket()
函数创建一个 TCP 套接字,然后调用connect()
函数向服务器发送一个 SYN(同步)报文段,表示请求建立连接。 -
socket 通信,
send()
函数返回 success ,此时发送的数据在哪?
在使用send()
函数进行 socket 通信时,如果该函数返回成功(通常返回值为发送的字节数),这意味着数据已经被成功地传送到操作系统的网络栈中,但并不一定意味着数据已经被接收方接收。
当send()
函数返回成功时,发送的数据已经被放入了操作系统的发送缓冲区(send buffer)。这个缓冲区是内存中的一块区域,用于存储待发送的数据。 -
讲解一下函数可重入?
函数的可重入性是一个重要的概念,尤其在多线程编程和中断处理等场景中。一个函数被称为可重入(Reentrant),如果它可以被多个线程或多个执行上下文(如中断处理程序)安全地调用,而不会导致数据损坏或不一致性。
可重入函数的特征:
无共享状态:可重入函数不依赖于任何全局变量或静态变量,或如果依赖,它们不会被修改。它们只使用参数传递的数据和局部变量。
不使用不可重入的库函数:可重入函数不能调用不可重入的函数,例如某些使用全局状态的库函数(如 malloc、printf 等)。
局部状态:所有的状态信息必须在函数内部保存,通常通过局部变量实现。每次调用都应该独立于其他调用。
无副作用:函数的执行不应影响外部环境(例如不修改全局变量的状态)。
可重入函数的示例:
int add(int a, int b)
{
return a + b; // 只依赖于参数,没有修改全局状态
}
-
Linux命令:ps 等是什么作用?
ps 是一个在 Unix 和类 Unix 操作系统(如 Linux)中使用的命令行工具,用于显示当前运行的进程的信息。它的全称是 “process status”。使用 ps 命令,用户可以查看系统中正在运行的进程及其相关信息,如进程 ID、用户、CPU 和内存使用情况等。 -
手写一下
memcpy()
函数实现?
参考 手写 str*、mem* 字符串相关函数 -
共享内存是如何使用的?键值?
shmget
是 System V 共享内存 API 中的一个函数,用于创建一个新的共享内存段或获取一个已存在的共享内存段的标识符。
函数原型为int shmget(key_t key, size_t size, int shmflg);
其中入参 key 是共享内存段的键值。这个值用于标识共享内存段,通常使用ftok()
函数生成,以确保唯一性。 -
指针是什么?
malloc
一块空间,返回的指针存储的是什么信息?
指针是编程语言(尤其是 C 和 C++)中的一种数据类型,用于存储内存地址。指针变量可以指向任何数据类型的内存地址,允许程序直接访问和操作内存。
每个变量在内存中都有一个唯一的地址。指针存储这个地址,而不是存储变量的值。
malloc
返回的是一个void*
类型的指针,表示指向分配的内存块的起始地址。
数据结构和算法&情景设计
-
写一下冒泡排序算法?
参考 十大排序算法(C语言) -
25 个运动员, 5 条跑跑道。至少需要几轮比赛能得出第一名?至少几轮得出前三名?为什么?
确定第一名:
将 25 个运动员分成 5 组,每组 5 人,进行 5 轮比赛,每组的第一名将晋级到下一轮。经过这 5 组比赛,我们确定了 5 个小组的第一名。然后用这 5 个小组的第一名进行一场比赛,确定这 5 个第一名中谁是最快的。所以决出第一名至少需要 6 轮比赛。
确定前三名:
前面 5 轮比赛记住每组的前 3 名。第 6 轮时假设分别是 A1、B1、C1、D1、E1,结果是 A1 取得了第一名,B1 第二名 C1 第三名。那么整体的第二、三名将在B1、C1、A2(因为 A1 胜出,其组的第二名可能是第二名)、A3(假设 A2 是第二名,其组的第三名可能是第三名)、B2(假设 B1 是第二名,B2 有可能是第三名) 这 5 人中产生,再加赛一轮即可。也就是最少 7 轮就可以得到前三名。
计算机网络
- TCP 和 UDP 的区别?应用场景?
TCP(传输控制协议)和 UDP(用户数据报协议)是传输层的两种主要协议,它们在数据传输的可靠性、顺序、速度等方面有显著的区别。以下是它们的主要区别及应用场景。主要区别如下:
特性 | TCP | UDP |
---|---|---|
连接性 | 面向连接,需要在数据传输前建立连接 | 无连接,不需要建立连接 |
可靠性 | 提供可靠的数据传输,确保数据包按顺序到达,使用确认机制 | 不提供可靠性,数据包可能丢失、重复或乱序 |
流量控制 | 提供流量控制,避免网络拥塞 | 不提供流量控制 |
拥塞控制 | 提供拥塞控制 | 不提供拥塞控制 |
数据传输方式 | 以字节流的形式传输数据 | 以数据报的形式传输数据 |
开销 | 由于连接管理和确认机制,开销较大 | 开销较小,适合快速传输 |
头部大小 | 20 字节(最小) | 8 字节 |
应用场景 | 适用于需要可靠性和顺序的应用,如网页,文件传输等 | 适用于不需要可靠性的应用,如音视流、在线游戏等 |
-
讲解一下 TCP 三次握手和四次挥手?
-
TCP 为什么要三次握手?能不能两次?如果不能,两次握手会出现什么问题呢?
-
TCP 滑动窗口?TCP 协议内部机制?
-
socket 延时如何更改?
-
UDP 协议内部机制讲解一下?不是如何使用
-
了解 ARP 协议不?讲解一下?
-
TCP 粘包如何解决?
-
TCP 相比 UDP 发送效率较低,如何优化发送效率呢?
-
TCP 的流量控制?拥塞控制?(慢开始。拥赛避免等)
-
让你自己设计一套通信协议,应该注意哪些方面呢?不能依赖于现有协议。
-
TCP socket 交互流程?
-
select 阻塞和非阻塞有什么区别?非阻塞如何设置?
-
select 描述符或者句柄有限,但是要处理大批量的连接请求该如何操作呢?
操作系统
-
线程互斥如何实现?
-
进程间通信的方式都有哪些?
-
线程和进程的关系和区别?主线程和子线程有什么不同?
-
多进程并发该如何控制?
-
互斥锁与自旋锁的区别?
-
一个进程创建出来的多个线程共享的资源有哪些?
-
进程malloc申请的空间属于哪个区?线程能否访问?
malloc
的空间属于堆区,多线程中堆是共享的,所以可以访问。 -
互斥锁和信号量有啥异同?
-
IO 多路复用:
select()
和epoll()
区别?
密码学
因为个人项目经历及部分应聘岗位和密码学有点联系,所以不可避免的会问到密码学相关问题,遂一并进行记录。
-
SM4 加密机制,SM4-CBC 的 iv 向量如何产生?如何使用?
-
ECB 模式、CBC 模式和 XTS 模式有什么优缺点?
-
密钥管理机制,主密钥依靠什么进行保护?
-
SM4 加密机制?
-
SM2、SM3、SM4分别属于哪些算法,其中哪些是可逆的?哪些不可逆?
-
密钥到底是什么?加密原理是什么?
-
SM4 与 AES 区别是什么?