文章目录
神奇的函数指针
一、什么是函数指针
我们知道函数名称反映了一个函数的地址,而指针恰恰也可以用地址来赋值,那么我们可不可以把二者结合起来呢?答案是可以的,我们可以通过指针来反应函数的地址,甚至可以声明一个有着函数指针语法的函数。
举一个简单的例子
double (*pf)(int);
这就是一个函数指针的声明,当然如普通指针一样,他需要一个初始化的地址,如果不初始化,就会出一些问题,所以我们可以在声明的同时或者声明以后为他赋值。
double pam(int);
double (*pf)(int)=pam;
double (*pf1)(int);
pf1=pam;
是不是和指针十分相似,没错,函数指针其实就是一种指向函数体的开始地址的指针(通俗来说就是指向函数的指针)。
二、为什么会出现函数指针
一些人可能在刚刚了解到函数指针的时候,会觉得好多鱼,奥不是,好多余啊,函数指针有什么用啊?
事实上,函数指针是一种十分优秀的设计。
下面举例说明
double pam(int lns){
return 0.03*lns+0.0004*lns*lns;
}
double besty(int lns){
return 0.05*lns;
}
void estimate(int lines,double (*pf)(int)){
cout<<(*pf)(lines);
}
这是什么意思呢,假如我们把pam作为参数传入estimate函数,那么estimate输出的值,就会使pam函数的返回值,假如我们把besty作为参数传入,输出的值又会是besty的返回值。
看,我们通过一个简易的示例说明了,我们可以在不修改主要函数的情况下,通过传入自己编写的函数,可以起到修改主要函数行为的作用,这种设计,很有助于大型的程序开发,可以使一个函数成为其他函数的**“载体”**,提高了代码的复用。
三、深入函数指针
我们也可以声明一个包含多个函数指针的数组。
const double *(*pa[3])(const double*,int)={
f1,f2,f3};
1.补充易错
区分数组指针和指针数组
(1)首先看数组指针
int (*p)[3];
这是一个指向包含三个元素的数组的指针p。
(1)接着看指针数组
int *p[3];
这是一个包含三个指针的数组
为什么是这样呢?
因为运算符[]的优先级大于*所以不加()的话, []先和p结合,构成p[3],表示这是一个有三个元素的数组,注意了,这里仅仅说包含三个元素,而没说元素的类型,因为元素的类型声明在前面**int ***,即int指针类型。
2.auto
auto是c++11新增的自动类型推断,它也可以用于简化函数指针的声明和初始化
const double *f1(int a,int b);
auto p1=f1;
3.如何创建指向整个函数指针数组的指针
(1)使用auto
const double *(*pa[3])(const double*,int)={f1,f2,f3};
auto p1=&pa
注意,这里加了一个**&**,代表获取了整个数组的地址。
对p1解引用,——*p1就获得了数组pa,对 *p1再一次解引用,——**p1就获得了数组pa的首元素
简单的证明了一下上述,函数指针也是同样的。
(2)不使用函数指针
const double *(*(*p1)[3])(const double *,int n)=&pa;
很繁琐吧,我们从内到外剥开,最内层(*p1),p1是指向数组的指针,因为这里加了括号,上文有解释。所以( *p1)就是这个数组, *( *p1)就是数组第一个元素的值,也就是第一个函数指针。
(*p1)[i]表示数组中下标为i的函数指针。
函数调用的两种方式
(1)
(*pd)[i](av,3);
(2)
(*(*pd)[i])(av,3);
我们可以这么理解吧,函数的构成简单来说是这样的
int a(int b);
返回值类型 函数名 特征标
为什么会有两种函数调用的方式呢?他们俩各有各的道理
先看第一个,这里就是表示一个指向函数的指针,也就是函数的地址,而函数名表示的就是地址,所以可以这么写
再看第二个,对函数指针解引用了,解出了函数名,似乎也能这么写