一眼辨別口訣:看 * 是否被 () 包圍
| 宣告 | * 位置 | 本質 | 口訣 |
int *func(int, int); | 函數名左側,無括號 | 函數 (回傳指標) | 指標函數 = 回傳指標的函數 |
int (*func)(int, int); | 函數名左側,被 () 包圍 | 指標 (指向函數) | 函數指標 = 指向函數的指標 |
1. 指標函數:回傳位址的函數
int *GetDate(int wk, int day) {
static int cal[5][7] = {{1,2,...}, ...};
return &cal[wk-1][day-1]; // 回傳陣列元素位址
}
int main() {
int *p = GetDate(3, 4);
printf("%d\n", *p); // 解參考取值
}
- 必須回傳有效位址 (靜態/全域/呼叫者提供緩衝區/動態分配)。
- 切勿回傳區域變數位址 (棧逃逸)。
2. 函數指標:指向函數入口的指標變數
void FileFunc() { puts("FileFunc"); }
void EditFunc() { puts("EditFunc"); }
int main() {
void (*fp)() = FileFunc; // 賦值函數位址
fp(); // 呼叫
fp = EditFunc;
fp(); // 動態切換行為
}
- 實現回呼、狀態機、插件架構、
qsort 比較函數等。
&Func 與 Func 等價 (函數名即位址)。
3. 多級指標:指標的指標
char c = 'A';
char *p = &c;
char **pp = &p;
printf("%c\n", **pp); // 經兩層解參考取值
核心用途:
• 函數修改呼叫者的指標變數 (如
malloc 封裝
void alloc(void **ptr, size_t sz))。
• 處理指標陣列 (如
char **argv)。
4. 指向指標陣列的指標
char *names[] = {"Bill", "Sam", "Jim", "Paul", "Charles", NULL};
char **p = names;
while (*p) puts(*p++); // 遍歷字串陣列
NULL 終結符簡化迴圈判斷。
- 動態增刪字串只需調整陣列,遍歷邏輯不變。
5. 參數傳遞三層境界
| 層級 | 原型 | 用途 |
| 值傳遞 | void f(int x) | 唯讀輸入 |
| 指標傳遞 | void f(int *p) | 修改呼叫者變數 / 輸出參數 |
| 指標的指標 | void f(int **pp) | 修改呼叫者指標 / 分配記憶體返回 |
總結
「指標函數」是函數,「函數指標」是指標——語法上 * 在括號內外一目了然。掌握函數指標實現動態派發、多級指標實現輸出參數與指標陣列遍歷,是 C 語言模組化、擴展性設計的關鍵技能。