當我們寫下int a[3][4]; 的時候,我不知道有多少學C語言的具體明白這個數組背後隱藏的東西。
a代表什麼,&a代表什麼,a[0]代表什麼等等。
我們暫且放棄我們腦海中C語言老師傳授給我們的那些教條概念:“a是二維數組名,表示二維數組第一個元素的地址...”
假設我們根本就沒有接觸過二維數組。當然我們至少得知道一維數組的知識。
我們採用從右到左的識別變量的方式來分析二維數組:
首先向右看,與a結合的是[3],即a[3],什麼意思,明白吧,a是一個包含3個元素的數組。那麼元素的類型是什麼呢,剩下的殼肯定就是它的類型薩。剩下的是:int [4] 。哦,知道了,元素的類型是:(包含4個整形數據的一維數組)類型。
a ->a[0] -->a[0][0],a[0][1],a[0][2],a[0][3]
a[1] -->a[1][0],a[1][1],a[1][2],a[1][3]
a[2] -->a[2][0],a[2][1],a[2][2],a[2][3]
那麼a[0]具體表示什麼意思呢: a[0] = a[0]+0 = &(*(a[0]+0)) = &a[0][0], 這不就明白了嗎,a[0]表示a[0][0]的地址,
而a[0][0]是第一個一維數組的第一個元素。也就是:a[0]是第一個數組元素的第一個元素的地址。而我們根據數組名的定義,數組名錶示數組第一個元素的地址。所以a[0]即第一個數組(元素)的數組名。同理a[1]表示第二個數組的數組名,a[2]表示第三個數組的數組名。
a是什麼意思? 好吧,我麼一樣來分析a = a+0 =&(*(a+0)) =&a[0] = &(a[0]+0) = &( & (*(a[0]+0)) = &&a[0][0].即a表示
第一個數組的第一個元素的地址的地址。第一個數組的第一個元素的地址即數組名a[0],所以a表示a[0]的地址,同理a+1表示a[1]的地址,a+2 表示a[2]的地址。
a的另外一種理解: a[3] 表示a是一個包含3個元素的一維數組,a是這個一維數組的數組名,即這個一維數組的地址。a+0 = =&(*(a+0) =&a[0] a是這個數組的第一個元素的地址(整個一維數組的地址,數組名都是一樣的),a+1=&a[0] 是這個數組第二個元素的地址。
&a有是什麼意思?暈了吧,這裏我們就要採取更絕的方式來理解拉,一維數組的概念我們都拋一邊。a是一個變量,整個變量的類型是什麼,剩下的就是它的類型貝,哦,int [3][4] ,我們不管這後面有多麼的一大堆的東西,反正變量a現在表示的是12個整形大小(48個字節)的一片內存。這12個整形是一個整體,和我們平時的任何基本數據類型都是一樣(思想:複雜問題傻瓜化)。即假設有這麼一種基本類型,它佔用48個字節大小的一個空間。那麼,&a好理解了吧,不就是這48個這麼大小的空間的地址嗎。不過我們注意拉,&a+1表示的是下一個48字節的空間的地址。
如果還不好理解,我們通過類型定義來看看:
typedef int type48bytes[3][4];//=== typedef int [3][4] type48bytes;
type48bytes a;
或者:
typedef struct {
char tmp[48];
//int tmp[12];
//48bytes;
}type48bytes;
type48bytes a;
我們再來分析怎麼定義指向二維數組的指針。
現來看看一維數組的指針是怎麼定義的:假設有 int b[4];
那我們看到的肯定就是則會樣的形式: int * p = b;
爲什麼是這樣的呢(我以前沒有思考過,你們估計也沒思考過),b = b+0 = &(*(b+0)) = &b[0] 所以b就是第一個元素的地址,這個元素是int型,所以,賦值符號兩邊類型剛好對應。
那二維數組呢: int a[3][4];
同理: a = &a[0] ,好了,上面分析中b[0]爲整形,所以b = &b[0] == int *, 可以推理,現在如果a[0]是什麼類型,那麼指針應該就是指向該類型的指針。a[0] 不就是 int [4]類型嗎? 所以指針的定義應該爲: int (*p)[4];
即int (*p)[4] = a;
我們驗證上面的是正確的,可以知道,p指針指向的是包含4個整形那麼個大小的空間 p+1應該就是指向下一個那麼大小的空間,也就是a[1],同理p+2 指向 a[2].
其實通過上面我們可以總結出這樣一條規律:即將我們等式右邊的式子表示爲:&type 則 type是什麼類型,那麼指針就是什麼類型的指針。
如: int a[3]; 顯然a = &a[0] a[0]是整形,所以指針爲int * ; int * p = a;
那麼&a呢,那不就是看a的類型嗎?a的類型不就是int [3]類型嗎?所以 int (*p)[3] =&a;
int a[3][4];
a[0] = &a[0][0] 所以指針類型爲a[0][0] 整形指針 int *; int * p = a[0];
a = &a[0] a[0]是int [4] 類型,所以指針爲 int (*)[4]; int (*p)[4] = a;
&a 這個有點麻煩,a是什麼類型呢,利a最近的是a[3],所以a是含有3個 int [4] 元素的數組類型,即指針類型爲,int [4] (*)[3]
= int (*)[3][4]
所以 int (*p)[3][4] = &a;
哈哈,發現了規律,對於數組名取地址,總是爲 類型 (*)p[一維][二維]...[N維]) =&a;
同理當地址越來越具體的話,就是依次去掉第一維,第二維,第三維,第N維;
如:int (*p)[4] = a
int *p = a[0];
output輸出如下:
a type=int *
&a type=int (*)[6]
p[0] type=int *
p type=int (*)[3]
&p type=int (*)[2][3]
a=0012FF68
&a=0012FF68
p[0]=0012FF50
p=0012FF50
&p=0012FF50
通過上面的分析,我們再結合老師的教條,對二維數組的理解就差不多拉。