C语言 ——函数指针变量、函数指针数组、回调函数

news2024/11/24 10:23:54

目录

一、函数指针变量

1、概念

2、函数调用

3、复杂的函数指针变量

分析:

结论:

二、typdef

普通类型重命名:

指针类型重命名:

三、函数指针数组

1、概念

2、转移表—函数指针数组的用途

模拟计算器

四、回调函数

1、概念

2、应用——模拟计算器


一、函数指针变量

1、概念

函数指针是指针,是指向函数的指针, 是存放函数地址的指针!!

对于函数而言,函数也是具有地址的,而函数指针变量就是存储函数地址的。

&函数名 和 函数名 都代表着地址的意思。

2、函数调用

 

如上所示,在使用指针变量进行函数调用的同时,我们还需要考虑传参的参数。

 而 当pf3 拿去后,只留下 int (*)(int,int)时。

我们便知道,int (*)(int,int)是pf3这个函数指针变量的类型。

3、复杂的函数指针变量

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

分析:

 

 

结论:

上面一串代码是一个函数声明。

signal 是一个函数名,它的有两个函数,分别是int类型的和返回值是void的参数是int的函数指针类型。

而signal这个函数的类型又是一个返回值是void的,参数是int类型的函数指针类型。

所以又有一种写法,但这种写法编译器是不会通过的:

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

 意思便是,返回类型为void(*)(int)的函数signal ,它的两个参数,一个参数的类型是int,另一个参数的类型是void(*)(int)

二、typdef

typedef是用来重命名的,可以将复杂的类型简单化

普通类型重命名:

typdef unsigned int  unint ;

int main()
{

    unsigned int a = 0;
    unint b = 0;
    //a和b的类型是一样的
    return 0;
}

指针类型重命名:

typdef int*  ptr ;

int main()
{

    int * p1;
    ptr p2;
    //p1和p2的类型是一样的
    return 0;
}

但是对于函数指针变量的重命名又有所不同:

如上一个复杂的函数指针变量为点,signal的函数指针变量类型是void(*)(int)

而要进行重新命名的话,与其他命名方式有所不同。

typdef  void(*) (int)  ptr ;  //错误!

typdef  void(*ptr ) (int) ;  //正确!

//意思是想把 函数指针变量类型 void(*) (int)  重新命名为ptr 

ptr p1 ;

void(*p2) (int) ;

//p1和p2都是函数指针变量,且二者的函数指针变量类型都是一样的,都是void(*) (int) 


//而后 void ( *signal(int , void(*)(int) ) ) ( int );
//又可以写为 ptr signal( int , ptr ) ;

相同,对于数组指针类型也如图函数指针类型的重命名方式一致:

typdef int (*)[10]  parr; //错误!

typdef int (* parr)[10] ; //正确!

//int (*)[10] 是数组指针变量的类型  

 parr p1 [10]  =  &arr;

 int (*p2)[10]  =  &arr;

// p1和p2的指针类型一致

三、函数指针数组

1、概念

函数指针数组:是数组,数组中存放的都是函数指针。

 

如图所示,parr[ ]中parr是一个数组名,而 int(*)(int, int)是一个函数指针变量的类型,二者相结合,就是一个函数指针数组。

而改数组中的每一个元素类型都是int(*)(int, int)

add和sub在数组中充当的是元素,也是函数指针,也是地址。

2、转移表—函数指针数组的用途

模拟计算器

加减乘除的函数调用。

主函数部分:

int main()
{
	int input = 0;
	do 
	{
		int x = 0;
		int y = 0;
		int ret = 0;
		printf("请选择");
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			printf("输入两个操作数");
			scanf("%d %d",&x,&y);
			ret = add(x, y);
			break;
		case 2:
			printf("输入两个操作数");
			scanf("%d %d", &x, &y);
			ret = sub(x, y);
			break;
		case 3:
			printf("输入两个操作数");
			scanf("%d %d", &x, &y);
			ret = mul(x, y);
			break;
		case 4:
			printf("输入两个操作数");
			scanf("%d %d", &x, &y);
			ret = div(x, y);
			break;
		case 0:
			printf("退出\n");
			break;
		defalut:
			printf("选择错误\n");
			break;

		}

	} while (input);
	return 0;
}

使用了函数指针数组后:

int main()
{
	int x = 0;
	int y = 0;
	int ret = 0;
	int input = 0;
	int(*parr[])(int, int) = { 0,add,sub,mul,div };//这一步操作就是转移表
	printf("请选择");
	scanf("%d", &input);//此刻的input是下标
	do
	{
		if (input >= 1 && input <= 4)
		{
			printf("输入两个操作数");
			scanf("%d %d", &x, &y);
			ret = parr[input](x, y);//和函数指针的有些相似 函数指针:ret = pf(x,y)
			printf("%d", ret);
		}
		else if (input == 0)
		{
			printf("退出\n");
			break;
		}
		else
		{
			printf("输入错误请重新选择\n");
		}

	} while (input);
	
	return 0;
}

