當(dāng)前位置:首頁 > 技術(shù)學(xué)院 > 技術(shù)前線
[導(dǎo)讀]指針與數(shù)組是C語言中很重要的兩個概念,它們之間有著密切的關(guān)系,利用這種關(guān)系,可以增強(qiáng)處理數(shù)組的靈活性,加快運(yùn)行速度,本文著重討論指針與數(shù)組之間的聯(lián)系及在編程中的應(yīng)用。

最早在大學(xué)里學(xué)c語言的時候?qū)χ羔樅蛿?shù)組這兩個概念混淆不清,經(jīng)?;鞛橐徽?,相信很多學(xué)友和我的情況類似。在這里,我會將自身對c語言的了解以及對這本書中相關(guān)內(nèi)容的理解,把指針和數(shù)組的聯(lián)系與區(qū)別總結(jié)一下。

一.指針與數(shù)組的聯(lián)系:

指針與數(shù)組是C語言中很重要的兩個概念,它們之間有著密切的關(guān)系,利用這種關(guān)系,可以增強(qiáng)處理數(shù)組的靈活性,加快運(yùn)行速度,本文著重討論指針與數(shù)組之間的聯(lián)系及在編程中的應(yīng)用。

1.指針與數(shù)組的關(guān)系

當(dāng)一個指針變量被初始化成數(shù)組名時,就說該指針變量指向了數(shù)組。如:

char str[20], *ptr;

ptr=str;

ptr被置為數(shù)組str的第一個元素的地址,因?yàn)閿?shù)組名就是該數(shù)組的首地址,也是數(shù)組第一個元素的地址。此時可以認(rèn)為指針ptr就是數(shù)組str(反之不成立),這樣原來對數(shù)組的處理都可以用指針來實(shí)現(xiàn)。如對數(shù)組元素的訪問,既可以用下標(biāo)變量訪問,也可以用指針訪問。

2.指向數(shù)組元素的指針

若有如下定義:

int a[10], *pa;

pa=a;

則p=&a[0]是將數(shù)組第1個元素的地址賦給了指針變量p。

實(shí)際上,C語言中數(shù)組名就是數(shù)組的首地址,所以第一個元素的地址可以用兩種方法獲得:p=&a[0]或p=a。

這兩種方法在形式上相像,其區(qū)別在于:pa是指針變量,a是數(shù)組名。值得注意的是:pa是一個可以變化的指針變量,而a是一個常數(shù)。因?yàn)閿?shù)組一經(jīng)被說明,數(shù)組的地址也就是固定的,因此a是不能變化的,不允許使用a++、++a或語句a+=10,而pa++、++pa、pa+=10則是正確的。由此可見,此時指針與數(shù)組融為一體。

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ò)大因子。

實(shí)際上編譯系統(tǒng)將數(shù)組元素的形式a[i]轉(zhuǎn)換成*(a+i),然后才進(jìn)行運(yùn)算。對于一般數(shù)組元素的形式:<數(shù)組名>[<下標(biāo)表達(dá)式>],編譯程序?qū)⑵滢D(zhuǎn)換成:*(<數(shù)組名>+<下標(biāo)表達(dá)式>),其中下標(biāo)表達(dá)式為:下標(biāo)表達(dá)式*擴(kuò)大因子。整個式子計算結(jié)果是一個內(nèi)存地址,最后的結(jié)果為:*<地址>=<地址所對應(yīng)單元的地址的內(nèi)容>。由此可見,C語言對數(shù)組的處理,實(shí)際上是轉(zhuǎn)換成指針地址的運(yùn)算。

數(shù)組與指針暗中結(jié)合在一起。因此,任何能由下標(biāo)完成的操作,都可以用指針來實(shí)現(xiàn),一個不帶下標(biāo)的數(shù)組名就是一個指向該數(shù)組的指針。

4.指針與多維數(shù)組

用指針變量可以指向一維數(shù)組,也可以指向多維數(shù)組。但在概念上和使用上,多維數(shù)組的指針比一維數(shù)組的指針要復(fù)雜一些。

例如,在一個三維數(shù)組中,引用元素c[i][j][k]的地址計算最終將換成:*(*(*(c+i)+j)+k)。了解了多維數(shù)組的存儲形式和訪問多維數(shù)組元素的內(nèi)部轉(zhuǎn)換公式后,再看當(dāng)一個指針變量指向多維數(shù)組及其元素的情況。

1)指向數(shù)組元素的指針變量

若有如下說明:

int a[3][4];

int *p;

p=a;

p是指向整型變量的指針;p=a使p指向整型二維數(shù)組a的首地址。

*(*(p+1)+2)表示取a[1][2]的內(nèi)容;*p表示取a[0][1]的內(nèi)容,因?yàn)閜是指向整型變量的指針;p++表示p的內(nèi)容加1,即p中存放的地址增加一個整型量的字節(jié)數(shù)2,從而使p指向下一個整型量a[0][1]。

2)指向由j個整數(shù)組成的一維數(shù)組的指針變量

當(dāng)指針變量p不是指向整型變量,而是指向一個包含j個元素的一維數(shù)組。如果p=a[0],則p++不是指向a[0][1],而是指向a[1]。這時p的增值以一維數(shù)組的長度為單位。

5.指針與字符數(shù)組

C語言中許多字符串操作都是由指向字符數(shù)組的指針及指針的運(yùn)算來實(shí)現(xiàn)的。因?yàn)閷τ谧址畞碚f,一般都是嚴(yán)格的順序存取方式,使用指針可以打破這種存取方式,更為靈活地處理字符串。

