1.c程序在内存中的布局
- 代码段(Code Segment)
位置:通常位于内存的最低地址。
用途:存储程序的可执行指令。
特点:只读,防止程序运行时被修改。 - 数据段(Data Segment)
位置:紧随代码段之后。
用途:
存储全局变量和静态变量。
包含初始化的全局变量和静态变量(已初始化的数据)。
包含未初始化的全局变量和静态变量(未初始化的数据,通常初始化为零)。
特点:数据段分为已初始化和未初始化两部分。 - BSS段(Block Started by Symbol)
位置:数据段的一部分,通常位于数据段的末尾。
用途:存储未初始化的全局变量和静态变量。
特点:在程序启动时,由操作系统自动初始化为零。 - 堆空间(Heap)
位置:数据段之后,栈空间之前。
用途:动态内存分配。
特点:
从低地址向高地址生长。
可以动态扩展,但扩展有限,受系统内存限制。
程序员通过malloc、calloc、realloc等函数手动管理。 - 栈空间(Stack)
位置:通常位于内存的高地址区域。
用途:
存储函数调用时的局部变量、函数参数和返回地址。
管理函数调用的执行流程。
特点:
从高地址向低地址生长。
自动管理,具有“后进先出”(LIFO)的特性。
每个函数调用都会在栈上分配一个栈帧,包含局部变量和返回地址。 - 内核虚拟内存(Kernel Virtual Memory)
位置:通常不直接显示在用户程序的内存布局中,但存在于操作系统内核中。
用途:操作系统内核的运行环境。
特点:与用户程序隔离,提供安全性。
±----------------------------------+
| 内核虚拟内存 |
±----------------------------------+
| 栈空间(Stack) |
| (高地址) |
±----------------------------------+
| 堆空间(Heap) |
| (低地址) |
±----------------------------------+
| 数据段(Data) |
| (包括BSS段) |
±----------------------------------+
| 代码段(Code) |
| (低地址) |
±----------------------------------+
2. 递归
递归要有三要素
1.要有递归体(即函数自己调用自己的语句)
2.递归的出口(如果不给递归设置结束条件,那么就一定会出现栈溢出的情况)
3.递归的深度(每次递归都会导致栈帧进栈,如果深度过大,那么栈会溢出)
long jiechen(int n) {
//先写边界条件
if (n == 1) {
return 1;
}
//再写递归体
return n * jiechen(n - 1);
}
int main() {
long result = jiechen(5);
printf("%d", result);
return 0;
}
递归的优点就是简洁,清晰
递归的缺点就是栈溢出风险高,效率低,内存消耗大,难以调试,难以思考
汉诺塔问题递归解法:
int hanoi(int n) {
if (n == 2) {
return 3;
}
return hanoi(n - 1) + 1 + hanoi(n - 1);
}
int main() {
//print_hello(5);
//long result = jiechen(5);
int result = hanoi(3);
printf("%d", result);
return 0;
}