个人主页:欢迎大家光临——>沙漠下的胡杨
各位大帅哥,大漂亮
如果觉得文章对自己有帮
可以一键三连支持博主
你的每一分关心都是我坚持的动力
☄: 本期重点:函数指针相关内容
希望大家每天都心情愉悦的学习工作。
目录
函数为什么要有地址?
首先,大家对变量有地址已经很清楚啦,那么函数有没有地址呢?或者函数的地址是干嘛呢?下面看个示意图分析下:
首先函数也是代码的一部分,就意味着函数也要被读入CPU,那么为了方便CPU读取就产生了函数的地址的说法。
函数地址怎么表示?
首先函数的地址有两种表示方式:
1.直接的函数名 2.取地址函数名:
这两个都代表函数的地址。
我们来通过汇编进一步观察下:
这里更能看出来函数是有地址的,地址就会被CPU访问到。
函数指针
上面说过了,函数是有地址的,那么怎么存放函数地址呢?用什么来接收呢?
当然用函数指针接收了,下面是函数指针的形式:
void Fan() { printf("胡杨树下\n"); } int main() { Fan(); void(*p)() = Fan; return 0; }
通过调试可以看出类型:
这里的Fan也可以使用&Fan。
那么怎么使用函数指针调用函数
如图所示,这是函数调用的示意图,首先对函数指针变量进行解引用,然后在后面加上参数,就可以完成使用函数指针调用函数的目的。
函数调用的方法总结:
void Test(int a) { static i = 0; printf("第%d次调用,a = %d\n",++i,a); } int main() { int a = 11223344; Test(a); void(*p)(int) = &Test; void(*q)(a) = Test; q(a); (*p)(a); return 0; }
第一次是正常调用的情况,打印a。
第二次是通过 q 函数指针调用的,初始化时放入&Test进行初始化,
第三次是通过 p 函数指针调用的,初始化放入Test进行初始化。
这里可以看出,传参数名和类型名都是可以的。
推荐使用函数名直接当地址,不用&地址数组名,在函数指针的初始化中也用函数名,在函数指针用函数时使用 p(),也不用解引用的形式。
void Test(int a) { static i = 0; printf("第%d次调用,a = %d\n",++i,a); } int main() { int a = 11223344; Test(a); //void(*p)(int) = &Test;//不推荐 void(*q)(a) = Test; q(a); //(*p)(a);//不推荐 return 0; }
函数指针的调用实例,作为回调函数使用
函数指针,使用范围有限,举一个作为回调函数的例子理解下:
void Scd() { printf("输入有效\n"); } void Fan(void(*p)()) { int a = 0; scanf("%d", &a); if (a != 0) { p(); } } int main() { Fan(Scd); return 0; }
这个函数的逻辑就是通过调用Fan函数,传参为一个函数指针,输入一个数,如果不为0,则调用Scd函数,打印“输入有效”。
复杂的函数指针
首先我们看一个经典的例子:
(*(void(*)())0)();
首先我们应该从向外的分析,首先 void(*) () 是函数指针(函数指针)0是强制类型转换,然后(*(函数指针)0)()这又是一个函数指针。
所以整体是把 0 地址转化为函数指针,在进行调用。
那么还有更复杂的函数指针数组和函数指针数组的指针就不在解释了,但是理解方法一样,还和函数指针和指针数组的知识有关。
另外分析任何复杂指针或数组时,把变量名去掉,就是类型,然后进行分析。
下期预告:
下期讲解动态开辟相关的知识
下期更精彩~!~!~!