C語言指針問題快速解惑_第1頁
C語言指針問題快速解惑_第2頁
C語言指針問題快速解惑_第3頁
C語言指針問題快速解惑_第4頁
C語言指針問題快速解惑_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、C語言指針問題快速解惑(一)1、int a3 = 2,5,8;int* p = a;把數(shù)組名賦值給指針表示將數(shù)組的首元素的地址賦予此指針。2、int a3 = 2,5,8;int* p = &a0;a0是a數(shù)組的首元素,而&則是取地址運(yùn)算符,所以“ &a0”取得的同樣是a數(shù)組的首元素的地址,因此這段代碼的含義和代碼段是一致的。3、char * c1 = Hello;char c26 = World;這兩句不都是聲明一個字符串嗎?有什么區(qū)別嗎?Hello是一個字符串,然后讓char指針c1指向這個字符串的首元素的地址。第二句是聲明一個長度為6的char類型數(shù)組,并且設(shè)置數(shù)組的初始值為World。

2、注意末尾還有一個隱藏的“0”,所以長度是6,而不是5。4、數(shù)組指針的加減運(yùn)算對于指向數(shù)組的指針變量可以進(jìn)行加減運(yùn)算,比如對于指向數(shù)組的指針p,p+、p-、p+2等都是合法的。這里的加減運(yùn)算并不是針對數(shù)組元素的,而是針對指針位置的,比如p當(dāng)前指在首元素上,那么p+后就指在第二個元素上;比如p當(dāng)前指在第5個元素上,那么p=p-2后,p就指在第3個元素上。例子:char * c1 = Hello;printf(%cn,*c1);/輸出H c1+;printf(%cn,*c1);/輸出e 5、指針之間的運(yùn)算兩個指針之間可以進(jìn)行減法運(yùn)算,只有指向同一個數(shù)組的兩個指針之間進(jìn)行減法運(yùn)算才有意義,而指向不同數(shù)

3、組的兩個指針之間進(jìn)行減法運(yùn)算則沒有意義。為什么呢? 指針其實(shí)就是內(nèi)存中的地址,兩個指針的減法運(yùn)算計(jì)算的就是兩個內(nèi)存地址之間的元素的個數(shù),比如整數(shù)指針p1指向內(nèi)存地址2008H,整數(shù)指針p2內(nèi)存地址2000H,而整數(shù)占4個字節(jié),所以p1-p2的結(jié)果就是(2008H-2000H)/4=2,也就是 p1和p2 之間相差 2 個元素。很顯然兩個指針進(jìn)行加法運(yùn)算或者兩個指向不同變量的指針進(jìn)行減法運(yùn)算都是沒有意義的。例子:int a15=3,5,6,8,2;int* p1 = a1;/p1是指向第0個元素的地址 int* p2 = &a13;/p2指向的是第3個元素的地址 p1+;/p1指向了第1個元素

4、printf(%d,p2-p1);/輸出2 6、指針之間的大小比較指向同一個數(shù)組的兩個指針之間進(jìn)行大小的比較是有意義的。比較結(jié)果為地址高低的比較:例子:int a15=3,5,6,8,2;int* p1 = a1;int* p2 = &a13;p1+;printf(%dn,p2p1);/輸出0,因?yàn)閜2的地址比p1高2位 p1=p1+2;/p1在數(shù)組內(nèi)向高位移動兩位 printf(%dn,p2=p1);/輸出1 ,因?yàn)閜1和p2的位相等 C語言指針問題快速解惑(二)7、數(shù)組做為參數(shù)傳遞給函數(shù)可以將數(shù)組做為傳遞給函數(shù),比如下面的代碼就是將傳入輸入的每個元素乘以2:void makeDoule(i

5、nt arr,int len)int i=0;for(i=0;ilen;i+)arri= arri*2;int main(int argc, char *argv)int a15=3,5,6,8,2;int i = 0;int len=sizeof(a1)/sizeof(int);makeDoule(a1,len);for(i=0;ilen;i+)printf(%d ,a1i);運(yùn)行結(jié)果:6 10 12 16 4傳遞給makeDoule函數(shù)的是a1,我們知道,一個數(shù)組的名字其實(shí)就是指向數(shù)組首元素的地址。所以makeDoule函數(shù)得到的arr就是數(shù)組a1的指針,那么在函數(shù)內(nèi)部對arr進(jìn)行操作的話

6、就會改變a1數(shù)組。所以makeDoule函數(shù)也可以寫成下面的樣子,這兩個函數(shù)是等價的:void makeDoule(int* arr,int len)int i=0;for(i=0;ilen;i+)arri= arri*2;當(dāng)然寫成下面的形式更符合指針的使用習(xí)慣,因此推薦這種用法:void makeDoule(int* arr)int i=0;for(i=0;i5;i+)/arr+i指向的值設(shè)置為arr+i指向的值的二倍。*(arr+i)= *(arr+i)*2;有的同學(xué)可能會問,為什么makeDoule函數(shù)還需要傳遞數(shù)組的長度len呢?makeDoule函數(shù)這樣寫不就行了嗎?void mak

