二維數組
在說二維數組前先來說下一維數組中的指針數組和和數組的指針
一、一維數組中指針數組和數組指針的區別
指針數組:
1 int *p[5];
[]的優先級比*高,首先它是一個數組,它的大小是5,它里面存放的數據類型是int *,也就是整型指針。 所以它叫指針數組,講到底這個p是一個數組,數組內的元素是5個指針,而數組內的每一個指針指向一個int型的變量
數組的指針:
int (*p)[5];
首先p是一個指針,指向大小為5的數組,因此這叫數組的指針,定義了一個指向5個元素的一維數組的指針。(括號優先)
二、兩者在賦值時的區別
指針數組的賦值
1 #include <stdio.h>
2
3 main() 4 { 5 int *p[5]; 6 int a = 10; 7
8 p[0] = &a; 9 printf("%d", *p[0]); 10 }
數組的指針的賦值
1 main() 2 { 3 int (*p)[5]; 4 int a[5] = {1, 2, 3, 4, 5}; 5
6 p = &a; 7 printf("%d", *p[0]); 8 }
三、關於數組的地址(這里只討論一維\二維數組)
一維數組
1 int a[5];
a表示的是數組的首地址,a等價於&a[0]
二維數組
1 int a[2][2] = {1, 2, 3, 4};
a表示的整個數組的首地址,a[0]表示的是第一行的首地址,這兩者者在數值上是一樣的,但含義不同(或者說類型不同),數組名a是對於整個數組,a[0]是對於第一行
對二者(a、a[0])的地址是否相同進行驗證
1 #include <stdio.h>
2
3 int main() 4 { 5 int a[2][2] = {1, 2, 3, 4}; 6
7 printf("%p\n%p\n", a, a[0]); 8
9 return 0; 10 }
運行結果
在用數組的地址進行賦值的時候,雖然三者值相同,但是三者不可隨意混用(以int a[2][2]為例)
a--------是int (*)[2]型
a[0]-----是int *型
對於a[0]和&a[0][0],兩個類型都是int *型的,所以下述兩種賦值方法等價
第一種:
1 int a[2][2] = {1, 2, 3, 4}; 2 int *p; 3 p = a[0];
第二種:
1 int a[2][2] = {1, 2, 3, 4}; 2 int *p; 3 p = &a[0][0];
對於int a[2][2]來說,如果將a[0]改為&a[0],那么&a[0]和a的類型相同,都為int (*)[2]類型,下面以int a[5][5]為例,列出了二維數組的元素在不同方式表達下的不同類型
也可以用一維指針數組來保存二維數組中某個元素的地址
1 int a[2][2] = {1, 2, 3, 4}; 2 int *p[2]; 3 p[0] = &a[0][0]; 4 printf("%d", *p[0]);
四、二維數組的解引用
以二維數組a[2][3]={1, 2, 3, 4 ,5, 6};為例(第一維是行,第二維是列)
第一種:*(*a+1)--------等價於a[0][1],因為*的優先級比+高,所以先解引用,進入第二維在第二維里面地址+1,再次解引用得到元素值
第二種:*(*(a+1))------等價於a[1][0],比上面第一種多加了一個括號,括號優先級最高,先+1移動地址(注意是在第一維里面移動),然后解引用進入第二維,再解引用得到元素的值
第三種:*(&a[0][0]+1)--等價於a[0][1],這里使用了&取地址符,將原本表示第一個元素的a[0][0]返回到第二個維度,然后第二維地址+1,再解引用得到元素的值
為方便讀者理解下面上圖
補充:
請讀者先看下面的代碼
1 #include <stdio.h>
2
3 main() 4 { 5 int a[2][3] = {1, 2, 3, 4, 5, 6}; 6
7 printf("%d***%d", *(a[1]+1), (*a+1)[1]); 8 }
*(a[1]+1)--------表示的是a[1][1]的值
(*a+1)[1]--------表示的是a[0][2]的值
為了方便描述先退回一維數組,以int a[5]來說,a表示的數組a的首地址,a[2]表示在a的基礎上移動2個地址(注意a的類型是int *型的),再解引用得到元素的值,意思是a[2]
實際上包含了兩步,第一步地址移動,第二步解引用得到元素的值(注意第二步,有點隱式轉換的意思,經常被人忽略)
現在來解釋上面的二維數組就容易多了
先來看第一個*(a[1]+1),a[1]代表第二行的首地址,注意這里的維度已經是第二維度了,然后括號優先第二維地址+1,最后解引用得到元素的值
來看第二個(*a+1)[1],這里提一句,因為[]的優先級是比*高的所以這里的括號不能去掉,第一步先解引用進入第二維度(*優先級高於+),然后第二維地址+1,然后再在當前基礎上再移動一次地址,最后解引用
得到元素的值,這里可能有點繞,換個說法就是[1]是在當前維度進行移動,然后解引用(“當前維度”有點不太嚴謹,為了方便理解先將就這么用了)
拿a[2][1]來說,一共有四步,其中包含了兩次地址移動,兩次解引用,執行順序是:地址移動->解引用->地址移動->解引用(這里提一句,[]的結合性是左結合的,所以在移動的時候先移動行(第一維)再移動列(第二維),小聲BB)
詳細步驟:第一步:在當前維度地址+2,因為a的維度是第一維,所以是第一維地址+2,即行+2
第二步:解引用進入第二維度
第三步:在當前維度地址+1,因為這時已經進入第二維,所以第二維地址+1,即列+1
第四步:解引用得到元素的值