当前位置: 首页 > news >正文

指针---进阶篇(二)

指针---进阶篇(二)

  • 前言
  • 一、函数指针
    • 1.抛砖引玉
    • 2.如何判断函数指针?(方法总结)
  • 二、函数指针数组
    • 1.什么是函数指针数组?
    • 2.讲解函数指针数组
    • 3.模拟计算器:讲解函数指针数组
  • 三、指向函数指针数组的指针
  • 四、回调函数
  • 五、qsort排序

前言

那么好了好了,宝子们,从今天开始开始总结暑假博客,从指针开始,后续,来吧开始整活!⛳️

一、函数指针

1.抛砖引玉

直接上代码:

//抛砖引玉
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}

在这里插入图片描述
我打印的是函数的地址。但是如果我们想要把函数的地址保存起来,我们该怎么样操作呢?

void test()
{printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();

在这里我们需要明白一点,当时我们学数组的时候,我们知道数组名就是数组首元素的地址,在这里函数也是一样的,函数名也可以代表函数的首元素地址!
首先,能给存储地址,就要求pfun1或者pfun2是指针,那哪个是指针?前面的进阶一里面我们讲过了:数组指针。我们呢可以类比一下
答案是:pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。

2.如何判断函数指针?(方法总结)

比如说下面这段代码:


int add(int x, int y)//加法
{return x + y;
}int main()
{int (*pf)(int, int) = add;int m = add(3, 4);int n = pf(4, 5);printf("%d %d\n", m, n);return 0;
}

在这里我来教一下大家怎样判别,什么是函数指针,指针函数,数组指针,指针数组之类的。
就以这个为例:int (*pf)(int,int)=add;
在这个语句里面变量是pf,pf被一个小括号扩住,pf先与 *结合,所以说它以指针结尾。首先分析完了他是一个指针,然后他是什么类型的指针呢?后面是参数,两个参数类型都是int,前面是返回类型也是int,所以说它是一个标标准准的函数指针。
(在这里一个规律就是:变量和XX先结合就以XX为结尾)

二、函数指针数组

1.什么是函数指针数组?

首先我们要明白什么是数组?
数组的概念是:数组是一个储存相同元素的集合。
不要害怕他前面这么复杂。又是函数,又是指针,又是数组,我们该如何判断呢?还是运用我上面的规律总结。

2.讲解函数指针数组

好的,我们现在直接上栗子:


int add(int x, int y)//加法
{return x + y;
}int sub(int x, int y)//减法
{return x - y;
}int mul(int x, int y)//乘法
{return x * y;
}int div(int x, int y)//除法
{return x / y;
}int main()
{int (*jia)(int, int) = add;int (*jian)(int, int) = sub;int (*cheng)(int, int) = mul;int (*chu)(int, int) = div;int (*pfarr[4])(int, int) = { add,sub,mul,div };//上面的数字里面储存的都是各个函数名,所以就是储存的函数的地址return 0;
}

我们来分析一下这个 函数指针数组:
int (*pfarr[4])(int, int) = { add,sub,mul,div };
看这样复杂的语句的时候,我们先看变量名,变量名是pfarr,先看变量名与谁先结合,由于这里的方括号[ ]的结合度比 *高,所以pfarr先与方括号[ ]结合,所以说它就是以数组来结尾的。

只要你有几个函数,并且函数的返回类型都是一模一样的,你就可以把这几个函数的地址放在一个数组里面,那么这个数组就叫做函数指针数组!
如何写一个函数指针数字呢?那当然是从函数指针来写起,然后再加一个数组

3.模拟计算器:讲解函数指针数组

1.常规的使用普通函数来实现


#include <stdio.h>
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 div(int a, int b)
{return a / b;
}//常规的使用普通函数来实现
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add           2:sub \n");printf(" 3:mul           4:div \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输入操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输入操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输入操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输入操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

2.函数指针数组实现


#include <stdio.h>
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 div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表while (input){printf("*************************\n");printf(" 1:add           2:sub \n");printf(" 3:mul           4:div \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf("输入操作数:");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);}elseprintf("输入有误\n");printf("ret = %d\n", ret);}return 0;
}

三、指向函数指针数组的指针

何为指向函数指针数组的指针?简单的来讲就是函数指针数组的地址
指向函数指针数组的指针是一个 指针 指针指向一个 数组 ,数组的元素都是 函数指针 ;

上代码:

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

四、回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

五、qsort排序

接下来我通过用qsort排序来展示一下回调函数的魅力:

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{return (*( int *)p1 - *(int *) p2);
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}

使用回调函数,模拟实现qsort(采用冒泡的方式)。
注意:这里第一次使用 void* 的指针,讲解 void* 的作用。


#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{int i = 0;int j = 0;for (i = 0; i < count - 1; i++){for (j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };//char *arr[] = {"aaaa","dddd","cccc","bbbb"};int i = 0;bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

好了,今天的分享就到这里了

如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!

在这里插入图片描述

相关文章:

指针---进阶篇(二)

指针---进阶篇&#xff08;二&#xff09; 前言一、函数指针1.抛砖引玉2.如何判断函数指针&#xff1f;&#xff08;方法总结&#xff09; 二、函数指针数组1.什么是函数指针数组&#xff1f;2.讲解函数指针数组3.模拟计算器&#xff1a;讲解函数指针数组 三、指向函数指针数组…...

Python实现SSA智能麻雀搜索算法优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 麻雀搜索算法(Sparrow Search Algorithm, SSA)是一种新型的群智能优化算法&#xff0c;在2020年提出&a…...

【go语言基础】结构体struct

主要是敲代码&#xff0c;敲的过程中会慢慢体会。 1.概念 结构体是用户定义的类型&#xff0c;表示若干字段的集合&#xff0c;目的是将数据整合在一起。 简单的说&#xff0c;类似Java中的实体类。存储某个实体属性的集合。 2.结构体声明 注意&#xff1a;结构体名字&…...

显卡服务器适用于哪些场景

显卡&#xff08;GPU&#xff09;服务器&#xff0c;简单来说&#xff0c;GPU服务器是基于GPU的应用于视频编解码、深度学习、科学计算等多种场景的快速、 稳定、弹性的计算服务。那么壹基比小鑫告诉你显卡服务器主要的用途有哪一些。 一、运行手机模拟器 显卡服务器可支持…...

MySQL DML 数据操作

文章目录 1.插入记录INSERTREPLACE 2.删除记录3.修改记录4.备份还原数据参考文献 1.插入记录 INSERT 使用 INSERT INTO 语句可以向数据表中插入数据。INSET INTO 有三种形式。 INSET INTO tablename SELECT...INSET INTO tablename SET column1value1,column2value2...INSET…...

服务端与网络相关知识

1. http/https 协议 1.0 协议缺陷: ⽆法复⽤链接&#xff0c;完成即断开&#xff0c;重新慢启动和 TCP 3 次握⼿head of line blocking : 线头阻塞&#xff0c;导致请求之间互相影响 1.1 改进: ⻓连接(默认 keep-alive )&#xff0c;复⽤host 字段指定对应的虚拟站点新增功…...

一分钟上手Vue VueI18n Internationalization(i18n)多国语言系统开发、国际化、中英文语言切换!

这里以Vue2为例子 第一步&#xff1a;安装vue-i18n npm install vue-i18n8.26.5 第二步&#xff1a;在src下创建js文件夹&#xff0c;继续创建language文件夹 在language文件夹里面创建zh.js、en.js、index.js这仨文件 这仨文件代码分别如下&#xff1a; zh.js export de…...

stm32 cubemx can通讯(1)回环模式

文章目录 前言一、cubemx配置二、代码1.过滤器的配置&#xff08;后续会介绍&#xff09;2.main.c3.主循环 总结 前言 介绍使用stm32cubemx来配置can&#xff0c;本节讲解一个简答&#xff0c;不需要stm32的can和外部连接&#xff0c;直接可以用于验证的回环模式。 所谓回环模…...

Python基础小项目

今天给大家写一期特别基础的Python小项目&#xff0c;欢迎大家支持&#xff0c;并给出自己的完善修改 &#xff08;因为我写的都是很基础的&#xff0c;运行速率不是很好的 目录 1. 地铁票价题目程序源码运行截图 2. 购物车题目程序源码运行截图 3. 名片管理器题目程序源码运行…...

Python Opencv实践 - 在图像上绘制图形

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png") print(img.shape)plt.imshow(img[:,:,::-1])#画直线 #cv.line(img,start,end,color,thickness) #参考资料&#xff1a;https://blog.csdn.ne…...

管理者应该编码,但不是在工作时

管理者应该编码吗?这个问题似乎没有一个明确的答案。这场辩论有支持者也有反对者&#xff0c;每一方都有自己的论点。我最近在工作中编写了一个副业项目&#xff0c;这让我重新评估了我在这个问题上的立场。经历了这些之后&#xff0c;我可以说&#xff0c;我的立场已经从管理…...

深度学习常用的python库学习笔记

文章目录 数据分析四剑客Numpyndarray数组和标量之间的运算基本的索引和切片数学和统计方法线性代数 PandasMatplotlibPIL 数据分析四剑客 Numpy Numpy中文网 ndarray 数组和标量之间的运算 基本的索引和切片 数学和统计方法 线性代数 Pandas Pandas中文网 Matplotlib Mat…...

C语言属刷题训练【第八天】

文章目录 &#x1fa97;1、如下程序的运行结果是&#xff08; &#xff09;&#x1f4bb;2、若有定义&#xff1a; int a[2][3]; &#xff0c;以下选项中对 a 数组元素正确引用的是&#xff08; &#xff09;&#x1f9ff;3、在下面的字符数组定义中&#xff0c;哪一个有语法错…...

阿里云PolarDB数据库倚天ARM架构详细介绍

阿里云云原生数据库PolarDB MySQL版推出倚天ARM架构&#xff0c;倚天ARM架构规格相比X86架构规格最高降价45%&#xff0c;PolarDB针对自研倚天芯片&#xff0c;从芯片到数据库内核全链路优化&#xff0c;助力企业降本增效。基于阿里云自研的倚天服务器&#xff0c;同时在数据库…...

pytest 编写规范

一、pytest 编写规范 1、介绍 pytest是一个非常成熟的全功能的Python测试框架&#xff0c;主要特点有以下几点&#xff1a; 1、简单灵活&#xff0c;容易上手&#xff0c;文档丰富&#xff1b;2、支持参数化&#xff0c;可以细粒度地控制要测试的测试用例&#xff1b;3、能够…...

Vue.use和vue.component的区别

Vue.use 注册全局插件vue.use时会将自动将开发者 vue构造函数传入插件,vue.use参数必须是function或者object,object中必须有install方法vue.use会自动判断当前插件时候已经被注册过了,防止重复注册 Vue.component 注册全局组件 为什么有了Vue.component还要用Vue.use呢 V…...

张驰咨询:提高企业竞争力,六西格玛设计公司(DFSS)在行动

六西格玛设计公司(DFSS)是一种专业从事六西格玛设计的企业&#xff0c;其主要作用是为客户提供高效的六西格玛设计服务&#xff0c;以帮助客户实现高品质、低成本和高效率的产品开发过程。六西格玛设计公司通常拥有一支专业的团队&#xff0c;具有丰富的六西格玛设计经验和技术…...

影响 40% 用户,Ubuntu 发行版被曝 2 个安全漏洞

导读近日消息&#xff0c;Wiz 的研究专家 S. Tzadik 和 S. Tamari 近日在 Ubuntu 系统中发现了 2 个安全漏洞&#xff0c;可以提升本地权限&#xff0c;预估影响 40% 的 Ubuntu 用户。 根据博文内容&#xff0c;汇总两个漏洞内容如下&#xff1a; 追踪编号&#xff1a;CVE-202…...

SpringCache的介绍和入门案例

文章目录 概述常用注解入门案例 概述 Spring Cache是Spring框架提供的一个缓存抽象层&#xff0c;用于在应用程序中实现缓存的功能。它通过在方法执行前检查缓存中是否已经存在所需数据&#xff0c;如果存在则直接返回缓存中的数据&#xff0c;如果不存在则执行方法体&#xf…...

闪马智能又上榜!

近日&#xff0c;上海市经济和信息化委员会公布了2023年度上半年&#xff08;第30批&#xff09;市级企业技术中心拟认定企业名单。凭借在技术创新方面的突出成就&#xff0c;闪马智能上榜其中。 本次认定由上海市经济和信息化委员会组织开展&#xff0c;综合企业的地位和作用、…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

多元隐函数 偏导公式

我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式&#xff0c;给定一个隐函数关系&#xff1a; F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 &#x1f9e0; 目标&#xff1a; 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z​、 …...