函数指针和指针函数

指针

指针函数

指针函数一个函数,只不过这个函数的返回值是一个地址值

  • 和普通函数唯一的区别就是在函数名前面多了一个*号

    函数返回值必须用同类型的指针变量来接受

    也可以将其返回值定义为 void*类型,在调用的时候强制转换返回值为自己想要的类型

struct Data{int a;char b;void show(){cout << a << "," << b << endl;}
};
//指针函数
Data* fun(int a,char b){Data *tmp = new Data;tmp->a = a;tmp->b = b;return tmp;
}
int main(){Data *aa = fun(100, 'c');aa->show();return 0;
}

采用强制类型转换

//指针函数,返回值改为void*
void* fun(int a,char b){Data *tmp = new Data;tmp->a = a;tmp->b = b;return tmp;
}
int main(){//强制类型转换Data *aa = static_cast<Data*>(fun(200,'v'));aa->show();return 0;
}

例子2:

int *f(int, int);
int main(){
int *p = nullptr;
p = f(100, 200);
cout << "The memory addr is" << p << endl;
cout << "The value is" << *p << endl;
return 0;
}
//函数定义
int* f(int a,int b){
int *p = new int;
cout << "The memory addr is" << p << endl;
*p = a * b;
cout << "The value is" << *p << endl;
return p;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

发现输出的地址是相同的

指针函数就是返回一个地址给调用者,用于需要地址的情况

函数指针

函数指针就是一个指针,但这个指针指向的函数,不是普通的基本数据类型或者类对象。

指向函数的指针包含了函数的地址,可以通过它来调用函数

函数指针就是指向函数的指针

int sum(int a,int b){
return a + b;
}
int mul(int a,int b){
return a * b;
}
//函数指针:指向函数的指针
int (*fun)(int, int);
int main(){
fun = sum;
cout << fun(100, 200) << endl;
fun = &mul;
cout << (*fun)(20, 30) << endl;
return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
例子

#include <iostream>
using namespace std;int max(int x, int y){return x > y ? x : y;
}
int min(int a,int b){return a < b ? a : b;
}
int main(void){int (*p)(int, int) = max;int (*q)(int, int) = &min;cout<<(*p)(300, p(100, 200))<<endl;cout << q(99, (*q)(33, 77)) << endl;
}

可以连续调用

struct Data{int a;int b;Data(int a,int b):a(a),b(b){}
};
int col(Data x,Data y){return x.a + y.a+ x.b + y.b;
}
int main(void){Data aa(3, 4);Data bb(5, 6);//赋值的函数名,取不取地址都可以int (*point)(Data, Data) =col;//&cal//函数指针调用cout << point(aa, bb) << endl;cout << (*point)(bb, bb) << endl;
}

函数指针赋值,参数表类型必须和函数名类型匹配

int (*point)(Data, Data) =col;

千万不要加参数,因为指针赋值地址

函数指针可以当回调函数

函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。

说白了就是回调函数参数里面存在函数指针

把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,就叫做回调。
--如果代码立即被执行就称为同步回调;
--如果在之后晚点的某个时间再执行,则称为异步回调。
int add(int a,int b){return a + b;
}
int mul(int c,int d){return c * d;
}
void getNUm1(vector<int>& vec,int (*p)(int,int),int (*q)(int,int)){for (int i = 1; i < vec.size();i++){cout << p(vec[i], vec[i - 1]) << ",";cout << q(vec[i], vec[i - 1]) << endl;}
}
void getNUm2(vector<int>& vec,int (*p)(int,int),int (*q)(int,int)){for (int i = 1; i < vec.size();i++){cout << (*p)(vec[i], vec[i - 1]) << ",";cout << (*q)(vec[i], vec[i - 1]) << endl;}
}
int main(void){vector<int> vec = {1, 2, 3, 4, 5};getNUm1(vec, add, mul);getNUm2(vec, &add, &mul);
}

总结

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 指针函数:返回值是一个指针的函数
  • 函数指针:指向一个函数地址的指针

数组指针

一个指针指向一个数组

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

int main(void){int temp[6] = {1, 2, 3, 4, 5, 6};for (int i = 0; i < 6;i++){cout << *(temp + i) << "," << temp[i] << ",";}cout << endl;int *p = temp; //&temp[0]for (int i = 0; i < 6;i++){cout << *(p + i) << "," << p[i] << ",";}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

 int a[5] = {10, 20, 30, 40, 50};int(*p)[5] = &a;//把数组a的地址赋给p,则p为数组a的地址for (int i = 0; i < 5;i++){cout << *(*p + i) << "," << (*p)[i] << endl;}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

指向二维数组

  int a[3][5] = {{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},{11, 12, 13, 14, 15}};int(*p)[5] = a;//&a[0]for (int i = 0; i < 3;i++){for (int j = 0; j < 5;j++){cout << (*p)[j] <<" ";}cout << endl;++p;}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里是把数组第一个元素赋值给p,因为二维数组在内存也是占一行的,不能赋值整个数组

int a[3][5] = {1, 2, 3, 4, 5,6, 7, 8, 9, 10,11, 12, 13, 14, 15};

&a[0]==&*(a+0)==a

注意p+1后,整个数组移动5个步长

二维数组的指向

int a[3][5] = {{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},{11, 12, 13, 14, 15}};for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){cout << a[i][j] << " ";cout << *(a[i] + j) << " ";cout << *(*(a + i) + j) << " ";cout << (*(a + i))[j] << " ";}cout << endl;}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


数组指针的行大小只要和数组吻合,可以把数组任意一行赋给它

利用:&a[i]或者a+i,都代表第i行

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

 int a[3][5] = {{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},{11, 12, 13, 14, 15}};int(*q)[5] = a + 1;for (int i = 0; i < 5;i++){cout << (*q)[i] << " ";}cout << endl;int(*p)[5] = &a[2];for (int i = 0; i < 5;i++){cout <<*((*p)+i) << " ";}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


 int a[3][5] = {{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},{11, 12, 13, 14, 15}};int(*p)[5] = a;for (int i = 0; i < 3;i++){for (int j = 0; j < 5;j++){cout << p[i][j] << ",";cout << (*(p+i))[j] << ",";cout << *(p[i]+j) << ",";cout << *(*(p+i)+j) << ",";}cout << endl;}

同样p [ i ] [ j ]可以访问到元素


 int a[3][5] = {{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},{11, 12, 13, 14, 15}};int(*p)[5] = a+1;//指向了第二行for (int i = 0; i < 2;i++){for (int j = 0; j < 5;j++){//注意:(*())[j]的括号en不可省cout << (*(p+i))[j] << ",";}cout << endl;}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

指针数组

指针数组

一个由n个指针类型元素组成的指针数组,或者说这个当一个数组里含有的元素为指针类型的时候,它就被成为指针数组

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

int a=100;int b = 200;int c = 300;int *p[3];//数组类型为n指针p[0] = &a;p[1] = &b;p[2] = &c;for (int i = 0; i < 3;i++){cout << *p[i] << endl;}

p[i]是指针,所以*(p[i])才能取到值但是[]优先级更高,不必加括号

 int arr[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};int *p[3];//指针数组for (int i = 0; i < 3;i++){cout << arr[i]<<","<<arr+i<<","<<*(arr+i) << endl;p[i] = arr[i];}for (int i = 0; i < 3;i++){for (int j = 0; j < 4;j++){cout << p[i][j] << ",";}cout << endl;}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

发现:arr[i]和arr+i和*(arr+i)都是表示的地址

同理:p[i] [j]可以写成等价的四种形式


    int a[3] = {1, 2, 3};int b[3] = {4, 5, 6};int c[3] = {7, 8, 9};int *p[3]; // 指针数组p[0] = a;p[1] = b;p[2] = &c[0];for (int i = 0; i < 3; i++){for (int j = 0; j < 3;j++){cout << *(p[i]+j) << ",";}cout << endl;}

扩展

   void test(const char* str)
{printf("%s\n", str);    
}int main( )
{//函数指针pfunvoid (*pfun) (const char*) = test;//函数指针的数组pfunArrvoid (*pfunArr[51)(const char* str); pfunArr[0] = test;//指向函数指针数组pfunArr的指针ppfunArrvoid (*(*ppfunArr)[10])(const char*) = &pfunArr;return 0;   

首先记住:

返回值 (*函数名)(含参表)一定是个函数指针

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有含参数表,在函数名内部写成:指针数组

上图是:指向函数的指针数组的指针

int Add(int x, int y) {return x + y;
} int main() {//函数指针int(*pAdd)(int, int) = Add;//&Add//函数指针的数组int (*pArr[5])(int, int);//指向函数指针数组的指针——基于函数指针的数组去写int (*(*ppArr)[5])(int, int)=&pArr;return 0;
}

用变量a给出如下定义:

*函数指针数组首先是个数组。这个数组(包含 6 个元素),每个元素都是一个函数指针。

int (*a[10])(int)

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

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

相关文章

一、selenium自动化简介selenium工具集

文章目录 一、简介二、组成部分三、selenium工具集3.1 Selenium IDE3.2 Selenium WebDriver3.3 Selenium Grid3.4 Appium 一、简介 官方网站 Selenium 是支持 web 浏览器自动化的一系列工具和库的综合项目。 它提供了扩展来模拟用户与浏览器的交互&#xff0c;用于扩展浏览器分…

Excel使用VLOOKUP公式匹配不出正确公式,返回#N/A

问题&#xff1a; Excel使用VLOOKUP公式匹配不出正确公式&#xff0c;返回#N/A 原因&#xff1a; 原数据和匹配的数据格式不一致 解决办法&#xff1a; 把格式都设置为文本。 例如添加一列&#xff0c;输入英文符号&#xff0c;然后把数据源拼接起来&#xff0c;转换为文…

Linux入门攻坚——31、rpc概念及nfs和samba

NFS&#xff1a;Network File System 传统意义上&#xff0c;文件系统在内核中实现 RPC&#xff1a;函数调用&#xff08;远程主机上的函数&#xff09;&#xff0c;Remote Procedure Call protocol 一部分功能由本地程序完成 另一部分功能由远程主机上的 NFS本质…

基于阿里云函数计算(FC)x 云原生 API 网关构建生产级别 LLM Chat 应用方案最佳实践

作者&#xff1a;计缘 LLM Chat 应用大家应该都不陌生&#xff0c;这类应用也逐渐称为了我们日常的得力助手&#xff0c;如果只是个人使用&#xff0c;那么目前市面上有很多方案可以快速的构建出一个LLM Chat应用&#xff0c;但是如果要用在企业生产级别的项目中&#xff0c;那…

C#高级:递归2-根据ID反向递归求其所有的祖先节点信息

目录 一、实现demo 二、封装方法 【ID>祖先ID】 【ID>祖先实体】 三、递归讲解 一、实现demo class MainClass {static List<Person> PersonList new List<Person>(){new Person(){ Id1,ParentIDnull,Name"小明曾祖父",},new Person(){ Id2…

python文件自动化(4)

接上节课内容&#xff0c;在开始正式移动文件到目标文件夹之前&#xff0c;我们需要再思考一个问题。在代码运行之前&#xff0c;阿文的下载文件夹里已经存在一些分类文件夹了&#xff0c;比如图例中“PDF文件”这个文件夹就是已经存在的。这样的话&#xff0c;在程序运行时&am…

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext new ClassPathXmlApplicationContext("bean.xml"); } BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanFactory的功能相似&#xff0c;都是…

linux 安装redis

1. 更新系统和安装依赖 sudo apt update sudo apt install build-essential tcl2. 下载 Redis 源码(没有opt文件夹&#xff0c;则先创建opt文件夹) cd /opt wget http://download.redis.io/releases/redis-6.2.6.tar.gz3. 解压和编译 Redis 解压下载的文件&#xff0c;并进入…

Qt/C++编写的Onvif调试助手调试神器工具/支持云台控制/预置位设置等/有手机版本

一、功能特点 广播搜索设备&#xff0c;支持IPC和NVR&#xff0c;依次返回。可选择不同的网卡IP进行对应网段设备的搜索。依次获取Onvif地址、Media地址、Profile文件、Rtsp地址。可对指定的Profile获取视频流Rtsp地址&#xff0c;比如主码流地址、子码流地址。可对每个设备设…

深入了解以太坊

1. 以太坊编程语言和操作码 以太坊中智能合约的代码以高级语言编写&#xff0c;如 Serpent、LLL、Solidity 或 Viper,并可转换为 EVM 可以理解的字节码&#xff0c;以便执行。 Solidity 是为以太坊开发的高级语言之一&#xff0c;它具有类似 JavaScript 的语法&#xff0c;可以…

用广播星历计算卫星运动的平均角速度

用广播星历计算卫星位置 1.计算卫星运动的平均角速度 首先根据广播星历中给出的参数计算参考时刻的平均角速度: 式中&#xff0c;GM为万有引力常数G与地球总质量M之乘积&#xff0c;其值为GM3.98600510^14b m3/s2。 然后根据广播星历中给定的摄动参数计算观测时刻卫星的平均…

使用AI写WebSocket知识是一种怎么样的体验?

一、WebSocket基础知识 1. WebSocket概念 1.1 为什么会出现WebSocket 一般的Http请求我们只有主动去请求接口&#xff0c;才能获取到服务器的数据。例如前后端分离的开发场景&#xff0c;自嘲为切图仔的前端大佬找你要一个配置信息的接口&#xff0c;我们后端开发三下两下开…

JDBC:连接数据库

文章目录 报错 报错 Exception in thread “main” java.sql.SQLException: Can not issue SELECT via executeUpdate(). 最后这里输出的还是地址&#xff0c;就是要重写toString()方法&#xff0c;但是我现在还不知道怎么写 修改完的代码&#xff0c;但是数据库显示&#…

ASIO网络调试助手之一:简介

多年前&#xff0c;写过几篇《Boost.Asio C网络编程》的学习文章&#xff0c;一直没机会实践。最近项目中用到了Asio&#xff0c;于是抽空写了个网络调试助手。 开发环境&#xff1a; Win10 Qt5.12.6 Asio(standalone) spdlog 支持协议&#xff1a; UDP TCP Client TCP Ser…

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略&#xff0c;该策略要求请求的域名、协议和端口必须与提供资源的服务相同。…

Linux线程管理进阶:分离,等待、终止与C++11线程接口的封装实践

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f351;线程终止&#x1f34d;线程等待*多线程创建&#xff0c;传自己定义的对象示例代码&#xff1a;* &#x1f34e;线程的分…

STM32(十二):DMA直接存储器存取

DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输&#xff0c;无须CPU干预&#xff0c;节省了CPU的资源。&#xff08;运行内存SRAM、程序存储器Flash、寄存器&#xff09; 12个独立可配置的通道&…

[数据集][目标检测]井盖丢失未盖破损检测数据集VOC+YOLO格式2890张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2890 标注数量(xml文件个数)&#xff1a;2890 标注数量(txt文件个数)&#xff1a;2890 标注…

页面要突破手机安全区域来全屏显示(沉浸式模式显示),其他页面不需要,如何设置安全区域文字颜色

#效果图 ##思路遇到的问题 在aboutToAppear中使用window模块的 getLastWindow 和 setWindowLayoutFullScreen两个方法来处理全屏显示 设置沉浸式模式的特点&#xff1a; 在任何一个页面中设置过一次之后&#xff0c;其他页面也会跟着全屏显示 这么处理会出现问题&#xff1a…

如何使用Spoon连接data-integration-server并在服务器上执行转换

1.建立连接 2.新建转换或任务 3.右键[子服务器]&#xff0c;新建一个服务器连接(data-integration-server服务器的连接信息) 4.右键[Run configurations],新建一个执行连接,勾选相应的选项即可: 5.选择服务器运行即可! 6.最后&#xff0c;你可以通过服务器端的WEB查看执行日志…