指針加減整數時,步長 = sizeof(指針指向的類型)。這是 C 語言指針運算與整數運算的本質區別。
#include <stdio.h>
int main() {
char str[] = {'a','b','c','d','e'};
int *p = (int*)str; // 強制轉換演示,實際應保持類型一致
char *q = str;
printf("str 首地址: %p\n", (void*)str); // 例: 0x7ffee4b8
printf("q 初始: %p\n", (void*)q); // 0x7ffee4b8
printf("p 初始: %p\n", (void*)p); // 0x7ffee4b8
q++; // char* +1 → 移動 1 字節
p++; // int* +1 → 移動 4 字節 (假設 32 位 int)
printf("q++ 後: %p\n", (void*)q); // 0x7ffee4b9
printf("p++ 後: %p\n", (void*)p); // 0x7ffee4bc
// 遍歷演示
q = str;
for (int i = 0; i < 5; i++) printf("%c ", *q++); // 正確遍歷 char 數組
return 0;
}
str 首地址: 0x7ffee4b8 q 初始: 0x7ffee4b8 p 初始: 0x7ffee4b8 q++ 後: 0x7ffee4b9 (+1 byte) p++ 後: 0x7ffee4bc (+4 bytes) 遍歷輸出: a b c d e
設指針 ptr 指向類型 T,sizeof(T) = S:
ptr + n → 地址增加 n * S 字節,結果類型仍為 T*ptr - n → 地址減少 n * S 字節ptr2 - ptr1 (同類型指針) → 返回元素個數差 (addr2 - addr1) / S,類型 ptrdiff_tint arr[5] = {1,2,3,4,5};
char *cp = (char*)arr; // 強制轉換
printf("%d\n", *cp); // 只讀取 arr[0] 低 8 位 (小端機: 1)
cp += 4; // 移動 4 字節 → 指向 arr[1]
printf("%d\n", *(int*)cp); // 讀取 arr[1] 完整 4 字節: 2
教訓: 指針類型必須與數據實際類型匹配,否則解引用會讀錯數據、對齊錯誤甚至未定義行為。
char str[] = "hello"; int len = sizeof(str) - 1; // 排除 '\0' // 1. 下標法 for (int i = 0; i < len; i++) putchar(str[i]); // 2. 數組名+偏移 for (int i = 0; i < len; i++) putchar(*(str + i)); // 3. 指針遍歷 (最高效,最地道) for (char *p = str; *p; p++) putchar(*p); // 利用 '\0' 結束
char *str = "hello world";
char *p = strchr(str, 'w'); // 找到 'w'
size_t offset = p - str; // 計算偏移量 = 6
printf("'w' at index %zu\n", offset);
| 錯誤代碼 | 問題 | 正確寫法 |
|---|---|---|
int *p; p += 100; | 未初始化指針運算 → UB | 先指向有效數組/內存 |
p = arr + 10; (arr 長度 5) | 指向數組尾後一個元素合法,再往後非法 | 確保 p 在 [arr, arr+len] 範圍 |
malloc(n); p += n; | 指向釋放後/越界內存 | 記錄基址 base = p,釋放用 free(base) |
printf("%d", p); | 指針用 %d 打印截斷/未定義 | printf("%p", (void*)p); |
指針運算不是整數運算。步長由指向類型決定,邊界由分配對象決定。永遠保持指針類型與數據類型一致,並在有效範圍內操作。