前面我们讲过用指针变量作为函数参数。这里讲指向函数的指针变量和返回指针的函数。
1、指向函数的指针变量
跟变量一样,函数也会存储在内存空间中,函数的内存空间有一个起始地址,每次调用函数时就从该入口地址开始执行函数代码。
既然函数有地址,我们就可以定义一个指向该函数的指针变量。比如,我们可以定义这样的指针变量:
int (*pfun)();
从右往左读,先是(),表示这是一个函数;然后是(*pfun),表示一个指针指向这个函数;最后是void,表示这个函数返回int。
如果我们把指针的挂号去掉:
int *pfun();
则表示一个返回int*类型的函数。
所以,定义指向函数的指针变量的形式为:
(1)类型名 (*指针变量名)(函数参数列表)
(2)typedef 类型名 (*指针变量名)(函数参数列表)
这里必须注意,一个函数的指针变量只能指向定义时指定的类型的函数。比如int (*p)()表示函数指针变量p可以指向返回值是int的无参数函数。
2、函数指针的使用
我们来看一个使用函数指针的例子:
int max(int a, int b) {
if (a > b) {
return a;
}
else {
return b;
}
}
int main()
{
int a = 3;
int b = 7;
int (*p)(int, int);
p = max;
int ret = p(3, 7);
//也可以这么调用
//int ret = (*p)(3, 7);
printf(" max = %d\n", ret);
return 0;
}
使用函数指针的注意事项:
(1)函数指针只能指向定义时指定的函数类型。比如int (*p)(int, int)就只能指向返回值是int,形参列表是2个int的函数。比如int max(int a, int b); int min(int a, int b)等这样的函数都可以。
(2)函数指针变量要调用哪个函数,就让指针指向哪个函数。
比如p = max,这里形参的列表是不用写的,只要写函数名就可以了。因为函数名代表函数的入口地址,让函数指针指向这个入口地址就可以了。
(3)用函数指针变量代替函数运行,比如p(a, b)。
(4)函数指针变量不能进行算术运算,p+n, p++等都是错误的。
3、用函数的指针作函数参数
指向函数的指针可以作为函数参数,把函数的指针作为形参,这样就能够在被调用函数中使用实参函数。
有下面几种传递函数指针的方式:
(1)显式地将形参定义为指向函数的指针
void func(int nValue,int (*pf)(int,int));
(2)第二个形参为函数类型,会自动转换为指向此类函数的指针
void func(int nValue,int pf(int,int));
(3)
typedef int (*PF)(int, int);
void func(int nValue, PF pf)
例子:
int add(int i, int j) {
return i + j;
}
int sub(int i, int j) {
return i - j;
}
typedef int (*pfun)(int i, int j);
int compute(pfun fun, int i, int j) {
return fun(i, j);
}
int main()
{
int a = 3;
int b = 7;
int (*pf1)(int i, int j);
pf1 = sub;
std::cout << compute(pf1, b, a) << std::endl;
return 0;
}
4、函数指针数组
函数指针也可以存放在数组中。
假如有这么一个应用场景,系统需要根据输入的参数来选择需要执行的具体函数。
输入'+',则执行add()函数;输入'-',则执行sub()函数。
typedef int (*operation)(int i, int j);
operation ops[128] = { 0 };
ops['+'] = add;
ops['-'] = sub;
operation op1 = ops['+'];
printf(" 3 + 4 = %d\n", op1(3, 4));
operation op2 = ops['-'];
printf(" 7 - 3 = %d\n", op2(7, 3));
这里我们用'+', '-'作为数组的索引,因为char其实就是int类型,我们把数组长度定义为128,是因为ASCII共有128个字符,这样每个ASCII字符都能作为数组的索引存放。
5、返回指针值的函数
定义返回指针值的函数的形式为:
类型名 *函数名(参数列表)
返回指针时要注意这几种情况:
(1)如果返回的是函数内部局部变量的指针,那么这个指针出函数作用域时,其指向的对象已经失效。这种情况下就成了迷途指针或悬空指针。
int* invalidPointer() {
int tmp = 3;
return &tmp; //出函数后tmp对象已被释放,返回的指针成了: 迷途指针/悬空指针
}
(2)如果是在函数内部动态分配了内存的指针,记得在函数外部释放内存,避免产生内存泄漏。
int* localPointer() {
int* pi = (int*)malloc(sizeof(int));
return pi;
}