一、數組的內存布局
先看下面的例子:? ?int a[5];
所有人都明白這里定義了一個數組,其包含了5 個int 型的數據。我們可以用a[0],a[1]等來訪問數組里面的每一個元素,那么這些元素的名字就是a[0],a[1]…嗎?看下面的示意圖:

如上圖所示,當我們定義一個數組a 時,編譯器根據指定的元素個數和元素的類型分配確定大小(元素類型大小*元素個數)的一塊內存,并把這塊內存的名字命名為a。名字a 一旦與這塊內存匹配就不能被改變。a[0],a[1]等為a 的元素,但并非元素的名字。數組的每一個元素都是沒有名字的。那現在再來回答第一章講解sizeof 關鍵字時的幾個問題:
? ?sizeof(a)的值為sizeof(int)*5,32 位系統下為20。
? ?sizeof(a[0])的值為sizeof(int),32 位系統下為4。
sizeof(a[5])的值在32 位系統下為4。并沒有出錯,為什么呢?我們講過sizeof 是關鍵字不是函數。函數求值是在運行的時候,而關鍵字sizeof 求值是在編譯的時候。雖然并不存在a[5]這個元素,但是這里也并沒有去真正訪問a[5],而是僅僅根據數組元素的類型來確定其值。所以這里使用a[5]并不會出錯。
sizeof(&a[0])的值在32 位系下為4,這很好理解。取元素a[0]的首地址。
sizeof(&a)的值在32 位系統下也為4,這也很好理解。取數組a 的首地址。但是在VisualC++6.0 上,這個值為20,我認為是錯誤的。
二、省政府和市政的區別----&a[0]和&a 的區別
這里&a[0]和&a 到底有什么區別呢?a[0]是一個元素,a 是整個數組,雖然&a[0]和&a的值一樣,但其意義不一樣。前者是數組首元素的首地址,而后者是數組的首地址。舉個例子:湖南的省政府在長沙,而長沙的市政府也在長沙。兩個政府都在長沙,但其代表的意義完全不同。這里也是同一個意思。三、數組名a 作為左值和右值的區別
簡單而言,出現在賦值符“=”右邊的就是右值,出現在賦值符“=”左邊的就是左值。比如,x=y。左值:在這個上下文環境中,編譯器認為x 的含義是x 所代表的地址。這個地址只有編譯器知道,在編譯的時候確定,編譯器在一個特定的區域保存這個地址,我們完全不必考慮這個地址保存在哪里。
右值:在這個上下文環境中,編譯器認為y 的含義是y 所代表的地址里面的內容。這個內容是什么,只有到運行時才知道。
C 語言引入一個術語-----“可修改的左值”。意思就是,出現在賦值符左邊的符號所代表的地址上的內容一定是可以被修改的。換句話說,就是我們只能給非只讀變量賦值。
既然已經明白左值和右值的區別,下面就討論一下數組作為左值和右值的情況:
當a 作為右值的時候代表的是什么意思呢?很多書認為是數組的首地址,其實這是非常錯誤的。a 作為右值時其意義與&a[0]是一樣,代表的是數組首元素的首地址,而不是數組的首地址。這是兩碼事。但是注意,這僅僅是代表,并沒有一個地方(這只是簡單的這么認為,其具體實現細節不作過多討論)來存儲這個地址,也就是說編譯器并沒有為數組a分配一塊內存來存其地址,這一點就與指針有很大的差別。
a 作為右值,我們清楚了其含義,那作為左值呢?
a 不能作為左值!這個錯誤幾乎每一個學生都犯過。編譯器會認為數組名作為左值代表的意思是a 的首元素的首地址,但是這個地址開始的一塊內存是一個總體,我們只能訪問數組的某個元素而無法把數組當一個總體進行訪問。所以我們可以把a[i]當左值,而無法把a當左值。其實我們完全可以把a 當一個普通的變量來看,只不過這個變量內部分為很多小塊,我們只能通過分別訪問這些小塊來達到訪問整個變量a 的目的。