当前位置: 首页 > news >正文

C语言指针进阶(2)

大家好,我们今天继续来分享指针进阶的内容。
在这里插入图片描述

目录

5.函数指针
6.函数指针数组
7. 指向函数指针数组的指针
8. 回调函数

5.函数指针
顾名思义函数指针里面存的就是函数的地址了。

那我们通过一段代码来理解函数指针:

#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
//&函数名 - 拿到的就是函数的地址
//函数名 - 也是函数的地址
int main()
{printf("%p\n", &Add);printf("%p\n", Add);//int (* pf)(int, int) = &Add;//pf就是一个函数指针变量的int (* pf)(int, int) = Add;int ret = pf(3, 5);int ret2 = Add(3, 5);printf("%d\n", ret);printf("%d\n", ret2);//int arr[10];//int (*pa)[10] = &arr;//pa就是数组指针变量return 0;
}

我们看到函数指针*pf,因为我们定义的函数传参传的是整形的变量,所以我们传递的参数类型也是int型的,又因为我们定义的函数也是int类型的,所以我们的指针 *p返回的类型也是int型,那么我们对于函数Add取地址和对函数名取地址和发现两个地址相同,那就说明&函数名和函数名都是函数的地址,所以我们最后用函数指针变量还是调用函数都可以打印出ret和ret2,且二者值相同。
在这里插入图片描述

相信大家对于函数指针有了深刻的理解。

6.函数指针数组
函数指针数组是存放函数指针的数组。

话不多说,直接看代码—>:

int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int main()
{int (*pf1)(int, int) = &Add;int (*pf2)(int, int) = &Sub;//数组中存放类型相同的多个元素int (* pfArr[4])(int, int) = {&Add, &Sub};//pfArr 是函数指针数组 - 存放函数指针的数组return 0;
}

在这里我们定义了两个函数,分别对他们取地址,并存入到一个数组中,这个数组我们就叫做函数指针数组,我们将函数指针和函数指针数组进行比较发现我们的函数指针数组比函数指针多了[ ]且里面定义了这个数组的大小,所以我们要设置一个函数指针数组的时候就可以多想想函数指针就可以很快的写出函数指针数组了。

  1. 回调函数
    回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个
    函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数
    的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进
    行响应。

在这里我们将会用很简单的例子来让大家更加的理解所谓的回调函数。

void menu()
{printf("****************************\n");printf("***  1. add      2. sub  ***\n");printf("***  3. mul      4. div  ***\n");printf("***  0. exit             ***\n");printf("****************************\n");
}
//+ - * / && || & | >> <<int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Add(x, y);printf("ret = %d\n", ret);break;case 2:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("请输入2个操作数:");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;
}

这里我们通过一个小程序来向大家讲述,我们这里定义了一个菜单来进行加减乘除运算,便于我们进行加减乘除运算。
1.首先我们打开程序
在这里插入图片描述
2.输入我们想要进行运算所代表的数字,我们代码块中通过swith来对这个加以控制,1代表加法运算,2代表减法运算,3代表乘法运算,4代表除法运算,0则是退出程序。我们就以加法运算为例输入1。
在这里插入图片描述
3.接着我们就得输入两个操作数,输入后我们的case1分支语句就会调用Add函数将这两个操作数传给函数,函数内通过运算返回两个数之后,在打印出来。我们以输入1和2为例。
在这里插入图片描述
4.我们结束一个运算过程之后紧接着就会让你进行下一个你想要的运算,除非输入0,否则这个程序永远都不会结束。
在这里插入图片描述
我们看到输入1就退出程序了,就结束程序了。那么问题来了如果我们要进行很多操作数的运算是不是就得一直进行程序运算呢,那么这样的过程是不是就会显得太冗杂了呢?为了提高操作的效率,那么就到了我们要讲的主体回调函数了。

我们对代码进行修改

void menu()
{printf("****************************\n");printf("***  1. add      2. sub  ***\n");printf("***  3. mul      4. div  ***\n");printf("***  0. exit             ***\n");printf("****************************\n");
}
//+ - * / && || & | >> <<int Add(int x, int y)
{return x + y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}void calc(int (*pf)(int,int))
{int x = 0;int y = 0;int ret = 0;printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}int main()
{int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:calc(Add);break;case 2:calc(Sub);break;case 3:calc(Mul);break;case 4:calc(Div);break;case 0:printf("退出计算器\n");break;default:printf("选择错误, 重新选择\n");break;}} while (input);return 0;

我们这里用了一个函数calc分装起来,通过将函数加减乘除的地址传给函数calc,在calc函数中输入的操作数将会传到我们要进行操作的函数中,通过操作后将结果返回到calc函数中在进行打印。所以我们这里的函数calc相当于一个中转站。所以我们想要进行什么运算就只要输入相应函数对应的数字就可以了。
在这里插入图片描述
我们在这里通过图片就可以很清楚的看到整个程序进行的过程。
通过今天的分享相信大家应该对指针进阶内容有了更加深刻的认识,今天的分享就到这里,谢谢大家。

http://www.lryc.cn/news/168244.html

相关文章:

  • 51 单片机 led 灯光操作
  • VSCODE 使用技巧
  • 数据库安全(Mysql,Hadoop,Redis)
  • C【动态内存管理】
  • Javase | 集合-上
  • Multitor:一款带有负载均衡功能的多Tor实例创建工具
  • AIGC专栏6——通过阿里云与AutoDL快速拉起Stable Diffusion和EasyPhoto
  • Mysql的逻辑架构、存储引擎
  • [ES6]模块
  • 物联网终端算法
  • 【面试刷题】——TCP三次握手,以及为什么要三次握手
  • 算法系列-力扣206-单链表反转
  • 网络基础-应用层协议-HTTP/HTTPS
  • problen(5)ubuntu版本问题
  • 写一篇nginx配置指南
  • rhel8防火墙firewalld操作
  • OpenCV项目实战(2)— 如何用OpenCV实现弹球动画
  • golang iris框架 + linux后端运行
  • linux shell操作- 02 常用命令及案例
  • 考研408 | 【计算机组成原理】 数据的表示和运算
  • 【小沐学NLP】AI辅助编程工具汇总
  • linux动态扩容系统盘(非lvm磁盘)
  • Gitlab仓库部署
  • Day46:项目-购物车案例
  • 【小沐学CAD】嵌入式UI开发工具:GL Studio
  • Python:Tornado框架之获取get和post的传参
  • JSON和全局异常处理
  • 骨传导耳机有害处吗、骨传导耳机真的不好用吗?
  • 第一类曲面积分:曲面微元dσ与其投影面积微元dxdy之间的关系推导
  • vue学习之Font Awesome图标