C/C++深入函数指针

       下面通过一个示例演示如何更好使用函数指针。首先,如下是一些函数的原型,它们的特征标和返回类型相同:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
       这些函数的特征标看似不同,但实际上相同。首先,前面说过,在函数原型中,参数列表const double ar [ ]与const double * ar的含义完全相同。其次,在函数原型中,可以省略标识符。因此,const double ar [ ]可简化为const double [ ],而const double * ar可简化为const double *。因此,上述所有函数特征标的含义都相同。另一方面,函数定义必须提供标识符,因此需要使用const double ar [ ]或const double * ar。
        接下来,假设要声明一个指针,它可指向这三个函数之一。假定该指针名为p1,则只需将目标函数原型中的函数名替换为(*p1):watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
       可在声明的同时进行初始化:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
      使用C++11的自动类型推断功能时,代码要简单得多:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
       现在来看下面的语句:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
       根据前面介绍的知识可知,(*p1) (av, 3)和p2(av, 3)都调用指向的函数(这里为f1()和f2()),并将av和3作为参数。因此,显示的是这两个函数的返回值。返回值的类型为const double *(即double值的地址),因此在每条cout语句中,前半部分显示的都是一个double值的地址。为查看存储在这些地址处的实际值,需要将运算符*应用于这些地址,如表达式*(*p1)(av,3)和*p2(av,3)所示。
        由于需要使用三个函数,如果有一个函数指针数组将很方便。这样,将可使用for循环通过指针依次调用每个函数。如何声明这样的数组呢?显然,这种声明应类似于单个函数指针的声明,但必须在某个地方加上[3],以指出这是一个包含三个函数指针的数组。问题是在什么地方加上[3],答案如下(包含初始化):

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
为何将[3]放在这个地方呢?pa是一个包含三个元素的数组,而要声明这样的数组,首先需要使用pa[3]。该声明的其他部分指出了数组包含的元素是什么样的。运算符[]的优先级高于*,因此*pa[3]表明pa是一个包含三个指针的数组。上述声明的其他部分指出了每个指针指向的是什么:特征标为const double *, int,且返回类型为const double *的函数。因此,pa是一个包含三个指针的数组,其中每个指针都指向这样的函数,即将const double *和int作为参数,并返回一个const double *。
这里能否使用auto呢?不能。自动类型推断只能用于单值初始化,而不能用于初始化列表。但声明数组pa后,声明同样类型的数组就很简单了:

0a80321f083b4fab8a058c84fd18c576.png
       数组名是指向第一个元素的指针,因此pa和pb都是指向函数指针的指针。
如何使用它们来调用函数呢?pa[i]和pb[i]都表示数组中的指针,因此可将任何一种函数调用表示法用于它们:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_17,color_FFFFFF,t_70,g_se,x_16
       要获得指向的double值,可使用运算符*: watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_13,color_FFFFFF,t_70,g_se,x_16

       可做的另一件事是创建指向整个数组的指针。由于数组名pa是指向函数指针的指针,因此指向该数组的指针将是一个指向“指向数组指针的指针”的指针。这听起来有点恐怖,但由于可使用单个值对其进行初始化,因此可使用auto:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
       如果喜欢自己声明,该如何办呢?显然,这种声明应类似于pa的声明,但由于增加了一层间接,因此需要在某个地方添加一个*。具体地说,如果这个指针名为pd,则需要指出它是一个指针,而不是数组。这意味着声明的核心部分应为(*pd)[3],其中的括号让标识符pd与*先结合:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16
        换句话说,pd是一个指针,它指向一个包含三个元素的数组。这些元素是什么呢?由pa的声明的其他部分描述,结果如下: watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p6t56CB,size_20,color_FFFFFF,t_70,g_se,x_16

       要调用函数,需认识到这样一点:既然pd指向数组,那么*pd就是数组,而(*pd)[i]是数组中的元素,即函数指针。因此,较简单的函数调用是(*pd)i,而*(*pd)i是返回的指针指向的值。也可以使用第二种使用指针调用函数的语法:使用(*(*pd)[i])(av,3)来调用函数,而*(*(*pd)[i])(av,3)是指向的double值。
       请注意pa(它是数组名,表示地址)和&pa之间的差别。正如您在本书前面看到的,在大多数情况下,pa都是数组第一个元素的地址,即&pa[0]。因此,它是单个指针的地址。但&pa是整个数组(即三个指针块)的地址。从数字上说,pa和&pa的值相同,但它们的类型不同。一种差别是,pa+1为数组中下一个元素的地址,而&pa+1为数组pa后面一个12字节内存块的地址(这里假定地址为4字节)。另一个差别是,要得到第一个元素的值,只需对pa解除一次引用,但需要对&pa解除两次引用:

18d28b90da004a58b71477176366ab8b.png

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小枭码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值