前提:一維數組和一維指針為什么可以替換使用?
int a[3] = { 1, 2, 3 }; int *p = a; for (int i = 0; i < 3; i++) printf("%d ", *(p + i));
上面測試表示可以相互替換使用
printf("%p %p, %p", a, &a[0],p);
a是數組名,在數組中代表了數組首地址,類似於&a[0]。 而int *p是一個int類型指針,也是指向每一個地址,所以兩者的類型相同,都是代表int類型字節地址。 int *p = a;是正確的。 我們再使用*(p+1),就是將指針P所指向的位置加上一個int類型字節(4),正好到達了a[1]的數據地址。所以這種使用方法是正確的。
一:二維數組的數組名代表了什么?
int a[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
這里數組名,還是整個數組的首地址,也可以看做第一行的首地址,還可以看做第一行第一列元素的首地址
printf("%p %p %p\n", a, &a[0], &a[0][0]);
要是我們想要獲取每一行的地址呢?
其實我們上面就使用了&a[0]獲取了第1行的首地址
printf("%p %p\n",&a[1], &a[1][0]); //測試第二行的地址
注意:
數組名a是一個地址,無論是幾維數組。都是數組的首地址
二:二級指針又代表了什么?
對於一級指針:
每次談到指針,想到的就是一個帶有門牌號的鑰匙,我們根據門牌號,才能找到對應的房間,才可以進去拿東西。
對於二級指針理解可以相同:
我們考慮,家里有個書房。書房要是在客廳。
那么我們現在人在外面,要回去去一本小黃書呵...
我們先要根據我們手中的要是找到房間號,開門進去,獲取到第二把鑰匙,查看標簽是書房的,我們就可以使用這把要是去開書房的門,獲取書籍來學習
我們可以看做:最靠近目標空間的那把鑰匙是一級指針,然后再遠一點的那把鑰匙就是二級指針,以此類推...就是多級指針了
就如同上面鑰匙和門牌號一樣,指針和地址也是密不可分的。指針變量中存放的就是地址
除了一級指針可以直接獲取到數據,其他級別的指針都是指向上一級指針的存儲地址。我們可以根據地址,一級一級直到獲取到一級指針就可以獲取到數據了,使用*就可以開門獲取數據了。
*星號的理解
int* p; //這是聲明了一個一級指針變量p,p是一個地址 *p; //*p就是去這個地址中獲取數據 int **p //這個P,也是一個指針變量,而且是一個二級,內部存放的也是一個地址 *p //就是使用二級地址去獲取了其中內容(內容是一級指針的地址) *(*p) //*p先獲取了一級指針的地址,*(*p)就是根據一級指針地址去獲取數據
二:二級指針和二維數組的錯誤用法
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
int **p=a;
或許你因為這只是一個警告而覺得無所謂。但是當你使用的時候,就會出現錯誤,崩潰
原因解析:
p是一個二級指針,p變量存放地址。a代表了數組的首地址。雖然間接級別不同,但是地址賦給地址,也沒有啥錯,所以只是警告
但是當我們試圖使用二級指針時:
num = *(*(p+0) + 0);
我們是想用*(p+0)獲取第一行的地址,然后使用*(*(p+0)+0)獲取第一行第一列的地址
但是會報錯
原因解析:
從上一個原因解析我們知道,是將a的地址賦給了二級指針p. 所以a=0x0028fce0 p=0x0028fce0 當我們使用*(p+0)==*p試圖去獲取一級指針地址時,結果發現地址0x0028fce0下存放的不是一個地址,而是1,
那么只能強制轉換1為地址0x00000001,所以*p=0x00000001。當我們再去嘗試訪問這塊地址時*(*(p+0)+0)==**p,這不是我們能訪問的,所以報錯
三:正確的使用指針和二維數組
(一)int(*p)[3] = a;
int a[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; int(*p)[3] = a; //指針變量p指向包含3個整型元素的一維數組 int num; printf("%p %p %p\n", p, p+1, p+2); num = *(*(p + 1) + 1); //指向第二行第二個 printf("%d\n", num);
指針變量p指向包含3個整型元素的一維數組,所以p的步長是其內部數據字節長度,所以p+1就是7B4-7A8=C===12就是含有3個整型元素的一維數組長度
int(*p)[3] = a;
p+1==a[1] p+2==a[2]
(二)int *p=a;//根據指針尋址是按照步長
int *p=a;將a的地址賦給p 而p是一個int* 指針,所以他的步長就是int類型4字節一步長。 因為數組在內存中的數據存儲時連續的,所以可以使用一級指針尋址獲取所有的數據
int a[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; int *p = a; for (int i = 0; i < 9;i++) printf("%d ", *p++); //p就是一個地址,每次按照步長增加四
四:正確使用二級指針
int **arr = (int **)malloc(n*sizeof(int*)); for (int i = 0; i < n; i++) { arr[i] = (int *)malloc(n*sizeof(int)); memset(arr[i], 0, n*sizeof(int)); } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) printf("%2d", arr[i][j]); printf("\n"); }