转移表的局限性:调用函数中的参数的数据类型必须保持一致!

就列如:如果add的参数类型是int和int ,那么和add在同一个函数指针数组中的sub的调用参数类型也必须是int和int

四、回调函数

1、概念

回调函数就是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

2、应用——模拟计算器

当我们需要使用add函数时,我们先调用了add函数的地址交予了cacl然后cacl的指针通过add的地址抵达了add函数并且返回了add中得到的数值。 

int main()
{
	int input = 0;
	do
	{
		int x = 0;
		int y = 0;
		int ret = 0;
		printf("请选择");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(add);//将add函数的地址传给calc函数,再有calc通过地址(指针)调用函数add
			break;
		case 2:
			calc(sub);//将sub函数的地址传给calc函数,再有calc通过地址(指针)调用函数sub
			break;
		case 3:
			calc(mul);//将mul函数的地址传给calc函数,再有calc通过地址(指针)调用函数mul
			break;
		case 4:
			calc(div);//将div函数的地址传给calc函数,再有calc通过地址(指针)调用函数div
			break;
		case 0:
			printf("退出\n");
			break;
		defalut:
			printf("选择错误\n");
			break;

		}

	} while (input);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/882263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

突破大模型 | Alluxio助力AI大模型训练-成功案例(一)

更多详细内容可见《Alluxio助力AI大模型训练制胜宝典》 【案例一&#xff1a;知乎】多云缓存在知乎的探索:从UnionStore到Alluxio 作者&#xff1a;胡梦宇-知乎大数据基础架构开发工程师&#xff08;内容转载自InfoQ&#xff09; 一、背景 随着云原生技术的飞速发展&#xff…

时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积门控循环单元时间序列预测

时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积门控循环单元时间序列预测 目录 时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积门控循环单元时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现WOA-CNN-GRU鲸鱼算法优化卷积…

金融助贷客户数据资源有哪些模式?

目前助贷行业百花齐放&#xff0c;各家都在竞新创造更优化的获客方式。那么从传统方式发展至今&#xff0c;助贷行业的获客主要模式都更新了那些呢&#xff1f; 无论做什么产品&#xff0c; 什么新项目&#xff0c; 拓展客户都成了最重要的问题。 特别是随着互联网技术的不…

【Linux命令详解 | top命令】 top命令用于动态显示系统中进程的活动情况,类似于任务管理器

文章标题 简介一&#xff0c;参数列表二&#xff0c;使用介绍1. 安装与基本使用2. 实时监控与交互操作3. 进程排序和筛选4. 杀死进程5. 查看系统总体性能6. 退出top 总结参考资料 简介 top命令是一个强大的终端工具&#xff0c;用于实时显示系统中运行的进程活动情况。类似于任…

OCR相关模块——版面分析技术、表格文本识别

OCR相关模块——版面分析技术、表格文本识别 版面分析技术表格识别技术 版面分析技术 版面分析模型&#xff1a;飞桨用到了yolov2检测模型&#xff0c;对文档图片中的文本、表格、图片、标题与列表区域进行检测。当前主流是用分割做。 表格识别技术 参考博文

【C语言】字符串函数的介绍一(strlen、strcpy、stract)

前言 这篇文章是对于字符串操作函数、内存函数的比较详细的介绍。 我们都知道&#xff0c;字符串在C语言中使用的特别频繁&#xff0c;但类型里&#xff0c;却没有字符串这种类型&#xff0c;这时&#xff0c;众多的库函数就可以帮助我们灵活地使用字符串了 这篇文章同样适合…

派克Parker伺服驱动器 高性能电机控制系统的应用详解

派克Parker伺服驱动器及电机是一种高性能的电机控制系统&#xff0c;广泛应用于机器人、医疗设备、工业自动化和航空航天等领域。具有高精度、高可靠性、高动态性能、低噪音、低振动、低能耗等优点&#xff0c;采用了先进的数字信号处理技术&#xff0c;能够实现高精度的位置控…

【es6】函数柯里化(Currying)

柯里化&#xff08;Currying&#xff09;&#xff1a;把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数&#xff0c;并且返回接受余下的参数且返回结果的新函数。 柯里化由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的&#xff0c;它是 Mos…

第四章:前端框架Vue基础入门

