C语言指针相关知识(第四篇章)(非常详细版)

文章目录

  • 前言
  • 一、什么是回调函数
  • 二、qsort函数的介绍(默认升序排序)
  • 三、qsort函数的模拟实现(通过冒泡排序)
  • 总结


前言

本文介绍了回调函数,qsort函数的使用,以用冒泡排序来模拟实现qsort函数


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是回调函数

  • 前面的博客里面我介绍了函数指针变量的相关概念,而回调函数就是通过一个函数指针调用的函数。进一步说,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数,注意哈,回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生的时候由另一方调用哒,用于对该事件或条件进行响应。
  • 我们使用回调函数其实可以简化代码,省去一些冗余重复的操作
    以下是实现一个计算器的代码,我们在没有使用回调函数之前:
#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;}
int main(){int x, y;int input = 1;int ret = 0;do{//菜单:
printf("*************************\n");printf("  1:add        2:sub\n");printf("  3:mul        4:div\n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){//这之后的代码就较为冗余,重复之处比较多case 1:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;//这里之前的代码较为冗余,重复地方过多case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;}

在实现计算器的过程中,我们可以发现在case语句中输入输出较为冗余,重复次数过多,这里我们就可以用回调函数来简化代码,设置一个操作函数,参数为函数指针变量来简化代码。具体操作如下:

#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 x, y;int input = 1;int ret = 0;do{//菜单:
printf("*************************\n");printf("  1:add        2:sub\n");printf("  3:mul        4:div\n");printf("*************************\n");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;}

很明显我重新定义了一个函数calc,而其参数为函数指针变量,我们将我们要执行的加减乘除函数传递到函数中,就可以减少重复的输入和输出代码,从而做到了简化代码的功效。

二、qsort函数的介绍(默认升序排序)

  • qsort函数是我们C语言库中用来专门用来排序的库函数(头文件为:stdlib.h)
  • 定义声明为:
  • void qsort (void* base, size_t num, size_t size, int (compar)(const void,const void*));
  • base代表待排序序列,num,为序列中元素个数,size,代表每个元素所代表的字节大小,最后一个参数为函数指针类型,是一个比较函数,用来阐述比较规则的。
  • 对于最后一个参数函数指针类型的参数,我们通过它的返回值来确定具体那个元素在前,那个元素在后:
    若返回值<0,则第一个指针指向的元素在前,第二个指针指向的元素在后;若返回值=0,则默认第一个指针指向的元素在前,第二个指向的元素在后;若返回值>0,则第一个指针指向的元素在后,第二个指针指向的元素在前。
  • 使用qsort函数来排序整型数据:
    代码显示:
#include<stdio.h>
#include<stdlib.h>
int int_cmp(const void *p1,const void*p2)
//实现泛式编程,我们定义void*指针,这样就可以接受任何类型的数据。后面只需要强制类型转换成我们所需要的数据类型即可。
{
return (*(int*)p1-*(int *)p2);
}
int main()
{
int arr[]={1,3,5,7,9,2,4,6,8,0};
int i =0;
qsort(arr,sizeof(arr)/sizeof(arr[0]),sizeof(int),int_cmp);//根据需要传递相应的参数。
for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
printf("%d ",arr[i] );
}
printf("\n");
}
  • 使用qsort函数排序结构数据
  • 我们来进行结构体的排序以学生结构体为例,我们进行分别以学生的名字为依据和学生的年龄为依据进行比较。
    以年龄为依据进行排序:
#include<stdio.h>
#include<stdlib.h>
struct Stu //定义学生结构体变量
{
char name[20];//学生名字
int age;//年龄
}//我们先以学生的年龄为依据进行比较
int cmp_stu_by_age(const void * e1,const void * e2)
{
return ((struct Stu*)e1)->age-((struct Stu*)e2)->age;
}
int main()
{
struct Stu arr[]={{"zhangsan,20"},{"lisi,30"},{"wangwu,35"}};//这里我们定义结构体序列
qsort(arr,sizeof(arr)/sizeof(arr[0]),sizeof(s[0]),cmp_stu_by_age);
}
return 0;

这里的排序结果我们通过调试来显示:
排序前:
在这里插入图片描述
排序后:
在这里插入图片描述
以名字为依据进行排序:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>//我们需要调用字符串函数strcmp函数进行字符串的比较
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 main()
{
struct Stu arr[]={{"zhangsan,20"},{"lisi,30"},{"wangwu,35"}};//这里我们定义结构体序列
qsort(arr,sizeof(arr)/sizeof(arr[0]),sizeof(s[0]),cmp_stu_by_age);
}
return 0;

我们通过调试来显示排序结果:
排序前:

在这里插入图片描述
排序后:
在这里插入图片描述
这里strcmp字符串比较函数的返回值正好符合我们qsort对于比较函数返回值的要求,二者可谓是不谋而合呀。

三、qsort函数的模拟实现(通过冒泡排序)

  • 我在之前的博客里面已经实现过我们所熟悉的冒泡排序代码算法:
#include<stdio.h>
void input(int* arr, int sz)//输入待排序序列
{for (int i = 0; i < sz; i++){scanf("%d", arr + i);}
}void bubble_sort(int* arr, int sz)//冒泡排序算法
{for (int i = 0; i < sz-1; i++)//sz-1趟比较{int change = 1;//小优化节省时间for (int 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;change = 0;}}if (change == 1)//说明已经有序 {break;}}
}
void print(int* arr, int sz)
{for (int i = 0; i < sz; i++){printf("%d ", *(arr + i));}printf("\n");
}
int main()
{int arr[10] = { 0};int sz = sizeof(arr) /sizeof(arr[0]);input(arr, sz);bubble_sort(arr, sz);print(arr, sz);return 0;
}

但是在这里我们为了响应qsort算法,我们应该根据qort函数中的参数来重新改编冒泡排序。
前面已经提到过qsort函数的函数声明:
void qsort (void* base, size_t num, size_t size, int (compar)(const void,const void*));
这里我们用void指针来接受待排序序列,是一种泛式的编程,这里就可以接受任何数据类型的排序,这便是void指针的最大优势。

我们用冒泡排序模拟实现qsort函数的代码如下(这里我们以排序整型数据为例):

#include<stdio.h>
int int_cmp(const void*p1,const void * p2)//定义比较函数
{ return (*( int *)p1 - *(int *) p2);
}
void _swap(void*p1,void*p2,int size)
{
for(int i=0;i<size;i++)
{
//每一位字节都进行交换,从而做到整个数据类型进行交换。char tmp = *((char *)p1 + i);//我们转换成char*类型可以理解为转换成单位字节,然后乘上数据类型字节大小就可以表示任意数据类型*(( char *)p1 + i) = *((char *) p2 + i);*(( char *)p2 + i) = tmp;
}}
void bubble(void*base,int count ,int size,int(*cmp)(void*,void*))
//这里完全模仿qsort函数来定义的
{
for(int i=0;i<count-1;i++)
{
for(int j=0;j<count-1-i)
{
if(cmp((char*)base+j*size,(char*)base+(j+1)*size)>0)//我们转换成char*类型可以理解为转换成单位字节,然后乘上数据类型字节大小就可以表示任意数据类型
{_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;}

总结

本文主要介绍了一个崭新的概念回调函数,并分析了qsort函数的使用,以及用冒泡排序来模拟qsort函数,如有错误,请批评指正,感谢支持

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

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

相关文章

如何在没有密码或Face ID的情况下解锁iPhone

iPhone 是一款以其一流的安全功能而闻名的设备&#xff0c;包括面容 ID 和密码。但是&#xff0c;你有没有想过&#xff0c;如果没有这些安全措施&#xff0c;你是否可以解锁iPhone&#xff1f;无论您是忘记了密码&#xff0c;Face ID不起作用&#xff0c;还是只是对其他方法感…

5.23-

回顾 I0多路复用的原理? 程序首先向操作系统发起一个IO多路复用请求&#xff0c;告诉操作系统需要监视哪些IO通道。这些IO通道可以包括网络套接字、文件描述符等操作系统随后会将这些IO通道放入一个队列中&#xff0c;并在某个IO通道就绪时&#xff08;如数据到达、文件可读…

「YashanDB迁移体验官」Mysql生产环境迁移至YashanDB数据库深度体验

「YashanDB迁移体验官」Mysql生产环境迁移至YashanDB数据库深度体验 1. 前言1.1 产品介绍1.2 产品架构1.3 产品规格1.3.1 数据库版本支持1.3.2 数据类型支持 2. YMP安装2.1 环境说明2.2 执行安装2.3 访问YMP2.3.1 YMP登录界面2.3.2 YMP迁移流程 3. YMP数据迁移3.1 创建数据源3.…

【pytorch】 Win11下cuda,cudnn以及pytorch环境安装

Win11下cuda&#xff0c;cudnn以及pytorch环境安装 CUDA环境安装1. 查看CUDA版本1.1 打开NVIDIA控制面板&#xff0c;可以点右下角的NVIDIA设置1.2 点击系统信息&#xff0c;选择组件查看CUDA版本 2. 下载对应的CUDA版本3. 安装3.1 启动exe文件安装 4. 验证安装结果 CUDNN 环境…

Apache CXF Aegis databinding SSRF 高危漏洞修复

一、漏洞修复 Apache CXF Aegis databinding SSRF漏洞 Spring Web UriComponentsBuilder URL解析不当漏洞 二、修复步骤 1、Apache CXF Aegis databinding SSRF漏洞修复 步骤&#xff1a; 进入服务器搜索 databinding find -name *databinding* 发现版本是3.1.6 果断…

数据结构~~带环链表的环开始的节点位置**两种方法

1.带环链表环开始的位置 &#xff08;1&#xff09;上面的这个测试用例使用的是包含了4个节点的带环链表&#xff0c;我们要找的就是链表里面的环开始的节点的位置&#xff0c;拿这个测试用例而言&#xff0c;就是2这个节点&#xff0c;从这个节点开始&#xff0c;我们的链表就…

【C/C++笔试练习】TCP、IP广播、ARP协议、IP路由器、MAC协议、三次握手、TCP/IP、子网划分年、会抽奖、抄送列表

文章目录 C/C笔试练习选择部分&#xff08;1&#xff09;TCP&#xff08;2&#xff09;IP广播&#xff08;3&#xff09;ARP协议&#xff08;4&#xff09;IP路由器&#xff08;5&#xff09;MAC协议&#xff08;6&#xff09;三次握手&#xff08;7&#xff09;TCP/IP&#xf…

PHP在线制作表白网源码

PHP在线制作表白网源码&#xff0c;送女友个惊喜吧&#xff0c;无数据库&#xff0c;上传就能用&#xff0c;后台/admin&#xff0c;账号密码都是admin 百度网盘&#xff1a;https://pan.baidu.com/s/1rbD2_8IsP9UPLK-cdgEXfA?pwdre59

【全开源】AJAX家政上门服务系统小程序自营+多商家(高级授权)+独立端

基于FastAdmin和原生微信小程序开发的一款同城预约、上门服务、到店核销家政系统&#xff0c;用户端、服务端(高级授权)、门店端(高级授权)各端相互依赖又相互独立&#xff0c;支持选择项目、选择服务人员、选择门店多种下单方式&#xff0c;支持上门服务和到店核销两种服务方式…

我在去哪儿薅到了5块钱火车票代金券,速薅

哈哈&#xff0c;亲爱的薅羊毛小伙伴们&#xff01; 刚刚在去哪儿大佬那儿发现了一个超级薅羊毛福利&#xff01;我只花了短短两分钟&#xff0c;就搞到了一张5块钱火车票代金券&#xff0c;简直是天上掉馅饼的节奏啊&#xff01; 话不多说&#xff0c;薅羊毛的姿势给你们摆好…

代码随想录算法训练营第十六天(py)| 二叉树 | 104.二叉树的最大深度、111.二叉树的最小深度、222.完全二叉树的节点个数

104.二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 思路1 迭代法 层序遍历 层序遍历的思路很简单&#xff0c;其结果本来就是按层数记录的&#xff0c;只需返回结果的长度皆可。…

【C语言回顾】联合和枚举

前言1. 联合体1.1 联合体的声明1.2 联合体的特点1.3 联合体的使用 2. 枚举2.1 枚举的声明2.2 枚举的特点2.3 枚举的使用 结语 #include<GUIQU.h> int main { 上期回顾: 【C语言回顾】结构体 个人主页&#xff1a;C_GUIQU 专栏&#xff1a;【C语言学习】 return 一键三连;…

Linux多线程系列三: 生产者消费者模型,信号量使用,基于阻塞队列和环形队列的这两种生产者消费者代码的实现

Linux多线程系列三: 生产者消费者模型,信号量,基于阻塞队列和环形队列的这两种生产者消费者代码的实现 一.生产者消费者模型的理论1.现实生活中的生产者消费者模型2.多线程当中的生产者消费者模型3.理论 二.基于阻塞队列的生产者消费者模型的基础代码1.阻塞队列的介绍2.大致框架…

别说废话!说话说到点上,项目高效沟通的底层逻辑揭秘

假设你下周要在领导和同事面前汇报项目进度&#xff0c;你会怎么做&#xff1f;很多人可能会去网上搜一个项目介绍模板&#xff0c;然后按照模板来填充内容。最后&#xff0c;汇报幻灯片做了 80 页&#xff0c;自己觉得非常充实&#xff0c;但是却被领导痛批了一顿。 这样的境…

树的非递归遍历(层序)

层序是采用队列的方式来遍历的 就比如说上面这颗树 他层序的就是&#xff1a;1 24 356 void LevelOrder(BTNode* root) {Que q;QueueInit(&q);if (root){QueuePush(&q, root);}while (!QueueEmpty(&q)){BTNode* front QueueFront(&q);QueuePop(&q);print…

简析网络风险量化的价值与应用实践,如何构建网络风险预防架构

网络风险量化能够让公司董事会和高管层看清当前的网络安全风险格局&#xff1b;它还将使安全团队能够在业务需求的背景下做出网络安全决策&#xff0c;帮助组织确定哪些风险对业务构成最大的威胁&#xff0c;以及预期的经济损失将是什么。 随着网络攻击手段的日益多样化和复杂…

多模态大模型新进展——GPT-4o、Project Astra关键技术丨青源Workshop第27期

青源Workshop丨No.27 多模态大模型新进展—GPT-4o、Project Astra关键技术主题闭门研讨会 刚刚过去的两天&#xff0c;OpenAI、Google纷纷发布了多模态大模型的最新成果&#xff0c;GPT-4o、Project Astra先后亮相。 本周五&#xff08;北京时间5月17日&#xff09;18点&#x…

O2OA(翱途)开发平台数据统计如何配置?

O2OA提供的数据管理中心&#xff0c;可以让用户通过配置的形式完成对数据的汇总&#xff0c;统计和数据分组展现&#xff0c;查询和搜索数据形成列表数据展现。也支持用户配置独立的数据表来适应特殊的业务的数据存储需求。本文主要介绍如何在O2OA中开发和配置统计。 一、先决…

【30天精通Prometheus:一站式监控实战指南】第6天:mysqld_exporter从入门到实战:安装、配置详解与生产环境搭建指南,超详细

亲爱的读者们&#x1f44b;   欢迎加入【30天精通Prometheus】专栏&#xff01;&#x1f4da; 在这里&#xff0c;我们将探索Prometheus的强大功能&#xff0c;并将其应用于实际监控中。这个专栏都将为你提供宝贵的实战经验。&#x1f680;   Prometheus是云原生和DevOps的…

PersonalLLM——探索LLM是否能根据五大人格特质重新塑造一个新的角色?

1.概述 近年来&#xff0c;大型语言模型&#xff08;LLMs&#xff09;&#xff0c;例如ChatGPT&#xff0c;致力于构建能够辅助人类的个性化人工智能代理&#xff0c;这些代理以进行类似人类的对话为重点。在学术领域&#xff0c;尤其是社会科学中&#xff0c;一些研究报告已经…