C++——函数指针与指针函数

函数指针与指针函数

1. 初识

在这里插入图片描述
一个区分的小技巧:
“函数指针”中函数是用来修饰指针的,所以主体是指针,它主要是用来指向函数的。
“指针函数”中指针是用来修饰函数的,所以主体是函数,该函数的返回类型是指针。

举个简单的例子:

#include<iostream>
using namespace std;int add(int a, int b) {return a + b;
}int sub(int a, int b) {return a - b;
}//函数指针
int (*f)(int, int);//指针函数
int* multi(int a, int b) {int c = a*b;return &c;
}int main() {int a = 3, b = 2;f = add; cout << f(a, b) << endl;f = &sub;cout << f(a, b) << endl;int* c = multi(a, b);cout << *c << endl;return 0;
}输出结果:
5
1
6

上面代码中,f = add;f = &sub 其实表达的是一个意思,函数指针f分别指向 add 和 sub。上面还有一个小细节,()的优先级比*高

2. 函数指针

函数凡是符合函数指针中的格式的,都可以传递给函数指针进行调用,具体说明,可以看下面代码例子。

函数指针一般用于回调函数、函数回调、函数指针数组等操作,提供了一种灵活的方式来实现动态的函数调用和扩展功能。

这里需要说明的一点就是回调函数和函数回调的区别
它们的区别跟“函数指针与指针函数的区别”同理,要看主体。函数回调是一种机制,回调函数是一个函数。在调用某个函数时,不是通过函数名,而是通过函数指针,这种方式就是函数回调,而这个“某个函数”就是回调函数。

2.1 回调函数和函数回调

#include <iostream>
using namespace std;// 定义回调函数
void callbackFunction(int result) {cout << "回调函数被调用,result = " << result << endl;
}// 调用回调函数的函数
void callCallbackFunction(int result, void (*callback)(int)) {// 执行一些操作cout << "执行一些操作" << endl;// 调用回调函数callback(result);
}int main() {// 调用函数并传递回调函数callCallbackFunction(123, callbackFunction);return 0;
}

上面代码中callbackFunction就是回调函数,而在callCallbackFunction里面调用函数指针callback去调用回调函数,这种方式就是函数回调。

回调函数callbackFunction的返回类型是 void ,而参数类型是 int 。函数指针的返回类型也是 void,参数类型也是 int ,所以callbackFunction可以传递给函数指针。

它有另外一种写法:

#include <iostream>
using namespace std;typedef void (*Callback)(int);// 定义回调函数
void callbackFunction(int result) {cout << "回调函数被调用,result = " << result << endl;
}// 调用回调函数的函数
void callCallbackFunction(int result, Callback callback) {// 执行一些操作cout << "执行一些操作" << endl;// 调用回调函数callback(result);
}int main() {// 调用函数并传递回调函数callCallbackFunction(123, callbackFunction);return 0;
}

typedef void (*Callback)(int); 是一个函数指针类型的定义。让我逐步解释一下这个定义:

typedef:这个关键字用于给一个数据类型起一个别名,可以通过这个别名来声明变量。
void:这是函数的返回类型,表示函数没有返回值。
(*Callback):这是一个函数指针的声明,Callback 是这个函数指针的名称。
(int):这是函数指针所指向的函数的参数列表,int 表示这个函数接受一个 int 类型的参数。
综合起来看,typedef void (*Callback)(int); 是一个将函数指针类型命名为 Callback 的语句。它定义了一个函数指针类型,该函数指针可以指向一个返回值为空(void)的函数,该函数接受一个 int 类型的参数。

通过使用这个类型定义,我们可以方便地创建符合该函数指针类型的函数指针变量。例如,可以定义一个函数指针变量 Callback callback;,然后将其指向一个满足上述函数指针类型要求的函数,以便在需要时进行回调操作。

使用 typedef 可以简化代码,使代码更加易读和易于维护,提高了代码的可读性和可移植性。

2.2 函数指针数组

#include <iostream>// 函数指针类型
typedef void (*PrintFunc)();// 打印函数示例
void printHello() {std::cout << "Hello ";
}void printWorld() {std::cout << "World!";
}int main() {// 声明函数指针数组PrintFunc printFuncArray[] = { printHello, printWorld };// 遍历函数指针数组并调用函数for (int i = 0; i < sizeof(printFuncArray) / sizeof(printFuncArray[0]); ++i) {printFuncArray[i]();}std::cout << std::endl;return 0;
}

