什么是函数指针
编译器在进行编译时,会为程序中的函数分配一段存储空间,用于存放函数,该存储空间位于内存的代码段,它的首地址就称为函数的地址,函数名表示的也是这个地址。既然是地址,我们就可以定义一个指针变量来表示它,这个指针变量就是函数指针。
指针变量如何定义?虽然同样是指向一个地址,但指向函数的指针变量同指向变量的指针变量的定义方式不同。函数指针的定义方式如下:
int(*pFunc)(int, int);
这个语句就定义了一个指向函数的指针变量 p。该函数指针:定义了一个指针变量 pFunc,该指针变量可以指向返回值类型为 int 型(最前面那个int),且有两个整型参数的函数。pFunc的类型为 int(*)(int,int)。
总结函数指针的定义方式为:
函数返回值类型 (* 指针变量名) (函数参数列表);
“函数返回值类型”表示该指针变量可以指向具有什么返回值类型的函数;“函数参数列表”表示该指针变量可以指向具有什么参数列表的函数。这个参数列表中只需要写函数的参数类型即可。
我们看到,函数指针的定义就是将“函数声明”中的“函数名”改成“(*指针变量名)”。但是这里需要注意的是:“(*指针变量名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个函数声明了,即声明了一个返回值类型为指针型的函数。
需要注意,函数指针变量没有 ++ 和 -- 运算。
如何用函数指针调用函数
举一个例子:
int Func(int x); int (*pFunc)(int x); pFunc = Func; /*将Func函数的首地址赋给函数指针*/
赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的首地址,因此可以直接进行赋值操作,这样指针变量 pFunc就指向函数 Func() 的首地址了。
通过如下一个程序,来进一步理解函数指针的用法:
# include <stdio.h>
int Max(int x, int y)
{
return x > y ? x : y;
}
int main(void)
{
int(*p)(int, int); // 定义一个函数指针
int a, b, c;
p = Max; // 把函数Max赋给指针变量p, 使p指向Max函数
printf("please enter a and b:");
scanf("%d%d", &a, &b);
c = (*p)(a, b); // 通过函数指针调用Max函数, 或c = p(a, b);
printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
return 0;
}
运行结果:
please enter a and b:3 4
a = 3
b = 4
max = 4
使用中需要注意的两点:
(1)用函数指针承接一个不带参数的函数,那么其含义为初始化,此时应该再执行函数指针才能得到所求结果。
(2)用函数指针承接带参数的函数,其含义为承接其返回值,返回值理论上也应该是一函数地址。
如下程序:
函数执行结果为:
a = 2
b = 3
(3)函数指针作为函数参数的使用方法
这也是较为常见的一种使用场景,使用方法如下:
// 定义函数指针
typedef void (*handle_rpc)(const void *recv, void **ret, unsigned short *ret_size);
// 函数声明
void reg_rpc_proc(int type, handle_rpc callback, int log_type);
// 函数定义
void reg_rpc_proc(int type, handle_rpc callback, int log_type)
{
....
g_handle_rpc_msg[type] = callback; // 传给全局函数指针数组,调用该全局变量时填入函数参数
}
// 调用带有函数指针参数的函数
reg_rpc_proc(MSG_TYPE_DISKFULL, disk_full_proc, RCVMSG_DISK);
// disk_full_proc为函数指针指向函数,函数形式和函数指针一样,定义如下
void disk_full_proc(const void *rcv_msg, void **ret_buf, uint16_t *ret_size)
{
....
}