|
腳本之家 你與百萬開發(fā)者在一起
前言函數(shù)指針是什么?如何使用函數(shù)指針?函數(shù)指針到底有什么大用?本文將一一介紹。 如何理解函數(shù)指針如果有int *類型變量,它存儲(chǔ)的是int類型變量的地址;那么對(duì)于函數(shù)指針來說,它存儲(chǔ)的就是函數(shù)的地址。函數(shù)也是有地址的,函數(shù)實(shí)際上由載入內(nèi)存的一些指令組成,而指向函數(shù)的指針存儲(chǔ)了函數(shù)指令的起始地址。如此看來,函數(shù)指針并沒有什么特別的。我們可以查看程序中函數(shù)的地址: #include <stdio.h>編譯: 查看test函數(shù)相對(duì)地址(并非實(shí)際運(yùn)行時(shí)的地址): $ nm testFun |grep test #查看test函數(shù)的符號(hào)表信息如何聲明函數(shù)指針聲明普通類型指針時(shí),需要指明指針?biāo)赶虻臄?shù)據(jù)類型,而聲明函數(shù)指針時(shí),也就要指明指針?biāo)赶虻暮瘮?shù)類型,即需要指明函數(shù)的返回類型和形參類型。例如對(duì)于下面的函數(shù)原型: 它是一個(gè)返回值為int類型,參數(shù)是兩個(gè)int類型的函數(shù),那么如何聲明該類型函數(shù)的指針呢?很簡(jiǎn)單,將函數(shù)名替換成(*pf)形式即可,即我們把sum替換成(*fp)即可,fp為函數(shù)指針名,結(jié)果如下: int (*fp)(int,int);這樣就聲明了和sum函數(shù)類型相同的函數(shù)指針fp。這里說明兩點(diǎn),第一,*和fp為一體,說明了fp為指針類型,第二,*fp需要用括號(hào)括起來,否則就會(huì)變成下面的情況: 這種情況下,意思就大相徑庭了,它聲明了一個(gè)參數(shù)為兩個(gè)int類型,返回值為int類型的指針的函數(shù),而不再是一個(gè)函數(shù)指針了。 在經(jīng)常使用函數(shù)指針之后,我們很快就會(huì)發(fā)現(xiàn),每次聲明函數(shù)指針都要帶上長(zhǎng)長(zhǎng)的形參和返回值,非常不便。這個(gè)時(shí)候,我們應(yīng)該想到使用typedef,即為某類型的函數(shù)指針起一個(gè)別名,使用起來就方便許多了。例如,對(duì)于前面提到的函數(shù)可以使用下面的方式聲明: typedef int (*myFun)(int,int);//為該函數(shù)指針類型起一個(gè)新的名字上面的myFun就是一個(gè)函數(shù)指針類型,在其他地方就可以很方便地用來聲明變量了。typedef的使用不在本文的討論范圍,但是特別強(qiáng)調(diào)一句,typedef中聲明的類型在變量名的位置出現(xiàn),理解了這一句,也就很容易使用typedef了。因而下面的方式是錯(cuò)誤的: 為函數(shù)指針賦值賦值也很簡(jiǎn)單,既然是指針,將對(duì)應(yīng)指針類型賦給它既可。例如: #include<stdio.h>在這里,聲明了返回類型為int,接受兩個(gè)int類型參數(shù)的函數(shù)指針f1和f2,分別給它們進(jìn)行了賦值。表達(dá)式1和表達(dá)式2在作用上并沒有什么區(qū)別。因?yàn)楹瘮?shù)名在被使用時(shí)總是由編譯器把它轉(zhuǎn)換為函數(shù)指針,而前面加上&不過顯式的說明了這一點(diǎn)罷了。 調(diào)用調(diào)用也很容易,把它看成一個(gè)普通的函數(shù)名即可: 在函數(shù)指針后面加括號(hào),并傳入?yún)?shù)即可調(diào)用,其中表達(dá)式1和表達(dá)式2似乎都可以成功調(diào)用,但是哪個(gè)是正確的呢?ANSI C認(rèn)為這兩種形式等價(jià)。 函數(shù)指針有何用函數(shù)指針的應(yīng)用場(chǎng)景比較多,以庫(kù)函數(shù)qsort排序函數(shù)為例,它的原型如下: void qsort(void *base,size_t nmemb,size_t size , int(*compar)(const void *,const void *));看起來很復(fù)雜對(duì)不對(duì)?拆開來看如下: 拿掉第四個(gè)參數(shù)后,很容易理解,它是一個(gè)無返回值的函數(shù),接受4個(gè)參數(shù),第一個(gè)是void*類型,代表原始數(shù)組,第二個(gè)是size_t類型,代表數(shù)據(jù)數(shù)量,第三個(gè)是size_t類型,代表單個(gè)數(shù)據(jù)占用空間大小,而第四個(gè)參數(shù)是函數(shù)指針。這第四個(gè)參數(shù),即函數(shù)指針指向的是什么類型呢? int(*compar)(const void *,const void *)很顯然,這是一個(gè)接受兩個(gè)const void*類型入?yún)?,返回值為int的函數(shù)指針。 在這里函數(shù)指針作為了參數(shù),而他同樣可以作為返回值,創(chuàng)建數(shù)組,作為結(jié)構(gòu)體成員變量等等,它們的具體應(yīng)用我們?cè)诤竺娴奈恼轮袝?huì)介紹,本文不作展開。本文只介紹一個(gè)簡(jiǎn)單實(shí)例。 實(shí)例介紹我們通過一個(gè)實(shí)例來看函數(shù)指針怎么使用。假設(shè)有一學(xué)生信息,需要按照學(xué)生成績(jī)進(jìn)行排序,該如何處理呢? 我們創(chuàng)建了一個(gè)學(xué)生信息結(jié)構(gòu),結(jié)構(gòu)成員包括名字,學(xué)號(hào)和成績(jī)。main函數(shù)中創(chuàng)建了一個(gè)包含三個(gè)學(xué)生信息的數(shù)組,并使用qsort函數(shù)對(duì)數(shù)組按照學(xué)生成績(jī)進(jìn)行排序。qsort函數(shù)第四個(gè)參數(shù)是函數(shù)指針,因此我們需要傳入一個(gè)函數(shù)指針,并且這個(gè)函數(shù)指針的入?yún)⑹莄ont void *類型,返回值為int。我們通過前面的學(xué)習(xí)知道了函數(shù)名本身就是指針,因此只需要將我們自己實(shí)現(xiàn)的studentCompare作為參數(shù)傳入即可。 最終運(yùn)行結(jié)果如下: name:two,id:2,score:77可以看到,最終學(xué)生信息按照分?jǐn)?shù)從低到高輸出。 總結(jié)本文介紹了函數(shù)指針的聲明和使用。更多使用將在后面的文章介紹,本文總結(jié)如下:
思考下面的聲明如何理解 |
|
|