【C语言指针】指针和函数

文章目录

  • 一、前言
  • 二、指针函数
    • 2.1 概念
    • 2.2 定义
    • 2.3 具体例子
  • 三、函数指针
    • 3.1 概念
    • 3.2 定义
    • 3.3 具体例子
    • 3.4 回调函数
      • 3.4.1 概念
      • 3.4.2 例子1
      • 3.4.3 例子2
  • 四、函数指针数组
    • 4.1 概念
    • 4.2 定义
    • 4.3 具体例子
  • 五、函数指针数组的指针
    • 5.1 概念
    • 5.2 定义
    • 5.3 具体例子

一、前言

关于指针和函数文章从有两方面入手,一方面是将指针作为实参传给函数;另一方面则是函数指针这一类函数和指针结合的数据类型。

科普

函数名本质上是函数的地址,其用法跟数组名类似。

二、指针函数

2.1 概念

指针函数本质上是一个函数,此函数返回一个指针。

2.2 定义

char *func(char a, char b){}

2.3 具体例子

在函数指针的使用中,大多数情况下需要动态分配内存来存放返回的数据。如果使用局部变量,当函数运行结束后,局部变量会被释放,上层代码访问时可能会导致非法访问,从而引发程序段错误。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>char *my_strcat(char *str1, char *str2)
{char *p = NULL;char *p1 = NULL;char *ptemp = NULL;/* 动态内存分配 */p = (char *)malloc(20 * sizeof(char));if(!p){return NULL;}p1 = p;ptemp = str1;while(*ptemp != '\0'){*p1++ = *ptemp++;}ptemp = str2;while(*ptemp !=  '\0'){*p1++ = *ptemp++;}*p1 = '\0';printf("p=%s\n", p);return p;
}int main()
{char str1[10] = "hello ";char str2[10] = "world!";char *return_str = NULL;return_str = my_strcat(str1, str2);printf("return str[%s]\n", return_str);if(return_str)free(return_str);return 0;
}

三、函数指针

3.1 概念

函数指针本质是一个指针,它指向一个函数的地址,通过它来调用函数。

3.2 定义

首先定义一个函数:

int add(int x, int y){}

此时,函数的地址就是函数名。我们声明一个函数指针并把函数的地址赋值给这个函数指针。这里要注意,定义的函数和声明的函数指针的参数列表应该保持一致。

int (*pf)(int, int) = add;

下面让我们看一个表达式:

(*(void(*)())0)();

这一行代码的意思是:调用0地址处的函数,该函数无参,返回类型是void。

我们再来看一下signal函数的原型

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

函数名:signal

两个参数:int和void(*)(int) (第二个参数也是一个函数指针)

返回值:void(*)(int)(函数指针)

这样看起来很复杂,我们可以使用typedef来简化表达。

首先,我们可以把signal函数的原型写成

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

但是,这种结构语法是不允许,C语言的语法要求函数的返回类型必须明确地写在函数名之前。接下来我们使用typedef简化。

typedef void(*pfun_t)(int);//void(*)(int) pfun_t
pfun_t signal(int, pfun_t);//pfun_t -> void(*)(int)

3.3 具体例子

int add(int a, int b) { return a + b; }int main()
{int (*pf)(int, int) = add;int ret = pf(3,5);printf("ret=%d\n", ret);return 0;
}

3.4 回调函数

3.4.1 概念

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

3.4.2 例子1

Handle函数第二个参数是该函数的首地址,把这个首地址用函数指针接收int (*Callback)(int),在Handle函数中使用这个首地址,Callback(x),这时就会运行主函数Handle第二个参数的函数。

int Callback_1(int a)   ///< 回调函数1
{printf("Hello, this is Callback_1: a = %d ", a);return 0;
}int Callback_2(int b)  ///< 回调函数2
{printf("Hello, this is Callback_2: b = %d ", b);return 0;
}int Callback_3(int c)   ///< 回调函数3
{printf("Hello, this is Callback_3: c = %d ", c);return 0;
}int Handle(int x, int (*Callback)(int)) ///< 注意这里用到的函数指针定义
{Callback(x);
}int main()
{Handle(4, Callback_1);Handle(5, Callback_2);Handle(6, Callback_3);return 0;
}

3.4.3 例子2

这是一个常用在工作中的使用形式。M26_WorkStatus_TypeDef的第二个参数保存的函数的首地址。

