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

#C语言——学习攻略:深挖指针路线(五)--回调函数,qsort函数,qsort函数的模拟实现

🌟菜鸟主页:@晨非辰的主页

👀学习专栏:《C语言学习》

💪学习阶段:C语言方向初学者

⏳名言欣赏:"暴力解法是上帝给的,优化解法是魔鬼教的。"


目录

1.  回调函数

1.1 什么是回调函数

1.2 回调函数试验:改造一般方式实现计算器功能

2. qsort函数

2.1 介绍qsort函数

2.2 qsort函数排序整型数据

2.3  qsort函数排序结构体数据

3. qsort函数模拟实现


1.  回调函数

1.1 什么是回调函数

--简单说,回调函数就是由一个通过函数指针调用的函数。

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

        --回调函数的一大特点回调函数简化代码避免重复代码——>如果多个函数需要类似的逻辑,回调可以提取公共部分,减少重复。

--就比如上一篇博客分享的:一般方式实现计算器功能的代码,就可以使用回调函数,来看一下吧:

int Add(int x, int y)//这里的Add就是回调函数
{return x + y;
}void test(int(*pf)(int, int))//参数时函数指针,因为要接收函数地址
{int r = pf(10, 20);printf("%d\n", r);
}int main()
{test(Add);//将Add函数的地址传给test函数return 0;
}

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;
}//函数的参数是函数指针,可以接收不同函数的地址
//接收的地址不同,调用的函数就不同
//这个函数根据参数的不同就能实现不同的功能
void calc(int(*pa)(int, int))
{int ret = 0;int x = 0;int y = 0;printf("请输入操作数:");scanf("%d %d", &x, &y);ret = pa(x, y);printf("%d\n", ret);
}void menu()
{printf("****************************\n");printf("******1.Add      2.Sub******\n");printf("******3.Mul      4.Div******\n");printf("*********  0.exit  *********\n");printf("****************************\n");
}int main()
{int input = 0;do{menu();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;
}

--看完这串代码,可以知道:里面的像add、sub、mul、div这四个函数都是回调函数

--从图中可以清楚的看到,add等函数将地址传给calc函数。calc函数的参数是函数指针用来接收地址,在内部调用函数。

--这样就看到了回调函数到底用来做什么:把调用的函数的地址以参数形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数。


2. qsort函数

2.1 介绍qsort函数

-- qsort 是C标准库(<stdli.h>)提供的快速排序(Quick Sort)函数,用于对任意类型的数组进行排序。

--优点

1. 通用性强(支持任意数据类型):                        2. 灵活性高(自定义排序规则)

基本类型(intfloatchar)                                升序 / 降序

指针类型(char*void*)                                      按字符串长度排序

结构体(struct)                                                   多关键字排序(如先按年龄,再按姓名)

动态分配的数组

 --qsort函数返回类型、参数:

void qsort(void *base,     ——>指向要排序的数组首元素的指针。size_t nmemb,   ——>数组元素个数size_t size,    ——>每个元素的字节大小int (*compar)(const void *, const void *)  ——>比较函数指针,用于比较数组中的两个元素
);

        --对于函数参数为两个void,可以接收任意类型的指针。

返回值

<0a 应排在 b 前面(升序)。

=0a 和 b 相等。

>0a 应排在 b 后面(降序)。

2.2 qsort函数排序整型数据

//升序,cmp_int1用来比较两个整形数据
int cmp_int1(const void* p1, const void* p2) 
{return (*(int*)p1) - (*(int*)p2);//void*指针不能直接进行解引用,强转为整型指针类型//默认升序是因为 a - b 的写法符合直观的“从小到大”逻辑
}
//降序
int cmp_int2(const void* p1, const void* p2)
{return (*(int*)p2) - (*(int*)p1);//反转逻辑
}
void print_arr(int arr[], int sz)
{int i = 0;for (i = 0;i < sz;i++){printf("%d ", arr[i]);}printf("\n");
}
int main()
{int arr[] = { 3,1,5,8,7,9,2,4,6,0 };int sz = sizeof(arr) / sizeof(arr[0]);print_arr(arr, sz);//使用qsort函数的,需要自己写一个比较函数qsort(arr, sz, sizeof(arr[0]), cmp_int1);printf("升序:");print_arr(arr, sz);qsort(arr, sz, sizeof(arr[0]), cmp_int2);printf("降序:");print_arr(arr, sz);
}

2.3  qsort函数排序结构体数据

#include<string.h>
#include<stdlib.h>
struct Stu
{char name[30];int age;
};//按年龄比较
int cmp_stu_by_age(const void* p1, const void* p2)
{return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);
}
//按名字
int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);//strcmp是专门用来比较两个字符串的大小的
}void print_stu(struct Stu arr[], int sz)
{int i = 0;for (i = 0;i < sz;i++){printf("%s:%d\n", arr[i].name, arr[i].age);}printf("\n");
}//按照年龄来排序 
void test2()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);print_stu(arr, sz);
}//按照名字来排序 
void test3()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);print_stu(arr, sz);
}
int main()
{test2();test3();return 0;
}

