大家好,我是网域小星球。
很多同学学到指针、动态内存、变量作用域时都会困惑:
- 为什么局部变量出函数就失效?
- 为什么
malloc出来的内存要手动free? - 为什么字符串常量不能改?
- 野指针、内存泄漏到底是怎么产生的?
答案都在内存四区 里。这一章不讲花哨语法,而是讲程序运行的底层原理,搞懂它,指针和内存相关的 BUG 你一眼就能看懂。
目录
[五、全局 / 静态区](#五、全局 / 静态区)
[六、常量区 & 代码区](#六、常量区 & 代码区)
[八、高频面试 & BUG 原理](#八、高频面试 & BUG 原理)
一、本章学习目标
- 认识 C 程序的四大内存区域:栈区、堆区、全局 / 静态区、常量区
- 知道每种变量存在哪里、生命周期多长
- 理解栈与堆的区别,彻底搞懂动态内存
- 明白野指针、内存泄漏、常量不能修改的本质
- 为后续写稳定、少 BUG 的程序打下底层基础
二、程序内存四区概览
程序运行时,操作系统会给它分配一块内存,主要分为 4 个区域:
-
**栈区(stack)**局部变量、函数形参,由系统自动分配、自动释放。
-
堆区(heap) 动态内存(
malloc/calloc/realloc),手动申请、手动释放。 -
全局 / 静态区(data segment) 全局变量、静态变量(
static),程序整个运行期间都存在。 -
**常量区 / 代码区(text & rodata)**代码指令、字符串常量、const 常量,只读不可修改。
三、栈区(stack)
特点
- 由系统自动管理,不需要手动申请释放
- 空间小、分配速度快
- 遵循后进先出
- 函数结束时,局部变量自动销毁
存放内容
- 函数内部的非静态局部变量
- 函数参数
- 函数返回地址
示例:
cpp
void func() {
int a = 10; // 栈上
char arr[10]; // 栈上
}
// 函数结束,a 和 arr 自动被回收
典型坑点
返回栈内存地址:
cpp
int *func() {
int a = 10;
return &a; // 危险!
}
函数结束后 a 已经销毁,返回的地址变成野指针。
四、堆区(heap)
特点
- 手动申请(
malloc)、手动释放(free) - 空间大、速度相对慢
- 生命周期由程序员控制
- 不主动释放会造成内存泄漏,程序结束后由系统回收
存放内容
malloc / calloc / realloc申请的内存
示例:
cpp
int *p = (int*)malloc(4 * sizeof(int));
// 手动释放
free(p);
p = NULL; // 避免野指针
五、全局 / 静态区
特点
- 程序运行期间一直存在
- 默认初始化为 0
- 作用域看定义位置
存放内容
- 全局变量:函数外定义
- 静态变量 :
static修饰的变量
示例:
cpp
int g_a = 10; // 全局区
void func() {
static int s_b = 20; // 静态区
}
static 局部变量特点:
- 只初始化一次
- 函数结束不销毁
- 下次进函数值还在
六、常量区 & 代码区
特点
- 只读,不能修改
- 修改会直接程序崩溃
存放内容
- 程序代码指令
- 字符串常量
- const 修饰的全局常量
典型坑点:
cpp
char *p = "hello"; // "hello" 在常量区
p[0] = 'H'; // 崩溃!
但下面这个没问题,因为在栈上:
cpp
char arr[] = "hello";
arr[0] = 'H'; // 正常
七、四区一张表总结
| 区域 | 存放内容 | 生命周期 | 管理方式 | 读写 |
|---|---|---|---|---|
| 栈区 | 局部变量、形参 | 函数内 | 系统自动 | 读写 |
| 堆区 | malloc 内存 | 手动控制 | 手动 free | 读写 |
| 全局区 | 全局 / 静态变量 | 整个程序 | 系统自动 | 读写 |
| 常量区 | 字符串、代码 | 整个程序 | 系统 | 只读 |
八、高频面试 & BUG 原理
-
野指针指向栈变量释放、堆内存已 free、未初始化的指针。
-
内存泄漏malloc 后没有 free,一直占着内存。
-
程序崩溃修改常量区、越界访问、野指针解引用。
-
static 作用改变生命周期(不改变作用域)。
九、本章核心总结
- 栈:自动、临时、小空间
- 堆:手动、持久、大空间
- 全局 / 静态:全程存在、默认 0
- 常量区:只读,不能改
- 搞懂四区 = 搞懂内存生命周期 = 少写 90% 指针 BUG
下期预告
下一篇我们讲编译之前的预处理指令,学会宏定义、文件包含、条件编译,写更通用、跨平台的代码。