7、eDoule(int* arr)int i=0;for(i=0;i5;i+)arri= arri*2;這樣寫在這個函數(shù)中是沒有問題的。但是這個makeDoule函數(shù)不一定為只為a1服務(wù),函數(shù)的最重要的特征是可以復(fù)用,也就是可以被其他地方調(diào)用,如果我們想用makeDoule函數(shù)為另外一個長度為20的數(shù)組進(jìn)行“每個元素乘以2”的操作,那么將數(shù)組長度5寫死在函數(shù)中就會有問題了。那么為什么不在函數(shù)內(nèi)部計(jì)算數(shù)組的長度呢?省得還傳遞一個len參數(shù)void makeDoule(int arr)int i=0;int len = sizeof(arr)/sizeof(int);for(i=0;ilen;i+)

8、arri= arri*2;int main(int argc, char *argv)int a15=3,5,6,8,2;int i = 0;int len=sizeof(a1)/sizeof(int);makeDoule(a1);for(i=0;ilen;i+)printf(%d ,a1i);運(yùn)行以后程序竟然輸出了:6 5 6 8 2只有第一個元素被“乘以2”。為什么呢?運(yùn)行下面的程序試一試:void test(int arr)printf(%dn,sizeof(arr)/sizeof(int);int main(int argc, char *argv)int a15=3,5,6,8,2;

9、printf(%dn,sizeof(a1)/sizeof(int);test(a1);運(yùn)行結(jié)果竟然是:51為什么在main函數(shù)中計(jì)算數(shù)組的大小是5,在test函數(shù)中計(jì)算數(shù)組arr的大小就變成了1了呢?在C語言中可以通過sizeof的方式取得一個數(shù)組的尺寸,這是我們已經(jīng)知道的。但是一旦把這個數(shù)組傳遞給函數(shù)的時候,到了函數(shù)內(nèi)部使用的就是指向這個數(shù)組的指針了,雖然在test函數(shù)中arr聲明的是數(shù)組,但是這里的arr只是一個指針而已了,arr本質(zhì)上只是一個int類型的指針,而int類型的指針的大小是4,所以sizeof(arr)/sizeof(int)的結(jié)果就是1。這點(diǎn)是經(jīng)常容易犯錯的,需要特別注意。

10、如果對指針還有什么不清楚的,可以到這個網(wǎng)址查詢指針的學(xué)習(xí)資料:url ,指針是比較不好理解的,因此學(xué)習(xí)過程中要多試驗(yàn),多思考,不要?dú)怵H。8、多維數(shù)組的指針設(shè)有一個二維數(shù)組int a34=0,1,2,3,4,5,6,7,8,9,10,11 (1)語言允許把一個二維數(shù)組分解為多個一維數(shù)組來處理。因此數(shù)組 a 可分解為三個一維數(shù)組,即 a0,a1,a2。每一個一維數(shù)組又含有四個元素。例如 a0數(shù)組,含有 a00,a01,a02,a03四個元素。(2)從二維數(shù)組的角度來看,a 是二維數(shù)組名,a 代表整個二維數(shù)組的首地址,也是二維數(shù)組 0 行的首地址。特別注意a+1表示第1行的首地址,而不是第0行第第1

11、列的地址,這是初學(xué)者最容易犯錯的地方。同樣a1也是第1行一維數(shù)組的數(shù)組名和首地址。所以a+1、*(a+1)、1是等價的。(4)在二維數(shù)組中不能把&ai理解為元素 ai的地址,因?yàn)閍i不是一個數(shù)組元素,ai是一種地址計(jì)算方法,它本身就表示數(shù)組 a 第 i 行首地址。所以&ai和 ai是等價的。這一點(diǎn)也是初學(xué)者最容易犯錯的地方。(5)從上邊的分析我們得知a0+1是 a0的 1 號元素首地址,由此可得出 ai+j 則是一維數(shù)組 ai的 j 號元素首地址,它等于&aij。由 ai=*(a+i)得 ai+j=*(a+i)+j。由于*(a+i)+j 是二維數(shù)組 a 的 i 行 j 列元素的首地址,所以,該

