内存管理
翻译整理自 cppreference - 内存分配。
1. 内存分区
C 程序运行时内存大致分:
| 区 | 用途 |
|---|---|
| 代码段 (text) | 程序指令 |
| 只读数据 (rodata) | 字符串字面量、const |
| 数据段 (data) | 已初始化全局/静态 |
| BSS | 未初始化或零初始化全局/静态 |
| 栈 (stack) | 局部变量、函数调用 |
| 堆 (heap) | 动态分配 |
2. 栈内存
void f(void) {
int x = 10; // 栈上
int arr[100]; // 栈数组,大小固定
}特点:自动分配释放,速度快,但空间有限(默认 Linux 8MB)。
3. 静态存储期
int global; // 全局,零初始化
static int file_local; // 文件内可见
void f(void) {
static int count = 0; // 仅初始化一次,跨调用保留
count++;
}4. 堆内存 malloc / calloc / realloc / free
#include <stdlib.h>
int *p = malloc(4 * sizeof(int)); // 不初始化
if (!p) { perror("malloc"); exit(1); }
int *q = calloc(4, sizeof(int)); // 清零
q = realloc(q, 8 * sizeof(int)); // 调整大小
free(p); free(q);
p = NULL; q = NULL;malloc 失败检查
int *buf = malloc(huge);
if (!buf) {
fprintf(stderr, "out of memory\n");
exit(1);
}5. 内存泄漏
void leak(void) {
int *p = malloc(100);
// 忘记 free → 泄漏
}工具检测:valgrind --leak-check=full ./a.out、AddressSanitizer:
gcc -fsanitize=address -g prog.c -o prog
./prog6. 二次释放与悬空指针
int *p = malloc(4);
free(p);
free(p); // UB! 二次释放
*p = 1; // UB! use after free
修复:释放后置 NULL:
free(p); p = NULL;7. 内存越界
int arr[10];
arr[10] = 0; // 越界写 UB
arr[-1] = 0; // 负索引 UB
8. 动态字符串示例
char *str_dup(const char *src) {
size_t n = strlen(src) + 1;
char *dst = malloc(n);
if (dst) memcpy(dst, src, n);
return dst;
}
char *s = str_dup("hello");
free(s);9. 二维动态数组
int **m = malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++)
m[i] = malloc(cols * sizeof(int));
// 使用
m[2][3] = 99;
// 释放
for (int i = 0; i < rows; i++) free(m[i]);
free(m);一次性连续分配更高效:
int *flat = malloc(rows * cols * sizeof(int));
int (*m)[cols] = (int (*)[cols])flat; // 变长数组指针(C99)
m[2][3] = 99;
free(flat);10. 自适应字符串缓冲
typedef struct {
char *data;
size_t len, cap;
} StrBuf;
void sb_init(StrBuf *s) {
s->cap = 16;
s->len = 0;
s->data = malloc(s->cap);
}
void sb_push(StrBuf *s, char c) {
if (s->len == s->cap) {
s->cap *= 2;
s->data = realloc(s->data, s->cap);
}
s->data[s->len++] = c;
}
void sb_free(StrBuf *s) { free(s->data); s->data = NULL; }11. 常见错误
- 数组越界
free非堆内存- 内存泄漏
- 使用未初始化的内存
- 二次释放
- 返回局部变量地址
- 字符串未
\0结尾
小结
C 不提供自动垃圾回收,每一处 malloc 必须对应 free。下一章学习输入输出。