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

【C语言】深入理解指针(4)

目录

一、回调函数

1.什么是回调函数

2.回调函数举例

3.代码的回调流程

二、冒泡排序使用回调函数模拟实现qsort

1.冒泡排序的缺陷

2.qsort()函数的使用

代码的回调流程

3.模拟实现

char*类型的指针变量的妙用

代码的回调流程

4、补充:数据大小的比较


一、回调函数

1.什么是回调函数

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

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

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

2.回调函数举例

每一个case语句中虽然执行计算的逻辑 是区别的,但是输入输出操作是冗余的,

 因为case语句中只有调用函数的逻辑有差异,并且实现具体计算的四个函数类型是一样的,所以我们可以把调用的函数的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这里其实使用的就是回调函数的功能。

没有使用回调函数

使用回调函数

3.代码的回调流程

二、冒泡排序使用回调函数模拟实现qsort

qsort()本身不能确定需要排序何种类型的数据,但是提供了一个需要由使用者自己实现的进行大小比较的函数接口

int (*compar)(const void*, const void*)

void*的指针变量只能得到变量地址,不能得到变量的类型,无从得知一个元素有多大,所以不能进行解引用和运算,但是可以接收任意类型的指针变量,使用void*就是为了能接收任意变量类型,再根据自己需要进行强转

冒泡排序使用回调函数模拟实现qsort()也采用这样的思路,底层使用冒泡排序,具体是什么类型的比较需要使用者自己先写出来一个大小比较函数

1.冒泡排序的缺陷

 冒泡排序:

一种排序算法,但是只能进行一种数据类型的排序(如果使用冒泡排序对字符串和结构体等元素进行排序,不能使用 > < 号)

void Bubble_sort(int* arr, int size)
{int tmp = 0;//总共比较的趟数for (int i = 0; i < size - 1; i++){//下标为0的元素在每一趟中比较的次数for (int j = 0; j < size - 1 - i; j++){if (arr[j] > arr[j + 1]){tmp = arr[j + 1];arr[j + 1] = arr[j];arr[j] = tmp;}}}
}

2.qsort()函数的使用

qsort()是库函数中用于实现任意数据类型排序的函数

  • 函数原型如下
  • 比较函数的实现要求
  • 因为qsort函数的设计者无法提前知道使用者需要进行何种类型的数据比较,所以留出来大小比较的函数由使用者自行设计
  • void*不能解引用,也不能进行+-整数的操作,需要使用者根据需要自行进行类型强转

应用实例:

代码的回调流程

3.模拟实现

char*类型的指针变量的妙用

事先不知道会比较何种数据类型,

所以直接使用刚好只能操作一个字节地址的 char 类型指针
通过 char* 加上 size 可以模拟得到任意类型的指针变量

循环size次的char*++可以访问任意类型变量的每个字节地址

//模仿 qsort 将冒泡排序改成使用回调函数实现任意类型的排序,自行实现(以比较整型为例)
int compar(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}//事先不知道会比较何种数据类型
//直接使用刚好只能操作一个字节地址的 char 类型指针
//通过 char* 加上 size 可以模拟得到任意类型的指针变量
//循环 size 次的 char* ++ 可以访问任意类型变量的每个字节地址
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++;}
}int Bubble_sort(void* base, size_t num, size_t size, int (*compar)(const void* p1, const void* p2))
{//总共比较次数for (int i = 0; i < num - 1; i++){//下标为0的元素在每一趟中比较的次数for (int j = 0; j < num - 1 - i; j++){//因为事先不知道比较的是何种数据类型//又因为 char类型的指针+1正好跳过一个字节//所以统一强转成 char* 指针变量,通过 size 跳过不同的距离,从而准确读取不同的数据if (compar((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[5] = { 5,3,4,1,2 };int num = sizeof(arr) / sizeof(arr[0]);Bubble_sort(arr, num, sizeof(arr[0]), compar);for (int i = 0; i < num; i++){printf("%d ", arr[i]);}return 0;
}

代码的回调流程

4、补充:数据大小的比较

整型和浮点型可以使用><号进行比较

字符串使用库函数strcmp()进行比较,需加上头文件#include <string.h>

结构体的比较实际是某一个成员变量的比较

http://www.dtcms.com/a/366797.html

相关文章:

  • nextcyber——常见应用攻击
  • 一个老工程师的“新生”:良策金宝AI,让我重新爱上设计
  • [光学原理与应用-389]:设计 - 深紫外皮秒脉冲激光器 - 元件 - 1064nm种子光准直透镜
  • 2025年经管领域专业资格认证发展路径分析
  • 数据结构 之 【模拟实现哈希表】
  • Python 值传递 (Pass by Value) 和引用传递 (Pass by Reference)
  • 电池预测 | 第36讲 Matlab基于CNN-BiGRU-Attention的锂电池剩余寿命预测
  • JVM 运行时数据区域
  • 开源本地LLM推理引擎(Cortex AI)
  • 【PZ-AU15P】璞致fpga开发板 Aritx UltraScalePlus PZ-AU15P 核心板与开发板用户手册
  • ZooKeeper核心ZAB选举核心逻辑(大白话版)
  • 性能堪比claude sonnet4,免费无限使用!claude code+魔搭GLM4.5在ubuntu上安装完整流程
  • 三高项目-缓存设计
  • SQL常见索引失效导致慢查询情况
  • Java 双亲委派机制解析和破坏双亲委派的方式
  • T检验(pearman)
  • 【全网最全】《2025国赛/高教杯》C题 思路+代码python和matlab+文献 一到四问 退火算法+遗传算法 NIPT的时点选择与胎儿的异常判定
  • 电商金融贷款服务市场趋势与竞争分析
  • [frontend]WebGL是啥?
  • 鸿蒙NEXT交互机制解析:从输入设备到手势响应的全面指南
  • Node.js 18+安装及Claude国内镜像使用、idea中claude插件下载指南
  • 【AI论文】UI-TARS-2技术报告:借助多轮强化学习推进图形用户界面(GUI)智能体发展
  • Django事务
  • 《Docker 零基础入门到实战:容器化部署如此简单,运维效率直接拉满》
  • 【有鹿机器人自述】我在社区的365天:扫地、卖萌、治愈人心
  • Android集成OpenCV4实例
  • Java 与 Docker 的最佳实践
  • docker更新jar包,懒人执行脚本
  • MaxKB4j智能体平台 Docker Compose 快速部署教程
  • 飞算JavaAI全面解析:重塑Java开发流程的智能引擎