/*********  工作状态处理  *********/
typedef struct
{uint8_t mStatus;uint8_t (* Funtion)(void); //函数指针的形式
} M26_WorkStatus_TypeDef;  //M26的工作状态集合调用函数/**********************************************
** >M26工作状态集合函数
***********************************************/
M26_WorkStatus_TypeDef M26_WorkStatus_Tab[] =
{    {GPRS_NETWORK_CLOSE,  M26_PWRKEY_Off  }, //模块关机{GPRS_NETWORK_OPEN,  M26_PWRKEY_On  }, //模块开机{GPRS_NETWORK_Start,   M26_Work_Init  }, //管脚初始化{GPRS_NETWORK_CONF,  M26_NET_Config  }, //AT指令配置{GPRS_NETWORK_LINK_CTC,  M26_LINK_CTC  }, //连接调度中心  {GPRS_NETWORK_WAIT_CTC, M26_WAIT_CTC  },  //等待调度中心回复 {GPRS_NETWORK_LINK_FEM, M26_LINK_FEM  }, //连接前置机{GPRS_NETWORK_WAIT_FEM, M26_WAIT_FEM  }, //等待前置机回复{GPRS_NETWORK_COMM,  M26_COMM   }, //正常工作{GPRS_NETWORK_WAIT_Sig,  M26_WAIT_Sig  },  //等待信号回复{GPRS_NETWORK_GetSignal,  M26_GetSignal  }, //获取信号值{GPRS_NETWORK_RESTART,  M26_RESET   }, //模块重启
}
/**********************************************
** >M26模块工作状态机,依次调用里面的12个函数   
***********************************************/
uint8_t M26_WorkStatus_Call(uint8_t Start)
{uint8_t i = 0;for(i = 0; i < 12; i++){if(Start == M26_WorkStatus_Tab[i].mStatus){          return M26_WorkStatus_Tab[i].Funtion();}}return 0;
}

四、函数指针数组

4.1 概念

函数指针数组本质是一个数组,数组中存放的函数指针。

4.2 定义

int (*pfArr[2])(int, int);

在函数指针的基础上,在函数名后面加上[]。

4.3 具体例子

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int division(int a, int b) { return a / b; }int main()
{/* 模拟键盘输入 */int input = 2;int ret;int (*pf[5])(int, int) = {NULL, add, sub, mul, division};ret = pf[input](3,5);printf("ret=%d\n", ret);return 0;
}

五、函数指针数组的指针

5.1 概念

函数指针数组的指针本质上是一个指针,指向一个函数指针数组。

5.2 定义

int(* (*p3)[4])(int, int);

在函数指针数组的基础上,在函数名前面加上*号并用小括号括起来。

5.3 具体例子

在这里面,一定是&pf才行,因为p1是指向数组的指针而不是指向数组首地址的指针,我们应该使用&把数组的地址取出来。

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int division(int a, int b) { return a / b; }int main()
{/* 模拟键盘输入 */int input = 2;int ret;int (*pf[5])(int, int) = {NULL, add, sub, mul, division};int (*(*p1)[5])(int, int) = &pf;ret = (*p1)[input](3,5);printf("ret=%d\n", ret);return 0;
}

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

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

相关文章

对比DeepSeek、ChatGPT和Kimi的学术写作撰写引言能力

引言 引言部分引入研究主题&#xff0c;明确研究背景、问题陈述&#xff0c;并提出研究的目的和重要性&#xff0c;最后&#xff0c;概述研究方法和论文结构。 下面我们使用DeepSeek、ChatGPT4以及Kimi辅助引言撰写。 提示词&#xff1a; 你现在是一名[计算机理论专家]&#…

LabVIEW微位移平台位移控制系统

本文介绍了基于LabVIEW的微位移平台位移控制系统的研究。通过设计一个闭环控制系统&#xff0c;针对微位移平台的通信驱动问题进行了解决&#xff0c;并提出了一种LabVIEW的应用方案&#xff0c;用于监控和控制微位移平台的位移&#xff0c;从而提高系统的精度和稳定性。 项目背…

javaEE-6.网络原理-http

目录 什么是http? http的工作原理&#xff1a; 抓包工具 fiddler的使用 HTTP请求数据: 1.首行:​编辑 2.请求头(header) 3.空行&#xff1a; 4.正文&#xff08;body&#xff09; HTTP响应数据 1.首行&#xff1a;​编辑 2.响应头 3.空行&#xff1a; 4.响应正文…

OpenCV:闭运算

目录 1. 简述 2. 用膨胀和腐蚀实现闭运算 2.1 代码示例 2.2 运行结果 3. 闭运算接口 3.1 参数详解 3.2 代码示例 3.3 运行结果 4. 闭运算的应用场景 5. 注意事项 相关阅读 OpenCV&#xff1a;图像的腐蚀与膨胀-CSDN博客 OpenCV&#xff1a;开运算-CSDN博客 1. 简述…

C++中的类与对象(下)

上一节我们将类与对象中一个比较难的也是一个比较重要的模块学习了&#xff0c;在这节主要是一些细节上的补充。 文章目录 目录 前言 一、初始化列表 初始化列表的性质 初始化列表的总结 二、类型转换 C中的类型转换 三、static成员 static的特点 一般情况下构造函数调用顺序&a…

Versal - 基础4(VD100+Versal IBERT)

1. 简介 在之前的一篇博文中&#xff0c;我分享了在 Zynq Ultrascale MPSoC 中使用 IBERT 的方法。 《Vivado - 集成眼图分析仪 Serial I/O IBERT 误码率_vivado ibert-CSDN博客》 本文进一步探讨 Versal 中使用 IBERT 的方法。 2. 硬件平台 芯片&#xff1a;XCVE2302-SF…

《HelloGitHub》第 106 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

英语语法 第一天

