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

news2025/2/2 9:26:41

文章目录

  • 一、前言
  • 二、指针函数
    • 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.coloradmin.cn/o/2289714.html

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

相关文章

因果推断与机器学习—用机器学习解决因果推断问题

Judea Pearl 将当前备受瞩目的机器学习研究戏谑地称为“仅限于曲线拟合”,然而,曲线拟合的实现绝非易事。机器学习模型在图像识别、语音识别、自然语言处理、蛋白质分子结构预测以及搜索推荐等多个领域均展现出显著的应用效果。 在因果推断任务中,在完成因果效应识别之后,需…

2025全自动企业站群镜像管理系统 | 支持繁简转换拼音插入

2025全自动企业站群镜像管理系统 | 支持繁简转换拼音插入 在全球化的今天&#xff0c;企业面临着管理多站点的挑战&#xff0c;尤其是跨语言和地理位置的站点。为此&#xff0c;我们设计了一套基于PHP的全自动企业站群镜像管理系统&#xff0c;它不仅能够自动化站点的管理&…

基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发

基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发 摘要 随着人工智能技术的不断发展&#xff0c;语音识别在会议记录、语音笔记等场景中得到了广泛应用。本文介绍了一个基于Python和阿里云百炼大模型的语音识别与文本保存工具的开发过程。该工具能够高效地识别东…

GIS与相关专业软件汇总

闲来无事突然想整理一下看看 GIS及相关领域 究竟有多少软件或者工具包等。 我询问了几个AI工具并汇总了一个软件汇总&#xff0c;不搜不知道&#xff0c;一搜吓一跳&#xff0c;搜索出来了大量的软件&#xff0c;大部分软件或者工具包都没有见过&#xff0c;不知大家还有没有要…

飞书项目流程入门指导手册

飞书项目流程入门指导手册 参考资料准备工作新建空间国际化配置新建工作项字段管理新建字段对接标识授权角色 流程管理基础说明流程节点配置流程节点的布局配置页面上布局按钮布局配置 流程节点驳回流程图展示自动化字段修改 局限性 参考资料 飞书官方参考文档&#xff1a;飞书…

Android学习制作app(ESP8266-01S连接-简单制作)

一、理论 部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客 以下直接上代码和效果视频&#xff0c;esp01S的收发硬件代码目前没有分享&#xff0c;但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动…

如何使用SliverList组件

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了沉浸式状态栏相关的内容&#xff0c;本章回中将介绍SliverList组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的SliverList组件是一种列表类组件&#xff0c;类似我们之前介…

单细胞分析基础-第一节 数据质控、降维聚类

scRNA_pipeline\1.Seurat 生物技能树 可进官网查询 添加链接描述 分析流程 准备:R包安装 options("repos"="https://mirrors.ustc.edu.cn/CRAN/") if(!require("BiocManager")) install.packages("BiocManager",update = F,ask =…

HTML<hgroup>标签

例子&#xff1a; 使用hgroup元素标记标题和段落是相关的&#xff1a; <hgroup> <h2>Norway</h2> <p>The land with the midnight sun.</p> </hgroup> 定义和用法&#xff1a; 标签<hgroup>用于包围标题和一个或多个<p&g…

【已解决】黑马点评项目Redis版本替换过程的数据迁移

黑马点评项目Redis版本替换过程的数据迁移 【哭哭哭】附近商户中需要用到的GEO功能只在Redis 6.2以上版本生效 如果用的是老版本&#xff0c;美食/KTV的主页能正常返回&#xff0c;但无法显示内容 上次好不容易升到了5.0以上版本&#xff0c;现在又用不了了 Redis 6.2的windo…

mybatis辅助配置

驼峰映射 sql里面定义字段通常是使用下划线定义 比如dept_id 而我们的后端属性通常就是驼峰命名 deptId 所以这两匹配进行自动赋值就比较麻烦 可以使用 select dept_id as deptId 来解决&#xff08;起别名&#xff09; 也可以用mybatis的辅助配置解决 第三种就是推荐的在spr…

基于YOLO11的肺结节检测系统

基于YOLO11的肺结节检测系统 (价格90) LUNA16数据集 数据一共 1186张 按照8&#xff1a;1&#xff1a;1随机划分训练集&#xff08;948张&#xff09;、验证集&#xff08;118张&#xff09;与测试集&#xff08;120张&#xff09; 包含 nodule 肺结节 1种…

C#面向对象(继承)

1.什么是继承 在 C# 编程语言中&#xff0c;继承是一个核心概念&#xff0c;它允许一个类&#xff08;称为派生类&#xff09;继承另一个类&#xff08;称为基类&#xff09;的成员&#xff0c;如方法、属性和其他成员。继承机制使得代码重用成为可能&#xff0c;简化了应用程…

Qt事件处理:理解处理器、过滤器与事件系统

1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中&#xff0c;所有事件都继承自 QEvent &#xff0c;并且每个事件都有特定的标识符&#xff0c;如&#xff1a;Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息&#xff…

为大模型提供webui界面的利器:Open WebUI 完全本地离线部署deepseek r1

为大模型提供webui界面的利器&#xff1a;Open WebUI Open WebUI的官网&#xff1a;&#x1f3e1; Home | Open WebUI 开源代码&#xff1a;WeTab 新标签页 Open WebUI是一个可扩展、功能丰富、用户友好的自托管AI平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&am…

17.1 图像操作

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.1.1 Image类 Image类为源自 Bitmap 和 Metafile 的类提供功能的抽象基类。 Image的属性大多数是只读的&#xff1a; FrameDim…

软件工程概论试题五

一、多选 1.好的软件的基本属性包括()。 A. 效率 B. 可依赖性和信息安全性 C. 可维护性 D.可接受性 正答&#xff1a;ABCD 2.软件工程的三要素是什么()? A. 结构化 B. 工具 C.面向对象 D.数据流! E.方法 F.过程 正答&#xff1a;BEF 3.下面中英文术语对照哪些是正确的、且是属…

深入解析“legit”的地道用法——从俚语到正式表达:Sam Altman用来形容DeepSeek: legit invigorating(真的令人振奋)

深入解析“legit”的地道用法——从俚语到正式表达 一、引言 在社交媒体、科技圈甚至日常对话中&#xff0c;我们经常会看到或听到“legit”这个词。比如最近 Sam Altman 在 X&#xff08;原 Twitter&#xff09;上发的一条帖子中写道&#xff1a; we will obviously deliver …

行业规范要当作业务实体画出来吗

第五元素 总觉得这些没有逻辑的实体&#xff0c;在绘制的时候不应该绘出来&#xff0c;他们没有责任啊。 比如以下:查阅规范 感觉不太对 UMLChina潘加宇 你这个规范是一个电脑系统还是一本书 第五元素 是书 UMLChina潘加宇 书没有智能&#xff0c;唯一暴露的接口是“翻”…

Cubemx文件系统挂载多设备

cubumx版本&#xff1a;6.13.0 芯片&#xff1a;STM32F407VET6 在上一篇文章中介绍了Cubemx的FATFS和SD卡的配置&#xff0c;由于SD卡使用的是SDIO通讯&#xff0c;因此具体驱动不需要自己实现&#xff0c;Cubemx中就可以直接配置然后生成SDIO的驱动&#xff0c;并将SD卡驱动和…