指針初始化
- 可初始化為
0、NULL 或合法地址。NULL 定義於 <stdio.h>,賦 0 會隱式轉換為對應類型的空指針。
- 未初始化指針值不定,解引用導致 UB。
指針與地址運算符
& 取地址:僅適用於變量/數組元素,不可用於常量、表達式、register 變量。
* 解引用:取地址中內容。
void * 可接收任意類型指針賦值,但不可解引用、不可算術運算(編譯器不知類型大小)。
* 和 & 優先級高於算術運算符,++*p ≡ (*p)++,*p++ ≡ *(p++)。
指針與數組的等價性
a[i] ≡ *(a + i) ≡ *(i + a) ≡ i[a](編譯器均轉換為指針形式)。
&a[i] ≡ a + i。
- 數組名是常量指針,不可修改指向(
a = p 非法),但可作為函數參數傳遞(實為值傳遞指針副本)。
- 指針可用負下標:
p[-1] 訪問前一元素(需確保有效)。
&a[n](尾後指針)允許參與指針算術,&a[-1] 非法。
指針數組 vs 數組指針
| 聲明 | 本質 | 指針算術單位 | 示例 |
int *a[3] | 指針數組(3個 int*) | sizeof(int*) | 字符串數組 char *argv[] |
int (*a)[3] | 數組指針(指向 3-int 數組) | 3*sizeof(int) | 二維數組行指針 |
[] 優先級高於 *,故 int *a[3] 為指針數組,需用括號改變結合:int (*a)[3]。
多維數組與指針實戰
int a[][3] = {{11,12}, {21,22,23}};
int (*p1)[] = a; // 未指定行長,不可移動
int (*p2)[3] = a; // 指定行長 3,移動單位 = 3*sizeof(int)
int (*p3)[2] = a; // 警告:行長不匹配,**(p3+1) 訪問錯誤位置
函數參數中的指針數組
void val(char *a[], int *b[]) {
// a, b 在函數內為指針副本,可修改指向(如 ++a)
// 但主調函數中數組名不可修改
}
複雜指針聲明讀法(右左規則)
| 聲明 | 含義 |
char **p | 指向字符指針的指針 |
int (*p)[3] | 指向 3-int 數組的指針 |
int *p[3] | 3 元素的 int 指針數組 |
void *comp() | 返回 void* 的函數 |
void *(*comp)() | 指向返回 void* 函數的指針 |
char (*(*x())[])() | x 是函數,返回指針,指向數組,數組元素是指向返回 char 的函數的指針 |
char (*(*x[3])())[5] | 3 元素數組,元素是指針,指向函數,函數返回指向 5-char 數組的指針 |
指針轉換規則
- 同類型指針可直接賦值;不同類型需強轉(警告)。
void * 為通用指針,雙向隱式轉換,無需強轉。
- 指針↔整數轉換需整數類型足夠寬(如
uintptr_t),轉換後再轉回保持原值。
- 指針轉換可能導致對齊問題,訪問未對齊地址屬 UB。