指针与内存
栈/堆、malloc/free、生命周期。
40 分钟
指针与内存
指针是 C 的灵魂,也是风险来源。对照 /roadmaps/c,本课讲解栈与堆、malloc/free 及指针的生命周期——C 区别于 Java 的核心。
学习目标
- 理解指针、取地址与解引用
- 区分栈变量与堆分配
- 正确使用
malloc、calloc、realloc、free - 避免悬空指针与重复释放
核心概念
栈指针与堆分配
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap_int(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
char *make_greeting(const char *name) {
size_t len = strlen(name) + 8;
char *buf = malloc(len);
if (buf == NULL) return NULL;
snprintf(buf, len, "Hi, %s!", name);
return buf; /* 调用方负责 free */
}
int main(void) {
int x = 10, y = 20;
int *px = &x;
printf("x=%d, *px=%d\n", x, *px);
swap_int(&x, &y);
printf("after swap: x=%d y=%d\n", x, y);
/* 堆分配 */
int *arr = calloc(5, sizeof(int));
if (arr == NULL) return 1;
for (int i = 0; i < 5; i++) arr[i] = i * i;
arr = realloc(arr, 8 * sizeof(int));
if (arr == NULL) return 1;
arr[5] = 25;
char *msg = make_greeting("CodeRoadMap");
if (msg) {
puts(msg);
free(msg);
msg = NULL; /* 避免悬空指针 */
}
free(arr);
arr = NULL;
int stack_val = 42;
int *danger = &stack_val;
printf("stack pointer ok: %d\n", *danger);
/* 切勿 return 栈变量地址给调用方 */
return 0;
}
生命周期对照
| 存储 | 分配 | 释放 | 典型用途 |
|---|---|---|---|
| 栈 | 自动 | 离开作用域 | 局部变量、小对象 |
| 堆 | malloc 等 | free | 动态大小、跨函数存活 |
| 静态 | 程序加载 | 程序结束 | 全局变量、static |
规则:每个 malloc 对应一次 free;释放后不再解引用;NULL 检查失败返回值。
与 C++/Java 对照
| 特性 | C | C++ | Java |
|---|---|---|---|
| 显式指针 | 核心 | 有(+ 引用) | 无(仅对象引用) |
| 堆管理 | malloc/free | /、智能指针 |