1. 程式人生 > >C語言之指標與二維陣列

C語言之指標與二維陣列

    指標,其實就是地址,可以指向一塊自己分配大小的空間。陣列即是多塊一位的空間的線性排布。二維陣列,雖然在人文定義的感覺上有了面的理解,但實際在記憶體中也是一維的線性空間。
    對於討論二維陣列,首先我們應該先討論一維陣列與指標。
    例:int a[3];
           int *p;
           p=a;
    上述的程式碼段可以經過編譯器,可得,p與a的指向型別相等,a是陣列a[3]的陣列名,也是陣列的首地址常量,a=&a[0],a是指標,指類(指向的資料的型別)是int,而p的指類也是int,由於a與p同為指標,但是有點區別,就是a是指標常量,p是指標變數,所以當我們sizeof(a)時,結果為12,當我們sizeof(p)時,結果為4,指標都是四個位元組的空間,但是由於a是指標常量,指向的是12個位元組大小的陣列空間,所以在使用sizeof()時,作業系統也就會根據它的指向空間來獲得其指向的大小,而p不是指向空間,是個變數,所以也就是隻能是4個位元組的空間了。
      a[] <=> *(a),
      a[0], a[1],...a[i] <=> *(a+0), *(a+1), ....*(a+i),
      &a[0], &a[1],...&a[i] <=> a+0, a+1, ....a+i
     由以上例子可知,*對於指標來說就是降階,&對於指標來說就是升階,*(a+i)代表的是a[i]的值,而&a[i]代表的是指向a[i]的指標。
     對於一維的陣列中的p=a的理解就是,把int當成“資料型別”可得:
         資料型別 a[3];
         資料型別 *p;
         p=a;
     根據上述,p與a指向的型別相同,所以可以賦值,換另一種理解:
資料型別 a[3] 中的中括號相當於*號,在型別宣告時,先忽略a[3]陣列的大小問題,即 資料型別 a[] ={0},<=> 資料型別 *a ={0},由此我們可以發現p與a的指類都是一樣的啦。
由此一維陣列的討論結束。

     二維陣列,依舊是一維陣列,只是一維數組裡面的每一個元素都是一段一維陣列。

     【圖片】

     對於討論二維陣列的程式碼如下:


#include <stdio.h>

void fun(int m[3000][4]);

void fun(int m[][4]){
printf("m=%p\nm+1=%p\nm[0]=%p\nm[0]+1=%p\n",
m, m+1, m[0], m[0]+1);
printf("&m[0]=%p\n&m[1]=%p\n&m[0][0]=%p\n&m[0][1]=%p\n",
&m[0], &m[1], &m[0][0], &m[0][1]);
printf("&m=%p\nm+1=%p\n&m+1=%p\n\n", &m, m+1, &m+1);
}

void main(void){
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

printf("a=%p\na+1=%p\na[0]=%p\na[0]+1=%p\n",
a, a+1, a[0], a[0]+1);
printf("&a[0]=%p\n&a[1]=%p\n&a[0][0]=%p\n&a[0][1]=%p\n",
&a[0], &a[1], &a[0][0], &a[0][1]);
printf("&a=%p\na+1=%p\n&a+1=%p\n\n", &a, a+1, &a+1);

fun(a);
}


該程式的結果如下:
a=0019FF10 m=0019FF10
a+1=0019FF20 m+1=0019FF20
a[0]=0019FF10 m[0]=0019FF10
a[0]+1=0019FF14 m[0]+1=0019FF14
&a[0]=0019FF10 &m[0]=0019FF10
&a[1]=0019FF20 &m[1]=0019FF20
&a[0][0]=0019FF10 &m[0][0]=0019FF10
&a[0][1]=0019FF14 &m[0][1]=0019FF14
&a=0019FF10 &m=0019FEC0
a+1=0019FF20 m+1=0019FF20
&a+1=0019FF40 &m+1=0019FEC4
     由於該程式設計到函式的形參的指標傳遞,與p=a的問題的本質是一樣的。
     為什麼a的值可以直接複製給m,由上述一維陣列討論可知:
int a[3][4];
int m[3][4] int m[300000][4] int m[][4] int (*m)[4]
a賦值給以上的m,結果兩者的指向型別都是一樣的,可以做如下理解:
int a[3][4] <=> int[4] a[3],理解為 :資料型別 a[3]
同理可得:
Int m[3][4] <=> int[4] m[3],理解為 :資料型別 m[3]
int m[300000][4] <=> int[4] m[300000],理解為 :資料型別 m[300000]
int (*m)[4] <=> int[4] *m,理解為 :資料型別 *m


     所以在形參中,m的三種宣告是等價的,3, 300000, 空,不影響結果。
由於m是變數,&m的值不等於&a的值,a是地址,&a=a,還是首元素的地址,有些人問a的值存放在哪裡,對於這個問題,每一次使用陣列,對應的a都不是同一個,因為它不是變數,它只是一個立即數,甚至它連常量都不是,使用陣列,作業系統就會給我們a的值,所以sizeof(a)裡面並沒有a的儲存空間。
    對於a+1,就是移動一個4*4個位元組空間
     a[0]+1,就是移動4個位元組空間
因為兩者的指類不一樣,不在同一階,a的指類是int[4],a[0]的是int型別
到此,所有討論完畢。