程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C:函數指針數組及驅動表程序解讀

C:函數指針數組及驅動表程序解讀

編輯:關於C

上一節/kf/201205/132375.html解讀了C程序中函數指針及回調函數的寫法,本節再看一下函數指針另一個較為廣泛的應用-驅動表程序,在這之前,首先需要了解函數指針數組的使用,依舊通過最簡單最容易理解的例子來講解。

  首先看下面這個函數指針數組的使用實例。


[cpp] #include <stdio.h>  
#include <stdlib.h>  
 
 
int Sum(int a, int b) 

    return a + b; 

 
int Sub(int a, int b) 

    return a - b; 

 
typedef int (*pfFun)(int, int); 
 
int TestFun(int a, int b, pfFun pf) 

    int i = 0; 
    i = pf(a, b); 
    return i; 

 
int main(int argc, char *argv[]) 

  int iTmp = 0; 
   
  pfFun pf[] = {Sum, Sub}; /*定義並一個函數指針數組,包含2個元素,並將其初始化為Sum和Sub函數地址*/ 
   
  iTmp = TestFun(20, 10, pf[0]); 
  printf("Tmp is: %d\n", iTmp); 
   
  iTmp = TestFun(20, 10, pf[1]); 
  printf("Tmp is: %d\n", iTmp); 
   
  system("PAUSE");   
   
  return 0; 

#include <stdio.h>
#include <stdlib.h>


int Sum(int a, int b)
{
    return a + b;
}

int Sub(int a, int b)
{
    return a - b;
}

typedef int (*pfFun)(int, int);

int TestFun(int a, int b, pfFun pf)
{
    int i = 0;
    i = pf(a, b);
    return i;
}

int main(int argc, char *argv[])
{
  int iTmp = 0;
 
  pfFun pf[] = {Sum, Sub}; /*定義並一個函數指針數組,包含2個元素,並將其初始化為Sum和Sub函數地址*/
 
  iTmp = TestFun(20, 10, pf[0]);
  printf("Tmp is: %d\n", iTmp);
 
  iTmp = TestFun(20, 10, pf[1]);
  printf("Tmp is: %d\n", iTmp);
 
  system("PAUSE"); 
 
  return 0;
}
運行一下:


[plain]
Tmp is: 30 
Tmp is: 10 
請按任意鍵繼續. . . 
Tmp is: 30
Tmp is: 10
請按任意鍵繼續. . .

有了上面的概念,讓我們通過另一個實例看看驅動表的使用,下面這個小程序幾乎每個程序員都應該寫過,一個沒有考慮精度的加減乘除運算程序,如下:


[cpp]
#include <stdio.h>  
#include <stdlib.h>  
 
/*加法*/ 
int Sum(int a, int b) 

    return a + b; 

 
/*減法*/ 
int Sub(int a, int b) 

    return a - b; 

 
/*乘法*/ 
int Multi(int a, int b) 

    return a * b; 

 
/*除法*/ 
int Division(int a, int b) 

    return (b == 0)? 0:(a / b); 

 
/*操作碼*/ 
typedef enum _ENOPCODE 

    OPCODE_ADD = 0,   /*加*/ 
    OPCODE_SUB,       /*減*/ 
    OPCODE_MULTI,     /*乘*/ 
    OPCODE_DIVISION,  /*除*/ 
    OPCODE_BUTT 
}enOpCode; 
 
/*通過Switch-case語句計算*/ 
int GetOpResultBySwitch(int a, int b, enOpCode enOp) 

    int iTmp = 0; 
     
    switch(enOp) 
    { 
        case OPCODE_ADD: 
             iTmp = Sum(a, b); 
             break; 
              
        case OPCODE_SUB: 
             iTmp = Sub(a, b); 
             break;       
         
        case OPCODE_MULTI: 
             iTmp = Multi(a, b); 
             break; 
              
        case OPCODE_DIVISION: 
             iTmp = Division(a, b); 
             break; 
        default: 
             iTmp = -1; 
    } 
     
    return iTmp;            

 
int main(int argc, char *argv[]) 

  int iTmp = 0; 
  int a = 10; 
  int b = 30; 
 
  iTmp = GetOpResultBySwitch(a, b, OPCODE_ADD); 
 
  printf("Tmp is: %d\n", iTmp); 
   
  system("PAUSE");   
  return 0; 

#include <stdio.h>
#include <stdlib.h>

/*加法*/
int Sum(int a, int b)
{
    return a + b;
}

/*減法*/
int Sub(int a, int b)
{
    return a - b;
}

/*乘法*/
int Multi(int a, int b)
{
    return a * b;
}

/*除法*/
int Division(int a, int b)
{
    return (b == 0)? 0:(a / b);
}

/*操作碼*/
typedef enum _ENOPCODE
{
    OPCODE_ADD = 0,   /*加*/
    OPCODE_SUB,       /*減*/
    OPCODE_MULTI,     /*乘*/
    OPCODE_DIVISION,  /*除*/
    OPCODE_BUTT
}enOpCode;

/*通過Switch-case語句計算*/
int GetOpResultBySwitch(int a, int b, enOpCode enOp)
{
    int iTmp = 0;
   
    switch(enOp)
    {
        case OPCODE_ADD:
             iTmp = Sum(a, b);
             break;
            
        case OPCODE_SUB:
             iTmp = Sub(a, b);
             break;     
       
        case OPCODE_MULTI:
             iTmp = Multi(a, b);
             break;
            
        case OPCODE_DIVISION:
             iTmp = Division(a, b);
             break;
        default:
             iTmp = -1;
    }
   
    return iTmp;          
}

