在正式探討指標運算之前,我們先透過兩個簡單的例子來熱身,這也能幫助我們更好地理解後續的核心概念。
#include <stdio.h>
int main(void) {
char *s = "Hello world.";
printf(s);
return 0;
}
這段代碼會報錯嗎?不會。printf 的常規用法是 printf("Please input a data:"),此時傳遞給函數的是字符串常量的首地址。上述代碼中,字符指針 s 同樣存儲了字符串首地址,因此運行完全正常,甚至編譯時連警告都不會出現。
#include <stdio.h>
int main(void) {
char *s = "Hello world.";
printf(s, 1, 2, 3);
return 0;
}
這段代碼正確嗎?同樣是正確的。printf 是變長參數函數,它根據格式字符串中的佔位符(如 %d)數量來解析後續參數。若格式字符串中無佔位符,後續傳入的參數會被忽略,因此編譯運行均無問題。
理解指標運算的關鍵在於:**指標運算依賴於指標指向的數據類型**,而非簡單的地址數值增減。
#include <stdio.h>
int main(void) {
int a[10];
printf("%p %p ", &a[0] + 1, &a[1]);
return 0;
}
問題:輸出的兩個地址值一樣嗎?不一樣的話相差多少?
常見誤區:許多人認為 &a[0] 是第 0 個元素地址,&a[1] 是第 1 個元素地址,兩者應相差 sizeof(int) 個字節(通常為 4)。
正確分析:&a[0] 的類型是 int (*)[10](指向含 10 個 int 的數組指針),但此處發生了隱式轉換為 int*。&a[0] + 1 並非地址值加 1,而是加上 1 * sizeof(int),即指向下一個 int 元素。因此 &a[0] + 1 與 &a[1] 完全等價,輸出地址相同。
#include <stdio.h>
int main(void) {
printf("%d ", (int *)0x04 - (int *)0x00);
return 0;
}
在 32 位機上運行,輸出為 1。這有力證明了指標減法的結果是「元素個數差」,而非字節差。兩個 int* 指標相減,結果為 1,表示相差 1 個 int 大小(4 字節)。
若嘗試將 char* 賦值給 int*,編譯器會報錯或警告:
char s; int *p = &s; // 警告:不能將 char* 賦值給 int*
這說明取地址操作 &s 的結果類型是 char*,嚴格區分了指標類型,進而決定了指標運算的步長。
ptr + n 相當於 ptr + n * sizeof(type))。掌握這些規則,是寫出正確、高效 C 代碼(尤其是涉及數組、動態內存、底層硬件操作)的基石。