軟考程序員輔導(dǎo):淺析函數(shù)指針
函數(shù)指針的概念是指向函數(shù)的指針變量。 因而“函數(shù)指針”本身首先應(yīng)是指針變量,只不過該指針變量指向函數(shù)。在大多數(shù)情況下我們使用不到,也忽略了它的存在。函數(shù)名實(shí)際上也是一種指針,指向函數(shù)的入口地址,但它又不同于普通的如int*、double*指針,看下面的例子來理解函數(shù)指針的概念:
view plain int function( int x, int y );int main ( void )
{ int (*fun) ( int x, int y );int a = 10, b = 20;function( a, b );fun = function;(*fun)( a, b );……
}第一行代碼首先定義了一個(gè)函數(shù)function,其輸入為兩個(gè)整型數(shù),返回也為一個(gè)整型數(shù)(輸入?yún)?shù)和返回值可為其它任何數(shù)據(jù)類型);后面又定義了一個(gè)函數(shù)指針fun,與int*或double*定義指針不同的是,函數(shù)指針的定義必須同時(shí)指出輸入?yún)?shù),表明這是一個(gè)函數(shù)指針,并且*fun也必須用一對括號(hào)括起來;并將函數(shù)指針賦值為函數(shù)function,前提條件是*fun和function的輸入?yún)?shù)和返回值必須保持一致,否則無法通過編譯。可以直接調(diào)用函數(shù)function(),也可以直接調(diào)用函數(shù)指針,二者是等效的。
聲明函數(shù)指針
回調(diào)函數(shù)是一個(gè)程序員不能顯式調(diào)用的函數(shù);通過將回調(diào)函數(shù)的地址傳給調(diào)用者從而實(shí)現(xiàn)調(diào)用。要實(shí)現(xiàn)回調(diào),必須首先定義函數(shù)指針。盡管定義的語法有點(diǎn)不可思議,但如果你熟悉函數(shù)聲明的一般方法,便會(huì)發(fā)現(xiàn)函數(shù)指針的聲明與函數(shù)聲明非常類似。請看下面的例子:
void f(); // 函數(shù)原型
上面的語句聲明了一個(gè)函數(shù),沒有輸入?yún)?shù)并返回void.那么函數(shù)指針的聲明方法如下:
void (*) ();
函數(shù)存放在內(nèi)存的代碼區(qū)域內(nèi),它們同樣有地址,我們?nèi)绾文塬@得函數(shù)的地址呢?
如果我們有一個(gè)int test(int a)的函數(shù),那么,它的地址就是函數(shù)的名字,這一點(diǎn)如同數(shù)組一樣,數(shù)組的名字就是數(shù)組的起始地址。
定義一個(gè)指向函數(shù)的指針用如下的形式,以上面的test()為例:
int (*fp)(int a); //這里就定義了一個(gè)指向函數(shù)的指針
函數(shù)指針絕對不能指向不同類型,或者是帶不同形參的函數(shù),在定義函數(shù)指針的時(shí)候我們很容易犯如下的錯(cuò)誤。
int *fp(int a); //這里是錯(cuò)誤的,因?yàn)榘凑战Y(jié)合性和優(yōu)先級來看就是先和()結(jié)合,然后變成了一個(gè)返回整形指針的函數(shù)了,而不是函數(shù)指針,這一點(diǎn)尤其需要注意!
例如函數(shù)原型為:
int fun(int *, int);
則函數(shù)指針可以聲明為: int (*pf)(int *, int);
當(dāng)然從上述例子看不出函數(shù)指針的優(yōu)點(diǎn),目的主要是想引出函數(shù)指針數(shù)組的概念。我們從上面例子可以得知,既然函數(shù)名可以通過函數(shù)指針加以保存,那們也一定能定義一個(gè)數(shù)組保存若干個(gè)函數(shù)名,這就是函數(shù)指針數(shù)組。正確使用函數(shù)指針數(shù)組的前提條件是,這若干個(gè)需要通過函數(shù)指針數(shù)組保存的函數(shù)必須有相同的輸入、輸出值。
view plain //首先定義256個(gè)處理函數(shù)(及其實(shí)現(xiàn))。
int function0( int *, int );……
int function255( int *, int );
//其次定義函數(shù)指針數(shù)組,并給數(shù)組賦值。
void (*fun[256])( int *, int );
fun[0] = function0;……
fun[255] = function255;
如果賦了不同的值給函數(shù)指針,那么調(diào)用者將調(diào)用不同地址的函數(shù)。賦值可以發(fā)生在運(yùn)行時(shí),這樣使你能實(shí)現(xiàn)動(dòng)態(tài)綁定。
下面我們來看一個(gè)具體的例子:
view plain int test(int a)
{ return a;}
int main(void)
{ int (*fp)(int a);fp = test; //將函數(shù)test的地址賦給函數(shù)指針fp cout《fp(5)《“|”《(*fp)(10)《endl; //輸出fp(5),這是標(biāo)準(zhǔn)c++的寫法,(*fp)(10)這是兼容c語言的標(biāo)準(zhǔn)寫法,兩種同意,但注意區(qū)分,避免寫的程序產(chǎn)生移植性問題!
return 0;} typedef定義可以簡化函數(shù)指針的定義,在定義一個(gè)的時(shí)候感覺不出來,但定義多了就知道方便了,上面的代碼改寫成如下的形式:
view plain int test(int a)
{ return a;}
int main(void)
{ typedef int (*fp)(int a); //注意,這里不是生命函數(shù)指針,而是定義一個(gè)函數(shù)指針的類型,這個(gè)類型是自己定義的,類型名為fp fp fpi; //這里利用自己定義的類型名fp定義了一個(gè)fpi的函數(shù)指針!
fpi = test;cout《fpi(5)《“|”《(*fpi)(10)《endl; //輸出fp(5),這是標(biāo)準(zhǔn)c++的寫法,(*fp)(10)這是兼容c語言的標(biāo)準(zhǔn)寫法,兩種同意,但注意區(qū)分,避免寫的程序產(chǎn)生移植性問題!
return 0;}