文章目录 一、Vue框架概述1.1 声明响应式的数据 二、Vue内置指令2.1、条件渲染指令v-if/v-show2.2 v-for: 列表渲染2.3、v-text/v-html 模板指令2.4 v-on:事件监听器2.6 动态绑定v-bind2.7 v-model表单元素值绑定 三、计算属性与监视3.1 计算属性computed3.2 watch侦听器3.3 wa…

摆脱焦虑,释放技术人的潜能!

引言 在这个瞬息万变的时代&#xff0c;每个人都或多或少会面临职场生涯中的焦虑与迷茫。这种焦虑具有时代性特质&#xff0c;既源于对自我的疑惑&#xff0c;也对这个变化太快的世界感到不安。 对于技术从业者来说&#xff0c;科技变革加速带来的冲击尤为强烈。面对日新月异的…

【Visual Studio Code】--- Win11 C盘爆满 修改 Code 插件数据和缓存的保存路径

Win11 C盘爆满 修改 Code 插件数据和缓存的保存路径 一、概述二、修改 Code 插件数据和缓存的保存路径 一、概述 一个好的文章能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径&#xff0c;学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成…

天津和则百顺国际贸易有限公司:连接中国和印度汽车品牌的国际间贸易桥梁

全球汽车产业正迎来前所未有的变革,而中国和印度作为两大新兴市场,其汽车品牌也在逐步崭露头角。在这个背景下,天津和则百顺国际贸易有限公司(以下简称和则百顺)以其出色的贸易服务,成为了连接中国和印度汽车品牌的重要国际间贸易桥梁。 中国和印度汽车市场的崛起 中国和印度分…

STM32CubeMx驱动SG90(360度)

SG90 360度是一直转 而不是给定角度转的 pwm周期必须为20ms 0.5ms占空比 反转速度最大 1.5ms 不转 2.5ms正转速度最大

如何实现安全上网

l 场景描述 政府、军工、科研等涉密单位或企业往往要比其他组织更早接触高精尖的技术与产品&#xff0c;相对应的数据保密性要求更高。常规的内外网物理隔离手段&#xff0c;已经满足不了这些涉密单位的保密需求&#xff0c;发展到现在&#xff0c;需求已经演变成既要保证网络…

学习笔记十四:K8S最小调度单元POD概述

K8S最小调度单元POD概述 k8s核心资源Pod介绍Pod是什么Pod如何管理多个容器Pod网络Pod存储代码自动发版更新收集业务日志 Pod工作方式自主式Pod控制器管理的Pod(防误删除) 如何基于Pod运行应用 k8s核心资源Pod介绍 K8s官方文档&#xff1a;https://kubernetes.io/ K8s中文官方文…

STM32--TIM定时器(3)

文章目录 输入捕获简介频率测量输入捕获通道输入捕获基本结构PWMI的基本结构输入捕获模式测量PWM频率和占空比代码 编码器接口正交编码器工作模式接口基本结构TIM编码接口器测速代码&#xff1a; 输入捕获简介 输入捕获IC(Input Capture)&#xff0c;是处理器捕获外部输入信号…

DDPM: Denoising Diffusion Probabilistic Models

DDPM: Denoising Diffusion Probabilistic Models 去噪扩散模型前向过程-加噪声反向过程-去噪声 去噪扩散模型 论文题目&#xff1a;Denoising Diffusion Probabilistic Models (DDPM) 论文来源&#xff1a;NIPS, 2020 论文地址&#xff1a;https://arxiv.org/abs/2006.11239 论…

ubuntu18.04安装cuda

卸载之前安装的驱动 sudo apt-get purge nvidia*安装驱动 方法1&#xff1a; 查看显卡适配的NVIDIA的驱动 ubuntu-drivers devices安装recommend推荐的版本 sudo apt-get install nvidia-driver-455方法2&#xff1a; 或者直接使用下面命令安装 sudo ubuntu-drivers au…

Python程序设计——函数

学习目标 定义带形参的函数。用实参来调用函数。区分带返回值和不带返回值的函数。使用位置参数和关键字参数调用函数。通过传参数的引用值来传递参数。开发可重用代码来模块化程序&#xff0c;使程序易读、易调试和易维护。为可重用函数创建模块。决定变量的作用域。定义带默认…

纷享销客位列“2023企业客户关系管理(CRM)服务TOP10”第一名

近日&#xff0c;《互联网周刊》&eNet研究院发布“2023企业客户关系管理(CRM)服务TOP10”榜单&#xff0c;纷享销客连接型CRM凭借出色的产品实力和服务实践&#xff0c;位居 CRM企业排名首位。 2023年&#xff0c;穿越周期&#xff0c;用数字化的力量重塑企业经营与增长的逻…