在上面的示例中,首先声明了一个函数指针类型 PrintFunc,它是一个指向返回类型为 void,不接受参数的函数指针。然后,我们定义了两个打印函数 printHello() 和 printWorld()。接下来,在 main 函数中,我们声明了一个函数指针数组 printFuncArray,其中存储了这两个打印函数的地址。最后,我们遍历函数指针数组,并通过函数指针调用函数来打印 “Hello World!”。

3. 指针函数

#include <iostream>// 指针函数的原型
int* createArray(int size);int main() {int size = 5;// 调用指针函数,分配内存并返回指针int* ptr = createArray(size);// 使用指针访问动态分配的数组for (int i = 0; i < size; ++i) {ptr[i] = i + 1;}// 打印数组元素for (int i = 0; i < size; ++i) {std::cout << ptr[i] << " ";}// 释放动态分配的内存delete[] ptr;return 0;
}// 指针函数的定义
int* createArray(int size) {return new int[size];
}

总结: 指针函数在 C++ 中常用于动态内存分配、返回动态数据结构等场景。通过返回指针,我们可以在函数外部访问和操作函数内部动态分配的数据。需要注意的是,使用指针函数时要小心管理内存,避免内存泄漏和悬空指针等问题。

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

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

相关文章

华为云云耀云服务器L实例评测 | 实例使用教学之软件安装:华为云云耀云服务器环境下安装 Docker

华为云云耀云服务器L实例评测 &#xff5c; 实例使用教学之软件安装&#xff1a;华为云云耀云服务器环境下安装 Docker 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器是什么华为云云耀云…

Oracle 11g_FusionOS_安装文档

同事让安装数据库&#xff0c;查询服务器信息发现操作系统是超聚变根据华为openEuler操作系统更改的自研操作系统&#xff0c;安装过程中踩坑不少&#xff0c;最后在超聚变厂商的技术支持下安装成功&#xff0c;步骤可参数该文。 一、 安装环境准备 1.1 软件下载 下载地址:…

基于微信小程序的网络安全科普题库答题系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

识别消费陷阱,反消费主义书单推荐

在消费主义无所不在的今天&#xff0c;商家是如何设置消费陷阱的&#xff1f;人们在做出消费决策时又是如何“犯错”的&#xff1f;如何才能做出更加理性的选择&#xff1f; 本书单适合对经济学、市场营销感兴趣的朋友阅读。 《小狗钱钱》 “你的自信程度决定了你是否相信自已…

线性代数(七) 矩阵分析

前言 从性线变换我们得出&#xff0c;矩阵和函数是密不可分的。如何用函数的思维来分析矩阵。 矩阵的序列 通过这个定义我们就定义了矩阵序列的收敛性。 研究矩阵序列收敛性的常用方法&#xff0c;是用《常见向量范数和矩阵范数》来研究矩阵序列的极限。 长度是范数的一个特…

Android widget 小部件使用指南强化版

Android widget 小部件使用指南强化版 一、简单UI的小部件二、含集合的小部件三、可配置的小部件四、可控制的小部件五、Android 12 Widget 更新 小部件是主屏幕定制的一个重要方面。您可以将它们视为应用程序最重要的数据和功能的“概览”视图&#xff0c;这些数据和功能可以直…

Linux 基本语句_5_创建静态库|动态库

静态库 创建主函数&#xff1a;main.c 应用函数&#xff1a;add.c、sub.c、mul.c 创建calc.h文件作为头文件 生成可执行文件*.o文件 gcc -c add.c -o add.o ....包装*.o文件为静态库 ar -rc libmymath.a add.o sub.o mul.o编译静态库并指明创建静态库的位置 sudo gcc mai…

零基础教程:Yolov5模型改进-添加13种注意力机制

1.准备工作 先给出13种注意力机制的下载地址&#xff1a; https://github.com/z1069614715/objectdetection_script 2.加入注意力机制 1.以添加SimAM注意力机制为例&#xff08;不需要接收通道数的注意力机制&#xff09; 1.在models文件下新建py文件&#xff0c;取名叫Sim…

1分钟快速实现Redis数据对比

在上篇「Redis高效、安全的不停机数据迁移方案」的文章中&#xff0c;介绍了NineData在Redis迁移场景下的性能和优势。因为数据在主备、多云和多区域环境之间的迁移流动&#xff0c;难免会产生数据一致性的问题&#xff0c;而结构与数据不一致往往是导致故障的原因之一。所以&a…