int main(int argc, char *argv[])
{
  int iTmp = 0;
  int a = 10;
  int b = 30;

  iTmp = GetOpResultBySwitch(a, b, OPCODE_ADD);

  printf("Tmp is: %d\n", iTmp);
 
  system("PAUSE"); 
  return 0;
}
   程序看上去很清晰,但如果要擴展一下功能,就發現要增加更多的case語句,記得ansi c標准中case的最大個數是256個,暫且不論這個值到底是多少,從代碼本身來看,增加過多的case使得圈復雜度不斷上升,程序維護困難加大。

   這時就可以考慮使用驅動表的方法,同樣看一下實現,請關注GetOpResultByTable函數。


[cpp]
#include <stdio.h>  
#include <stdlib.h>  
 
/*加法*/ 
int Sum(int a, int b) 

    return a + b; 

 
/*減法*/ 
int Sub(int a, int b) 

    return a - b; 

 
/*乘法*/ 
int Multi(int a, int b) 

    return a * b; 

 
/*除法*/ 
int Division(int a, int b) 

    return (b == 0)? 0:(a / b); 

 
/*定義函數指針*/ 
typedef int (*pfFun)(int, int); 
 
/*操作碼*/ 
typedef enum _ENOPCODE 

    OPCODE_ADD = 0,   /*加*/ 
    OPCODE_SUB,       /*減*/ 
    OPCODE_MULTI,     /*乘*/ 
    OPCODE_DIVISION,  /*除*/ 
    OPCODE_BUTT 
}enOpCode; 
 
/*使用驅動表計算*/ 
int GetOpResultByTable(int a, int b, enOpCode enOp) 

    if (OPCODE_BUTT == enOp) 
    { 
       return -1; 
    } 
    pfFun pf[OPCODE_BUTT] = {Sum, Sub, Multi, Division}; 
    return pf[enOp](a, b); 
     

 
int main(int argc, char *argv[]) 

  int iTmp = 0; 
  int a = 10; 
  int b = 30; 
 
  iTmp = GetOpResultByTable(a, b, OPCODE_ADD); 
  printf("Tmp is: %d\n", iTmp); 
   
  system("PAUSE");   
  return 0; 

#include <stdio.h>
#include <stdlib.h>

/*加法*/
int Sum(int a, int b)
{
    return a + b;
}

/*減法*/
int Sub(int a, int b)
{
    return a - b;
}

/*乘法*/
int Multi(int a, int b)
{
    return a * b;
}

/*除法*/
int Division(int a, int b)
{
    return (b == 0)? 0:(a / b);
}

/*定義函數指針*/
typedef int (*pfFun)(int, int);

/*操作碼*/
typedef enum _ENOPCODE
{
    OPCODE_ADD = 0,   /*加*/
    OPCODE_SUB,       /*減*/
    OPCODE_MULTI,     /*乘*/
    OPCODE_DIVISION,  /*除*/
    OPCODE_BUTT
}enOpCode;

/*使用驅動表計算*/
int GetOpResultByTable(int a, int b, enOpCode enOp)
{
    if (OPCODE_BUTT == enOp)
    {
       return -1;
    }
    pfFun pf[OPCODE_BUTT] = {Sum, Sub, Multi, Division};
    return pf[enOp](a, b);
   
}

int main(int argc, char *argv[])
{
  int iTmp = 0;
  int a = 10;
  int b = 30;

  iTmp = GetOpResultByTable(a, b, OPCODE_ADD);
  printf("Tmp is: %d\n", iTmp);
 
  system("PAUSE"); 
  return 0;
}
   實現相當簡單,如果增加其他操作等功能,僅需要擴展pf數組,程序圈復雜度不會隨功能增多而增加,從而也降低了維護成本。

 


附:圈復雜度概念,來自百度百科:http://baike.baidu.com/view/3553594.htm


圈復雜度
概念
  所謂圈復雜度是一種代碼復雜度的衡量標准,中文名稱叫做圈復雜度。在軟件測試的概念裡,圈復雜度“用來衡量一個模塊判定結構的復雜程度,數量上表現為獨立現行路徑條數,即合理的預防錯誤所需測試的最少路徑條數,圈復雜度大說明程序代碼可能質量低且難於測試和維護,根據經驗,程序的可能錯誤和高的圈復雜度有著很大關系”。

 

計算
  它的計算方法很簡單,計算公式為:V(G)=e-n+2。其中,e表示控制流圖中邊的數量,n表示控制流圖中節點的數量。其實,圈復雜度的計算還有更直觀的方法,因為圈復雜度所反映的是“判定條件”的數量,所以圈復雜度實際上就是等於判定節點的數量再加上1,也即控制流圖的區域數,對應的計算公式為:V(G)=區域數=判定節點數+1。   h r0U&T#@-g o,J o114943 對於多分支的CASE結構或IF-ELSEIF-ELSE結構,統計判定節點的個數時需要特別注意一點,要求必須統計全部實際的判定節點數,也即每個ELSEIF語句,以及每個CASE語句,都應該算為一個判定節點。判定節點在模塊的控制流圖中很容易被識別出來,所以,針對程序的控制流圖計算圈復雜度V(G)時,最好還是采用第一個公式,也即V(G)=e-n+2;而針對模塊的控制流圖時,可以直接統計判定節點數,這樣更為簡單。

 

 

摘自 Socrates的專欄

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved