函数指针

基础知识

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