【C语言】指针进阶[下](回调函数(模拟实现qsort-采用冒泡方式))

news2024/11/16 13:04:23

简单不先于复杂,而是在复杂之后。

 89efcc89ac61428db4d5b6639b2bd948.jpeg

目录

1. 回调函数 

1.1 qsort 函数的使用 

1.2 qsort 排序结构体类型 

1.3 回调函数模拟实现 qsort(排序整型) 

1.4 回调函数模拟实现 qsort(排序结构体类型)  


 

1. 回调函数 

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

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

1.1 qsort 函数的使用 

首先演示一下 qsort 函数的使用

在之前我们写过冒泡排序,但我们只能排序整形数据;

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void bubble_sort(int arr[], int sz)
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//假设数组是排好序的
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}

	}
}

int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

 

 

 我们想使用 qsort 函数,把需要传的参数依次输入后发现,我们需要自己写一个比较函数,比如我们想要比较两个整形,写出 cmp_int 函数,参数是 qsort 要求的(const void* e1, const void* e2), qsort函数对比较函数的返回值也有规定:

 把函数内容写完之后,发现 e1、e2 是 void* 的指针,是不能解引用的。

当我们写出这样的代码,发现用 char* 的指针来接收 int型变量的地址是不行的。

如果我们这样写:

 我们要想正确写出比较函数,那就可以将 e1、e2 强制类型转换成 int* 类型的指针:

 

 我们修改过后的代码过程还是比较繁琐,不妨这样写:

 

qsort 函数默认是把降序排成升序

如果我们想把升序排成降序,只需要把比较函数中 e1 和 e2 的位置调换一下就好,逻辑相反,就可以排成降序。

不要忘记使用 qsort 需要引头文件

#include<stdlib.h>

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>


int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}

int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	//bubble_sort(arr, sz);

	qsort(arr, sz, sizeof(arr[0]), cmp_int);

	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

1.2 qsort 排序结构体类型 

我们当然也可以使用 qsort 排序其他类型的数据,比如结构体类型:

假设我们按照名字来排序

 

 同理,我们也可以按照年龄来排序:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}


struct Stu
{
	char name[20];
	int age;
};

int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}


void test_2()
{
	//测试使用 qsort 排序结构体数据
	struct Stu s[] = { {"zhangsan",15},{"lisi",30},{"wangwu",25} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);//假设依据名字来排序
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);//假设依据年龄来排序

}

int main()
{
	test_1();//排序整型
	test_2();//排序结构体数据

	return 0;
}

void test_1()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	//bubble_sort(arr, sz);

	qsort(arr, sz, sizeof(arr[0]), cmp_int);

	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

}

1.3 回调函数模拟实现 qsort(排序整型) 

学会了使用 qsort 函数,那么我们也可以使用回调函数,模拟实现 qsort (采用冒泡的方式)

 

cmp 函数的参数不能简单地写成 (base + j, base + j +1)

因为我们并不知道要比较的数据是哪种类型,所以要改写成这样:

 下面是完整的使用回调函数,模拟实现 qsort (采用冒泡的方式)的代码:

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}

void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}


void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//假设数组是排好序的
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				//交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = -1;
			}
		}
		if (flag == 1)
		{
			break;
		}

	}
}


void test_3()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]),cmp_int );

	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

}



int main()
{
	//test_1();//排序整型
	//test_2();//排序结构体数据
	test_3();

	return 0;
}

1.4 回调函数模拟实现 qsort(排序结构体类型)  

我们使用回调函数,模拟实现 qsort (采用冒泡的方式)排序了整型的数据,当然也可以排序结构体类型的,只需要稍作修改:

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct Stu
{
	char name[20];
	int age;
};

int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}



void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}


void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//假设数组是排好序的
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				//交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = -1;
			}
		}
		if (flag == 1)
		{
			break;
		}

	}
}

void test_4()
{
	//测试使用 qsort 排序结构体数据
	struct Stu s[] = { {"zhangsan",15},{"lisi",30},{"wangwu",25} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);

}

