a = 10;,編譯器自動轉換為位址存取。int *p = &a; 宣告 p 為指向 int 的指標,*p 即為 a 的別名。
int *p; // 宣告 int a = 10; p = &a; // 指向 a *p = 20; // 間接修改 a → a 變 20 int val = *p; // 間接讀取 a → val = 20
鐵律:指標未指向確定位址前,嚴禁解參考(*p = ...)。
int ary[5] = {1,2,3,4,5};
int *q = ary; // 陣列名轉為首元素位址
for (int i = 0; i < 5; ++i) {
printf("%d ", *(q + i)); // 位址 + i * sizeof(int)
// 或
printf("%d ", *q++); // 移動指標本身
}
陣列名 ary 是常量指標,不可修改(ary++ 錯誤)。
void swap(int *x, int *y) {
int t = *x; *x = *y; *y = t;
}
int main() { int a=3,b=5; swap(&a,&b); } // a=5,b=3
int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] = a; // p 指向「含 3 個 int 的陣列」
// p+1 跳過一整列(3*sizeof(int))
// 等價存取:a[i][j] == *(a[i]+j) == *(*(a+i)+j)
char *s = "hello"; // s 指向唯讀區字串常量,不可修改 *s char t[] = "hello"; // t 為陣列,可修改內容 char *p = t; *p = 'H'; // 合法
| 宣告 | 儲存區 | 可修改內容 | 可修改指向 |
|---|---|---|---|
char *p = "abc"; | .rodata | ❌ | ✅ |
char a[] = "abc"; | stack | ✅ | ❌ |
char *p = malloc(4); | heap | ✅ | ✅ |
int add(int a, int b) { return a + b; }
int (*fp)(int, int) = add; // 宣告函數指標
int res = fp(3, 4); // 呼叫 → 7
// 回調範例
void sort(int *arr, int n, int (*cmp)(int, int)) {
// 使用 cmp 決定排序順序
}
int *p = malloc(10 * sizeof(int)); if (!p) exit(1); // 檢查分配失敗 // 使用 p[0]..p[9] free(p); p = NULL; // 釋放並置空,防野指標
| 錯誤 | 後果 | 修正 |
|---|---|---|
int *p; *p = 1; | 野指標寫入 → 崩潰 | 先 p = &var; 或 malloc |
free(p); 使用 p | Use-after-free → UB | free(p); p = NULL; |
char *p = "abc"; *p = 'x'; | 修改唯讀記憶體 → SIGSEGV | 改用 char p[] = "abc"; |
int a[10]; a++; | 編譯錯誤:陣列名非左值 | 用指標 int *p = a; p++; |
malloc 未檢查 NULL | 後續解參考崩潰 | 永遠檢查返回值 |
typedef void (*CmdFunc)(void);
void cmd_help(void) { puts("Help"); }
void cmd_quit(void) { exit(0); }
CmdFunc table[] = { cmd_help, cmd_quit };
table[0](); // 執行 help