大部分人,特别是初學者對于一些奇怪的數組表達式表示詫異。
舉個例子:
恩,很複雜,很無聊,感覺這樣來表達根本沒有意義。我也承認,把故意把它複雜化了,目的是講清楚一些有關數組與指針的關系。
上面的程式,運作結果是把數組元素順序輸出,也就是分别輸出1,2,3。
先來看看數組的定義:int a[3];
a 是數組名,相信大家都有過數組名 a 作為函數實參的經曆,也就是把數組首元素位址 &a[0] 傳給函數。這說明什麼,說明數組名 a 一個指針,預設指向了數組的第一個元素 a[0]。
那麼 a 作為指針,*a 是什麼也就清楚了,*a 可以說是數組第一個元素的引用,也就是說,
*a = a[0]。以此類推 *(a+1) = a[1]……
明白這個之後,再來看看下面這個推導“公式”。
*a = *(a+0) = a[0] = *(0+a) = 0[a];
*(a+1) = a[1] = *(1+a) = 1[a];
這些表達式都是對的,a[i] = i[a] 也是成立的。再看看下面的推導:
*(a+1+1) = a[2] = *(1+a+1) = 1[a+1];
是以,a[2] = 1[a+1] 成立。可以這樣來想,(i)[a+j] = a[i+j];
通過以上說明,對c語言數組與指針的關系可能更加清晰了。很多時候,我們會自己另外定義指針來指向數組:
通過自己另外定義的指針來對數組進行操作,然而低調的數組名 a ,卻淡然于世外,被人遺忘。
是以,回頭看看一開始的那個程式,一切也就明白了,核心就是:數組名就是一個指針,預設指向了數組的首元素。是以,你對數組名的任何指針式的操作都是合法的。
上面是一維數組的操作,下面來說說二維數組。
呵呵,這段代碼也挺讓人抓狂的,沒人會這麼做,這麼做的不是優秀的程式員。我還是那句話,誇張化來說明一些道理。不這麼寫,但是一定要明白為什麼可以這麼寫,這是我的一點追求。
如果上面一維數組的講解清楚了,那麼二維數組其實不難了解。
先來看看定義:
int a[2][3];
代表什麼意思?可以有很多了解,有些人覺得這可以看成是一個類似坐标的矩陣,比如把第一個[]裡面的想成是x軸,第二個[]裡面是y軸,是以這樣對a[1][2]就很容易了解,這樣了解是可以的。
有意思的是,它不過就是一維數組裡面有個一維數組而已。拿a[2][3]舉例,也就是說,首先,數組名是 a ,它是一個一維數組a[2],這個一維數組的每一個元素放着什麼呢?放着3個元素,把表達式就寫成a[2][3]。跟一維數組一樣,數組名 a 是指針,預設指向a[0][i],但是問題來了,因為a[0][i]當中的記憶體塊裡面有三個int型的分别是a[0][0],a[0][1],a[1][2],究竟指向哪個呢?哪個都不指向,就隻是指向a[0][i]而已,那麼指向a[0][0]的指針在哪?在這:*a 。 *a 就是指向a[0][0]的指針,明白這種關系嗎?這裡有個雙重指針。我結合一維數組來解釋一下:
一維數組中,a 是指針指向首元素,那麼有等式【1】 *a = a[0];
二維數組中,a 是指針指向首元素a[0][i],那麼利用上面的等式【1】,a[0][i]可以推導寫出這樣的等式:a[0][i] = *a[i],*a 可以看成是數組名,是以,*a 就是指向 a[0][0] 的指針,這樣就清楚多了,呼~
是以,理清楚這個關系,輸出**a,也就是輸出a[0][0]了,*(*a+1),當然就是a[0][1]。
是以,對于三維數組也清楚了吧,***a 就是 a[0][0][0],多元數組以此類推……
對于這樣的表達式:0[*(a)],也能了解了,推導:(見笑,筆者對邏輯步驟比較感興趣)
0[*(a)] = *(a)[0] = *a[0] = a[0][0];
恩,對c語言的數組與指針說得有點複雜,但這些确實很重要,平時程式設計可以不這麼寫,但是一定要懂得裡面的原理,這樣的好處不是讓自己能運用,而是讓自己不會運用錯誤。(指針操作錯誤可能引發很大的麻煩)
水準有限,有些包含不到,有些分析欠佳的,還請諒解。