什么是函数指针?
在程序运行中,函数代码是程序的算法指令部分,它们和数组一样也占用存储空间,都有相应的地址。可以使用指针变量指向数组的首地址,也可以使用指针变量指向函数代码的首地址,指向函数代码首地址的指针变量称为函数指针。
以上内容是截取百度某用户的文字,根据他所描述,我们不难翻译为以下文字:
数组有内存地址,所以就有了数组指针或者指针数组,那么,函数在内存中也有与其对应的内存地址,所以当我们定义一个指针变量p和函数test,令p指向test,那么次指针变量p即为函数指针
那我们知道概念后,怎么去定义一个函数指针呢?
函数类型 (*指针变量名)(形参列表) = 函数名1;
从上面的定义中,我们不难看出函数指针并不复杂,接下来代码演示一下,我们就知道了
#define _CRT_SCURE_NO_WARINGS 1
#include<stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 1;
int b = 2;
int(*p)(int ,int ) = &Add;
//这里*p,因为p指向函数地址,所以,*进行解引用,所以,得到的就是add函数名,也就函数本身
//所以(*p)(3, 5) = add(3,5)
int result = (*p)(3, 5);
printf("%d\n", result);
return 0;
}
运行结果如下:
接下来我们简单的解析这个函数指针
首先我们定义了两个变量a和b,并且为他们赋值1和2
紧接着,我们有了以下函数指针定义
int(*p)(int ,int ) = &Add;
这个程序难点就是这个函数指针,我们来简单的 分析一下
首先,根据优先级情况,在这条语句中,我们不难发现,()的优先级是最高的,但是这里有两个括号,那么先执行哪一个?
非常简单,也很明显,执行(*p)这个括号,因为括号是左结合性,所以,这个语句,首先定义了指针变量p,然后才去执行第二个括号(int ,int ),那么,我们能够看出来,在这个括号中,有两个int,很显然,这是数据类型,那么说明这个括号是函数,只是,形参名省略了, 所以,我们得到了以下文字
此语句定义了一个指针变量p,并且这个指针变量p指向一个函数(这个函数有两个形参,且都为int类型),那么,问题来了,这个函数返回类型是什么样的数据呢?int?double?float?char?结构体变量?指针变量?.........
于是,“函数类型”的作用就体现出来了。我想,我说到这里,大家都明白了这个
“数据类型”有什么用了吧。
没错,正如你所想
这个“数据类型”的作用就是用来声明这个函数是返回一个什么样类型的数据。
那么,文章写到这里,其实最难得部分就己经接近尾声了,
那么,问题超多的小明就又问了,“这个=&tets”有啥用?
其实,大家动脑子想一想就知道了,既然我定义了一个指针变量p,那么说明,我们必须要为p指针赋值一个地址,那么,这个地址从哪来?
很显然,就是从“=函数名”这部分来
我们上一篇文章就讲到过这么个结论
函数名 = &函数名
数组名 != &数组名
那么,既然我要为指针变量p赋值一个地址,那么,我传入某一个函数的函数名和&函数名,不就是将这个函数的首地址传给了指针变量p吗?,所以,我们就有了以下语句:
int(*p)(int ,int ) = &Add;
现在我们就可以完美的解释,完整的写成以下文字:
定义了一个指针变量p,次指针变量p指向一个函数,且这个函数返回值为int类型的函数指针。
那么,写到这,我们成功的完成函数指针的定义,祝贺你,已经成功迈入指针进阶这个世界的第一步!!!
接下里,让我们迈出第二步,即函数指针的调用.
如何调用函数指针?
还是上面那个程序,我们来看一下这个程序是如何调用的。
int result = (*p)(3, 5);
这条语句最简单的地方我想一定是int result,这只是一个变量定义而已,现在请将我们的目光看向(*p)(3,5),还是老样子,语句中出现括号,所以,先执行括号,但是同时出现两个,所以根据左结合性,我们即可发现,此语句首先执行“*p”,非常明显,这是指针基础的内容,只是简单地解引用而已,
注意!,这里*p的*是解引用,而上面的int(*p)(int ,int ) = &Add;中的*p中的*是定义指针变量,如何区别*是解引用还是定义指针变量,我在上一篇文章中已经做了阐述,若不懂,可以去看看。
所以,我们不难发现*p是解引用,而且p是指向test函数的首地址,那么,对它进行解引用,那么不就是test么?所以,*p = test,所以上面调用语句,就可以等价写成
test(3,5);
当我们写成这种形式的时候,我们居然发现了一个神奇的现象,test(3,5)这种函数调用形式居然是我们在C语言基础课程中“函数”这一章节的最基础,最简单的调用方式。
所以,其实,在我们C语言中很多东西它在底层,编译器中都是转换成指针形式的,为什么?
这是因为,指针的执行效率是非常非常非常高的,可以大大加大编译器,代码的运行效率!!!
这也就是为什么当大家去学习“函数”这一章的时候,会出现非常多的同学学不明白,有的同学就对这种调用方式有疑问“test(3,5)”为什么可以这么写?我想,很多老师都不会对这个进行解释,原因就是解释它的话,要牵扯到C语言指针进阶的内容
说了一些废话后,让我们整理一下函数指针调用方式的方法,截止到目前,我们知道了两种函数调用方式,即:
test(3,5);//最简单,也是最基础
(*p)(3,5);//只有当p指向test函数或者别的函数时,此语句成立,且(*p)左右两边括号万万不可省去,原因一会阐述。
接下来,让我们在学习一个函数指针调用方式,即:
int result = p(3, 5);
没错,你没看错,p左边的*可以省去,
注意,只有在函数指针中,且指针变量指向函数,可以省去,只有这一种情况,在别的情况不可省去
这是因为,p既然指向tets首地址,那么就算我给它+1或者-1都会使程序报错,因为此时出现指针变量+整数,这是C语言当中不允许的,报错如下(VS2022)
所以,讲到现在,我想,你已经知道有三种方法可以调用函数即:
test(3,5);//最简单,也是最基础
(*p)(3,5);//只有当p指向test函数或者别的函数时,此语句成立,且(*p)左右两边括号万万不可省去,原因一会阐述。
p(3,5);//只有p指向某个函数时,才可以省去*
那么,写到这里,其实就把我的程序大体意思写完了,完整文档:
#define _CRT_SCURE_NO_WARINGS 1
#include<stdio.h>
/*
注意:
数组名 != &数组名
函数名 == &函数名
*/
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 1;
int b = 2;
int(*p)(int ,int ) = &Add;
//第一种函数调用
//这里*p,因为p指向函数地址,所以,*进行解引用,所以,得到的就是add函数名,也就函数本身
//所以(*p)(3, 5) = add(3,5)
int result = (*p)(3, 5);
printf("%d\n", result);
//第二种函数调用
int(*p)(int ,int ) = Add;
//因为这里函数名,代表的是函数地址,而p指向这个地址,所以,p的值与Add相同,
//又因为*p,即为Add函数,所以,p与Add等价,所以,有以下表达式p(3,5),所以,这里的*只是解引用,意义不是很大。
int result2 = p(3, 5);
printf("%d\n", result2);
//第三种函数调用
int result3 = Add(3, 5);
printf("%d\n", result3);
return 0;
}
,那么,这就是函数指针,是不是很简单?很好玩?很有意思?
问题:
为什么int (*p)(int,int);中指针变量p括号不可省去?
解:
当我们去掉它两边的括号,即
int *p(int,int);
还是老样子,语句中出现括号,先执行括号,编译器一看括号内是两个形参,它就知道了这是用户定义了一个函数,那么p就会与()结合,形参函数,
注意,此时p就不是指针变量了,而是函数!!!
那么,这个函数的返回类型是什么?是 int *!!!
所以,一旦这样写,意思就变成了:
定义一个函数p,且返回类型是int *//int *是一个指向整数的指针,所以,它可以接收别的函数返回的整数地址,从而指向它。
而不是
定义一个指针变量p,且返回类型是int!!!
所以,我们可以发现,少一个符号,意思和功能居然相差千里。
我相信,如果你懂了这个,那么(*p)(3,5); 你也能懂!
那么,我们
将int *p(int,int);这种形式定义为 指针函数
将int (*p)(int,int);这种形式定义为 函数指针
总结:
在这个文章我们了解并掌握了C语言指针进阶----函数指针
并且我们也知道如何调用函数指针(三种方式)
test(3,5);//最简单,也是最基础
(*p)(3,5);//只有当p指向test函数或者别的函数时,此语句成立,且(*p)左右两边括号万万不可省去,原因一会阐述。
p(3,5);//只有p指向某个函数时,才可以省去*
并解释了“test(3,5);”在编译器的形式。
最后,我们知道了函数指针与指针函数的区别。
再次感谢您的观看,如果您觉得不错,清点赞,收藏,评论,让更多人看到,以此帮助到更多小白
数组与函数指针又会擦出怎样的爱恨情仇呢?小明想写一个计算器程序,但老师要求代码越少越好,又该怎么做呢?敬请期待下一篇内容----C语言指针进阶-----函数指针数组