C語言指向函數的指標

2020-07-16 10:04:27
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 中的陣列定義可讀性更高。