在學C語言的時候,每次遇到二維數組,都特別頭疼,並不是它難用,而是我搞不清楚它的數組名代表的是什麼。但我們知道:當我們定義一個一位數組的時候,它的數組名就是第一個元素的地址,也就是,下面的語句是等價的:
int a[3]={1,2,3}; printf ("%d\n",a); printf ("%d\n",&a[0]);
他們將會輸出相同的值,而且更重要的是,他們的意義是一樣的。因為在數組訪問成員的過程中,它是完全轉化成指針的形式來間接訪問的,也就是:
a[i]等價於*(a+i) &a[i]等價於(a+i)
也就是根據這種思想,我們來看看二位數組:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; printf ("%u\n",a); //地址我們使用%u來輸出,防止地址過大。 printf ("%u\n",a[0]); printf ("%u\n",&a[0]);
在一個二位數組中,上面輸出結果的數值是一樣,但,僅僅是數值一樣而已,他們的意義是大不一樣的。那麼,上面的二維數組名到底和誰等價呢? 答案是&a[0];//行地址
其實,C語言並沒有二維數組,但C語言有一維數組,那麼,要模仿出N維數組,也就不是難事了。所以,二維數組只是數組的數組,只不過數組的沒一個元素也是一個數組罷了。
那麼就是,每一個元素a[i]代表的就是一個數組,那我們用一維數組來理解,就不是難事了。上面說過,在一維數組中,數組名和第一個元素的首地址是等價的就是a <-->&a[0];(一維數組)。
那麼,我們的數組的數組(二維數組),每一個元素都是一個數組,
所以a[0] <--> &a[0][0];//這裡代表的是列地址,後面會區分列地址和行地址的區別
所以 a <--> &a[0];//這裡代表的是行地址
到了這裡,我們已經知道了二維數組的數組名的含義,和它與那個等價。那麼,我們現在看看行地址和列地址的區別。
其實,在上面二維數組的代碼中,輸出的結果是一樣的,但是,他們的含義是大相徑庭的。含義不同?區別在哪裡呢?區別就是:在指針的移動中。
我們知道,在指針的移動是以數據類型所占字節大小為單位進行移動的。兩個指針所指向的地址可能相同,但他們的單位卻很可能不同。
int b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; printf ("%u\n",b+1);//+16 printf ("%u\n",b[0]+1);//+4 printf ("%u\n",&b[0]+1);//+16
可以看到,同樣是加一,但是指針移動的距離卻很是不同(本人覺得這點很重要)。這是因為,b和&b[0]是等價的,而且,他們代表的是行地址,也就是,每次移動1個單位,就移動一行的距離。
而b[0]等價於&b[0][0],代表的是列地址,每次移動,只移動sizeof(b[0][0])個字節,就是一個元素所占的字節,這就是它們含義不同的一個區別。
在我以前用memset函數的時候,最怕要用到二維數組, 我真的不知道是傳入a,a[0],&a[0],還是&a[0][0]。我們知道,他們的值是一樣的,只是代表的含義不一樣,我們需要傳入哪一個呢?其實,那個都行,這已經不是二維數組的知識了,這關乎到void *指針和memset函數內部處理的方式,
void *memset( void *dest, int c, size_t count ); //memset函數的聲明
void *指針,代表的一個地址,僅僅是一個地址,我們不考據他們的含義,為什麼呢?剛不是說指針的含義很重要嗎?現在又不考據?這是因為,memset函數可以把任可的內存置成某一個值,我們可以傳int *,double * ,float *,char *甚至struct _Person *。我們沒可能每個類型都寫一個函數,因為我們有了結構體這個類型後,數據類型已經不能捉摸了。所以,我們要做到這一點,只能僅僅傳入一個地址,我們一個字節一個字節地處理(因為計算機是已字節為單位的).下面就貼代碼算了,已經不是二維數組的知識了。
void *mymemset(void *str,int number,int ByteSize) { char *ptr = (char *)str; int i; for (i=0;i<ByteSize;i++) { *ptr=number; ptr++; } //*ptr='\0';//調用完memset後,如果是字符串的話,記得設置結束符 return str; }
以上僅是個人理解觀點,如有錯誤,希望讀者們指出,樓主感激不盡。