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.mzph.cn/news/80580.shtml

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

相关文章

LeetCode 1584. 连接所有点的最小费用【最小生成树】

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

【CVPR2020】DEF:Seeing Through Fog Without Seeing Fog论文阅读分析与总结

Challenge&#xff1a; 之前网络架构的设计假设数据流是一致的&#xff0c;即出现在一个模态中的对象也出现在另一个模态中。然而&#xff0c;在恶劣的天气条件下&#xff0c;如雾、雨、雪或极端照明条件&#xff0c;多模态传感器配置中的信息可能不对称。不同传感器在特征提取…

Ts中的Pick,Omit,Extract和Exclude区别

前言 ts内置的一些常用工具类型&#xff0c;简化ts的操作。它们都是基于泛型实现的&#xff0c;并且内置的&#xff0c;可直接使用。 希望对大家有所帮助同时欢迎讨论并指出问题&#xff01; 1. Pick(选择) 通俗的说法就是&#xff1a;在已经定义的对象中选取一些 pick<T&am…

如何将两个或多个组件嵌入到一个组件中?

将两个或多个组件嵌入到一个组件中是React中的一个常见做法。这通常通过使用React.Children.map函数和React.cloneElement函数来完成。以下是一个示例&#xff0c;说明如何将两个子组件嵌入到父组件中&#xff1a; import React from react;class ParentComponent extends Rea…

MySQL常见的性能优化方法技巧以及示例

MySQL常见的性能优化方法技巧以及示例 MySQL是一种广泛用于管理和存储数据的关系型数据库管理系统。在处理大规模数据和高并发请求时&#xff0c;MySQL的性能优化变得尤为重要。本文将介绍一些常见的MySQL性能优化方法和技巧&#xff0c;以及相应的示例&#xff0c;帮助您提升…

Python 08学习之文件操作

&#x1f600;前言 欢迎来到Python 08学习之文件操作。在本文中&#xff0c;我们将介绍计算机中常见的文本文件和二进制文件&#xff0c;并探讨在Python中操作文件的步骤和相关函数/方法。通过学习本文&#xff0c;您将能够了解如何使用Python打开、读取、写入和关闭文件&#…

pyhton内置的数据类型(二)

pyhton内置的数据类型 一、内置数据类型的解释创建及赋值二、表示转义的符号实例操作 二、字符串的基本特性1.连接操作符 “ ” &#xff0c;提示&#xff1a;必须是同一数据类型才能相加2. 重复操作符 “ * ”3.成员操作符 “ in ”4. 正向索引和反向索引5. 切片&#xff08;…

MySQL与Oracle的分页

MySQL与Oracle的分页 当我们通过SQL去查询一个结果集的时候&#xff0c;并不需要查看所有行&#xff0c;可能只是查看前几行&#xff0c;或者中间的几行。则需要像MySQL的limit或Oracle的ROWNUM与FETCH NEXT来实现。 MySQL 语法 SELECT * FROM table_name LIMIT [offset,] ro…

Redis的介绍,安装Redis的方式

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Redis 初识Redis1.1 认识Redis1.2 安装Redis的方式…

自定义Dynamics 365实施和发布业务解决方案 - 6. Azure集成

在本章中,我们将讨论可用于实现快速和可扩展解决方案的Azure集成。我们将重点关注在Dynamics365实现中有用的三种类型的Azure技术。它们是Azure WebJobs、函数和逻辑应用程序。Azure WebJobs非常适合在后台运行的批处理。由于我们在本章中讨论的是Azure技术,我们还将快速了解…

Hadoop生态圈中的Flume数据日志采集工具

Hadoop生态圈中的Flume数据日志采集工具 一、数据采集的问题二、数据采集一般使用的技术三、扩展&#xff1a;通过爬虫技术采集第三方网站数据四、Flume日志采集工具概述五、Flume采集数据的时候&#xff0c;核心是编写Flume的采集脚本xxx.conf六、Flume案例实操1、采集一个网络…

嵌入式系统设计与应用---嵌入式系统概述(学习笔记)

目录​​​​​​​ 嵌入式系统 概念 组成 嵌入式常用的操作系统 与PC机的区别 开发 软件开发 硬件开发 嵌入式处理器 分类 嵌入式系统 概念 以应用为中心&#xff0c;以计算机技术为基础&#xff0c;软硬件可载剪&#xff0c;适应对功能、可靠性、成本&#xff0c…

图像处理之频域滤波DFT

摘要&#xff1a;傅里叶变换可以将任何满足相应数学条件的信号转换为不同系数的简单正弦和余弦函数的和。图像信号也是一种信号&#xff0c;只不过是二维离散信号&#xff0c;通过傅里叶变换对图像进行变换可以图像存空域转换为频域进行更多的处理。本文主要简要描述傅里叶变换…

机器学习笔记之最优化理论与方法(十)无约束优化问题——共轭梯度法背景介绍

机器学习笔记之最优化理论与方法——共轭梯度法背景介绍 引言背景&#xff1a;共轭梯度法线性共轭梯度法共轭方向共轭VS正交共轭方向法共轭方向法的几何解释 引言 本节将介绍共轭梯度法&#xff0c;并重点介绍共轭方向法的逻辑与几何意义。 背景&#xff1a;共轭梯度法 关于…

手摸手系列之前端Vue实现PDF预览及打印的终极解决方案

前言 近期我正在开发一个前后端分离项目&#xff0c;使用了Spring Boot 和 Vue2&#xff0c;借助了国内优秀的框架 jeecg&#xff0c;前端UI库则选择了 ant-design-vue。在项目中&#xff0c;需要实现文件上传功能&#xff0c;同时还要能够在线预览和下载图片和PDF文件&#x…

投资 - 股市顺势加仓方式

作为一个趋势交易者来说&#xff0c;有了好机会时&#xff0c;怎么能浪费呢&#xff1f;趁势加仓是必然之举。 形势大好&#xff0c;就要出大招&#xff0c;这样才能获得最大的收益。趁势加仓就是这个道理。形势不佳&#xff0c;出大招即便能胜&#xff0c;效果也有限。 那么加…

虹科分享 | 软件供应链攻击如何工作?如何评估软件供应链安全?

说到应用程序和软件&#xff0c;关键词是“更多”。在数字经济需求的推动下&#xff0c;从简化业务运营到创造创新的新收入机会&#xff0c;企业越来越依赖应用程序。云本地应用程序开发更是火上浇油。然而&#xff0c;情况是双向的&#xff1a;这些应用程序通常更复杂&#xf…

路由缓存问题 | vue-router的导航守卫

路由缓存问题 带参路由&#xff0c;当参数发生变化时&#xff0c;相同的组件实例将被复用&#xff0c;组件的生命周期钩子不会被调用&#xff0c;导致数据无法更新。 两种解决方法&#xff1a; 1. 给 RouterView绑定key值&#xff0c;即 <RouterView :key"$route.ful…

Java手写基数排序和算法案例拓展

Java手写基数排序和算法案例拓展 1. 算法思维导图 #mermaid-svg-aZdOEsqN6XWIvaAA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-aZdOEsqN6XWIvaAA .error-icon{fill:#552222;}#mermaid-svg-aZdOEsqN6XWIvaAA .er…

手机木马远程控制复现

目录 目录 前言 系列文章列表 渗透测试基础之永恒之蓝漏洞复现http://t.csdn.cn/EsMu2 思维导图 1&#xff0c;实验涉及复现环境 2,Android模拟器环境配置 2.1,首先从官网上下载雷电模拟器 2.2,安装雷电模拟器 2.3, 对模拟器网络进行配置 2.3.1,为什么要进行配置…