指標算術 -- 指標的加減法,很容易會造成錯誤
在 C 語言當中,指標型態的變數,像是下列範例中的 char cp; int ip; 等,其加減法的表現,會根據型態而有所不同。
舉例而言,假如 cp = 0x0022FF77,那麼 cp+1 就是 0x0022FF78,因為 cp 是一種字元指標,這種結果是理所當然的。
但是,假如 ip = 0x0022FF6C,那麼 ip+1 卻是 0x0022FF70,這是因為 ip 是整數指標,因此當我們將 ip 加上 1 單位距離時,這個一單位距離的大小就相當於整數 int 的大小,也就是 sizeof(int) = 4。
範例程式
#include <stdio.h>
int main() {
char c = 'a';
char *cp = &c;
printf("&c=%p\n", &c);
printf("cp=%p\n", cp);
printf("cp+1=%p\n", cp+1);
printf("cp+3=%p\n", cp+3);
int i = 1;
int *ip = &i;
printf("&i=%p\n", &i);
printf("ip=%p\n", ip);
printf("ip+1=%p\n", ip+1);
printf("ip+3=%p\n", ip+3);
}
執行結果
D:\cp>gcc ptradd.c -o ptradd
D:\cp>ptradd
&c=0022FF77
cp=0022FF77
cp+1=0022FF78
cp+3=0022FF7A
&i=0022FF6C
ip=0022FF6C
ip+1=0022FF70
ip+3=0022FF78
習題
這個設計的邏輯,是為了讓您寫程式時,可以都用 ptr ++ 來將指標前進一格,而不需要用 ptr += sizeof(*ptr) 這樣複雜的寫法,但是這也造成了一些問題。
假如您的認知錯誤,很可能會多此一舉,萬一您自己計算大小以便調整指標時,就會產生錯誤的結果,像是以下程式一樣。
#include <stdio.h>
int main() {
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *ptr = a;
int i;
for (i=0; i<3; i++) {
printf("%d ", *ptr);
ptr += sizeof(int);
}
}
習題的輸出
D:\cp>gcc ptrerror.c -o ptrerror
D:\cp>ptrerror
1 5 9
補充
根據 jserv 的來信補充,提到下列這幾點,是本文原本所沒提到的:
* pointer type 的變數可以對一個純量作 '+' 和 '-' 操作
* 兩個 pointer type 的變數可以施加 '-' 操作,以得知位移量 (offset),但不能施加 '+' 操作
意思是說,假設:
int a, b;
void *ptrA = &a, *ptrB = &b;
那麼:
ptrB - ptrA; // 合法
ptrA + 1; 合法
ptrA - 1; 合法
ptrA + ptrB; // 不合法
ptrA / 1; // 不合法