c语言-浅谈指针(4)

文章目录

    • 1.回调函数
      • 概念
      • 举例
    • 2.qsort函数
      • qsort的使用
    • 3.通过冒泡排序来模拟qsort函数
      • 排序int类型
      • 排序结构体类型


这是指针最后一篇了喔,完结撒花 !
前三篇:
浅谈指针(1)http://t.csdnimg.cn/JTRjW
浅谈指针(2)http://t.csdnimg.cn/1aPkr
浅谈指针(4)http://t.csdnimg.cn/TndpD

1.回调函数

概念

回调函数就是⼀个通过函数指针调⽤的函数。
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。通过回调函数能够是代码简便。

如:
实现加法

int add(int x, int y) {
	return x + y;
}
void   su(int (*p)(int, int)) {
	int a=10, b=20;
	printf("%d", p(a, b));
}

int main() {
	su(add);
	return 0;
}

注:要通过函数指针来接收函数地址

举例

通过回调函数实现计算器
1.选择界面
2.实现加、减。乘、除函数
3.一个接收这四个函数地址的函数
实现:

#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;
}
void calc(int(*pf)(int, int))//接收函数地址的函数
{
 int ret = 0;
 int x, y;
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = pf(x, y);//调用
 printf("ret = %d\n", ret);
}
int main()
{
 int input = 1;
 do
 {
 printf("******************
 printf(" 1:add 
 printf(" 3:mul 
 printf("******************
 printf("请选择:");
 scanf("%d", &input);
 switch (input)
 {
 case 1:
 calc(add);//传函数地址
 break;
 case 2:
 calc(sub);
 break;
 case 3:
 calc(mul);
 break;
 case 4:
 calc(div);
 break;
 case 0:
 printf("退出程序\n");
 break;
 default:
 printf("选择错误\n");
 break;
 }
 } while (input);
 return 0}

虽然说现在看起来还是那么多,那是因为这里只是四个函数而已,如果加上其他的计算功能呢。这样就能够大大减少代码量了

2.qsort函数

对所指向的数组元素进行排序,每个元素的长度为字节,使用函数确定顺序。
此函数使用的排序算法通过调用指定的函数来比较元素对,并将指向元素的指针作为参数。
该函数不返回任何值,而是通过对数组的元素进行重新排序来修改所指向的数组的内容.

在这里插入图片描述
注意的是 compar函数的创建的格式和 qsort的一样: int (*compar)(const void*,const void*));//这个是自己创建的
在这里插入图片描述

qsort的使用

void qsort (void* base, size_t num, size_t size,   
 int (*compar)(const void*,const void*));

我们来实现一个整形排序

int hanshu(const void* p1,const void* p2) {//这里要按照qsort中的函数参数类型来写 
//int (*compar)(const void*,const void*));
	return  (*((int*)p1) - *((int*)p2));//返回-上面有解释  (int*)p1--强制转换为int类型指针
}
int main() {
	int arr[] = { 5,3,2,4,1 };
	int zs = sizeof(arr) / sizeof(arr[0]);//数组大小
	qsort(arr, zs, sizeof(arr[0]), hanshu);//按照规则填入, sizeof(arr[0])一个元素占多少字节
	for (int i = 0; i < zs; i++)//打印
		printf("%d ", arr[i]);
	return 0;
}

我们来看看运行结果:
在这里插入图片描述
成功完成排序
那么我们再来试一下结构体

struct sl {//构建结构体

	char arr[20];
	int a;
};
int hanshu(void* p1, void* p2) {
	return  strcmp(((struct sl*)p1)->arr,((struct sl*)p2)->arr);//判断结构体中arr的大小,
	//strcmp--用于比较两个字符大小   (struct sl*)p1>>强制类型转换成结构体类型指针
}

int main() {
	struct sl s[] = { {"zhangsan",18} ,{"lisi",19}, {"wanwu",12}};
	int zs = sizeof(s) / sizeof(s[0]);//计算大小
	qsort(s, zs, sizeof(s[0]), hanshu);//进行排序
	for (int i = 0; i < zs; i++)//打印
		printf("%s  %d\n", s[i].arr,s[i].a);//打印结构体
	return 0;
}

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/7ca32c0532c84b19a017828d447fe73a.png

总结:qsort函数能够实现多种数据的排序

3.通过冒泡排序来模拟qsort函数

接下来我们通过冒泡排序来模拟qsort函数
不懂冒泡排序的可以看看这个哦:冒泡排序:http://t.csdnimg.cn/0uNZH

1.一般的冒泡排序只能用来排序整数类型,我们想要通过冒泡排序的方式来模拟qsort函数那么我们创造的冒泡函数的参数类型我们也和qsort和参数类型一样。

c void maopao (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));

2.我们比大小时要改变传递给比大小函数的参数,因为我们不知道从主函数传过来的是什么类型数据(如有:char、short、int等类型)。那么怎么改变呢?我们可以将从主函数传过来的数据进行强制类型转换,转为char*
类型(由于char类型的为1字节满足最小的数据类型),转化为char *
后,再通过从主函数传过来的的类型宽度和在循环中的变量来改变指针指向的位置,这样就可以控制传递给比大小函数的指针了。
3.交换时传递的参数和如何交换,跟比大小函数一样,不知道从主函数传过来的数据类型是什么,那么怎么样设置参数和交换呢?我们可以通过一个字节一个字节来交换数据(我们可以通过传递从主函数传过来的数据类型宽度来控制循环次数),那样不管是什么类型都可以交换了,那么我们还是将从主函数传过来的强制类型转换为char

  • 再传过去给交换函数,进行交换。

排序int类型

代码实现:

int  cmp(const void* p1,  const void* p2) {
	//比大小,因为返回类型为 int ,所以强行转为(int*),再解引用
	return (*(int*)p1 - *(int*)p2);
}

void  huan(char* p1,char* p2, int ws) {//交换函数,ws为类型长度,一个字节一个字节换
	int i = 0;
	for (i = 0; i < ws; i++) {//循环的次数和我们比较类型的宽度有关
		char te = *(p1 + i);
		*(p1+i) = *(p2+i);
		*(p2+i) = te;
	}
}
void  maopao(void* p, int zs, int ws, int (*cmp)(const void*,const  void*)) {
	//冒泡模拟的qsort函数,传入参数和qsort函数一样
	int i = 0;
	for (i = 0; i < zs - 1; i++) {//正常冒泡排序的流程,走n-1趟
		int j = 0;
		for (j = 0; j < zs - 1 - i; j++) {//前后对比
			if (cmp((char*)p + ws * j, (char*)p + ws * (j + 1)) > 0) {
				//传给cmp函数的参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针p
				huan((char*)p + ws * j, (char*)p + ws * (j + 1), ws);//交换
				//参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针p
			}
		}
	}
  }
void dayin1(int arr[], int zs) {//打印
	for (int i = 0; i < zs; i++)
		printf("%d ", arr[i]);
	printf("\n");
}

int main() {
	int arr[10] = { 2,3,6,7,1,4,9,5,0,8 };
	int zs = sizeof(arr) / sizeof(arr[0]);//求数组元素个数
	dayin1(arr, zs);//打印原来的数组
	maopao(arr, zs, sizeof(arr[0]), cmp);//sizeof(arr[0])元素宽度
	dayin1(arr, zs);
	printf("\n");
	return 0;
}

运行结果:
在这里插入图片描述
成功进行排序了
交换过程图解:
在这里插入图片描述

排序结构体类型

代码实现:

struct sl {//创建结构体
	char r[20];//名字
	int b;//年龄
};
int  cmp(const void* p1, const void* p2) {

	return strcmp(((struct sl*)p1)->r, ((struct sl*)p2)->r);//对结构体中的名字比大小
}//strcmp函数  用于字符串比大小

void  huan(char* p1, char* p2, int ws) {//交换函数,ws为类型长度,一个字节一个字节换
	int i = 0;
	for (i = 0; i < ws; i++) {//循环的次数和我们比较类型的宽度有关
		char te = *(p1 + i);
		*(p1 + i) = *(p2 + i);
		*(p2 + i) = te;
	}
}
void  maopao(void* p, int zs, int ws, int (*cmp)(const void*, const  void*)) {
	//冒泡模拟的qsort函数,传入参数和qsort函数一样
	int i = 0;
	for (i = 0; i < zs - 1; i++) {//正常冒泡排序的流程,走n-1趟
		int j = 0;
		for (j = 0; j < zs - 1 - i; j++) {//前后对比
			if (cmp((char*)p + ws * j, (char*)p + ws * (j + 1)) > 0) {
				//传给cmp函数的参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针p
				huan((char*)p + ws * j, (char*)p + ws * (j + 1), ws);//交换
				//参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针p
			}
		}
	}
}
void dayin2(struct sl s[], int zs) {
	for (int i = 0; i < zs; i++)
		printf("%s  %d\n", s[i].r, s[i].b);//打印结构体中的数据
	printf("\n");
}
int main() {
	struct sl s[] = {{"zhangsan",18},{"lisi",12},{"wangwu",87}};
	int zs = sizeof(s) / sizeof(s[0]);//求数组元素个数
	dayin2(s, zs);//打印原来的数组
	maopao(s, zs, sizeof(s[0]), cmp);//sizeof(arr[0])元素宽度
	dayin2(s, zs);
	printf("\n");
	return 0;
}

运行结果:
在这里插入图片描述
当然冒泡模拟的qsort还可以进行其他数据类型的排序

以上就是我的分享了,如果有什么错误,欢迎在评论区留言。
最后,谢谢大家的观看!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业远程访问业务系统:对比MPLS专线,贝锐蒲公英为何更优优势?

如今&#xff0c;企业大多都会采用OA、ERP、CRM等各种数字化业务系统。 私有云、公有云混合架构也变得越来越常见。 比如&#xff1a;研发系统部署在公司本地私有云、确保数据安全&#xff0c;OA采用公有云方案、满足随时随地访问需求。 如此一来&#xff0c;也产生了远程访问…

【分布式】分布式事务及其解决方案

目录 一、分布式事务二、分布式事务的解决方案1. 全局事务&#xff08;1&#xff09;DTP模型&#xff08;2&#xff09; 两阶段提交协议&#xff08;2PC&#xff09;原理二阶段提交的缺点 &#xff08;3&#xff09;三阶段提交协议&#xff08;3PC&#xff09;原理 2. 基于可靠…

ModuleNotFoundError: No module named ‘torch_sparse‘

1、卸载 先把torch-geometric、torch-sparse、torch-scatter、torch-cluster、 torch-spline-conv全部卸载了 pip uninstall torch-geometric torch-scatter torch-sparse torch-cluster torch-spline-conv 2.conda list确定PyTorch的版本&#xff0c;我的是1.10 3、确定下载地…

Excel表中合并两个Sheet的方法?

按AltF11&#xff0c;调出Visual Basic 界面。 在左侧窗口中&#xff0c;右键选择“插入”—“模块”&#xff1a; 将如下代码粘贴进去&#xff0c;点击运行按钮&#xff0c;完成数据表合并。 Sub MergeAllSheetsInThisWorkbook() On Error Resume Next Application.ScreenU…

38 关于 redo 日志

前言 undo 和 redo 是在 mysql 中 事务, 或者 异常恢复 的场景下面 经常会看到的两个概念 这里 来看一下 redo, redo 主要是用于 异常恢复 的场景下面 测试表结构如下 CREATE TABLE tz_test (id int(11) unsigned NOT NULL AUTO_INCREMENT,field1 varchar(128) DEFAULT NULL…

通过线性回归进行房价预测

房价预测一直是房地产行业和投资者关注的重要问题。线性回归是一种常用的回归算法&#xff0c;可以建立输入变量和连续输出变量之间的关系。在本文中&#xff0c;我们将探讨如何使用线性回归算法来进行房价预测&#xff0c;并介绍该方法的步骤和实践技巧。 一、线性回归算法简…

拼图游戏制作

1.创建4个包 2.创建用户界面 package domain;/*** ClassName: User* Author: Kox* Data: 2023/2/2* Sketch:*/ public class User {private String username;private String password;public User() {}public User(String username, String password) {this.username usernam…

浅谈 Binius:用 Rust 实现的硬件优化 SNARK 协议

作者&#xff1a;Ulvetanna 团队 编译&#xff1a;TinTinLand 原文链接&#xff1a;https://www.ulvetanna.io/news/binius-hardware-optimized-snark 在一篇新的研究论文中&#xff0c;零知识证明技术开发团队 Ulvetanna 展示了一种基于二进制域塔 &#xff08;Towers of Bi…

迪科DTC-F81收费机DTC-F82

迪科DTC-F81收费机是一款挂式收费机&#xff0c;广泛应用的学校食堂刷卡消费&#xff0c;DTC-F82收费机是台式消费机&#xff0c;常用在学校超市&#xff0c;放在桌子上使用的&#xff0c;这2款消费机是迪科畅销机型&#xff0c;如下图 机器质量可靠稳定&#xff0c;不少用户使…

NFT Insider115:The Sandbox开设元宇宙Diorama快闪店,​YGG Web3 游戏峰会已开幕

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…

Vue3框架中让table合计居中对齐

第一步&#xff1a;给它加一个类名 center-table 如下&#xff1a; <el-table:data"datas.shows"max-height"600px"show-summarystripeborderstyle"width: 100%":header-cell-style"{ textAlign: center }":cell-style"{ text…

threejs创建一个旋转的正方体【完整代码】

效果&#xff1a; 中文网three.js docs 1.搭建环境 安装three 首先我们需要新建一个项目 vue/react都可 这里以vue为演示 npm i three 找到一个新的页面 在页面script的地方导入three import * as THREE from "three" 或者自己逐个导入 import {PerspectiveC…

SQLite 和 SQLiteDatabase 的使用

实验七&#xff1a;SQLite 和 SQLiteDatabase 的使用 7.1 实验目的 本次实验的目的是让大家熟悉 Android 中对数据库进行操作的相关的接口、类等。SQLiteDatabase 这个是在 android 中数据库操作使用最频繁的一个类。通过它可以实现数据库的创建或打开、创建表、插入数据、删…

保姆级 ARM64 CPU架构下安装部署Docker + rancher + K8S 说明文档

1 K8S 简介 K8S是Kubernetes的简称&#xff0c;是一个开源的容器编排平台&#xff0c;用于自动部署、扩展和管理“容器化&#xff08;containerized&#xff09;应用程序”的系统。它可以跨多个主机聚集在一起&#xff0c;控制和自动化应用的部署与更新。 K8S 架构 Kubernete…

【nlp】3.6 Tansformer模型构建(编码器与解码器模块耦合)

Tansformer模型构建(编码器与解码器模块耦合) 1. 模型构建介绍2 编码器-解码器结构的代码实现3 Tansformer模型构建过程的代码实现4 小结1. 模型构建介绍 通过上面的小节, 我们已经完成了所有组成部分的实现, 接下来就来实现完整的编码器-解码器结构耦合. Transformer总体架…

聚类笔记:HDBSCAN

1 算法介绍 DBSCAN/OPTICS层次聚类主要由以下几步组成 空间变换构建最小生成树构建聚类层次结构(聚类树)压缩聚类树提取簇 2 空间变换 用互达距离来表示两个样本点之间的距离 ——>密集区域的样本距离不受影响——>稀疏区域的样本点与其他样本点的距离被放大——>…

Unity Android FireBase bugly报错查询

报错如下图&#xff0c;注意&#xff0c;标红的三处 使用的il2cpp和架构是arm64-v8a 那我们就可以根据这些去找对应的符号表&#xff0c;在unity安装目录下 Unity2020.3.33f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Release\Symbols\arm64-v8a 找到l…

缓存组件状态,提升用户体验:探索 keep-alive 的神奇世界

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

晨控CK-FR03-EIP读卡器与欧姆龙NX/NJ系列EtherNet/IP通讯手册

晨控CK-FR03-EIP读卡器与欧姆龙NX/NJ系列EtherNet/IP通讯手册 CK-FR03-EIP是一款基于射频识别技术的高频RFID标签读卡器&#xff0c;读卡器工作频率为13.56MHZ&#xff0c;支持对I-CODE 2、I-CODE SLI等符合ISO15693国际标准协议格式标签的读取。 读卡器同时支持标准工业通讯…

Linux文件查看命令

1.cat加上文件名 &#xff08;因为所有文件内容都会打印到屏幕上&#xff0c;所以内容少时使用这个&#xff0c;总不能用cat来定义一本小说&#xff09; 3.往文件中写入数据——cat加上>(重定向符&#xff09;加上文件名&#xff0c;写完之后&#xff0c;按键 cat原本是把…