【微服务保护】

文章目录 Sentinel 微服务雪崩问题&#xff1a; 微服务中&#xff0c;服务间调用关系错综复杂&#xff0c;一个微服务往往依赖于多个其它微服务。服务D有 故障进而导致服务A有故障&#xff0c;进而导致服务雪崩。 解决雪崩问题的常见方式有四种&#xff1a; 超时处理&#xff1…

掌动智能:UI自动化测试工具的重要性和应用

在软件开发过程中&#xff0c;测试是至关重要的环节。而UI自动化测试工具则成为了测试团队提高效率、降低成本、保证软件质量的重要利器。本文将介绍UI自动化测试工具的概念和重要性&#xff0c;并探讨其在软件开发中的应用和好处。 一、UI自动化测试工具的概念 UI自动化测试工…

Java之SpringCloud Alibaba【六】【Alibaba微服务分布式事务组件—Seata】

一、事务简介 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。 在关系数据库中&#xff0c;一个事务由一组SQL语句组成。 事务应该具有4个属性: 原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 原子性(atomicity) ∶个事务…

ubuntu20安装nvidia驱动

1. 查看显卡型号 lspci | grep -i nvidia 我的输出&#xff1a; 01:00.0 VGA compatible controller: NVIDIA Corporation GP104 [GeForce GTX 1080] (rev a1) 01:00.1 Audio device: NVIDIA Corporation GP104 High Definition Audio Controller (rev a1) 07:00.0 VGA comp…

9.30号作业

1.消息队列实现进程间的通信 服务端 #include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__:",__LINE__);\perror(msg);\ }while(0)typedef struct{ long msgtype; //消息类型char data[1024]; //消息正文 }Msg;#define SIZE sizeof(Msg)-s…

STM32F4X UCOSIII任务消息队列

STM32F4X UCOSIII任务消息队列 任务消息队列和内核消息队列对比内核消息队列内核消息队列 UCOSIII任务消息队列API任务消息队列发送函数任务消息队列接收函数 UCOSIII任务消息队列例程 之前的章节中讲解过消息队列这个机制&#xff0c;UCOSIII除了有内核消息队列之外&#xff0…

ESP32S3的MPU-6050组件移植教程

前言 &#xff08;1&#xff09;实习公司要搞ESP32BOX的驱动移植&#xff0c;所有资料自己找还是比较折磨人的现在我分享几个官方的组件移植资料&#xff1a; <1>Find the most exciting ESP-IDF components&#xff08;ESP32的官方组件都可以在里面查&#xff0c;按照他…

安卓玩机-----反编译apk 修改apk 去广告 去弹窗等操作中的一些常识

安卓机型app的编译与反编译 apk文件的简单说明与解析 -安卓修改apk apk的组成和编译 一 电脑端几种反编译apk工具操作步骤解析 前面几个博文有说明关于反编译apk和apk架构等有些常识.今天对以上做个补充。初学者记住一点。对于一个apk文件使用压缩软件7zip打开可以查看到文件…

BUUCTF刷题十一道(09)

文章目录 October 2019 Twice SQL Injection[GYCTF2020]EasyThinking[BJDCTF2020]EzPHP[HFCTF2020]JustEscape(vm2沙箱逃逸)[GXYCTF2019]StrongestMind[GKCTF 2021]easycms[SUCTF 2018]GetShell[b01lers2020]Life on Mars[WMCTF2020]Make PHP Great Again[MRCTF2020]Ezaudit[CS…

关于Java的IO流里面的方法read()的细究

我们会经常看到上面的代码&#xff0c;很显然read(b)&#xff0c;是把字节读入到b这个字节数组里&#xff0c;然后read()返回一个成功读取的字节长度&#xff0c;如果现在用不带参的read()去一个一个字节的读了&#xff1f;那么len bInput.read()就是把这一个节字读入到len&am…

modbusTCP【codesys】

1添加控制器【控制器】&#xff1a; 右击左侧树型菜单【Device】→选择【添加设备】&#xff0c;在弹出对话框中下拉选择【以太网适配器】下的【Ethernet】&#xff0c;最后点击【添加设备】。 注意固件能支持的版本。我的是3.5.17 2添加主站【主站】 2添加从站【从站】 双…