指針懸空是 C/C++ 開發中極具隱蔽性且破壞力極強的錯誤類型。它像一顆定時炸彈,程式當下可能運行正常,卻在未來某個時刻觸發不可預期的崩潰或數據損壞。本文將剖析成因、展示實例並給出最佳防範實踐。
定義:指針指向的內存已被釋放(或超出作用域),但指針本身未被置為 NULL,仍保存著已失效的地址值。
核心危害:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // sleep()
int *global_ptr; // 全局指針
void func(void) {
int n = 8; // 局部變量,棧上分配
global_ptr = &n; // 指針指向棧地址
printf("函數內:指針指向數據 = %d\n", *global_ptr);
// global_ptr = NULL; // 若取消註釋,主函數將觸發段錯誤
}
int main(void) {
func(); // func 結束,n 的棧幀被銷毀
sleep(2); // 延遲,增加棧內存被覆寫機率
printf("主函數:解引用懸空指針 = %d\n", *global_ptr); // 未定義行為
return 0;
}
| 場景 | 現象 | 原因 |
|---|---|---|
| 未置 NULL | 可能輸出 8、亂碼或崩潰 | 棧內存可能未被覆寫,也可能已被後續調用覆蓋 |
| 置為 NULL | 穩定觸發 Segmentation Fault | 解引用空指針,作業系統直接終止程式 |
free(p); /* 缺少 p = NULL; */vector 擴容、realloc 移動內存塊。free(ptr); ptr = NULL; 封裝為宏或內聯函數(如 SAFE_FREE(ptr))。-Wall -Wextra -Werror(GCC/Clang),/W4(MSVC)。-fsanitize=address)、Valgrind Memcheck。指針懸空的本質是「指針生命週期 > 所指對象生命週期」。養成「釋放即置空」習慣,配合現代檢測工具,可將此類 Bug 殲滅於萌芽狀態。寫 C 代碼時,請時刻記住:野指針比空指針可怕百倍。