第三章 數組的解剖學

來源:互聯網
上載者:User

        這一章我們來討論一下數組的內涵,對數組的內部構造進行一次解剖,看看裡面究竟隱藏了什麼秘密。 有了前面兩章對數組名和C語言數組本質的澄清,再來理解這一章的內容,就容易多了。

        在下面的敘述中,筆者會用到一個運算子sizeof,由於在不同的編譯器和編譯模式下,對一個地址進行sizeof運算的結果有可能是不同的,為了方便討論,我都假設地址長度為4個位元組。

        多數教材在講述數組的時候,都是把重點放在外部表格現形式上,很少涉及數組的內部,只告訴你如何做,卻忽視了為什麼要這樣做。在解釋的過程中,還會列出各種各樣的運算式,例如:a、a+1、a[0]、a[0][0]、&a[0]、&a[0][0]、*(a+1)等等,讓人眼花繚亂。但實際上真正能夠用來描述數組內部構造的運算式只有其中的幾個。

        上一章講到,C語言的數組實現並非真正的多維陣列,而是數組嵌套,訪問某個元素的時候,需要逐層向下解析。仍然以上一章的例子數組int a[7][8][9]來說,第一維元素0的值a[0]是a[0]所代表的那個數組的首地址,這個運算式在C語言的數組裡面具有特殊的意義,之所以特殊,不僅僅在於它所代表的東西與一般的地址不同,而且類型也並非一般的地址類型,它的類型叫做數群組類型,數群組類型這個名稱在絕大多數教材中是從來沒有出現過的,在C89標準中,也僅僅出現在介紹數組定義的那一段。具有數群組類型的地址跟一般類型地址的主要區別,在於長度不一樣,對一個一般類型的地址進行sizeof運算,結果是4個位元組,而a[0]由於代表了一個數組,sizeof(a[0])的結果是整個數組的長度8x9xsizeof(int),並非4個位元組。具有數群組類型的地址跟數組名一樣都是一個符號地址常量,因此它必定是一個右值。數群組類型在數組的定義與引用中具有非常重要的作用,它可以用來識別一個標識符或運算式是否真正的數組,一個真正數組的數組名,是一個具有數群組類型的符號地址常量,它的長度,是整個數組的長度,並非一般地址的長度,如果一個標識符不具備數群組類型,那它就不是一個真正的數組。在後面的章節裡,還會再次使用這個概念。

        與a[0]類似的數群組類型地址還有a[0][0],a[0][0]是a[0]的下一層數組,因此sizeof(a[0][0])的結果是9xsizeof(int)。類似地,對於一個三維數組:

a[i][j][k]

a、a[x]、a[x][y](其中x、y大於等於0而小於i、j)都是具有數群組類型的地址常量,而且都是一個右值。這一點要牢牢記住。正是由這些特殊類型的地址構成了整個數組。

以上結論對於n維數組同樣適用。

接下來跟各位一起討論一下跟數組有關的各種運算式的意義及其類型:

&a[0][0][0]:

&a[0][0][0]僅僅是一個地址,它的意義,僅僅表示元素a[0][0][0]的地址,sizeof(&a[0][0][0])的結果是4。不少人把它說成是數組a的首地址,這是錯誤的,這是對數組首地址概念的濫用。真正能代表數組a的數組首地址只有a本身,a與&a[0][0][0]的意義根本就是兩回事,真正的數組首地址是具有數群組類型的地址,sizeof(a)結果是ixjxkxsizeof(int),而不是4,只不過由於a[0][0][0]位置特殊,恰好是數組a的第一個元素,所以它們的地址值才相同。而對於a[0]和a[0][0],它們是在數組a內部a[0]和a[0][0]所代表的那個數組的首地址,它們的地址值也是由於位置“特殊”,因此才跟a和&a[0][0][0]一樣。這一點一定要區分清楚了。

a+i:

可能有些人會對a+i感到迷惑,數組的首地址加上一個整數是什麼呢?它是第一維元素i的地址,sizeof(a+i)為4。

a[i]+j:

跟上面的類似,a[i]+j是a[i]所代表的那個數組的元素j的地址,sizeof(a[i]+j)的結果也為4。

&a:

對數組名取地址在C標準裡面是未定義的。這個運算式曾經引起過爭論,焦點在於對一個右值取地址的合法性。C89規定&運算子的運算元必須具有具體的記憶體空間,換言之就是一個左值,但數組名卻是一個右值,按照&運算子的要求,這是非法行為。因此,早期的編譯器通常規定&a是非法的。但不知道什麼原因,現在的編譯器都把&a人為地定義成一個比a高一級而地址值跟a一樣的地址,但作為比a高一級的地址,有一個行為卻非常怪誕,sizeof(&a)的結果跟sizeof(a)相同,這也是人為的痕迹。筆者傾向於把&a定義為非法,應該維護&運算子的權威性,而不是在規定對某個右值取地址為非法的同時,又允許對另一個右值取地址,這是互相矛盾的。

&a[i]和&a[i][j]:

跟&a一樣,也是未定義的,同樣不符合&運算子的規則。由於a[i]是a[i][j]的上一層數組,有些人可能會想當然地以為:a[i]=&a[i][j],錯也,實際上,由於a[i][j]=*(a[i]+j),因此&a[i][j]=&*(a[i]+j),結果是a[i]+j。對於sizeof(&a[i])和sizeof(&a[i][j]),由於是未定義的,因此有些編譯器規定其值跟sizeof(a[i])和sizeof(a[i][j])相同,有些編譯器卻規定為4,就是一個地址的長度。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.