函数指针
基础知识
1. 获取函数地址
只要使用函数名,后面不跟参数即可,也就是说,如果 think()
是一个函数,那么 think
就是该函数的地址。
传递参数时一定要区分传递的是函数地址还是函数返回值
process(think) // 传递think()函数地址给process()
thought(think()) // 传递think()函数的返回值给thought()
process()
调用使得process()
函数能够在其内部调用think()
函数thought()
调用首先调用think()
函数,然后将think()
的返回值传递给thought()
函数
2. 声明函数指针
- 声明指向某种数据类型的指针时,必须指定指针指向的类型
- 同理,声明指向函数的指针时,也必须指定指针指向的函数类型
比如:
double pam(int)
对应的指针类型声明如下,(*pf)
是函数,pf
是函数指针
double (*pf)(int);
注意:括号的优先级比
*
高,因此*pf(int)
意味着pf()
是一个返回指针的函数,而(*pf)(int)
意味着pf是一个指向函数的指针
此时,可以将相应函数的地址赋给它:
pf = pam;
例:
void estimate(int lines, double (*pf)(int));
...
estimate(50, pam);
3. 使用指针来调用函数
double pam(int);
double (*pf)(int);
pf = pam;
double x = pam(4);
double y = (*pf)(5);
double z = pf(5); // 也可以
示例
double betsy(int);
double pam(int);
void estimate(int lines, double (*pf)(int));
int main(void)
{
int code;
cin >> code;
estimate(code, betsy);
estimate(code, pam);
return 0;
}
double betsy(int lns)
{
return 0.05 * lns;
}
double pam(int lns)
{
return 0.03 * lns + 0.0004 * lns * lns;
}
void estimate(int lines, double (*pf)(int));
{
cout << lines << " will take " << (*pf)(lines) << hour(s) << endl;
}
其他
const double *f1(const double ar[], int n);
const double *f2(const double [], int);
const double *f3(const double *, int);
这三个函数其实是一样的
声明指针:
const double *(*pl)(const double *, int) = f1;
// 也可以使用C++11的自动推断
auto p2 = f2;
cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl;
cout << p2 (av, 3) << ": " << p2 (av, 3) << endl;
可以创建一个函数指针数组来使用三个函数并进行调用:
const double *(*pa[3])(const double *, int) = {f1, f2, f3};
auto pb = pa;
// 等价于 const double *(**pb)(const double *, int) = pa;
// 调用函数
const double *px = pa[0](av, 3);
const double *py = (*pb[1])(av, 3);
// 获得指向的double值
double x = *pa[0](av, 3);
double y = *(*pb[1])(av, 3);
请注意 pa
(它是数组名,表示地址)和 &pa
之间的差别:
pa
是单个指针的地址,是数组第一个元素的地址,即&pa[0]
&pa
是整个数组(即三个指针块)的地址。
从数字上说,pa
和 &pa
的值相同,但它们的类型不同。
- 一种差别是,
pa+1
为数组中下一个元素的地址,而&pa+1
为数组pa
后面一个12字节内存块的地址(这里假定地址为4字节)。 - 另一个差别是,要得到第一个元素的值,只需对
pa
解除一次引用,但需要对&pa
解除两次引用
**&pa == *pa == pa[0]
使用typedef进行简化
这里采用的方法是,将别名当做标识符进行声明,并在开头使用关键字typedef
typedef const double *(*p_fun)(const double *, int);
p_fun p1 = f1;
// 一个包含3个函数指针的数组
p_fun pa[3] = {f1, f2, f3};
// 指向一个有3个函数指针的数组
p_fun (*pd)[3] = &pa;
pd
是指针*pd
是
综合示例代码
#include<iostream>
using namespace std;
const double *f1(const double ar[], int n);
const double *f2(const double[], int);
const double *f3(const double *, int);
int main()
{
double av[] = {3.14, 3.285, 12.284};
// pointer to a function
const double *(*p1)(const double *, int) = f1;
auto p2 = f2;
cout << "Using pointers to functions:" << endl;
cout << "Address Value" << endl;
cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl
<< endl;
// an array of pointers
const double *(*pa[3])(const double *, int) = {f1, f2, f3};
// a pointer to first element of pa
// const double *(**pb)(const double *, int) = pa;
auto pb = pa;
cout << "Using an array of pointers to functions: " << endl;
cout << "Address Value" << endl;
for (int i = 0; i < 3; ++i)
cout << pa[i](av, 3) << ": " << *pa[i](av, 3) << endl;
cout << "Using a pointer to a pointer to a function: " << endl;
cout << "Address Value" << endl;
for (int i = 0; i < 3; ++i)
cout << pb[i](av, 3) << ": " << *pb[i](av, 3) << endl;
cout << endl;
// const double *(*(*pc)[3])(const double *, int) = &pa;
auto pc = &pa;
cout << "Using an array of pointers to functions: " << endl;
cout << "Address Value" << endl;
cout << (*pc)[0](av, 3) << ": " << *(*pc)[0](av, 3) << endl;
// hard way to declare pd
const double *(*(*pd)[3])(const double *, int) = &pa;
// store return value in pdb
const double *pdb = (*pd)[1](av, 3);
cout << pdb << ": " << *pdb << endl;
// alternative notation
cout << (*(*pd)[2])(av, 3) << ": " << *(*(*pd)[2])(av, 3) << endl;
return 0;
}
const double *f1(const double *ar, int n)
{
return ar;
}
const double *f2(const double ar[], int n)
{
return ar + 1;
}
const double *f3(const double ar[], int n)
{
return ar + 2;
}
运行结果
Using pointers to functions:
Address Value
0xd1c57ff7d0: 3.14
Using an array of pointers to functions:
Address Value
0xd1c57ff7d0: 3.14
0xd1c57ff7d8: 3.285
0xd1c57ff7e0: 12.284
Using a pointer to a pointer to a function:
Address Value
0xd1c57ff7d0: 3.14
0xd1c57ff7d8: 3.285
0xd1c57ff7e0: 12.284
Using an array of pointers to functions:
Address Value
0xd1c57ff7d0: 3.14
0xd1c57ff7d8: 3.285
0xd1c57ff7e0: 12.284