参考资料:《c++ primer plus》,下面是个人的一些笔记和对书上内容的理解
一.基础知识
1.获取函数的地址:函数名即为函数的地址
假设think是一个函数,那么,think即为函数的地址,而think(),加上括号,就变成了函数的返回值
这里有两个例子,
process(think); 传入的是think的地址,在执行process时会先调用think函数
而process(think());传入的是think的返回值,在调用完think后,返回值作为参数继续传入process函数中
2.声明函数指针:
与普通的指针
int * p
相比
函数的指针同样需要指定
指针指向的类型,如上面的 int
设一个函数原型为 double pam(int);
那么,函数指针只需要将函数名pam换为指针(*pf)。可以类比普通指针的声明
int p ; ->int *p ;
double pam(int); -> double (*pf)(int);
在调用该函数时,可以将(*pf)当做函数名用,比如 double x =(*pf)(5) ;
而事实上,直接使用指针也同样可以,如double y = (pf)(5);
个人倾向于 第一种,这样不容易记混.......
注意点:
1.在声明时,*pf一定要括起,
double (*pf)(int) ; 这里的pf是一个指向函数的指针
double *pf(int) ; 这里的pf是一个返回指针的函数
2.指针的赋值要注意返回类型和传入参数类型必须相同
double (*pf)(int) ; 这里的类型必须一一对应才能赋值
3.使用指针调用函数:
调用时和普通函数名调用一样,将(*pf)指针和函数名(pam)替换就可以
因此上面的程序就有三种调用方式
pam(1);使用函数名
(*pf)(2) ;使用函数指针
pf(3);
下面是对书上示例部分的理解
首先,程序声明了三个函数,它们返回值为指向double类型的指针(见上文,关于将*括起与不括起的区别)
const double *f1(const double ar[],int n);
const double *f2(const double[],int) ;
const double *f3(const double *,int);
要注意这三个声明语句实际上是等价的,在函数原型中,标识符可以省略,这意味f1和f2的等价
double ar[]代表该double类型数组首元素的首地址,因此本质上和double *也是相同的
const double *f1(const double ar[],int n)
{
return ar;
}
另外两个函数就不再写了。
double av[3] = (1111.1,2222.2,3333.4);
再来看两句函数指针的声明
const double *(*p1)(const double *,int) =f1;
auto p2 = f2;
第一句话就是将函数名替换为指针所得,注意不要混淆内外*,外面的*仅代表函数返回的是指针类型
auto为自动类型推断
输出的语句为:
Address(地址) Value(值)
cout << (*p1)(av,3) << ": "<<*(*p1)(av,3) << endl;
cout << p2(av,3) << ": "<< *p2(av,3) << endl;
函数返回值是地址,所以直接调用(*p1)得到的是地址值,具体见前文的调用函数的三种方式
这里还可以使用typedef别名
typedef const *(*p_fun)(const double * ,int );
p_fun p1 = f1 ;
将p_fun作为了一个类型名
下面是一个函数指针的数组
在这之前先列出普通的指针数组的定义,这对学习函数指针的数组也有所帮助
int *p[3]; //声明了一个数组,每个元素都是指向int的指针
int (*p)[3]; //声明了一个指针,指向三维数组
下面是函数指针的数组的定义
const double *(*pa[3])(const double *,int) = {f1,f2,f3};
先忽视外面的*,因为它只代表返回值为指针,
再比照上面的两句就好理解了
这句话代表声明一个数组,它的每个元素都为(返回double *类型的函数)的指针
因此可以将f1,f2,f3作为数组赋值
在64位电脑上,使用sizeof(pa)可以得到结果12 (sizeof(double *)为4)
在使用auto时,注意不能用
auto = {f1,f2,f3}这种语句,auto不能用于初始化列表
正确的,可以使用
auto pb = pa ;
而用别名表示可以表示为
p_fun pa[3] = {f1,f2,f3};
相比上面的数组定义更容易理解
输出语句如下:
cout << "\nUsing an array of pointers to function:\n";
cout << " Address Value\n";
for (int i = 0 ; i < 3 ; i++ )
cout << pa[i](ar,3) << ": " << *pa[i](ar,3) << endl ;
cout << "\nUsing a pointer to a pointer to a function:\n"; //这样说是因为pb由pa赋值而来,二者都为指针。
cout << " Address Value\n";
for (int i = 0 ; i < 3 ; i++)
cout << pb[i](ar,3) << ": " << *pb[i](ar,3) << endl ;
使用
cout << pa[0](ar,3) << " "<< f1(ar ,3) << endl;
可以发现二者结果相同,都为地址值。即 pa[i]与f1,f2,f3对应,相当于调用了三个函数,当然(*f1)(ar,3)也与它们的值相同
后面还有指针指向指针数组来调用函数的,个人的理解为取几次地址,就解除几次引用就好
cout << "\nUsing pointers to an array of function pointers:\n";
cout << " Address Value\n";
auto pc = &pa;
cout << (*pc)[0](ar,3) << ": " << *(*pc)[0](ar,3) << endl ;
const double *(*(*pd)[3])(const double * ,int) = &pa ;
const double *pdb = (*pd)[1](ar,3) ;
cout << pdb << ": " << *pdb << endl ;
在前文的基础上,加上取地址等来理解就可以