1、指針與數(shù)組的區(qū)別和聯(lián)系 2010-06-27 22:29:04分類: C/C+一指針與數(shù)組的聯(lián)系:指針與數(shù)組是C語言中很重要的兩個概念,它們之間有著密切的關(guān)系,利用這種關(guān)系,可以增強(qiáng)處理數(shù)組的靈活性,加快運行速度,本文著重討論指針與數(shù)組之間的聯(lián)系及在編程中的應(yīng)用。1指針與數(shù)組的關(guān)系當(dāng)一個指針變量被初始化成數(shù)組名時,就說該指針變量指向了數(shù)組。如: char str20, *ptr;ptr=str;ptr被置為數(shù)組str的第一個元素的地址,因為數(shù)組名就是該數(shù)組的首地址,也是數(shù)組第一個元素的地址。此時可以認(rèn)為指針ptr就是數(shù)組str(反之不成立),這樣原來對數(shù)組的處理都可以用指針來實現(xiàn)。如對數(shù)組元素
2、的訪問,既可以用下標(biāo)變量訪問,也可以用指針訪問。2指向數(shù)組元素的指針若有如下定義:int a10, *pa; pa=a; 則p=&a0是將數(shù)組第1個元素的地址賦給了指針變量p。 實際上,C語言中數(shù)組名就是數(shù)組的首地址,所以第一個元素的地址可以用兩種方法獲得:p=&a0或p=a。這兩種方法在形式上相像,其區(qū)別在于:pa是指針變量,a是數(shù)組名。值得注意的是:pa是一個可以變化的指針變量,而a是一個常數(shù)。因為數(shù)組一經(jīng)被說明,數(shù)組的地址也就是固定的,因此a是不能被賦值不能改變的,不允許使用a、a或語句a=10,而pa、pa、pa=10則是正確的。由此可見,此時指針與數(shù)組融為一體。3指針
3、與一維數(shù)組理解指針與一維數(shù)組的關(guān)系,首先要了解在編譯系統(tǒng)中,一維數(shù)組的存儲組織形式和對數(shù)組元素的訪問方法。一維數(shù)組是一個線形表,它被存放在一片連續(xù)的內(nèi)存單元中。C語言對數(shù)組的訪問是通過數(shù)組名(數(shù)組的起始地址)加上相對于起始地址的相對量(由下標(biāo)變量給出),得到要訪問的數(shù)組元素的單元地址,然后再對計算出的單元地址的內(nèi)容進(jìn)行訪問。通常把數(shù)據(jù)類型所占單元的字節(jié)個數(shù)稱為擴(kuò)大因子。 實際上編譯系統(tǒng)將數(shù)組元素的形式ai轉(zhuǎn)換成*(ai),然后才進(jìn)行運算。對于一般數(shù)組元素的形式:<數(shù)組名><下標(biāo)表達(dá)式>,編譯程序?qū)⑵滢D(zhuǎn)換成:*(<數(shù)組名><下標(biāo)表達(dá)式>),其中下標(biāo)
4、表達(dá)式為:下標(biāo)表達(dá)式*擴(kuò)大因子。整個式子計算結(jié)果是一個內(nèi)存地址,最后的結(jié)果為:*<地址>=<地址所對應(yīng)單元的地址的內(nèi)容>。由此可見,C語言對數(shù)組的處理,實際上是轉(zhuǎn)換成指針地址的運算。數(shù)組與指針暗中結(jié)合在一起。因此,任何能由下標(biāo)完成的操作,都可以用指針來實現(xiàn),一個不帶下標(biāo)的數(shù)組名就是一個指向該數(shù)組的指針。4指針與多維數(shù)組用指針變量可以指向一維數(shù)組,也可以指向多維數(shù)組。但在概念上和使用上,多維數(shù)組的指針比一維數(shù)組的指針要復(fù)雜一些。例如,在一個三維數(shù)組中,引用元素cijk的地址計算最終將換成:*(*(*(ci)j)k)。了解了多維數(shù)組的存儲形式和訪問多維數(shù)組元素的內(nèi)部轉(zhuǎn)換公式
5、后,再看當(dāng)一個指針變量指向多維數(shù)組及其元素的情況。1)指向數(shù)組元素的指針變量若有如下說明:int a34;int *p;p=a;p是指向整型變量的指針;p=a使p指向整型二維數(shù)組a的首地址。*(*(p1)2)表示取a12的內(nèi)容;*p表示取a01的內(nèi)容,因為p是指向整型變量的指針;p表示p的內(nèi)容加1,即p中存放的地址增加一個整型量的字節(jié)數(shù)2,從而使p指向下一個整型量a01。2)指向由j個整數(shù)組成的一維數(shù)組的指針變量當(dāng)指針變量p不是指向整型變量,而是指向一個包含j個元素的一維數(shù)組。如果p=a0,則p不是指向a01,而是指向a1。這時p的增值以一維數(shù)組的長度為單位。5指針與字符數(shù)組C語言中許多字符串
6、操作都是由指向字符數(shù)組的指針及指針的運算來實現(xiàn)的。因為對于字符串來說,一般都是嚴(yán)格的順序存取方式,使用指針可以打破這種存取方式,更為靈活地處理字符串。另外由于字符串以0作為結(jié)束符,而0的ASCII碼是0,它正好是C語言的邏輯假值,所以可以直接用它作為判斷字符串結(jié)束的條件,而不需要用字符串的長度來判斷。C語言中類似的字符串處理函數(shù)都是用指針來完成,使程序運行速度更快、效率更高,而且更易于理解。二指針與數(shù)組的區(qū)別:1.把數(shù)組作為參數(shù)傳遞的時候,會退化為指針數(shù)組名作為函數(shù)形參時,在函數(shù)體內(nèi),其失去了本身的內(nèi)涵,僅僅只是一個指針;很遺憾,在失去其內(nèi)涵的同時,它還失去了其常量特性,可以作自增、自減等操作
7、,可以被修改。所以,數(shù)組名作為函數(shù)形參時,其淪落為一個普通指針!它的貴族身份被剝奪,成了一個地地道道的只擁有4個字節(jié)的平民。典型的情況是void func(int A)/sizeof(A)得到的是4bytesint main()int a10; /sizeof(a) 得到的結(jié)果是40bytesfunct(a);2、數(shù)組名可作為指針常量根據(jù)結(jié)論2,數(shù)組名可以轉(zhuǎn)換為指向其指代實體的指針,所以程序1中的第5行數(shù)組名直接賦值給指針,程序2第7行直接將數(shù)組名作為指針形參都可成立。下面的程序成立嗎?int intArray10;intArray+;讀者可以編譯之,發(fā)現(xiàn)編譯出錯。原因在于,雖然數(shù)組名可以轉(zhuǎn)換
8、為指向其指代實體的指針,但是它只能被看作一個指針常量,不能被修改。而指針,不管是指向結(jié)構(gòu)體、數(shù)組還是基本數(shù)據(jù)類型的指針,都不包含原始數(shù)據(jù)結(jié)構(gòu)的內(nèi)涵,在WIN32平臺下,sizeof操作的結(jié)果都是4。順便糾正一下許多程序員的另一個誤解。許多程序員以為sizeof是一個函數(shù),而實際上,它是一個操作符,不過其使用方式看起來的確太像一個函數(shù)了。語句sizeof(int)就可以說明sizeof的確不是一個函數(shù),因為函數(shù)接納形參(一個變量),世界上沒有一個C/C+函數(shù)接納一個數(shù)據(jù)類型(如int)為"形參"。 3對于問題:為什么用strcpy()函數(shù)時,char a3 = "a
9、bc"strcopy(a,"end");-沒有錯。用-char *a = "abc"strcopy(a,"end");-運行時就有錯呢?解釋如下:char *a = "abc" abc是一個字符串常量,有它自己的存儲空間,因為分配在只讀數(shù)據(jù)塊,我們無法直接訪問。這樣賦值后,a只能讀,不能寫所以strcpy(a, "end")不行,只有當(dāng)你為a分配非常量的存儲空間后才行 如:char *a = new char4;strcpy(a, "end");printf(&qu
10、ot;%s", a);delete a;4/main.cppint array3 = 7, 8, 9; /全局變量int main()Test1();Test2();return 0;/Test1.cppextern int array3;void Test1()cout << array1 << endl;/Test2.cppextern int *array; /這個地方是不同的void Test2()cout << array << endl;cout << array1 << endl;Test1()和T
11、est2()的輸出結(jié)果相同嗎?編譯一下再看看,就發(fā)現(xiàn)執(zhí)行Test2會有奇怪的結(jié)果,第一條語句的輸出是7, 第二條語句會死機(jī)。而Test1()卻一切正常。這是為什么?原因在編譯器。在Test1.cpp中,由于使用了extern所以編譯的時候要先用占位符將array標(biāo)志一下,在連接的時候用main.cpp中的array進(jìn)行替換。當(dāng)編譯器給變量賦值的時候,他認(rèn)為這個值是該變量的地址。就好比:int i = 5;在編譯器中編譯后會把5的地址0x8291記錄而不是5,在i需要值的時候去0x8291這個地址去取出值給i(這里的i是全局的或者靜態(tài)變量,這時候才能在編譯階段確定地址)。所以在Test1.cpp
12、中,把array的地址給了array,假設(shè)這個地址是0x34fe,但是由于數(shù)組的特性array = &array,所以這里是正常的。而在Test2.cpp中,array是個指針,所以會去0x34fe中取出值給array,所以array = 0x0007(數(shù)組的第一個值,這里要做地址,因為是給指針用)。這就是看到的Test2()的輸出結(jié)果。顯然array1會死機(jī),因為0x0007地址是沒有被分配的,并且是給操作系統(tǒng)用的而不是給用戶用的。5數(shù)組和指針的分配數(shù)組是開辟一塊連續(xù)的內(nèi)存空間,數(shù)組本身的標(biāo)示符代表整個數(shù)組,可以用sizeof取得真實的大?。恢羔槃t是只分配一個指針大小的內(nèi)存,并可把它
13、的值指向某個有效的內(nèi)存空間。全局的和靜態(tài)的char *p= "hello "一個指針,指向只讀數(shù)據(jù)塊(section)里的 "hello ",可被編譯器放入字符串池(也就是說, 你在寫一個char *q= "hello ",可能和p共享數(shù)據(jù))char a= "hello "一個數(shù)組,分配在可寫數(shù)據(jù)塊(section),不會被放到字符串池中。局部char *p= "hello "一個指針,指向只讀數(shù)據(jù)塊(section)里的 "hello ",可被編譯器放入字符串池(也就是說, 你在寫一個char *q= "hello ",可能和p共享數(shù)據(jù)),另外,在函數(shù)中可以返回它的地址,也就是說,指針是局部變量,他指向的數(shù)據(jù)卻是全局的.char a= "hello "一個數(shù)組,分配在堆棧上,初始化由編譯器進(jìn)行(短的話直接用指令填充,長的就從全局字符串表拷貝),不會被放到字符串池中(但是卻可能從字符串池中拷貝過來),也不應(yīng)該返回它的地址。代碼中的字面字符串printf( "%sn ", "hello ");這兩個字面常量( "%sn "和 "
評論
0/150
提交評論