前面已經(jīng)討論了指針和數(shù)組的一些區(qū)別,然而在某些情況下,指針和數(shù)組是等同的,下面討論一下什么時(shí)候指針和數(shù)組是相同的。 C語言標(biāo)準(zhǔn)對(duì)此作了說明: 規(guī)則1:表達(dá)式中的數(shù)組名被編譯器當(dāng)做一個(gè)指向該數(shù)組第一個(gè)元素的指針; 注:下面幾種情況例外 1)數(shù)組名作為sizeof的操作數(shù) 2)使用&取數(shù)組的地址 規(guī)則2:下標(biāo)總是與指針的偏移量相同; 規(guī)則3:在函數(shù)參數(shù)的聲明中,數(shù)組名被編譯器當(dāng)做指向該數(shù)組第一個(gè)元素的指針。 規(guī)則1和規(guī)則2結(jié)合在一起理解,就是對(duì)數(shù)組下標(biāo)的引用總是可以寫成“一個(gè)指向數(shù)組的起始地址的指針加上偏移量”。如a[i]總是被編譯器解析為*(a+i)的形式。
規(guī)則1:表達(dá)式中的數(shù)組名總被編譯器解析為指針,因此如下語句int a[3];int *p=a;是可以正確編譯執(zhí)行的。在表達(dá)式中a被解析為指向數(shù)組第一個(gè)元素的指針,那么賦值符號(hào)兩邊的類型匹配,因此可以正確編譯執(zhí)行。 規(guī)則2:下標(biāo)總是和指針的偏移量相同。C語言中將數(shù)組的下標(biāo)改寫成指針偏移量的主要原因在于指針和偏移量是底層硬件所使用的基本類型。如a[i]中的i總被編譯器解析為偏移量,所以a[i]總是被改寫成*(a+i)的形式,a是指向數(shù)組第一個(gè)元素的指針,加上偏移量i,表示該指針向后移i個(gè)步長,然后取a+i所在單元的內(nèi)容。由此就可以解釋為什么C語言中數(shù)組的下標(biāo)可以為負(fù),而且在我看來,C語言中不檢查數(shù)組的下標(biāo)是否越界同樣跟這個(gè)有關(guān),如下面這段程序: #include<stdio.h> 程序執(zhí)行結(jié)果為3,雖然下標(biāo)為-1,但是被編譯器解析為偏移量,因此相當(dāng)于*(p-1)。 規(guī)則3:在函數(shù)參數(shù)的聲明中,數(shù)組名被編譯器當(dāng)做指向該數(shù)組第一個(gè)元素的指針。在C語言中將形參的數(shù)組和指針等同起來是出于效率的考慮。假如不這么做,將整個(gè)數(shù)組的每個(gè)元素的值都拷貝一份進(jìn)行傳遞,這樣無論在時(shí)間上還是空間上的開銷都可能是非常大的。但是又要能操作到數(shù)組中的元素,只需將數(shù)組第一個(gè)元素的地址傳遞給調(diào)用函數(shù),然后通過指針去訪問想要訪問的空間,這樣一來時(shí)空消耗將大大減少。因此在函數(shù)內(nèi)部,編譯器始終把參數(shù)中聲明的數(shù)組名當(dāng)做一個(gè)指向數(shù)組第一個(gè)元素的指針,這樣一來,編譯器可以產(chǎn)生正確代碼,并不需要對(duì)數(shù)組和指針這兩種情況作區(qū)分。因此void fun(int a[]);和void fun(int *a)兩種形式的效果完全等同,在函數(shù)內(nèi)部去引用a的話,始終都會(huì)被編譯器認(rèn)為是指針。因?yàn)関oid fun(int a[]);這種形式最終還是會(huì)被編譯器解析為void fun(int *a);這種形式告訴我們調(diào)用時(shí)必須傳遞一個(gè)指向整型數(shù)據(jù)的指針。所以下面這段代碼可以正確編譯和執(zhí)行: void fun(int a[]) { printf("%d\n",a[0]); } int main(void) { int a[3]={1,2,3}; int *p1,*p2; int b=4; p1=a; p2=&b; fun(a); fun(&a[1]); fun(p1); fun(p2); fun(&b); return 0; } 區(qū)分幾個(gè)表達(dá)式的含義: &p,p,a,&a &p:表示取存儲(chǔ)指針變量p的內(nèi)存單元的地址; sizeof(&p)=4; p:表示取指針變量p存儲(chǔ)的地址; sizeof(p)=4; a:表示取數(shù)組第一個(gè)元素的地址; sizeof(a)=3*4=12; &a:表示取整個(gè)數(shù)組的首地址; sizeof(&a)=4(在VC++6.0中該值為12,我認(rèn)為是錯(cuò)誤的,因?yàn)槠漕愋褪菙?shù)組指針) 雖然a和&a的值相同,但是所表達(dá)的含義完全不同,a表示取數(shù)組第一個(gè)元素的地址,而&a表示取數(shù)組的首地址。它們所代表的類型也完全不同,a是一個(gè)int型指針,而&a是一個(gè)int (*p)[]型指針,即數(shù)組指針(在后續(xù)文章中會(huì)作解釋)。所以a+1和&a+1得到的結(jié)果不同,a+1表示將指向該數(shù)組的第一個(gè)元素的指針向后移一個(gè)步長(這里的步長為數(shù)組元素類型所占的字節(jié)數(shù));而&a+1表示將指向該數(shù)組的指針向后移動(dòng)一個(gè)步長(而此處的步長為數(shù)組元素個(gè)數(shù)*元素類型所占的字節(jié)數(shù))。 #include<stdio.h> |
|