今天的話題從一段代碼說起:

#include <stdio.h>

int main(){

int arr[2][2] = {{1, 2}, {3, 4}};
int *p1 = arr[0]; //一級指針

int **p2 = &p1; // 二級指針
int (*p3)[2] = arr; // 指向二維數組的指針

printf("I am p2:%d
", **p2);
printf("I am p3:%d
", **p3);
printf("p2:%p, * of p2:%p
", p2, *p2);
printf("p3:%p, * of p3:%p
", p3, *p3);

return 0;
}

運行結果如下:

我們重點關注的指針變數 p2 與 p3,

p2 是二級指針,指向二維數組中第一個數組中的第一個元素 1.

p3 是指向二維數組的指針

然後我們分別讓他們訪問到 arr 二維數組的第一個數組的第一個元素 1.

printf("I am p2:%d
", **p2);
printf("I am p3:%d
", **p3);

可以看到他們使用相同的運算方法來得到 1.

I am p2:1
I am p3:1

但是他們卻存在著本質的區別。

我們分別列印出 p2, p3, *p2, *p3 的地址。

printf("p2:%p, * of p2:%p
", p2, *p2);
printf("p3:%p, * of p3:%p
", p3, *p3);

p2:0x7fff4a0101b8, * of p2:0x7fff4a0101d0
p3:0x7fff4a0101d0, * of p3:0x7fff4a0101d0

結果是 二級指針 p2 與 *p2 所指向的地址不同。這個應該是符合我們對指針的理解。

而 p3 的結果有些意外,兩次指向同一個地址,那 *p3 豈不是什麼也沒做?

其實也不是。

程序是數據結構加演算法。

我們要知道的是:指針里除了存儲了他要指向的內存地址,其實還有一個信息,

那就是他所指向的地址的類型,這個類型有什麼作用呢?決定了在對指針進行加 1 運算時

指針實際上增加的地址長度。再來看一個例子:

#include <stdio.h>

int main(void){
char *p1 = (char *)1;
printf("I am char pointer p1:%p, p1+1:%p
", p1, p1+1);
int *p2 = (int *)p1;
printf("I am int pointer p2:%p, p2+1:%p
", p2, p2+1);
return 0;
}

結果如下:

I am char pointer p1:0x1, p1+1:0x2
I am int pointer p2:0x1, p2+1:0x5

同樣的一個地址值,賦值給不同的指針變數,在進行加1運算時增加的長度不同。

回到上一個問題:*p3 不是什麼也沒做,而是改變了步進長度。

printf("p3:%p, p3+1:%p
", p3, p3+1);
printf("*p3:%p, *p3+1:%p
", *p3, *p3+1);

運行結果:

p3:0x7ffe3ecc88c0, p3+1:0x7ffe3ecc88c8
*p3:0x7ffe3ecc88c0, *p3+1:0x7ffe3ecc88c4

推薦閱讀:

相关文章