Function Pointer
定義:
Function Pointer (中文直譯「函式指標」),即為儲存某一個函式起始memory address的變數,此變數可以提供我們在之後進行呼叫。
乍聽之下,function pointer就只是多一個別名再呼叫,似乎沒什麼實質的用處,但其實我們可以藉由function pointer省去繁複的 if/switch,後面會一一介紹。
使用方法:
現在假設我們有以下這個函式:
int Square(int n)
{
return n*n;
}
然後宣告一個function pointer變數,以便於指向函式Square:
int (*fptr)(int);
fptr = Square;
這邊有幾個小細節必須注意:
1.最前面的int是變數data type(資料型態),和要指向的函式回傳值型態相同。第一個小括號代表指標變數名稱,第二個小括號代表傳入的parameter資料型態們,且理所當然的type必須與我們要指向的函式傳入值相同。
2. function pointer 的 pointer operator(*)必須與變數名稱一起被小括號括起來並接參數的小括號。若沒有這個小括號,會變成以下:
int *fptr(int);
在意義上,表示fptr為一個"函式"而不是變數,回傳的資料型態為 int* ,會有3種情況;
a. 回傳一個pointer of int(整數指標變數的指標) -> int *a; return a;
b. 回傳一個address of int(整數一般變數的位址) -> int a; return &a;
c. 回傳一個int array(整數型態的陣列) -> int a[100]; return a;
延伸:
在知道function pointer的妙用前,還必須介紹以下兩種功能:
1.typedef
typedef是c/c++中的關鍵字,其允許programmer為data type(資料型態)創造一個全新的名字。同時也可以為函式創造一個別名,其好處在於若要把function當做一參數傳入另外一fumction時,可以讓該參數簡略化。這邊將其和function pointer做結合:
int Mul(int a, int b)
{
return a*b;
}
int *FuncA(int x, int y, int (*Opt)(int, int))
{
return Opt(x, y);
}
int result = FuncA(5, 10, Mul); // 第三個參數可以傳入更多不同的計算方法,因為是function pointer
觀察FunctA,第三個帶入參數是一個function pointer,只是長的有點醜,就可以用typedef做簡化,如下:
typedef int (*MathMethod)(int, int); // 注意*要在()之中
int Mul(int a, int b)
{
return a*b;
}
int *FuncA(int x, int y, MathMethod Opt)
{
return Opt(x, y);
}
int result = FuncA(5, 10, Mul);
以上簡化是連同回傳型態也簡化,同時作為新的型態(別名)可供使用,可以理解為把
int (*)(int, int)
簡化成
MathMethod
但注意,function的typedef,不能寫成以下:
typedef int (*)(int, int) MathMethod;
呈上,配合typedef就可以讓各種擁有不同功能function(上面是實做乘法,也可以增加除法等)更直觀的當做參數傳入其他function。
typedef int (*MathMethod)(int, int);
int Mul(int a, int b) { return a*b; }
int Divide(int a, int b) { return a/b; }
int Minus(int a, int b) { return a-b; }
int Add(int a, int b) { return a+b; }
int *Calc(int x, int y, MathMethod Opt){
return Opt(x, y);
}
int main()
{
int a = 8, b = 7;
printf("a x b = %d\n", Calc(a, b, Mul));
printf("a / b = %d\n", Calc(a, b, Divide));
printf("a + b = %d\n", Calc(a, b, Minus));
printf("a - b = %d\n", Calc(a, b, Add));
}
2. Array of Function Pointer
以上方法可以透過array of function pointer(指標函式陣列),讓工作更加簡便。所謂的array of function pointer是一個儲存function pointer的array,因此可以透過一些自訂的條件(例如輸入),去取得想要呼叫的function使用。光說不練假把戲,直接上例子。
typedef int (*MathMethod)(int, int);
int Mul(int a, int b) { return a*b; }
int Divide(int a, int b) { return a/b; }
int Minus(int a, int b) { return a-b; }
int Add(int a, int b) { return a+b; }
int (*calcArray[])(int, int) = // Array of function pointer,存放會使用到的function名稱
{
Mul, // 這邊亦可以打&Mul,&可省略
Divide,
Minus,
Add
};
char* operation[] = //做為判斷的自訂條件,與argv比對用
{
"x",
"/",
"-",
"+"
};
int main(int argc, char** argv)
{
int size = sizeof(calcArray) / (sizeof(int(*))); // 使用此方法可以避免每次增加功能時修改長度
int i = 0;
if(argc > 1)
for(i; i<size; i++)
{
if( strcmp(argv[2], operation[i]) == 0)
{
int a = atoi(argv[1]), b = atoi(argv[3]);
printf("%d %s %d = %d\n", a, argv[2], b, calcArray[i](a, b));
break;
}
}
}
執行如下圖:
以上特別適用於很多條件且傳入參數相近時使用,若要新增新功能時,只要加上新的函式,並將其加入Array中,並加進自己的條件做判斷條件即可。
又例如不同按鍵有不同的操作函式(似乎BBS的鍵盤輸入操作就是使用這個方式去實現),就可以省去大量的if/switch的statement,讓程式可讀性與維護更加簡易。
感謝草神的分享,讓我對函式指標有另一層面的認識
回覆刪除我在執行您的程式碼時,有發現一些筆誤的地方
原版
int *Calc(int x, int y, MathMethod Opt){
return Opt(x, y);
}
---------------------------------------------------------------------
修改後
int Calc(int x, int y, MathMethod Opt){
return Opt(x, y);
}
同上
回覆刪除int *FuncA(int x, int y, MathMethod Opt)
{
return Opt(x, y);
}
---------------------------------------------------------------------
修改後
int FuncA(int x, int y, MathMethod Opt)
{
return Opt(x, y);
}