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