3. 空指针与野指针
任务目标
本案例通过三个最小可运行示例,分别演示空指针的合法判断与非法解引用、野指针的产生原因,以及如何通过“先置空再释放”和“出作用域置空”两种手段避免野指针。最终给出一个可执行的验证路径,帮助你在本地观察两类指针错误的典型表现。
核心代码
#include <stdio.h>
#include <stdlib.h>
/* 示例1:空指针的合法判断与非法解引用 */
void null_pointer_demo(void) {
int *p = NULL;
/* 合法用法:解引用前判空 */
if (p != NULL) {
*p = 10;
} else {
printf("[空指针] p 为 NULL,跳过解引用,安全\n");
}
/* 非法用法:直接解引用空指针(运行时会崩溃) */
/* 取消下面注释可观察段错误 */
/* *p = 10; */
}
/* 示例2:野指针的产生——指向已释放的内存 */
void wild_pointer_demo(void) {
int *p = (int *)malloc(sizeof(int));
*p = 42;
printf("[野指针] 释放前 *p = %d\n", *p);
free(p);
/* 此时 p 是野指针:仍保存已释放内存的地址 */
/* 取消下面注释可观察到不确定行为(可能打印垃圾值或崩溃) */
/* printf("释放后 *p = %d\n", *p); */
}
/* 示例3:避免野指针——释放后立即置空 */
void safe_free_demo(void) {
int *p = (int *)malloc(sizeof(int));
*p = 7;
printf("[避免野指针] 释放前 *p = %d\n", *p);
free(p);
p = NULL; /* 关键:释放后立即置空 */
if (p == NULL) {
printf("[避免野指针] p 已置空,后续判空可拦截非法访问\n");
}
}
int main(void) {
null_pointer_demo();
wild_pointer_demo();
safe_free_demo();
return 0;
}
编译与运行
gcc -o pointer_demo pointer_demo.c -Wall
./pointer_demo
验证方法与判定标准
- 正常路径:运行程序应看到三行输出,依次为“空指针跳过解引用”“释放前 *p = 42”“避免野指针置空”。程序正常退出,无崩溃。
- 空指针崩溃验证:取消示例1中
/* *p = 10; */的注释,重新编译运行,程序应因段错误(Segmentation Fault)退出——这证明空指针解引用是非法操作。 - 野指针风险验证:取消示例2中
printf("释放后 *p = %d\n", *p);的注释,重新编译运行,程序可能打印垃圾值、崩溃或表现正常——这种不确定行为正是野指针的危害特征。 - 避免野指针验证:示例3中
free(p)后立即执行p = NULL,后续通过if (p == NULL)判空即可安全拦截,不会访问非法内存。
关键要点
- 空指针(
NULL)是“不指向任何对象”的合法状态,解引用前判空是标准防御写法。 - 野指针是“指向已释放或无效内存”的指针,其值本身无法预判,解引用结果未定义。
- 避免野指针的两条铁律:
free后立即置NULL;指针离开作用域前确保不再被引用。