指针修仙之实现qsort

ops/2024/9/22 15:28:47/

文章目录

  • 回调函数
    • 什么是回调函数
    • 回调函数的作用
  • 库函数qsort
    • 使用qsort函数排序整形
    • 使用qsort函数排序结构体
  • qsort函数模拟实现
    • 说明
    • 源码`and`说明


回调函数

什么是回调函数

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

回调函数的作用

回调函数可以减少函数的冗余,并且可以使函数的功能更加丰富,实现泛型编程,我们之间从下面qsort的模拟实现中体会

库函数qsort

我们看一下qsort的官方描述
在这里插入图片描述
分析以下函数的参数,依次是:

  1. 数组首元素地址
  2. 数组元素个数
  3. 数组元素大小
  4. 自定义比较函数的地址

使用qsort函数排序整形

int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
int main()
{int arr[] = { 2,4,3,5,9,8,6,7,1,0 };qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), cmp_int);return 0;
}

注意 自定义比较函数的参数类型是void*,要先将地址强制类型转换成int*再解引用

使用qsort函数排序结构体

#include<string.h>
int cmp_stu_by_age(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
struct Stu
{char name[10];int age;
};
int main()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}

注意 比较字符串时要用库函数strcmp

qsort函数模拟实现

说明

回顾我这个编程小白的排序技能库,似乎只会一种冒泡排序,所以下面模拟实现qsort是在冒泡排序的基础上改进完成的

源码and说明

主体部分

void bubble_sort_plus(void* base, size_t num, size_t size, void* cmp(const void*, const void*))
{for (int i = 0; i < num-1; i++){for (int j = 0; j < num - 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);}}}
}

注意

  • 函数参数和库函数中的qsort类型相同
  • 内层循环的判断条件
    • 通过地址来调用用户自定义的比较函数,自定义的比较函数的参数,强制转换成char* 找到元素第 一个字节的地址,然后再加上每一个元素的宽度,即可访问数组中的元素
    • 使用函数地址来调用函数,cmp函数是一个回调函数,使用户自定义函数类型,丰富了函数的功能
  • 实现交换功能
    • 由于不知道用户传递来的函数数据类型,因此只能先强制转换为char*类型的数据,通过一个一个的字节来访问元素

Swap函数

void Swap(char* p1, char* p2, size_t size)
{for (int i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}

注意

  • 函数参数直接用char*类型来接收
  • 设计参数size,可以控制交换字节的个数
  • 交换的原理是一个字节一个字节的交换


http://www.ppmy.cn/ops/114301.html

相关文章

react hooks--概述

前言 ◼ Hook 是 React 16.8 的新增特性&#xff0c;它可以让我们在不编写class的情况下使用state以及其他的React特性&#xff08;比如生命周期&#xff09;。 ◼ 我们先来思考一下class组件相对于函数式组件有什么优势&#xff1f;比较常见的是下面的优势&#xff1a; ◼ …

2024/9/21黑马头条跟学笔记(十)

1&#xff09;今日内容 1.1&#xff09;定时计算流程 1.不想用户看到的全是最新的&#xff0c;实时计算最火的推送 2.定时计算热度最高&#xff0c;存redis&#xff0c;推送到推荐页面 1.2&#xff09;使用schedule 多个服务部署&#xff0c;多次执行 硬编码定时时间在cron…

python基础(1)pyenv安装和对Django使用

pyenv安装 pyenv主要针对类 Unix 系统&#xff08;如 Linux、macOS&#xff09;用户&#xff0c;pyenv-win 是专为 Windows 开发的 pyenv 版本&#xff0c;允许您在不使用 WSL 的情况下管理多个 Python 版本和虚拟环境。 建议Git Bash&#xff1a; Powershell或Git Bash&…

NoSQL数据库实战派

第二章 Redis基础 缓存通过“用空间换时间”来达到数据获取的目的。 缓存的成本较高&#xff0c;在实际设计架构中需要权衡访问延迟和成本。 通过缓存&#xff0c;可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。 一般情况下&#xff0c;数据被存放在数据库…

macOS平台编译libidn2库给iOS及macOS用

1.克隆源码: git clone https://gitlab.com/libidn/libidn2.git --recursive 2.安装依赖库: pkg-config也要安装 3.启动bootstrap生成configure 配置成功 configure生成成功

PHP发邮件教程:配置SMTP服务器发送邮件?

PHP发邮件的几种方式&#xff1f;如何使用PHP通过SMTP协议发信&#xff1f; PHP作为一种广泛使用的服务器端脚本语言&#xff0c;提供了多种方式来发送邮件。AokSend将详细介绍如何通过配置SMTP服务器来实现PHP发邮件教程的核心内容。 PHP发邮件教程&#xff1a;设置参数 这…

hive分区详细教程

为什么要分区&#xff1f; 为了提高sql的查询效率 比如&#xff1a; select * from orders where create_date20230826; 假如数据量比较大&#xff0c;这个sql就是全表扫描&#xff0c;速度肯定慢。 可以将数据按照天进行分区&#xff0c;一个分区就是一个文件夹&#xff0c;当…

安装selenium、chrome、chromedriver.exe相对应的版本

第一步&#xff1a;安装python3.8 第二步&#xff1a;安装selenium pip install selenium4.3.0 第三步&#xff1a;安装chrome 参考这个博客的版本信息。以104.0.5112.102为例。 https://blog.csdn.net/tekin_cn/article/details/136817228 第四步&#xff1a;安装chromed…