12、元素的值等于*(*(a+i)+j)。理解了下面的算法也就理解了多維數(shù)組的指針問題:int main(int argc, char *argv)int a34=0,1,2,3,4,5,6,7,8,9,10,11;printf(%dn,*(*(a+1)+2);printf(%dn,*(a1+2);程序輸出如下:66兩個表達(dá)式都輸出a12的值。*(a+1)則表示二維數(shù)組a的第1行,也就是等價于a1。a1、*(a+1)都表示數(shù)組的第1行。所以*(a1+2)和*(*(a+1)+2)都表示數(shù)組的第1行的第2個元素的值。有的同學(xué)會問了,既然“*(a+1)”和“a+1”是等價的,為什么“printf(%dn,

13、*(a+1)+2)”輸出結(jié)果是錯誤的呢?編譯器在編譯“*(a+1)+2)”的時候會把“(a+1)+2”優(yōu)化成“a+3”,因此“*(a+1)+2)”就變成了“*(a+3)”,也就是a數(shù)組第3個一維數(shù)組的首地址,顯然這個只是一個地址,并不是我們想像中的a12的值,所以輸出了一個非常大的數(shù)。為了避免編譯器的這種誤解,建議大家表示“二維數(shù)組a的第1行”的時候用a1或者*(a+1),而盡量不要用(a+1)因?yàn)楹苋菀壮鲥e。C語言指針問題快速解惑(三)9、函數(shù)指針 在語言中,一個函數(shù)總是占用一段連續(xù)的內(nèi)存區(qū),而函數(shù)名就是該函數(shù)所占內(nèi)存區(qū)的首地址。我們可以把函數(shù)的這個首地址(或稱入口地址)賦予一個指針變量,使

14、該指針變量指向該函數(shù)。然后通過指針變量就可以找到并調(diào)用這個函數(shù)。我們把這種指向函數(shù)的指針變量稱為“函數(shù)指針變量”。 函數(shù)指針變量定義的一般形式為: 函數(shù)的返回值的類型(*指針變量名)(參數(shù)列表); 其中“參數(shù)列表”可以省略,不過建議明確標(biāo)明“參數(shù)列表”。例子:void PrintIt(int i)printf(%dn,i);int main(int argc, char *argv)int i = 0;int arr5 = 3,5,8,2,1;void (*myAction)(int);myAction = PrintIt;for(i=0;isizeof(arr)/sizeof(int);i+

15、)myAction(arr);上面的程序遍歷數(shù)組arr的所有元素,并且打印每個元素。有的同學(xué)會說,這樣做有什么意義嗎?把“myAction(arr)”直接換成“PrintIt(arr)”不就得了嗎?這么替換在這里是非常合理,也是非常正確的,但是有一天我發(fā)現(xiàn)很多地方都要遍歷數(shù)組做不同的事情,為了避免每次都寫for循環(huán),我將遍歷數(shù)組的功能抽取到一個單獨(dú)的公共函數(shù)中完成void eachItem(int* pArray,int len,void (*action)(int)int i = 0;for(i=0;ilen;i+)/調(diào)用函數(shù)指針action(*(pArray+i);注意函數(shù)eachItem

16、的最后一個參數(shù)為函數(shù)指針類型。這樣main函數(shù)就可以簡化成如下的樣子了:void PrintIt(int i)printf(%dn,i);int main(int argc, char *argv)int arr5 = 3,5,8,2,1;int len = sizeof(arr)/sizeof(int);eachItem(arr,len,PrintIt);以后在其他的地方想對int數(shù)組做其他處理,那么只要寫不同的函數(shù)就可以了,比如說要將數(shù)組中的奇數(shù)輸出:void PrintOdd(int i)if(i%2)=1)printf(%d是奇數(shù)n,i); 在main函數(shù)中如下調(diào)用即可:eachIte

17、m(arr,len,PrintOdd);可以看到通過函數(shù)指針,將循環(huán)遍歷算法和具體的處理算法隔離了,實(shí)現(xiàn)了代碼的復(fù)用。函數(shù)指針在編程中有非常多的應(yīng)用。函數(shù)指針有時候又被稱為回調(diào),在事件機(jī)制、模板算法等場合有著廣泛應(yīng)用,因此一定要掌握好。MFC、STL等流行的框架中都大量的應(yīng)用了函數(shù)指針,在的C語言也能干大事系列在線教學(xué)中也將進(jìn)一步講解函數(shù)指針的更生動的應(yīng)用。附錄:本小節(jié)用到的代碼:void PrintIt(int i)printf(%dn,i);void PrintOdd(int i)if(i%2)=1)printf(%d是奇數(shù)n,i); void eachItem(int* pArray,int len,void (*action)(int)int i = 0;for(i=0;i成員名 應(yīng)該注意(*pstu)兩側(cè)的括號不可少,因?yàn)槌蓡T符“.”的優(yōu)先級高于“*”。12、結(jié)構(gòu)指針變量作函數(shù)參數(shù)允許用結(jié)構(gòu)變量作函數(shù)參數(shù)進(jìn)行整體傳送。但是這種傳送要將全部成員逐個傳送,特別是成員為數(shù)組時將會使傳送的時間和空間開銷很大,嚴(yán)重地降低了程序的效率。因此最好的辦法就是使用指針,即用指針變量作函數(shù)參數(shù)進(jìn)行傳送。13、動態(tài)存儲分配注:“語言中不允許動態(tài)數(shù)組”是C89標(biāo)準(zhǔn)中的規(guī)定,所以TC、VC6等C89等老的編譯器會有這個問題,新的C99中已經(jīng)不存在這個問題。語言中不允許動態(tài)數(shù)組類型。例如下面的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論