3. qsort函数模拟实现

--使用回调函数,模拟实现qsort(采用冒泡的方式)。(首次使用void*类型)

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 };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;
}

往期复习:

1. #C语言——学习攻略:深挖指针路线(一)--指针变量、地址、意义与指针运算

2. #C语言——学习攻略:深挖指针路线(二)--const修饰、野指针分析、断言和指针的作用

3. #C语言——学习攻略:深挖指针路线(三)--数组与指针的结合、冒泡排序

4.#C语言——学习攻略:深挖指针路线(四)--字符指针变量,数组指针变量,二维数组传参的本质,函数指针变量,函数指针数组


结语:本篇内容就到这里了,主要分享了指针变量类型的一些内容,后续仍会分享指针的相关知识;指针的内容需要反复研读 ,如果这篇文章对你的学习有帮助的话,欢迎一起讨论学习,你这么帅、这么美给个三连吧~~~

http://www.lryc.cn/news/605513.html

相关文章:

  • axios封装对比
  • 《C#与.NET Core跨平台开发的融合架构与实践逻辑》
  • 编程语言Java——核心技术篇(六)解剖反射:性能的代价还是灵活性的福音?
  • 【[CSP-J 2022] 上升点列】
  • RabbitMQ 的死信队列完整指南 (With Spring Boot)
  • 从遮挡难题到精准测量:激光频率梳技术如何实现深孔 3D 轮廓的 2um 级重复精度?
  • Mac上优雅简单地使用Git:从入门到高效工作流
  • 05百融云策略引擎项目交付-laravel实战完整交付定义常量分文件配置-独立建立lib类处理-成功导出pdf-优雅草卓伊凡
  • LCM中间件入门(1):工作原理核心概念及Ubuntu环境下的C++实践
  • 【Debian】4-‌2 Gitea搭建
  • Git踩坑
  • windows服务器 maven 配置环境变量,验证maven环境变量是否配置成功
  • es的histogram直方图聚合和terms分组聚合
  • Ubuntu/Debian 搭建 Nginx RTMP 服务器全攻略
  • [Broken IOS] 配置CLI | 终端用户界面TUI
  • 分布式ID方案(标记)
  • 【Linux】linux基础开发工具(二) 编译器gcc/g++、动静态库感性认识、自动化构建-make/Makefile
  • BasicAuthenticationFilter处理 HTTP 基本认证(Basic Authentication)的核心过滤器详解
  • 打破数据质量瓶颈:用n8n实现30秒专业数据质量报告自动化
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | LiveUserFilter(实时用户过滤组件)
  • ensp安全策略实验
  • 【工具】NVM完全指南:Node.js版本管理工具的安装与使用详解
  • 嵌入式仿真教学的革新力量:深圳航天科技创新研究院引领高效学习新时代
  • 【n8n】如何跟着AI学习n8n【03】:HTTPRequest节点、Webhook节点、SMTP节点、mysql节点
  • 从“碎片化”到“完美重组”:IP报文的分片艺术
  • mysql笔记02:DML插入、更新、删除数据
  • 【读书笔记】Design Patterns (1994)✅
  • 微软发布Microsoft Sentinel数据湖国际版
  • JVM之【Java虚拟机概述】
  • Python实现调整矩阵维度: view