指標變數儲存的是記憶體位址。透過此位址,程式可存取該記憶體位置的資料。指標型別決定了解參考時如何解讀位址處的位元組(如 `int*` 讀 4 位元組,`char*` 讀 1 位元組)。
int *p1; // 指向 int 的指標 char *p2; // 指向 char 的指標 int a = 123; int *p3 = &a; // 取址運算子 & 取得變數位址 int *p4; p4 = &a; // 分開宣告與指派
int a = 12; int *p = &a; int b = *p; // *p 取得 p 指向位址的值(12) *p = 20; // 修改 p 指向位址的值,a 變為 20
int arr[5] = {1,2,3,4,5};
printf("%d\n", arr[0]); // 1
printf("%d\n", *arr); // 1,等價 *(arr+0)
printf("%d\n", *(arr+2)); // 3,等價 arr[2]
| 型別 | 解參考大小 | 算術步長 | 典型用途 |
|---|---|---|---|
| `char *` | 1 byte | 1 | 字串、位元組操作 |
| `int *` | 4 bytes | 4 | 整數陣列 |
| `double *` | 8 bytes | 8 | 浮點數陣列 |
| `void *` | 不可解參考 | 1 (GNU 延伸) | 泛型指標、記憶體分配 |
| `int **` | 指標大小 | 指標大小 | 二維陣列、修改指標值 |
void swap(int *a, int *b) {
int tmp = *a; *a = *b; *b = tmp;
}
int main() { int x=1,y=2; swap(&x,&y); }
int *arr = malloc(n * sizeof(int));
if (arr) { /* 使用 */ free(arr); }
char *str = "hello"; // 指向唯讀區字串常值 char buf[100]; strcpy(buf, str); // 複製到可寫緩衝區
int add(int a, int b) { return a+b; }
int (*func_ptr)(int,int) = add;
func_ptr(3,4); // 7
| 風險 | 後果 | 防禦 |
|---|---|---|
| 野指標(未初始化) | 隨機存取,崩潰/靜默錯誤 | 宣告即初始化 `= NULL` 或 `= &var` |
| 懸空指標(free 後未置 NULL) | Use-after-free,未定義行為 | `free(p); p = NULL;` |
| 緩衝區溢位 | 覆蓋相鄰記憶體,安全漏洞 | 使用 `strncpy`、`snprintf`、邊界檢查 |
| 型別懲罰 | 違反 strict aliasing,優化器誤編譯 | 避免 `float*` 轉 `int*` 存取同一記憶體 |
const int *p1; // *p1 唯讀 int *const p2 = &x; // p2 唯讀(常數指標) const int *const p3 = &x; // 兩者唯讀
指標是 C 語言的靈魂:**位址運算賦予了對記憶體的絕對控制力**。精通指標需內化三大核心:
建議多畫記憶體圖(箭頭圖)追蹤指標變化,將抽象符號轉化為具體視覺模型。