【C语言】指针进阶_函数指针_函数指针数组_指向函数指针数组的指针_回调函数_指向函数指针数组的指针用途

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

printf(“%p\n”, &test);
return 0;
}


 看一下输出结果:


![](https://img-blog.csdnimg.cn/463b761cf621407b9f59dce401f477b0.png)


**这里输出的其实就是两个地址,这两个地址是test函数的地址,那么我们如果想要把函数的地址保存起来,该怎么做?**


下面我们直接上代码:



void test()
{
printf(“hehe\n”);
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();


**代码中有两种指针地址的存放形式pfun1和pfun2,那么究竟是pfun1的使用更好,还是pfun2更胜一筹?**



> 
> **首先,能够存储地址,就要求pfun1或者pfun2是一个指针变量,那么哪一个是指针呢?**
> 
> 
> **答案是:**
> 
> 
> **pfun1可以存放。pfun1先和\*结合,说明pfun1是指针变量,指针指向的是一个函数,指向的函数无参数值,返回值为void。**
> 
> 
> **那么pfun2为什么不行?这里注意:()的优先级是高于\*的,所以pfun2先和()结合,所以pfun2表示的是一个函数,而不是一个指针,返回类型是void\*。**
> 
> 
> 


**纵有疾风起****传奇永不落幕**



### **1.2两段有趣的代码(自主探究)**


阅读两段有趣的代码:



//代码1
((void ()())0)();
//代码2
void (signal(int , void()(int)))(int);


 这两段代码在函数指针中是相对较难分析的,如果有小伙伴对这两段代码有兴趣的话,可以自主研究一下,这里就不做过多解释了,当然有问题可以和博主一起讨论,这两段代码来自**《C语言陷阱和缺陷》**,这本书还是很值得推荐的,里面的内容对初学者还是非常友好的,值得大家入手。


这里提示一下,可以对代码2进行一下简化:



typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);


## 2.函数指针数组


### 2.1函数指针数组的定义方式


数组是一个存放相同类型元素的集合,在创建数组的同时也开辟了空间。


那我们已经学习了指针数组,比如:



int arr[10];
//数组的每个元素是int


 那要把函数的地址存到一个数组中,那这个函数就叫函数指针数组,那函数指针数组该如何定义?



int (*parr1[10])();
int parr210;
int (
)() parr3[10];



> 
> **答案是:parr1**
> 
> 
> **parr1先和[ ]结合,说明parr1是数组,数组的内容是什么呢?**
> 
> 
> **是int(\*)()类型的函数指针。**
> 
> 
> 


### 2.2函数数组指针的用途:转移表


说到函数指针数组,那就要聊聊我们日常所使用的计算机了。


**计算机是如何实现的呢?下面有两种实现方式:**


#### **2.3计算机的两种实现方式**


**方式一:**



int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
do
{
printf(“\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf("
\n”);
printf(“请选择:”);
scanf(“%d”, &input);
switch (input)
{
case 1:
printf(“输入操作数:”);
scanf(“%d %d”, &x, &y);
ret = add(x, y);
printf(“ret = %d\n”, ret);
break;
case 2:
printf(“输入操作数:”);
scanf(“%d %d”, &x, &y);
ret = sub(x, y);
printf(“ret = %d\n”, ret);
break;
case 3:
printf(“输入操作数:”);
scanf(“%d %d”, &x, &y);
ret = mul(x, y);
printf(“ret = %d\n”, ret);
break;
case 4:
printf(“输入操作数:”);
scanf(“%d %d”, &x, &y);
ret = div(x, y);
printf(“ret = %d\n”, ret);
break;
case 0:
printf(“退出程序\n”);
break;
default:
printf(“选择错误\n”);
break;
}
} while (input);
return 0;
}


**方式二(使用函数指针数组实现):**



int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
int(p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
while (input)
{
printf("
\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf("
*\n");
printf(“请选择:”);
scanf(“%d”, &input);
if ((input <= 4 && input >= 1))
{
printf(“输入操作数:”);
scanf(“%d %d”, &x, &y);
ret = (*p[input])(x, y);
}
else
printf(“输入有误\n”);
printf(“ret = %d\n”, ret);
}
return 0;
}


**对比以上两种代码,代码一种有很多的代码事冗余的,但是代码二在使用函数指针数组后就解决了这种情况。**



![img](https://img-blog.csdnimg.cn/img_convert/f140f232238d795e3be7d3df945914c1.png)
![img](https://img-blog.csdnimg.cn/img_convert/f03b1b630ed4e2210247a61ea7912e4b.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

zkS-1715851444987)]
[外链图片转存中...(img-WU2sbi7W-1715851444987)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值