因近期在进行面试,所以想着对过程中遇到的面试题进行记录,供大家进行参考。
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;
-
<