int main()
{
	//test_1();//排序整型
	//test_2();//排序结构体数据
	//test_3();
	test_4();

	return 0;
}

同理,上面是按照年龄来排序,如果想按照名字排序,修改一下比较函数就可以了。

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

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

相关文章

【WebAssembly】编译c++ Demo ->HelloWorld

好的开始等于成功了一半&#xff0c;本篇逐条讲解如何将一个cpp通过WebAssembly编译并运行在网页上。 一、环境准备 前提条件 需要安装CMake&#xff0c;VS&#xff0c;python2.7及以上 拉取emsdk代码 仓库地址&#xff1a;GitHub - emscripten-core/emsdk: Emscripten SD…

04_前端包管理工具模块化

注意事项: ​ 改模块代码不用重启服务器,修改config文件的时候需要重启服务器 ​ nvm的安装路径和node的安装路径不能在同一路径下面 ​ 有乱码问题使用管理员权限进行使用use方法 下载安装node ​ 使用命令进行安装 1.nvm list 查看已下载所有的node版本 2.nvm install…

VR工地安全虚拟现实体验:多种事故模拟,第三人称回看

建筑工地五大伤害是指&#xff1a;高处坠落、坍塌、物体打击、机械伤害、触电。利用VR(虚拟现实)技术体验建筑工地五大伤害&#xff0c;可以为建筑工人提供更真实、更安全的工作环境&#xff0c;同时也可以帮助他们更好地了解和掌握工作技能。 以下是VR工地安全虚拟现实体验软件…

C++ Primer(读书笔记)

C源文件通常以.cc、.cxx、.cpp、.cp、.C作为后缀来命名 C语言未定义输入输出语句&#xff0c;而是提供了一个全面的标准库来提供IO机制&#xff0c;对应 iostream、fstream、sstream std::cout<<"Enter Two Numbers"<<std::endl;&#xff0c;这条语句执…

在四维轻云使用过程中,出现这些问题应该怎么办?

在四维轻云的使用过程中&#xff0c;可能会出现在地图中无法显示加载的点云或倾斜摄影模型数据、无法上传数据等问题。出现以下这些问题时&#xff0c;可采取一定的措施来解决&#xff0c;若无法解决可联系工作人员处理。 1、在地图中无法显示加载的点云或倾斜摄影模型数据&am…

推特色情机器人账号泛滥,马斯克的“治推谋略”何在?

据BleepingComputer消息&#xff0c;推特虚假机器人账户泛滥的问题不仅还未得到解决&#xff0c;其中传播色情信息的机器人账户近期反而严重泛滥。 在安全研究小组MalwareHunterTeam最近的一项调查研究中曝光了多个传播虚假消息的机器人账户&#xff0c;它们为真实用户发出的帖…

为汽车制造商赋能,CarFramework定制AOSP技术,提升汽车信息娱乐系统

车载CarFramework&#xff08;车载框架&#xff09;是Android Automotive操作系统中的一个关键组件&#xff0c;它提供了与车辆系统交互的基础设施和功能。CarFramework旨在为车载应用程序提供统一的开发和执行环境&#xff0c;以便它们可以与车辆的硬件和软件进行交互。CarFra…

华为云专家出品《字节码编程指南》电子书上线

Javaagent非入侵全链路监控设计和实现入门 ASM、Javassist、Byte-Buddy三套字节码框架案例 市面上少有的成体系字节码知识 都在这里&#xff01; 华为云出品《深入理解边缘计算》电子书上线 本书适合超过3年经验的高级开发者&#xff0c;适合对字节码编程有学习需求或想拓展…

赛效:CAD怎么转PDF

1&#xff1a;打开91ai在线工具并登录自己的账号&#xff0c;从“CAD转换”菜单里点击CAD转PDF。 2&#xff1a;点击上传电脑本地的CAD文件。 3&#xff1a;文件上传成功后点击“开始转换”。 4&#xff1a;转换成功后&#xff0c;点击下载按钮将文件保存本地。 如果你想了解更…

【超详细】MySQL环境安装

