【c++基础】函数指针

参考书籍:《c++ primer plus》。
这是一个非常容易搞晕的概念,特此记录。

基本使用

函数指针:指向函数的指针
与变量指针相同,要使用函数指针,至少需要获知以下信息:

1. 获取函数地址:函数名,不含括号

double pam(int);  //声明,又称原型:prototype

2. 声明函数指针:返回类型 (*函数名)(传参)

double (*pf)(int);  // 函数指针

注意:“ * ”和括号的位置

 (*pf)(int);//pf是指向函数的指针
 *pf(int);//pf是返回指针的函数

正确声明函数指针pf后,可以将相应函数的地址赋给它:

double pam(int);  //函数
double (*pf)(int);  // 函数指针
pf=pam;//pf指向函数pam(int)

注意:函数的特征标返回类型必须与函数指针一致
将函数指针运用于其他函数中。例如

void estimate(int line,double (*pf)(int));//声明一个函数,传参为一个int和一个函数指针
estimate(50,pam);// 传址简单

3. 使用函数指针

一个十分方便的tip:函数指针pf等价于(*pf)
这是由于(*pf)相当于函数名,而函数名本身又相当于函数的地址。
这是一个逻辑冲突的现实——也得益于c++的新特性。

double pam(int);
double (*pf)(int);
pf=pam;
double x=pam(3);
double y=(*pf)(3);//代码正在使用函数指针
double z=pf(3);

以上三种操作结果完全相同,只是内在逻辑不同。

深入探讨

复习一个知识:以下三种函数声明的特征标看似不同,实则完全相同

1、函数指针数组

const double *f1(const double arr[],int n);
const double *f2(const double [],int);
const double *f3(const double *,int);
  • const double arr[]和const double *arr含义完全相同
  • 函数原型中可以省略标识符:
    const double arr[] -> const double []
    const double *arr -> const double *

顺带一提,函数定义必须又完整的参数类型和参数名
声明一个指针pa,指向三个函数之一。直接将目标函数原型中的函数名替换为(*pa)即可

const double* (*pa)(const double arr[],int n);
//第一个"*":返回类型指向为const double的指针;
//第二个"*":声明函数指针

或者在声明时进行初始化:

const double* (*pa)(const double arr[],int n)= f1;
//类似变量指针:int * ptr = &a;

更方便的,使用auto(自动类型推断)

auto p2=f2;

现在,调用函数f1有三种方法:

f1(arr,2);// 直接的函数调用
(*p1)(arr,2); // p1指向的函数调用
p1(arr,2); // p1存储的地址=函数名的调用

以上返回值都与函数f1的返回值相同:一个指向const double类型变量的指针,即一个double值的地址。如果想查看这一指针指向的double变量的值,需要将运算符*应用于这些地址:

*f1(arr,2);// 直接的函数调用
*(*p1)(arr,2); // p1指向的函数调用
*p1(arr,2); // p1存储的地址=函数名的调用

继续考虑更复杂的情况:将多个函数指针变量存入一个数组时,这时的声明(初始化)应为:

const double* (*pa[3])(const double arr[],int n)= {f1,f2,f3};
//类似变量指针:int * ptr[3] = {&a,&b,&c};

运算符[]的优先级高于*,*pa[3]表明pa是一个包含三个指针的数组;
其他部分表明了这些指针是函数指针:指向一个返回值为const double*类型,特征标为const double *和int。
此处不能使用auto。自动类型判断只能用于单值初始化,而不能用于初始化列表。但声明函数pa后,声明同样类型的数组就很简单了:

auto pb=pa;//pb也是一个包含三个函数指针的数组

利用这个数组进行函数调用:

//pa[i]和pb[i]都表示数组中的函数指针,因此借用上文调用的方法:
const double * x = pa[0](av,3);// double地址
const double y = *(pa[0])(av,3);// double值

2、指向函数指针的指针(的指针)

借用变量数组的概念

int arr[3];//arr=&arr[0](为一个元素的地址),是指向这个数组/第一个元素的指针
const double* (*pa[3])(const double arr[],int n)= {f1,f2,f3};
auto pb=pa;//pb也是一个包含三个函数指针的数组
//类似变量指针:int * ptr[3] = {&a,&b,&c};

pa和pb即指向函数指针的指针。(开始绕了)

创建指向整个数组的指针:

auto pc=&pa;//自动类型判断

如果想挑战自己书写声明,可以这样思考

*arr[3];//包含三个指针的数组
(*arr)[3];//指向包含三个元素的数组的指针

因此我们可以得到这样的一个声明

const double* (*(*pd)[3])(const double *, int)=&pa;

考虑如何调用这个圈圈绕绕:
pd指向数组,那么*pd就是数组,(*pd[i])就是数组中的元素,为函数指针。

(*pd[0])(arr,3);//函数调用,返回double的地址
(*(*pd)[0])(arr,3);//函数调用,返回double的地址。
//*pd:指向数组的数组名,(*pd)[0]:指向数组的第一个元素(函数指针,pa)
//*(*pd)[0]:调用这个指针(*pa)

*(*pd[0])(arr,3);//函数调用,返回double的值
*(*(*pd)[0])(arr,3);//函数调用,返回double的地址
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值