理解了C中的声明和指针的话题后再来看函数指针的用法就很容易了。
C中函数指针主要有两个用途:
1.作为参数传递给另外一个函数(即作为回调函数)
2.转换表(jump table)
下面分别来介绍作为回调函数的用法和作为转换表的用法
1.回调函数
在链表的查找中使查找函数与类型无关
/*在一个单链表中查找一个指定值的函数。它的参数是一个指向链表第一个节点的指针
* 一个指向我们需要查找的值的指针和一个函数指针,它所指向的函数用于比较存储于链表中的类型的值*/
#include <stdio.h>
#include <node.h>
Node * search_list(Node *node,void const *value,int (*compare)(void const *,void const *)){
while(node!=NULL){
if(compare(&node->value,value)==0)
break;
node=node->link;
}
return node;
}
然后编写比较函数:
int compare_ints(void const *a,void const *b){
if(*(int *)a==*(int *)b)
return 0;
else
return 1;
}
最后这样调用即可:
desired_node=search_list(root,&desired_value,compare_ints);
2.转移表
创建转移表的两个步骤:首先,声明并初始化一个函数指针数组。唯一需要留心之处就是确保这个函数的原型出现在这个数组的声明之前。
double add(double,double);
double sub(double,double)
...
double (*oper_func[])(double,double);
第二步就是使用oper_func[oper](op1,op2)代替switch语句.
下面是一个从标准输入中读取一些字符,并根据下面的分类计算各类字符所占的百分比的程序:
控制字符 iscntrl
空白字符 isspace
数字 isdigit
小写字母 islower
大写字母 isupper
标点符号 ispunct
不可打印字符isprint为可打印字符
上面这些字符的分类在ctype.h中都有对应的函数
不使用if语句而使用转换表的方法如下:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
/*计算从标准输入的积累字符的百分比*/
/*定义一个函数,判断一个字符是否为可打印字符。这可以消除下面代码中的这类
* 特殊的情况*/
int is_not_print(int ch){
return !isprint(ch);
}
/*用于区别每种类型的分类函数的跳转表*/
static int(*test_func[])(int)={
iscntrl,
isspace,
isdigit,
islower,
isupper,
ispunct,
is_not_print
};
#define N_CATEGORIES \
(sizeof(test_func)/sizeof(test_func[0]))
/*每种字符的名字*/
char * label[]={
"control",
"whitespace",
"digit",
"lower case",
"upper case",
"punctuation",
"non-printable"
};
/*目前见到的每种类型的字符数以及字符的总量*/
int count[N_CATEGORIES];
int total;
int main(){
int ch;
int category;
/*读取和处理每个字符*/
while((ch=getchar())!=EOF){
total+=1;
/*为这个字符调用每个测试函数,如果结果为真,增加对于计数器的值*/
for(category=0;category<N_CATEGORIES;category++){
if(test_func[category](ch))
count[category]++;
}
}
/*打印结果*/
if(total==0)
printf("No characters in the input!\n");
else{
printf("total characters:%d\n",total);
for(category=0;category<N_CATEGORIES;category++){
printf("%3.0f%% %s characters\n",count[category]*100.0/total,label[category]);
}
}
return 0;
}
可以很明显的看出使用转换表的好处,代码简短了很多,也很清晰。
下面是测试结果:
添加一个小的知识点,就是EOF,在命令行下新输入一行,按下ctrl+z组合键,再点击回车,就是EOF