另外由于字符串以′\0′作為結(jié)束符,而′\0′的ASCII碼是0,它正好是C語言的邏輯假值,所以可以直接用它作為判斷字符串結(jié)束的條件,而不需要用字符串的長度來判斷。C語言中類似的字符串處理函數(shù)都是用指針來完成,使程序運(yùn)行速度更快、效率更高,而且更易于理解。

二.指針與數(shù)組的區(qū)別:

1.把數(shù)組作為參數(shù)傳遞的時候,會退化為指針

數(shù)組名作為函數(shù)形參時,在函數(shù)體內(nèi),其失去了本身的內(nèi)涵,僅僅只是一個指針;很遺憾,在失去其內(nèi)涵的同時,它還失去了其常量特性,可以作自增、自減等操作,可以被修改。

所以,數(shù)組名作為函數(shù)形參時,其淪落為一個普通指針!它的貴族身份被剝奪,成了一個地地道道的只擁有4個字節(jié)的平民。

典型的情況是

void func(int A[])

{

//sizeof(A)得到的是4bytes

}

int main()

{

int a[10]; //sizeof(a) 得到的結(jié)果是40bytes

funct(a);

}

2、數(shù)組名可作為指針常量

根據(jù)結(jié)論2,數(shù)組名可以轉(zhuǎn)換為指向其指代實(shí)體的指針,所以程序1中的第5行數(shù)組名直接賦值給指針,程序2第7行直接將數(shù)組名作為指針形參都可成立。

下面的程序成立嗎?

int intArray[10];

intArray++;

讀者可以編譯之,發(fā)現(xiàn)編譯出錯。原因在于,雖然數(shù)組名可以轉(zhuǎn)換為指向其指代實(shí)體的指針,但是它只能被看作一個指針常量,不能被修改。

而指針,不管是指向結(jié)構(gòu)體、數(shù)組還是基本數(shù)據(jù)類型的指針,都不包含原始數(shù)據(jù)結(jié)構(gòu)的內(nèi)涵,在WIN32平臺下,sizeof操作的結(jié)果都是4。

順便糾正一下許多程序員的另一個誤解。許多程序員以為sizeof是一個函數(shù),而實(shí)際上,它是一個操作符,不過其使用方式看起來的確太像一個函數(shù)了。語句sizeof(int)就可以說明sizeof的確不是一個函數(shù),因?yàn)楹瘮?shù)接納形參(一個變量),世界上沒有一個C/C++函數(shù)接納一個數(shù)據(jù)類型(如int)為"形參"。

3.對于問題:為什么用strcpy()函數(shù)時,

char a[3] = "abc";

strcopy(a,"end");

-------------------沒有錯。

用-----------------

char *a = "abc";

strcopy(a,"end");

------------------運(yùn)行時就有錯呢?

解釋如下:

char *a = "abc"; abc是一個字符串常量,有它自己的存儲空間,因?yàn)榉峙湓谥蛔x數(shù)據(jù)塊,我們無法直接訪問。這樣賦值后,a只能讀,不能寫

所以strcpy(a, "end")不行,只有當(dāng)你為a分配非常量的存儲空間后才行

如:

char *a = new char[4];

strcpy(a, "end");

printf("%s", a);

delete []a;

4//main.cpp

int array[3] = {7, 8, 9}; //全局變量

int main()

{

Test1();

Test2();

return 0;

}

//Test1.cpp

extern int array[3];

void Test1()

{

cout << array[1] << endl;

}

//Test2.cpp

extern int *array; //這個地方是不同的

void Test2()

{

cout << array << endl;

cout << array[1] << endl;

}

Test1()和Test2()的輸出結(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中,把a(bǔ)rray的地址給了array,假設(shè)這個地址是0x34fe,但是由于數(shù)組的特性array == &array,所以這里是正常的。而在Test2.cpp中,array是個指針,所以會去0x34fe中取出值給array,所以array = 0x0007(數(shù)組的第一個值,這里要做地址,因?yàn)槭墙o指針用)

這就是看到的Test2()的輸出結(jié)果。顯然array[1]會死機(jī),因?yàn)?x0007地址是沒有被分配的,并且是給操作系統(tǒng)用的而不是給用戶用的。

5.數(shù)組和指針的分配

數(shù)組是開辟一塊連續(xù)的內(nèi)存空間,數(shù)組本身的標(biāo)示符代表整個數(shù)組,可以用sizeof取得真實(shí)的大小;指針則是只分配一個指針大小的內(nèi)存,并可把它的值指向某個有效的內(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( "%s\n ", "hello ");

這兩個字面常量( "%s\n "和 "hello "),都在只讀數(shù)據(jù)塊里

[用途]

全局指針

用于不需要修改內(nèi)容,卻可能會修改指針的情況(當(dāng)然,不修改也沒人反對)

全局?jǐn)?shù)組,用于不需要修改地址,卻需要修改內(nèi)容的場合

既需要修改指針,有需要修改內(nèi)容怎么辦呢?定義一個數(shù)組,在定義一個指針指向它就可以了

函數(shù)中如果不需要修改字符串的內(nèi)容,應(yīng)該盡量用char*p= "xxx "這種寫法.

初始化的局部字符數(shù)組影響效率,一般應(yīng)該盡量避開(應(yīng)該使用的情況下則不要猶豫)

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