I’m a student. 我是个学生 我是个新东方的学生 I’m a student of New Oriental School 我爱你 I love you 我在心中爱你 I love you in my heart. 这是一朵花 This is a flower 这是一朵在公园里的花 This is a flower in the park.(修饰部分在修饰词后面) 主干…

“新月之智”智能战术头盔系统(CITHS)

新月人物传记&#xff1a;人物传记之新月篇-CSDN博客 相关文章链接&#xff08;更新&#xff09;&#xff1a; 星际战争模拟系统&#xff1a;新月的编程之道-CSDN博客 新月智能护甲系统CMIA--未来战场的守护者-CSDN博客 目录 一、引言 二、智能头盔控制系统概述 三、系统架…

猿人学web 19题(js逆向)

这题直接点击翻页抓包&#xff0c;然后获取seesion ID请求即可 求和代码 import requestssession requests.Session() cookies {sessionid:eao9i00r8pt4xu6uzzx2k01ttqn51yc9} urlhttps://match.yuanrenxue.cn/api/match/19?page sum0 for i in range(1,6):response sess…

c语言:编译和链接(详解)

前言 要将编译和链接&#xff0c;就不得不提及编译器是如何运作的&#xff0c;虽然这部分知识是针对于要创造编译器和创作语言的人所需要清楚的&#xff0c;但作为c语言的学习者也需要了解一下&#xff0c;修炼内功&#xff0c;尤其是对于想学习c的人而言。 编译器的运作过程…

积分和微分的区别

积分&#xff1a; 积分是由微小量求大量&#xff0c;由微观的数据求得整体的状况。运算是对总量求和。 微分&#xff1a; 微分是由大量求微小量&#xff0c;反应微观的状况&#xff0c;运算是伴随着求导。 峰值检测电路: 上图检测的误差主要来自与二极管的正向导通电压降&am…

OVS-DPDK

dpdk介绍及应用 DPDK介绍 DPDK&#xff08;Data Plane Development Kit&#xff09;是一组快速处理数据包的开发平台及接口。有intel主导开发&#xff0c;主要基于Linux系统&#xff0c;用于快速数据包处理的函 数库与驱动集合&#xff0c;可以极大提高数据处理性能和吞吐量&…

亚博microros小车-原生ubuntu支持系列:18 Cartographer建图

Cartographer简介 Cartographer是Google开源的一个ROS系统支持的2D和3D SLAM&#xff08;simultaneous localization and mapping&#xff09;库。基于图优化&#xff08;多线程后端优化、cere构建的problem优化&#xff09;的方法建图算法。可以结合来自多个传感器&#xff0…

安卓(android)实现注册界面【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的&#xff08;如果代码有错漏&#xff0c;可查看源码&#xff09; 1.掌握LinearLayout、RelativeLayout、FrameLayout等布局的综合使用。 2.掌握ImageView、TextView、EditText、CheckBox、Button、RadioGroup、RadioButton、ListView、RecyclerView等控件在项目中的…

爬虫基础(四)线程 和 进程 及相关知识点

目录 一、线程和进程 &#xff08;1&#xff09;进程 &#xff08;2&#xff09;线程 &#xff08;3&#xff09;区别 二、串行、并发、并行 &#xff08;1&#xff09;串行 &#xff08;2&#xff09;并行 &#xff08;3&#xff09;并发 三、爬虫中的线程和进程 &am…

自签证书的dockerfile中from命令无法拉取镜像而docker的pull命令能拉取镜像

问题现象&#xff1a; docker pull images拉取镜像正常 dockerfile中的from命令拉取镜像就会报出证书错误。报错信息如下&#xff1a; [bjxtbwj-kvm-test-jenkins-6-243 ceshi_dockerfile]$ docker build . [] Building 0.4s (3/3) FINISHED …

计算机网络 IP 网络层 2 (重置版)

IP的简介&#xff1a; IP 地址是互联网协议地址&#xff08;Internet Protocol Address&#xff09;的简称&#xff0c;是分配给连接到互联网的设备的唯一标识符&#xff0c;用于在网络中定位和通信。 IP编制的历史阶段&#xff1a; 1&#xff0c;分类的IP地址&#xff1a; …

面对企业文件交换难题,镭速跨网文件交换系统是如何解决的?

在当今这个数字化快速发展的时代&#xff0c;企业越来越依赖于数据交换来维持其业务运作。无论是内部网络之间的沟通还是与外部合作伙伴的数据共享&#xff0c;高效且安全的跨网文件交换都显得尤为重要。然而&#xff0c;在实际操作中&#xff0c;许多企业面临着各种各样的挑战…

Many Whelps! Handle It! (10 player) Many Whelps! Handle It! (25 player)

http://db.nfuwow.com/80/?achievement4403 http://db.nfuwow.com/80/?achievement4406 最少扣你50DKP! 第二阶段 当奥妮克希亚升空后&#xff0c;在10秒内引出50只奥妮克希亚雏龙&#xff0c;随后击败奥妮克希亚。 World of Warcraft [CLASSIC][80猎人][Grandel][最少扣你5…