近段時間在整理自己大學幾年來學習c++的點點滴滴,寫這篇文章源於看林銳博士的《高質量c++指南》時,看到文章直接把指標和陣列名視為同一東西,原文為「陣列名本身就是乙個指標,是乙個指標常量,即a等價於int * const a,因此你不能試圖修改陣列名的值」,摘自第三版127頁第7.2.1小節。
自己初學c++時也被陣列和指標搞得昏頭轉向過,通過多方求證和對比實驗已把指標和陣列弄得稍明白,但是今天又看到乙個人說「陣列名就是指標」這樣的言論,我就有這個想法把自己對指標和陣列名的理解寫出來,我不敢說我的理解是正確的,但是,至少沒那麼徹底的禍害人。
陣列名絕對不等於指標,而且不是指標,這是我的觀點
首先看c標準對指標的解釋為:指標是乙個變數,變數的值是另外乙個變數的位址。那麼,既然指標是變數,那麼指標必然有自己的儲存空間,只不過是該儲存空間內的值是乙個位址值,而不是別的內容。如果按照林博士的觀點「陣列名就是指標」,想必,陣列名也會是乙個變數,而且有自己的儲存空間?下面上彙編**反駁之,彙編**沒有騙我們,陣列名僅僅是乙個符號,不是變數,它沒有自己的儲存空間,而指標實實在在的是個變數,有自己的空間:
下面是c++**:
#include using namespace std;
int main()
這段**的目的是通過4個對比實驗逐一證明指標和陣列名不是用乙個東西,請看下面的彙編**便可一目了然,每個對比實驗的結果都能說名:陣列名不是指標,它就是乙個符號。6: int i = 10;
00401048 mov dword ptr [ebp-4],0ah //(1)
7: int *pi = &i;
0040104f lea eax,[ebp-4]
00401052 mov dword ptr [ebp-8],eax //(2)
8:9: int a[2];
10: a[0] = 5;
00401055 mov dword ptr [ebp-10h],5 //(3)
11: a[1] = 15;
0040105c mov dword ptr [ebp-0ch],0fh
12:13: int *pa = a;
00401063 lea ecx,[ebp-10h] //(4)
00401066 mov dword ptr [ebp-14h],ecx
14: pa = a+1;
00401069 lea edx,[ebp-0ch] //(5)
0040106c mov dword ptr [ebp-14h],edx
15:16: int j = a[0];
0040106f mov eax,dword ptr [ebp-10h] //(6)
00401072 mov dword ptr [ebp-18h],eax
17: int k = *pa;
00401075 mov ecx,dword ptr [ebp-14h]
00401078 mov edx,dword ptr [ecx]
0040107a mov dword ptr [ebp-1ch],edx
18:19: //++a;
20: ++pa;
0040107d mov eax,dword ptr [ebp-14h] //(7)
00401080 add eax,4
00401083 mov dword ptr [ebp-14h],eax
21:22: return 0;
00401086 xor eax,eax
23:24: }
簡單學過彙編的人都基本能看懂上面的**,下面逐一分析(1)-(7)的彙編**告訴我們的事實:
(1)、i是個整型變數,可以看出編譯器為i分配了空間,位址為ebp-4
(2)、先lea取i的位址,然後存入到ebp-8的空間中,這就是pi的位址,足矣證明pi是個變數,有自己的空間
(3)、重點之處,定義了乙個陣列,但是,彙編**告訴我們,編譯器只給a[0]和a[1]分配了記憶體空間,a[0]的位址為:ebp-10,a[1]為:ebp-0c,卻沒有給,陣列名a也分配空間,這裡起碼可以斷定陣列名a不是乙個變數只是個符號
(4)、從**lea ecx,[ebp-10h]可以看出,ebp-10是a[0]的位址,對陣列名a的引用已經被替換為對陣列首元素的位址了
(5)、a+1的彙編**也是程式設計了對ebp-0c位址單元的引用,而這個位址是a[1]的位址,更進一步說明了問題
(6)、是為了對比,對陣列的引用和對指標的引用不同之處,通過下面三行彙編**可以看出:
17: int k = *pa;
00401075 mov ecx,dword ptr [ebp-14h]
00401078 mov edx,dword ptr [ecx]
0040107a mov dword ptr [ebp-1ch],edx
對指標pa的引用是乙個間接訪問,epb-14h是pa的位址,而mov ecx,dword ptr [ebp-14h]是先取得pa的位址,然後[ecx]取該位址中的內容,並mov到ebp-1c中,改記憶體就是變數k的記憶體空間首位址,這樣就完成了對pa的引用
(7)這個是重點分析的地方,很對多人對於陣列名就是指標持贊同觀點的乙個冠冕堂皇的證據是「
陣列名不能被修改,因為陣列名是乙個常量指標
」,也就是不能執行 a = a+1;這句話對一般,錯一半,對的是,陣列名確實不能被修改,錯的是,不能被修改的原因不是因為陣列名是常量指標,而是因為陣列名只是乙個符號,不是乙個變數,因此不能作為乙個左值,因此不能被修改,這裡又涉及到左值和右值的問題,就不再贅述,網上資料很多。
通過上述幾個對比實驗,能夠非常清晰的看到,陣列名和指標的本質區別:指標是乙個變數,有自己對應的儲存空間,而陣列名僅僅是乙個符號,不是變數,因而沒有自己對應的儲存空間,到此已經可以得出結論,「陣列名永遠不等於指標」。
我認為,林博士的意思是說,陣列名和指標在參與表示式運算時效果是一樣的,但是不能簡單粗暴的說兩者是相等的
上述如有錯誤之處,懇請指出,我必會虛心聽取,認真論證修改,以免更多的人困惑
上述觀點有不少不妥之處,討論在此可自行結合自己的知識進行分析
陣列名和指標區別
前兩天同學問了我乙個問題 陣列名和指標有什麼區別,或者說這兩者有沒有區別?我回顧了下,大學課堂上老師講的,貌似記得老師說陣列名就相當於指標,比如 一維陣列就是一級指標 二維陣列是二級指標 之類的。結果同學告訴說原來我也是這麼理解的,其實 陣列名與指標有著本質的區別 然後給我推薦了一篇博文。我們經常見...
陣列名和指標的區別
魔幻陣列名 請看程式 本文程式在win32平台下編譯 1.include 2.int main int argc,char argv 3.size 3 1 陣列名不是指標 size 我們先來推翻 陣列名就是指標 的說法,用反證法。證明 陣列名不是指標 假設 陣列名是指標 則 pstr和str都是指標...
陣列名和指標的區別
引言 指標是c c 語言的特色,而陣列名與指標有太多的相似,甚至很多時候,陣列名可以作為指標使用。於是乎,很多程式設計者就被搞糊塗了。而許多的大 學老師,他們在c語言的教學過程中也錯誤得給學生講解 陣列名就是指標 很幸運,我的大學老師就是其中之一。時至今日,我日復一日地進行著c c 專案的開發,而身...