C:函数指针数组及驱动表程序解读
2012-05-19 13:09
489 查看
上一节解读了C程序中函数指针及回调函数的写法,本节再看一下函数指针另一个较为广泛的应用-驱动表程序,在这之前,首先需要了解函数指针数组的使用,依旧通过最简单最容易理解的例子来讲解。
首先看下面这个函数指针数组的使用实例。
有了上面的概念,让我们通过另一个实例看看驱动表的使用,下面这个小程序几乎每个程序员都应该写过,一个没有考虑精度的加减乘除运算程序,如下:
程序看上去很清晰,但如果要扩展一下功能,就发现要增加更多的case语句,记得ansi c标准中case的最大个数是256个,暂且不论这个值到底是多少,从代码本身来看,增加过多的case使得圈复杂度不断上升,程序维护困难加大。
这时就可以考虑使用驱动表的方法,同样看一下实现,请关注GetOpResultByTable函数。
附:圈复杂度概念,来自百度百科: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;而针对模块的控制流图时,可以直接统计判定节点数,这样更为简单。
首先看下面这个函数指针数组的使用实例。
#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; }运行一下:
Tmp is: 30 Tmp is: 10 请按任意键继续. . .
有了上面的概念,让我们通过另一个实例看看驱动表的使用,下面这个小程序几乎每个程序员都应该写过,一个没有考虑精度的加减乘除运算程序,如下:
#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函数。
#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;而针对模块的控制流图时,可以直接统计判定节点数,这样更为简单。
相关文章推荐
- C:函数指针数组及驱动表程序解读
- 优化程序-- -函数指针数组及驱动表程序解读
- 使用函数指针数组驱动的菜单系统示例
- 函数指针系列之函数数组指针
- NDIS网络数据监控程序NDISMonitor(2)-----驱动与应用的中间层NdisHook
- 函数指针及函数指针数组的妙用
- 微信小程序传递参数(字符串、数组、对象)
- 改善java程序的151个建议--数组和集合
- 黑马程序员——程序函数与数组
- 十八、函数指针高级(函数指针数组)
- matlab示例程序--Motion-Based Multiple Object Tracking--卡尔曼多目标跟踪程序--解读
- 彻底了解指针数组,数组指针,以及函数指针,以及堆中的分配规则
- keil5如何调试程序并查看数组值
- 彻底了解指针数组,数组指针,以及函数指针,以及堆中的分配规则(转)
- 函数指针数组
- 编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议79~82)
- 借助 数组 实现一个关于大整数乘法的 c 程序
- 读书笔记--编写高质量代码:改善java程序的151个建议(五)数组和集合
- 深度解读 - TDD(测试驱动开发)