指針運算是 C 語言靈活高效操作記憶體的核心機制。本文詳細闡述指針比較、指針-整數加減、指針差值運算的規則與語義,並揭示指針與數組「等價但不相同」的深層關係,為掌握指針算術奠定堅實基礎。
== != < > <= >=。p < q 表示 p 指向的元素在 q 之前。==/!= 外)。p + n、p - n、n + p(n 為整數)。n 個**元素**的位置(非位元組)。sizeof(*p)(所指類型大小)。| 類型 | sizeof | p+1 位移位元組 |
|---|---|---|
char | 1 | 1 |
short/int (16-bit) | 2 | 2 |
long/float | 4 | 4 |
double | 8 | 8 |
| 結構/聯合 | 結構大小 | 結構大小 |
例如:int *p 指向 a[0],則 p+3 指向 a[3],位移 6 位元組。
p - q 為 **ptrdiff_t** 有符號整數,表示相隔元素個數(非位元組)。sizeof(*p)。「任何能由數組下標完成的操作,均可用指針實現;指針代碼更緊湊、更靈活。」
int a[5]、int *pa = a 為例)| 數組表示 | 指針表示 | 語義 |
|---|---|---|
a | pa | 首元素地址 (&a[0]) |
a[i] | *(pa + i) | 第 i 元素值 |
&a[i] | pa + i | 第 i 元素地址 |
sizeof(a) | sizeof(*pa)*5 | 整個數組大小 (指針失效) |
a++ 非法),編譯期確定大小。sizeof(a) = 整個數組大小;sizeof(pa) = 指針大小。/* 模式 1:指針自增遍歷 */
int *pa = a;
for (int i = 0; i < 5; i++) {
*pa = i; // 賦值
pa++; // 移至下一元素
}
/* 模式 2:指針作循環條件 */
int *pend = a + 5;
for (int *p = a; p < pend; p++) {
printf("%d ", *p);
}
/* 模式 3:指針差值計算已處理數 */
int *pa = a;
int *start = pa;
while (pa < a + 5) *pa++ = 0;
printf("Cleared %td elements\n", pa - start);
| 陷阱 | 說明 | 對策 |
|---|---|---|
| 指針越界訪問 | p + n 超出分配範圍(含 a+5 合法但不可解引用) | 嚴守 [base, base+size) 半開區間 |
| 不同數組指針相減 | 未定義行為 | 僅在同一數組/塊內相減 |
| void* 算術 | GNU 擴展允許按 1 字節算術,標準 C 禁止 | 轉為 char* 再運算 |
| 指針差值溢出 | 極大數組超過 PTRDIFF_MAX | 使用 size_t 索引而非指針差值 |
指針運算的三大支柱——**比較、整數加減、差值**——均建立在「以元素為單位、按類型大小縮放」的統一模型之上。指針與數組在**表達式語境下等價**(a[i] ≡ *(a+i)),但**本質不同**(常量 vs 變量、sizeof 語義)。深諳此道,方能寫出 memcpy、qsort 回調、環形緩衝區等經典系統級代碼。