從編譯器角度分析C語言中陣列名和指標的區別

2021-09-23 01:36:21 字數 2395 閱讀 2294

陣列名和指標是兩個往往很容易讓人們混淆的概念,很多人以為陣列名就是乙個指標,也有很多人知道陣列名不同於指標但是僅知道陣列名的值不能像指標一樣改變。

例如你可以寫出下面這樣的**:

int *p;

p++;

卻不能寫這樣的**:

int a;

a++;

那麼陣列名跟指標之間到底有什麼區別呢?

第一,在宣告上,只有作為函式引數的陣列名編譯器總是轉化成指標,其他情況下,陣列名就是陣列名,指標就是指標,二者不能混淆,你不能在乙個檔案中定義乙個陣列,而在另乙個檔案中把它宣告成乙個指標。

char a;    //

定義乙個陣列a

extern char* a;    //

在另乙個檔案中將

a宣告成乙個指標

在編譯器中,符號表用來存放

c語言中有關識別符號的屬性資訊,這些資訊集中反應了識別符號的特徵屬性。等到詞法分析到**聲稱的各個階段的時候,編譯器需要根據源**提出的要求,從表中獲取不同識別符號的不同屬性。值得注意的是,陣列識別符號的屬性和指標是完全不同的。

因此,在乙個檔案中定義乙個陣列的時候,編譯器會把它記錄在符號表中,而在編譯器分析另乙個檔案中的宣告時,通過符號的語義檢查發現不一致。也許這樣的宣告可以編譯通過(在

gcc下通過了

),但是把乙個陣列名當成乙個指標來使用,別指望它能執行起來。

第二,指標是乙個變數,而陣列名不是。陣列名是陣列的首位址,它本身就是乙個位址,對應到組合語言級別就是乙個常量,乙個固定的數(位址)。因此陣列名不能進行

++,--

等運算。

在大多數編譯器中,對陣列的引用

a[i]

總是被編譯器改寫成

*(a+i)

的格式。也就是說,編譯器每遇到

a[i]

,都會把它當作

*(a+i)

來處理。我們都知道,

*addr

表示記憶體中(

addr

)的位置儲存的值,比如

*0x8048000

就表示位址為

0x8048000

的記憶體中所儲存的值。所以

a[i]

就表示a

的值加上

i所得到的數作為乙個記憶體位址裡面所儲存的值。那麼

a的值是什麼呢??

編譯器在做詞法分析和語法分析的時候,遇到乙個陣列的定義,就會把陣列的有關資訊匯集在乙個叫做「內情向量」或「資訊向量」的**中,其中的資訊包括陣列的型別,維數,各維的上、下邊界,以及陣列的首位址,然後將這個「內情向量」相關資訊儲存在符號表中。陣列定義後位置就是固定的,因此其首位址可以在編譯階段得到。

當編譯器到達**生成的各階段時,每次遇到陣列名這個識別符號,編譯器都會從符號表中取出這個陣列的首位址,然後用這個位址來替代陣列名,例如,假設陣列

a起始位址是

0x8048000

,則a[1]

就會被編譯器轉化成

*(0x8048000+1)

,因此在生成的彙編**中,陣列名已經完全被轉化成乙個常量,乙個固定的數(位址

)。但是對於指標

p,它是乙個變數,其值儲存在位址

&p中,這個值在編譯時是不能得到的。因為是變數,所以指標可以作為表示式中的左值操作,如++或

--,而被認為是常量的陣列名卻不可以,正如你可以騎走一輛自行車,但是不能騎走一棵樹。

另外,c語言把陣列下標改寫成指標偏移量的根本原因是指標偏移量是底層硬體所使用的基本模型。

第三,對陣列的引用,如

a[i]

,或*(a+1)

,需要訪存一次;而對指標的引用,如

*(p+1)

,需要訪存兩次。 a

被認為是常數,所以取

*(a+1)

的值只需將

a所表示的常數加

1,然後從得到的位址裡訪訪問一次即可。對於指標,需要先從

&p這個位址裡把

p的值取出來,然後加

1,再從得到的位址裡訪訪問一次,一共需要兩次訪存。

第四,假設

a是乙個陣列名,而

p是乙個指標,當你使用a 和

&a 時,得到值是一樣的,都是陣列的起始位址。而使用p 和

&p 時,得到的值是不一樣的,

p 表示指標

p 所指向的位址,而

&p 表示

p 這個變數的位址。

再假設p = a; 則

p 就表示陣列

a的起始位址,而

&p是儲存陣列

a的起始位址的那個位址。

這是因為編譯器把

a當成陣列首位址,而

&a當作陣列第乙個元素的位址,因此得到的值是一樣的。

另外,sizeof(a)

得到的是

a所表示的陣列的大小,而

sizeof(p)

得到的是指標的大小。

C語言中陣列名與 陣列名的區別

include int main void int ptr int a 1 a代表整個陣列的位址,1應該加上sizeof a 的長度,所以ptr指向a 5 位置處。printf d d n a 1 ptr 1 a代表陣列首元素的位址,1應該加上sizeof a 0 所以a 1指向a 1 處。retu...

c語言中陣列名和陣列名取位址理解

1 陣列名是個指標型常量,也就是值不能被改變。指標常量和常量指標區別見本文 char str hello char ch 6 hello ch str 錯誤,常量不能被賦值,正如 1 2,字面值常量1被賦值為2一樣錯誤。char ch 2 定義後,陣列名相當於char const ch 0x.ch就...

C語言中陣列名和陣列下標

整理自 c陷阱與缺陷 陣列注意點 1.c陣列中只有一維陣列,陣列的大小必須在編譯期作為常數確定。但c陣列的元素可以是任何型別的物件,當然也可以是另乙個陣列,所以 出乙個多維陣列。不太明白為什麼要強調只有一維陣列,難道 模擬 出來的多維陣列和真正的多維陣列不一樣?2.對於乙個陣列,我們只能夠做兩件事 ...