一、什么是函数指针?
普通指针保存的是:数据的地址。函数指针保存的是:函数入口地址
例如:
void hello()
{
printf("hello\n");
}函数名 hello 本身就是函数地址。
可以:
void (*p)();
p = hello;
p();二、函数指针定义方式
语法:
返回值类型 (*指针名)(参数列表);例如:
普通函数:
int add(int a, int b)
{
return a+b;
}函数指针:
int (*p)(int,int);含义:
p指向:
返回int
参数两个int
的函数。
p = add;
int result = p(1,2);
int result2 = add(1,2); // 二者等价三、为什么需要函数指针?
核心:
实现运行时选择函数。
比如:
普通写法:
if(type == 1)
{
add();
}
else if(type == 2)
{
sub();
}如果有100种操作:
代码很难维护。
函数指针:
建立一个函数表:
func_table[type]();四、最常见场景:回调函数
例如,有一个排序函数:
void sort(int *arr, int n, int (*cmp)(int,int))
{
}cmp就是函数指针。
升序:
int ascending(int a,int b)
{
return a>b;
}降序:
int descending(int a,int b)
{
return a<b;
}调用:
sort(arr,n,ascending);sort内部:
if(cmp(a,b))
{
swap();
}这样排序逻辑可以和比较规则解耦。
五、工程里面的典型用途
1. 状态机
比如服务端响应协议:
请求类型:
#define LOGIN_REQ 1
#define QUERY_REQ 2
#define DOWNLOAD_REQ 3如果不用函数指针:
switch(type)
{
case LOGIN_REQ:
login_handler();
break;
case QUERY_REQ:
query_handler();
break;
}函数越来越多,switch越来越大。
使用函数指针可以:
typedef void (*handler)(void);
handler table[3]=
{
login_handler,
query_handler,
download_handler
};收到请求:
table[type]();这就是网络服务器常见设计。
2. 面向对象抽象
定义接口:
struct device_ops
{
int (*open)();
int (*close)();
int (*send)(char *);
};不同厂商:
broadcom_ops
marvell_ops实现不同函数。
上层调用:
ops->send(data);不用关心底层是谁。
六、typedef简化函数指针
原始:
int (*callback)(int,int);typedef:
typedef int (*callback)(int,int);以后:
callback cb;等价:
int (*cb)(int,int);七、函数指针和普通指针区别
面试回答:
八、几个容易错的地方
1. 括号不能少
错误:
int *func();表示:
一个返回int*的函数
不是函数指针。
正确:
int (*func)();表示:
一个指向函数的指针
2. 函数名和&函数名等价
例如:
p = add;等价:
p = &add;