文章目录 说明1、关闭不需要的环境2、检查并删除系统安装包3、获取 mysql 官方 yum 源4、安装 mysql yum 源&#xff0c;对比前后 yum 源5、看看 yum 源是否安装成功6、安装 mysql 服务7、查看配置文件和数据存储位置8、启动服务9、登录 mysql方法一&#xff1a;方法二&#xf…

jedis使用,操作Redis数据库2

在刚刚ping通的基础上,再来通过jedis连接池连接redis 在resources下创建redis.properties配置文件,在配置文件中写如下内容 # 必配 # Redis服务器地址(域名或IP) redis.host192.168.40.100 # Redis服务器连接端口(Redis默认端口号是6379) redis.port6379 # Redis服务器连接密码…

Redis从入门到精通【进阶篇】之持久化 AOF详解

文章目录 0.前言1.详解1.1 AOF 文件的创建1.2. AOF 文件的写入1.3. AOF 文件的同步1. 3.1 同步磁盘上的所有数据1. 3.2 定期同步磁盘上的数据 1.4. AOF 文件的重写1.5. AOF 文件的恢复1.6. 小结 2. RDB和AOF混合方式3. Redis从入门到精通系列文章 0.前言 Redis 支持多种持久化…

Axure设计之滑动验证组件(动态面板)

一、案例效果 1、默认显示滑块、背景及提示文案&#xff1b; 2、滑块仅允许向右水平拖动&#xff0c;且不能超过背景区域&#xff1b; 3、滑块移动过程中&#xff0c;左侧区域样式跟随变化&#xff0c;右侧区域保持不变&#xff1b; 4、滑块为未拖动到最右侧时释放&#xff…

后书《乡村振兴战略下传统村落文化旅游设计》,交浅而言深者,愚也

后书《乡村振兴战略下传统村落文化旅游设计》&#xff0c;交浅而言深者&#xff0c;愚也

初学Spring boot (六) 自定义starter

学习回顾&#xff1a;初学Spring boot &#xff08;五&#xff09; 自动配置原理 自定义Starter 我们分析完毕了源码以及自动装配的过程&#xff0c;我们可以尝试自定义一个启动器来玩玩&#xff01; 1、说明 启动器模块是一个 空 jar 文件&#xff0c;仅提供辅助性依赖管理&am…

B2a实例学习记录

B2a简介 只是把hit存到了hitcollection&#xff0c;只是统计了各自event结果&#xff0c;将每次event的运行结果存起来了&#xff0c;并没有做总的求和 如何在B2a的基础上&#xff0c;实现对某一个chamber的能量的累加 1 hit和SD&#xff08;sensitive detector) 每一个s…

越权访问漏洞

越权漏洞 越权访问漏洞示意图 一、越权访问漏洞简介 1.类型 水平越权&#xff1a;通过更换的某个ID之类的身份标识&#xff0c;从而使A账号获得&#xff08;增删查改&#xff09;B账号的数据 垂直越权&#xff1a;使用低权限身份的账号&#xff0c;发送高权限账号的请求&…

Java——内部类

一、成员内部类 类中的东西都是成员&#xff0c; 1.1、成员内部类定义 定义成员内部类的格式&#xff1a; class OuterClass {//外部类class InnerClass{//内部类&#xff08;内部类实际是外部类的一个属性&#xff09;} }示例 public class Outer {private static int r…

使用Selenium-PO设计模式提高Web自动化测试效率

PO&#xff08;page object&#xff09;设计模式是在自动化中已经流行起来的一种易于维护和减少代码的设计模式。在自动化测试中&#xff0c;PO对象作为一个与页面交互的接口。测试中需要与页面的UI进行交互时&#xff0c;便调用PO的方法。这样做的好处是&#xff0c;如果页面的…

.Net之AOP - 使用Fody的代码静态编织实现AOP

简介&#xff08;好久没写博客了&#xff09; 万物皆可AOP&#xff0c;本篇文章主要讲解在.Net7中使用Fody的代码静态编织实现AOP。 一、前言 AOP AOP是指面向切面编程 &#xff08;Aspect Oriented Programming&#xff09;&#xff0c;相信大家都再熟悉不过了&#xff0c;…