C++函数指针

本文详细介绍了C++中的函数指针,包括如何获取函数地址、声明和使用函数指针,以及函数指针数组的声明和操作。通过实例展示了函数指针调用函数的多种方式,并探讨了函数名作为指针的特性。还提到了C++11的自动类型推断简化了函数指针的声明,并讨论了typedef在简化函数指针使用上的作用。
摘要由CSDN通过智能技术生成

函数指针

获取函数的地址

函数名 就是 函数地址。

int sum();

不需要&sum来获取其地址,函数的地址就是 sum

声明一个函数指针

函数原型:

double * get_address(double * a, int b);

声明一个 指向该函数 的 函数指针 funcp,并赋值:

double * (*funcp)(double * a, int b);
funcp = get_address;

声明的时候,需要指定返回值和参数列表,(*funcp)中*代表了这是一个指针,括号是必不可少的,因为()的优先级大于*:

double *  *funcp(double * a, int b);

上面声明的是一个函数 funcp,返回值类型是double **

返回指针的函数,指向函数的指针,就差一个括号


定义一个函数指针 funcp,指向该函数:

double * (*funcp)(double * a, int b) = get_address;
auto funcp1 = get_address;

C++11的自动类型推断,可以简化函数指针的声明

使用函数指针调用函数

使用2中的函数指针调用函数

double  a[2] = {1.135,2.246};
get_address(a, 1);
(*funcp)(a, 1);
funcp(a, 1);

三次调用都执行了get_address函数,(*funcp) 中的*是取值的意思,既然funcp是函数指针,那么对funcp取值就是函数呗,所以编译器对函数调用的支持有两种方式:

  1. 通过函数名
  2. 通过对函数指针取值

但是这里有个陷阱:既然函数指针指向函数的入口地址,那么对函数指针取值,不应该是函数的第一条指令吗?

编译器的动作是很复杂的,所以我个人观点,编译器在处理函数调用时,将函数指针取值后的调用——(*funcp)(a, 1),进行了特殊处理,而不同于数据指针取值的的逻辑。

funcp(a, 1)也调用get_address函数是因为:C++允许向使用函数名一样使用函数指针

我支持这种观点:函数名是指向函数的指针,那么函数指针和函数名具有同等地位

为什么不用 funcp = &get_address,因为函数名本身就是指针

funcp = get_address,获取的就是指针的值,即函数的入口地址

funcp = *get_address, 获取的是get_address函数中第一条代码的值

将函数名当函数指针用

g++编译器支持下面的代码:

double  a[2] = {1.135,2.246};
(*get_address)(a, 1);

所以函数指针和函数名在数值和功能上是一样的

但是,却不能在定义函数原型的时候使用函数指针,如编译器不支持这样定义函数:

double * get_address(double *a, int b)
{
    return a;
}
//出错,return前缺少初级表达式
double * (*haha)(double *a, int b)
{
    return a;
}

函数指针数组

进阶的用法。

声明一个函数指针数组:

double * (*pa[3])(double *a, int b) = {f1, f2, f3};

因为[]的优先级高于*,所以*pa[3]表示pa是包含三个指针的数组,指针类型由代码其他部分确定

因为pa是数组,每一个元素是函数指针,所以调用f1函数:

pa[0](a, 1);
(*pa[0])(a, 1);

获取返回的指针指向的值:

*pa[0](a, 1);
*(*pa[0])(a, 1);

指向函数指针数组

使得一个指针,指向函数指针数组:

double * (*(*pd)[3])(double *a, int b) = {f1, f2, f3};
auto pd1 = &pa;

(*pa)[3] 表示指向数组的指针,数组元素的类型由其他部分确定,在此为函数指针

自动类型推断只能用于单值初始化

调用f1函数:因为pd是指向数组的指针,则*pd为数组

(*pd)[0](a, 1);
(*(*pd)[0])(a, 1);

注意pa和&pa的差别:

  1. pa是数组名,在取值上,是数组第一个元素的地址

​ &pa是整个数组的地址

​ 所以,在取值的大小上没有差别

​ 差别在取值的方式:p[0] = *pa = **&pa

  1. 二者在运算上有差别,若内存32位地址(四字节,内存变化以字节为单位):

    pa+1,是数组第二个元素的地址,即&pa[0]+4 或&pa[1]

    而&pa+1,则是以数组大小为单位加一,则&pa[0] +12

typedef简化函数指针的使用

函数指针的使用很简单,声明很麻烦,解决办法:typedef

所以,要定义函数指针的时候可以这样简化代码:

typedef double * (*funcp)(double *a, int b);
funcp fp = get_address;

代码实践

#include <iostream>
double * get_address(double *a, int b)
{
    return a;
}
//编译器不支持
// double * (*haha)(double *a, int b)
// {
//     return a;
// }
int main(int argc, char * argv[])
{
    using namespace std;
    double a[2] = {1.135, 2.246};

    cout <<"通过函数名调用get_address函数:" <<endl;
    cout <<get_address(a, 1) <<":" <<*get_address(a, 1) <<endl;

    double *(*funcp)(double *a, int b);
    funcp = get_address;
    cout <<"通过函数指针调用get_address函数:" <<endl;
    cout <<(*funcp)(a, 1) <<":" <<*(*funcp)(a, 1) <<endl;

    cout <<"将函数指针看作函数名调用get_address函数:" <<endl;
    cout <<funcp(a, 1) <<":" <<*funcp(a, 1) <<endl;

    cout <<"将函数名看作函数指针掉用get_address函数:" <<endl;
    cout <<(*get_address)(a, 1) <<":" <<*(*get_address)(a, 1) <<endl;

    double * (*pa[3])(double *a, int b) = {get_address, get_address, get_address};
    cout <<"函数指针数组首元素:" <<endl;
    cout <<pa[0] <<"(" <<get_address <<")" <<endl;

    cout <<"使用函数指针数组元素调用get_address函数:" <<endl;
    cout <<pa[0](a, 1) <<":" <<*pa[0](a, 1) << endl;

    double * (*(*pd)[3])(double *a, int b) = &pa;
    cout << "使用指向“函数指针数组”的指针 调用get_address函数" << endl;
    cout << (*pd)[0](a, 1) << ":" << *(*pd)[0](a, 1) << endl;
    auto pd1 = &pa;
    cout << "pd1:   " << pd1 << endl;
    cout << "pd:    " << pd << endl;

    cout << "pa:    " << pa << endl;
    cout << "&pa[0]:" << &pa[0] << endl;
    cout << "&pa:   " << &pa << endl;

    cout << "pa+1   " << pa+1 << endl;//64位地址,增加8字节
    cout << "&pa+1  " << &pa+1 << endl;//增加24字节

    return 1;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值