函数指针
函数指针初始化及使用函数指针调用函数
最常见的两个用途是转换表和作为参数传递给另外一个函数。
简单声明一个函数指针并不意味着可以马上使用,和其他指针一样,对函数指针执行间接访问之前必须把它初始化为指向某个函数。初始化方式:
int f(int);
int (*pf)(int)=&f;
这里的&是可选的,因为函数名被使用时总是由编译器将它转换成函数指针,&操作符只是显示地说明了编译器的隐式执行任务。
函数指针被初始化之后可以采用三种方式调用函数:
int ans;
ans=f(25);//使用函数名调用,实际执行时函数名会转换成函数指针,该指针指定了函数在内存中的位置。
ans=(*pf)(25);//先把函数指针转换成函数名,这个转换并不是真正需要的,跟上一条的方式并没有什么不同。
ans=pf(25);//直接使用函数指针调用函数。
回调函数
我们先看看下面这段程序:
int comp(int a,int b)
{
if(a==b)return 0;
else return 1;
}
完成的功能实在是简单,就是比较一下两个数是否一致。但是你是否发现这个只能比较int型的数据,要是比较char的呢,那必须得重新写一个函数,比较float也得重新写一个,这样是不是有点麻烦,并且易用性也不好,换一个类型就要换一个函数。那么我们考虑是否在comp的时候不传具体的类型呢,因为我们根本也不知道要传什么类型给comp。解决难题的办法就是把参数类型声明为void *,表示"一个指向未知类型的指针"。然后加一个回调函数作为参数,这样在按照不同的类型编写不同的回调函数,在上层就保证了comp函数的易用性。下面请看改写的函数:
int comp(void *a,void *b, int (*compare)(void const *,void const *))
{
if(compare(a,b))return 1;
else return 0;
}
int compare_int(void const *a,void const *b)
{
if(*(int*)a==*(int*)b) return 0;
else return 1;
}
int compare_char(void const *a,void const *b)
{
if(*(char*)a==*(char*)b) return 0;
else return 1;
}
在主函数中可以这样调用:
int a=2;int b=2;
comp(&a,&b,compare_int);
char c='d';char d='d';
comp(&d,&c,compare_char);
转移表
我们下面看个例子,在一个计算器的例子中,有如下一些语句:
switch(oper)
case ADD:
result=add(op1,op2);
break;
case SUB:
result=sub(op1,op2);
break;
case MUL:
result=mul(op1,op2);
break;
case DIV:
result=div(op1,op2);
break;
...
对于一个功能复杂的计算器,那么switch语句将非常长。为了使用switch语句,表示操作符的代码必须是整数。如果它们是从零开始连续的整数,我们可以使用转换表来完成这个任务。转换表就是一个函数指针数组。
创建一个转换表需要两个步骤。首先,声明并初始化一个函数指针数组。唯一需要留心之处就是确保这些函数的原形出现在这个数组的声明之前。
double add(double,double);
double sub(double,double);
double mul(double,double);
...
double (*oper_func[])(double,double)={add,sub,mul,div,...};
初始化列表中各个函数名的正确顺序取决于程序中用于表示每个操作符的整型代码。这个例子假定ADD是0,SUB是1,MUL是3...
第2个步骤是用下面语句替换前面整条switch语句:
result=oper_func[oper](op1,op2);
oper从数组中选择正确的函数指针,而函数调用操作符将执行这个函数。
注意:
在转换表中,越界下标引用就像在其它任何数组中一样的不合法。
命令行参数
main()函数具有两个形参,第一个参数int argc,表示命令行参数的个数。第二个参数char *argv[],是一个指向命令行参数的指针数组,每一参数又都是以空字符(null) 结尾的字符串。第一个字符串,亦即argv[0]指向的(通常)是该程序的名称。argv中的指针列表以NULL指针结尾(即argv[argc]为NULL)。

浙公网安备 33010602011771号