函数指针
函数指针,顾名思义,这里 函数为修饰词,用于修饰 核心词:指针。即其本质是一个指针,这个指针指向一个函数。其形式:
int (*pf)(int,int)//不理解函数指针为什么长这样?没关系,后面会详细讲解
这里拓展一下另一个容易和函数指针混淆的概念:指针函数:
顾名思义,这里 指针为修饰词,用于修饰 核心词:函数。即其本质是一个函数,这个函数的返回类型为 指针。其形式为:
int* pf(int,int)//这里pf为函数名,函数返回类型为int*,即返回类型为整型指针
函数指针 ====即存放函数地址的指针
&函数名 ====取到的就是函数的地址
函数名 ====存放的依旧是函数的地址
即 函数名 与 &函数名 是等价的
如下方示例:
#include <stdio.h>
int Add(int x,int y)
{
return x + y;
}
int main()
{
printf("%p\n",&Add);
printf("%p\n",Add);
return 0;
}
输出结果:
00007ff776d814a4
00007ff776d814a4
二者输出的结果一致,均为add函数的地址
函数指针的变量类型
&Add
即可取出函数的地址,此时如果想要创建一个变量pf
接收该地址(此时pf
即为 函数指针),那么该 变量(即pf
) 的 类型 是什么呢?
这个变量pf
,即是一个函数指针类型的变量。
关于函数指针类型该如何表示,可以套用以往学的知识:
我们知道,一个 类型 的 指针类型,即在该类型合适的位置加上*
。
即:
类型 | 指针变量类型 | 指针 例(含变量名 p) |
---|---|---|
int | int* | int* p |
int* | int** | int** p |
int[5] | int(*)[5] | int(*p)[5] |
int[2][3] | int(*)[2][3] | int(*p)[2][3] |
int*[2][3] | int* (*)[2][3] | int* (*p)[2][3] |
对于数组类型,再补充一点,所有多维数组都可以看成是一维数组的嵌套。
如int[2][3][4]
,其包括了2个元素,每个元素数据类型是int[3][4]
。
而int[3][4]
其中包括了3个元素,每个元素数据类型为int[4]
。
而int[4]
其中包括4个元素,每个元素数据类型为int
。
同样的,对于int*[2][3]
,其包含了2个元素,每个元素变量类型为int*[3]
。
int*[3]
其中包括3个元素,每个元素数据类型为int*
。
……
因此,对于函数指针类型,我们可以有如下推理:
我们知道,在定义一个变量时,去掉变量名,剩下的即该变量的类型:
如 int a
;去掉变量名a
,剩下的即该变量的类型 int
。
因此以函数int Add(int x,int y)
为例:
去掉函数名Add
,以及形参变量名x,y
,剩下的int (int ,int )
即为该函数变量(Add)的类型。
因此知道函数类型(即int (int ,int )
)后,该 函数的 指针类型 即在该 函数类型 合适的位置加上*
。
即:
类型 | 指针变量类型 | 指针 例(含变量名) |
---|---|---|
int (int ,int ) | int(*) (int , int ) | int(*pf) (int , int ) |
因此在最开始的例子中,可以以如下方式创建一个函数指针类型的变量pf
来接收:
int (*pf)(int,int) = &Add;//显式地取函数地址
同样的,上文有提到 函数名 和 &函数名 是等价的,因此也可以写成:
int (*pf)(int,int) = Add;//隐式地使用函数名作为地址
(这两种写法的区别仅在于可读性方面)
因此在使用时,可以:
std::cout<<(*pf)(3,4)<<std::endl;
std::cout<<pf(3,4)<<std::endl;
输出结果一致。
(但是要注意,这里输出时,使用的pf(3,4)
是 (*pf)(3,4)
的语法糖。C/C++语言编译器会识别出 pf
是一个函数指针,并自动将其视为解引用操作,因此不需要显式地写出(*pf)
。
(*pf)(3,4)
明确地显示了解引用操作,有助于提高代码的可读性。然而大多数情况下,使用pf(3 ,4 )
就足够了,因为它更简洁一些。)
第一次写博客,仍在学习C/C++中, 如有概念上的错误,恳请斧正!