文章目錄
-
-
- 函數指針
- 指針函數
- 傳回函數指針的函數
- 函數指針實作函數重載
-
函數指針
函數指針是指向函數的指針變量,因而函數指針本身首先應是指針變量,正如用指針變量可指向整型變量、字元型、數組一樣,函數指針隻不過是指向函數的指針。-
函數指針的兩個用途
調用函數和作函數的參數
- 函數指針定義格式如下:
"函數類型"為函數的傳回類型,由于()的優先級高于*,是以指針變量名外的括号必不可少,後面的"形參清單"表示指針變量指向的函數所帶的參數清單函數類型 (* 指針變量名) (形參清單)
例如:
int (*pf)(int x);
若寫成
int *pf(int x);
按照結合性和優先級來看就是pf先和()結合,它就變成了一個傳回整型指針的函數而不是函數指針了
- 函數名和數組名一樣,實際上是一個位址,函數名代表了函數代碼的首位址,是以在指派時,直接将函數指針指向函數名就好了,
和pf=func
,都是func的首位址pf=&func
int (*pf)(int x);
pf=func;
pf=&func;
- 用typedef方法可以有效減少括号的數量,以及理清層次。
typedef int (*PF)(int x);
PF pf;
pf=func;
//指派時函數func不帶括号,也不帶參數
pf=func();//error
pf=func(int x);//error
- 函數指針絕對不能指向不同類型或者帶不同形參的函數
int main(){
int func1(int x);
double func2(double x);
int func3(int x,int y);
int (*pf)(int x);
pf=func1;
pf=func2;//錯誤
}
- 函數指針作為變量,函數指針調用函數
void caller(void (*ptr)())//函數指針作為變量
{
ptr();//調用ptr指向的函數
}
void func(){};
int main(){
void (*p) ();
p=func;
caller(p);//傳遞函數位址到調用者
return 0;
}
通過賦予不同的值給p,那麼調用者可以調用不同位址的函數,指派可以發生在運作時,這樣便能實作動态綁定,
虛函數的動态聯編是這樣實作的- 回調函數(Callback),實際上所謂回調函數,本質就是函數指針,使用回調函數實際上就是在調用某個函數(通常是API函數)時,将自己的一個函數(這個函數為回調函數)的位址作為參數傳遞給所調用的那個函數。
例如:C++标準模闆庫裡的sort排序函數:
template void sort{
RandomAccessIterator _First,//需排序資料的第一個元素位置
RandomAccessIterator _Last,//需排序資料的最後一個元素位置
BinaryPredicate _Comp,//排序使用的比較算法
}
指針函數
指針函數是指傳回值是指針的函數,其本質上是一個函數。函數都有傳回類型(如果不傳回值,則為無值型),隻不過指針函數傳回類型是某一類型的指針。
- 定義格式
例如:傳回類型* 函數名稱(形式參數表);
int *func(int x,int y);
- 指針函數傳回的是一個位址值,經常用于傳回數組的某一進制素位址
- 指針函數可以傳回堆位址,可以傳回全局或靜态變量的位址,但不要傳回局部變量的位址
int* func()//指針函數
{
int value=1;
return &value;//warning:傳回局部變量或臨時變量的位址
}
int main(){
int *pret=func();//
printf("%s",* pret);
return 0;
}
程式能夠通過編譯,但會有運作時的錯誤。
傳回函數指針的函數
例如要聲明一個函數,它帶一個int參數,然後傳回一個函數指針,指針類型為int(*)(int int);
這個函數的名字叫func,如何寫呢?應寫成
int (* func(int))(int int);
用typedef定義傳回的函數類型,寫法如下
typedef int (* RetFunPtr) (int,int);//給函數指針取别名RetFunPtr
RetFunPtr func(int);//聲明函數func,函數func的參數為int,傳回值為函數指針
例如:
int add(int x,int y){
int i=x+y;
return i;
}
int (* FuncPtr()) (int,int)//定義傳回函數指針的函數
{
return add;
}
int main(){
int (* fptr) (int,int)=FuncPtr();
printf("%d",fptr(10,10);
return 0;
}
技巧:
了解複雜聲明時的“右左法則”:從變量名看起,先往右,再往左,碰到一個圓括号就跳轉閱讀的方向;括号内分析完就跳出括号,還是按先右後左的順序,如此循環,直到整個聲明分析完。在上面代碼中,了解注釋部分,可以按右左法則進行:FuncPtr是它的名稱,先往右,碰到一個括号,說明FuncPtr為函數,且無函數參數,再往左,碰到*,說明該函數傳回為指針,
(* FuncPtr())
中的内容分析完了,跳出括号,繼續向右,再次碰到括号,說明該傳回的是一個函數指針,該括号中有兩個int參數,說明函數指針所指向函數帶兩個int型參數,再往左,碰到int,說明該函數指針指向的函數的傳回值為int類型,到此分析完畢。
總結起來,這串代碼的意思是,FuncPtr是一個無參函數且傳回值為函數指針,該函數指針指向函數帶兩個int型參數,且所指向函數傳回值為int
函數指針實作函數重載
C語言中無重載特性,隻能通過函數指針的方式實作類似重載的功能。在此不做展開,僅作了解