【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;
}
相关文章:
【C语言指针】指针和函数
文章目录 一、前言二、指针函数2.1 概念2.2 定义2.3 具体例子 三、函数指针3.1 概念3.2 定义3.3 具体例子3.4 回调函数3.4.1 概念3.4.2 例子13.4.3 例子2 四、函数指针数组4.1 概念4.2 定义4.3 具体例子 五、函数指针数组的指针5.1 概念5.2 定义5.3 具体例子 一、前言 关于指针…...
因果推断与机器学习—用机器学习解决因果推断问题
Judea Pearl 将当前备受瞩目的机器学习研究戏谑地称为“仅限于曲线拟合”,然而,曲线拟合的实现绝非易事。机器学习模型在图像识别、语音识别、自然语言处理、蛋白质分子结构预测以及搜索推荐等多个领域均展现出显著的应用效果。 在因果推断任务中,在完成因果效应识别之后,需…...
2025全自动企业站群镜像管理系统 | 支持繁简转换拼音插入
2025全自动企业站群镜像管理系统 | 支持繁简转换拼音插入 在全球化的今天,企业面临着管理多站点的挑战,尤其是跨语言和地理位置的站点。为此,我们设计了一套基于PHP的全自动企业站群镜像管理系统,它不仅能够自动化站点的管理&…...
基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发
基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发 摘要 随着人工智能技术的不断发展,语音识别在会议记录、语音笔记等场景中得到了广泛应用。本文介绍了一个基于Python和阿里云百炼大模型的语音识别与文本保存工具的开发过程。该工具能够高效地识别东…...
日志2025.2.1
日志2025.2.1 1.做了敌人状态机 public class EnermyStateMachine { public EnermyState currentState { get; private set; } public void InitializeState(EnermyState startState) { currentState startState; currentState.Enter(); } public void Change…...
GIS与相关专业软件汇总
闲来无事突然想整理一下看看 GIS及相关领域 究竟有多少软件或者工具包等。 我询问了几个AI工具并汇总了一个软件汇总,不搜不知道,一搜吓一跳,搜索出来了大量的软件,大部分软件或者工具包都没有见过,不知大家还有没有要…...
webrtc编译需要常用环境变量以及相关名词解释
set vs2022_installD:\\vs2022 set GYP_MSVS_OVERRIDE_PATHD:\\vs2022 set GYP_GENERATORSmsvs-ninja,ninja set WINDOWSSDKDIRD:\\Windows Kits\10 set DEPOT_TOOLS_WIN_TOOLCHAIN0 set GYP_MSVS_VERSION2022 这些环境变量是为了编译 WebRTC 时让 GYP/Depot Tools 正确找到 V…...
飞书项目流程入门指导手册
飞书项目流程入门指导手册 参考资料准备工作新建空间国际化配置新建工作项字段管理新建字段对接标识授权角色 流程管理基础说明流程节点配置流程节点的布局配置页面上布局按钮布局配置 流程节点驳回流程图展示自动化字段修改 局限性 参考资料 飞书官方参考文档:飞书…...
Android学习制作app(ESP8266-01S连接-简单制作)
一、理论 部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客 以下直接上代码和效果视频,esp01S的收发硬件代码目前没有分享,但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动…...
docker直接运行arm下的docker
运行环境是树莓派A 处理器是 arm32v6 安装了docker,运行lamp 编译安装php的时候发现要按天来算,于是用电脑vm下的Ubuntu系统运行arm的docker 然后打包到a直接导入运行就可以了 第一种方法 sudo apt install qemu-user-static 导入直接运行就可以了…...
PYH与MAC的桥梁MII/MIIM
在学习车载互联网时,看到了一句话,Processor通过DMA直接存储访问与MAC之间进行数据的交互,MAC通过MII介质无关接口与PHY之间进行数据的交互。常见的以太网硬件结构是,将MAC集成进Processor芯片,将PHY留在Processor片外…...
如何使用SliverList组件
文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了沉浸式状态栏相关的内容,本章回中将介绍SliverList组件.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的SliverList组件是一种列表类组件,类似我们之前介…...
SQL UCASE() 函数详解
SQL UCASE() 函数详解 在SQL中,UCASE() 函数是一个非常有用的字符串处理函数,它可以将字符串中的所有小写字母转换为大写字母。本文将详细介绍UCASE() 函数的用法、语法、示例以及其在实际应用中的优势。 一、UCASE() 函数简介 UCASE() 函数是SQL标准…...
单细胞分析基础-第一节 数据质控、降维聚类
scRNA_pipeline\1.Seurat 生物技能树 可进官网查询 添加链接描述 分析流程 准备:R包安装 options("repos"="https://mirrors.ustc.edu.cn/CRAN/") if(!require("BiocManager")) install.packages("BiocManager",update = F,ask =…...
Vue 与 Electron 结合开发桌面应用
1. 引言 1.1 什么是 Electron? Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。它结合了 Chromium 渲染引擎和 Node.js 运行时,使得开发者可以使用 Web 技术创建原生桌面应用。1.2 为什么选择 Vue.js 和 Electron? Vue.js 是一个渐进式 JavaSc…...
Golang 应用的 Docker 部署方式介绍及使用详解
本文将介绍如何使用 Docker 部署一个基于 Go 语言的后台服务应用 godco,并介绍如何配置 MongoDB 数据库容器的连接,确保应用能够成功启动并连接到容器方式部署的mongoDB数据库。 前提条件 1.已安装 Docker/Podman 2.已安装 MongoDB 数据库容器ÿ…...
DeepSeek的提示词使用说明
一、DeepSeek概述 DeepSeek是一款基于先进推理技术的大型语言模型,能够根据用户提供的简洁提示词生成高质量、精准的内容。在实际应用中,DeepSeek不仅能够帮助用户完成各类文案撰写、报告分析、市场研究等工作,还能够生成结构化的内容&#…...
python小知识-typing注解你的程序
python小知识-typing注解你的程序 1. Typing的简介 typing 是 Python 的一个标准库,它提供了类型注解的支持,但并不会强制类型检查。类型注解在 Python 3.5 中引入,并在后续版本中得到了增强和扩展。typing 库允许开发者为变量、函数参数和…...
HTML<hgroup>标签
例子: 使用hgroup元素标记标题和段落是相关的: <hgroup> <h2>Norway</h2> <p>The land with the midnight sun.</p> </hgroup> 定义和用法: 标签<hgroup>用于包围标题和一个或多个<p&g…...
【已解决】黑马点评项目Redis版本替换过程的数据迁移
黑马点评项目Redis版本替换过程的数据迁移 【哭哭哭】附近商户中需要用到的GEO功能只在Redis 6.2以上版本生效 如果用的是老版本,美食/KTV的主页能正常返回,但无法显示内容 上次好不容易升到了5.0以上版本,现在又用不了了 Redis 6.2的windo…...
mybatis辅助配置
驼峰映射 sql里面定义字段通常是使用下划线定义 比如dept_id 而我们的后端属性通常就是驼峰命名 deptId 所以这两匹配进行自动赋值就比较麻烦 可以使用 select dept_id as deptId 来解决(起别名) 也可以用mybatis的辅助配置解决 第三种就是推荐的在spr…...
基于YOLO11的肺结节检测系统
基于YOLO11的肺结节检测系统 (价格90) LUNA16数据集 数据一共 1186张 按照8:1:1随机划分训练集(948张)、验证集(118张)与测试集(120张) 包含 nodule 肺结节 1种…...
C#面向对象(继承)
1.什么是继承 在 C# 编程语言中,继承是一个核心概念,它允许一个类(称为派生类)继承另一个类(称为基类)的成员,如方法、属性和其他成员。继承机制使得代码重用成为可能,简化了应用程…...
Qt事件处理:理解处理器、过滤器与事件系统
1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中,所有事件都继承自 QEvent ,并且每个事件都有特定的标识符,如:Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息ÿ…...
为大模型提供webui界面的利器:Open WebUI 完全本地离线部署deepseek r1
为大模型提供webui界面的利器:Open WebUI Open WebUI的官网:🏡 Home | Open WebUI 开源代码:WeTab 新标签页 Open WebUI是一个可扩展、功能丰富、用户友好的自托管AI平台,旨在完全离线运行。它支持各种LLM运行程序&am…...
Arduino可以做哪些有意思的项目
Arduino 是一个非常适合初学者和高级开发者的开源电子平台,可以用来实现各种有趣的项目。以下是一些有意思的 Arduino 项目: 1. 智能家居自动化 智能灯光控制: 使用 Arduino 控制 LED 灯带,根据时间或传感器输入自动调整亮度和颜色。温湿度…...
EtherCAT主站IGH-- 27 -- IGH之globals.h文件解析
EtherCAT主站IGH-- 27 -- IGH之globals.h文件解析 0 预览一 该文件功能宏定义数据结构打印宏三 h文件翻译四 c文件翻译该文档修改记录:总结0 预览 一 该文件功能 该文件包含了一些全局定义和宏,用于 IgH EtherCAT 主站(EtherCAT Master)的实现。包括了一些超时设定、宏定义…...
17.1 图像操作
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 17.1.1 Image类 Image类为源自 Bitmap 和 Metafile 的类提供功能的抽象基类。 Image的属性大多数是只读的: FrameDim…...
基于Scrapy采集豆瓣电影Top250的详细数据
基于Scrapy采集豆瓣电影Top250的详细数据 Scrapy 官方文档:https://docs.scrapy.org/en/latest/豆瓣电影Top250官网:https://movie.douban.com/top250写在前面 实验目的:基于Scrapy框架采集豆瓣电影Top250的详细数据。 电脑系统:Windows 使用软件:PyCharm、Navicat Python…...
软件工程概论试题五
一、多选 1.好的软件的基本属性包括()。 A. 效率 B. 可依赖性和信息安全性 C. 可维护性 D.可接受性 正答:ABCD 2.软件工程的三要素是什么()? A. 结构化 B. 工具 C.面向对象 D.数据流! E.方法 F.过程 正答:BEF 3.下面中英文术语对照哪些是正确的、且是属…...
