*p 兩層含義:聲明時標識指針類型;使用時解引用操作目標內存。p++ ≡ (char*)p + sizeof(*p)。三個必要條件:
形參 = &實參。*形參 = 新值 間接修改實參。推論:n 級指針形參可間接修改 n-1 級指針實參。這是 C 語言模擬「引用傳遞」的核心機制。
十大典型接口模式:
| 級別/方向 | 典型場景 | 內存分配方 | 例子 |
|---|---|---|---|
| 一級輸入 | 只讀緩衝區/數組 | 主調分配(棧/堆) | show(buf), showArray(arr, len) |
| 一級輸出 | 返回長度/狀態碼 | 主調分配,被調寫入 | getLen(file, &len) |
| 二級輸入 | 字符串數組/二維數組 | 主調分配 | main(argc, argv), showMatrix(mat, rows) |
| 二級輸出 | 動態分配結構體/數組 | 被調分配堆,主調負責釋放 | getTeacher(&p), getData(&buf, &len) |
| 三級輸出 | 多行文本/多維數組 | 被調分配堆,提供釋放函數 | getFileAllLine(&lines, &cnt) |
void showArray(int *arr, int n) { for(int i=0;i
主調在棧/堆分配,被調僅讀取,const 修飾增強可讀性。
鐵律 6:二級指針輸出 —— 動態構建數組/結構體
int getTeacher(Teacher **pp) {
*pp = malloc(sizeof(Teacher));
(*pp)->name = malloc(100);
return 0;
}
void freeTeacher(Teacher **pp) { free((*pp)->name); free(*pp); *pp = NULL; }
- 被調分配堆內存,通過
*pp 回傳地址。
- 提供配套釋放函數,參數用
void** 可置空實參,防野指針。
鐵律 7:三級指針輸出 —— 多層動態結構
int getFileAllLine(char ***content, int *lineCnt) {
*content = malloc((*lineCnt+1) * sizeof(char*));
for(int i=0;i<*lineCnt;i++) (*content)[i] = malloc(MAX_LINE);
return 0;
}
鐵律 8:野指針防禦三部曲
- 定義即初始化
NULL。
free 前判空,free 後置 NULL。
- 輸出型接口提供
Free(void**) 統一釋放並置空。
鐵律 9:一般業務代碼禁用裸 malloc/free/new/delete
封裝為模塊內部實現,對外提供 Create/Destroy 或 Get/Free 對,統一內存策略,便於檢測洩漏、池化、統計。
鐵律 10:函數指針是 C 語言實現多態與回調的基石
typedef int (*Handler)(void *ctx, int cmd, void *data);
// 註冊回調
void registerHandler(Handler h) { g_handler = h; }
// 面向對象雛形
struct VTable { void (*init)(void*); void (*process)(void*); };
struct Object { struct VTable *vptr; void *priv; };
函數指針讓 C 具備「行為參數化」能力,是框架設計、驅動開發、狀態機實現的核心工具。
附錄:字符串與結構體指針實戰模式
字符串函數接口規範
- 主調分配目標緩衝區,傳入指針與容量,被調寫入並返回實際長度。
- 被調分配情況:返回
char*,文檔註明調用方負責 free,或提供 FreeStr(char**)。
結構體淺拷貝 vs 深拷貝
// 編譯器默認淺拷貝:指針成員僅複製地址
// 深拷貝手動實現:
void deepCopy(Teacher *dst, Teacher *src) {
memcpy(dst, src, sizeof(Teacher));
dst->name = malloc(strlen(src->name)+1);
strcpy(dst->name, src->name);
}
柔性數組成員
struct Packet { int len; char data[]; }; // C99
struct Packet *p = malloc(sizeof(struct Packet) + 100);
p->len = 100; // data 緊隨結構體,單次分配
總結
指針是 C 語言的靈魂。掌握內存四區、函數調用棧幀、間接賦值三條件、輸入輸出語義、野指針防禦、函數指針回調這六大支柱,即可駕馭 90% 的 C 工程難題。記住:畫圖驗證、邊界測試、所有權清晰是寫出健壯指針代碼的鐵律。