C 語言的函數指標有很多用法。例如,當呼叫一個函數時,可能不僅想傳入該函數需要被處理的資料,還希望傳入指向子程式的指標,該子程式決定如何處理資料。
也
可以在陣列中儲存函數指標,然後使用陣列的索引來呼叫這些函數。例如,鍵盤驅動程式可能使用函數指標陣列,陣列索引對應到了鍵盤編碼。當使用者按下一個鍵時,程式就會跳到對應的函數。
與陣列指標的宣告一樣,函數指標的宣告也需要括號。下面的例子展示了如何宣告函數指標。這個宣告定義了一個指向函數的指標,該函數具有兩個 double 型別的引數和 double 型別的返回值:
double (*funcPtr)(double, double);
該宣告中採用括號將星號和識別符號包圍起來,這個括號很重要。如果沒有它,宣告 double*funcPtr(double,double);則為函數原型,而不是指標定義。
無論是否必須,函數名會被隱式地轉換成函數指標。因此,下面的語句會將標準函數 pow()的地址賦值給指標 funcPtr,然後利用該指標呼叫這個函數:
double result;
funcPtr = pow; // 使得funcPtr指向函數pow()
// 因此,表示式*funcPtr獲得函數pow()
result = (*funcPtr)( 1.5, 2.0 ); // 通過funcPtr呼叫函數
result = funcPtr( 1.5, 2.0 ); // 與上等效的函數呼叫
如本例中最後一行所示,當使用指標呼叫函數時,可以不用間接運算子,因為函數呼叫運算子的左運算元具有函數指標型別。
例 1 所示程式提示使用者輸入兩個數位,然後對它們進行簡單的計算。該數學函數通過儲存在陣列 funcTable 中的指標呼叫獲得。
【例1】函數指標的簡單用法
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double Add( double x, double y ) { return x + y; }
double Sub( double x, double y ) { return x - y; }
double Mul( double x, double y ) { return x * y; }
double Div( double x, double y ) { return x / y; }
// 具有5個函數指標的陣列,這些函數需要兩個double型別引數,返回值為double型別
double (*funcTable[5])(double, double)
= { Add, Sub, Mul, Div, pow }; // 初始化器列表
// 一個字串指標陣列,用於輸出:
char *msgTable[5] = {"Sum", "Difference", "Product", "Quotient", "Power"};
int main()
{
int i; // 索引變數
double x = 0, y = 0;
printf( "Enter two operands for some arithmetic:n" );
if ( scanf( "%lf %lf", &x, &y ) != 2 )
printf( "Invalid input.n" );
for ( i = 0; i < 5; ++i )
printf( "%10s: %6.2fn", msgTable[i], funcTable[i](x, y) );
return 0;
}
表示式 funcTable[i](x,y)會呼叫地址儲存在指標 funcTable[i] 中的函數。陣列名稱和下標不需要被包含在括號內,因為函數呼叫運算子()和下標運算子 [] 都具有最高的優先順序,以及從左至右的結合律。
再次提醒,
採用 typedef 定義簡單的型別名稱,對於諸如函數指標陣列這樣的複雜型別,將更容易管理。例如,可以採用如下形式定義陣列 funcTable:
typedef double func_t( double, double ); // 函數型別名稱定義為func_t
func_t *funcTable[5] = { Add, Sub, Mul, Div, pow };
上述定義方法顯然比例 1 中的陣列定義可讀性更高。