沒覺得指針函數這個概念有什麽大的意義。。。。可能其最大的意義就是拿過來和函數指針壹起混淆初學者的視聽吧。
指針函數指的是返回壹個指針的函數,比如我們常見的gets(),strcpy(),strcat(),malloc()等等。如果單獨把它當成壹個新概念真的沒有什麽意義。這些函數除了返回壹個指針之外沒有任何***性,但是返回的指針又天差地遠。
下面說說函數指針。
指針分為三種類型:對象指針,函數指針和void指針。
函數指針的聲明形式是T (*p)(...),其中*p使用括號括起來的原因是函數類型解析的優先級高於指針的解析,故使用括號防止解析成上面的指針函數(其實這兩個之間就相差了壹對括號)。
函數指針可以綁定到與其返回值和參數類型都相同的函數上。比如:
int?foo(int,?double);?//?函數聲明int?(*bar)(int,?double)?=?foo;?//?函數指針
在上面的初始化中,寫成&foo也是可以的。
函數指針的最大特點就在於,其不能做壹元+-運算(當然也不能做+= -= ++ --等),且對其做壹元*運算的結果還是其本身。例如:(接著上面的例子)
bar(1,1.0);(*bar)(1,1.0);?//?兩種情況等價
甚至妳還可以這樣:
(**************bar)(1,1.0);依然是對的。
所以實際應用中壹般采取類似函數調用的方式,這樣更加自然。
剛剛去測試了壹下,還有壹個更加隱蔽的問題:
C中的函數可以采用使用原型或者不使用兩種方式。(不使用原型被視為過時)
原型即在函數頭中將參數類型及個數都聲明,而不使用就是很簡單的壹對括號。例如:
int?foo();?//?非原型int?bar(void);?//?原型
int?foo1(int);?//?原型
這有什麽影響呢?看壹看下面的壹段代碼:
int?foo(int?i){return?i;}?//?原型int?foo1(double?c){return?(int)c;}?//?原型
int?bar(){return?1;}?//?非原型
int?main(void)
{
int?(*foobar)(int);?//?原型
int?(*barfoo)();?//?非原型
foobar?=?foo;
foobar?=?&foo;
foobar?=?bar;
foobar?=?foo1;?//?this
barfoo?=?foo;
barfoo?=?bar;
barfoo?=?foo1;
foobar(1);
(*foobar)(1);
(*************foobar)(1);
return?0;
}
我的編譯器對this指的壹行進行了警告,提醒指針類型不匹配。
我們可以看到,非原型的函數指針可綁定到任意的函數上,而帶有原型的函數指針在綁定時可以起到更嚴格的類型限制。
容易忽略的壹點是,不接受任何參數的函數(帶原型)的聲明方式是int foo(void);,不應該省略void,特別是在使用對應類型的函數指針時,如果省略void,那麽錯誤的綁定也不會被警告。
我還註意到了壹個現象:
int?foo(char);int?(*bar)()?=?foo;
這段代碼同樣也給了警告。為什麽呢?
因為在不使用原型的情況下,char,short,float等會被隱式提升到與其對應的更高級類型。
而在這個綁定中,bar是非原型,這時可能會進行整型提升,而foo帶有原型,調用時不需要進行提升。這樣就有可能引發錯誤。
以上就是函數指針使用過程中需要註意的壹點。不過提醒LZ,函數指針使用過程中最好還是使用帶有原型的函數指針。