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

C语言指针:从零掌握指针(5) 完结篇

文章目录C语言指针从零掌握指针5 完结前言一、回调函数1.1 什么是回调函数1.2 使用回调函数二、qsort函数2.1 qsort基础2.2 排序整形数据2.3 排序浮点型数据2.4 排序结构数据三qsort函数模拟实现C语言指针从零掌握指针5 完结前言本篇是C语言指针知识的收尾。我们学习回调函数qsort函数及其模拟实现一、回调函数1.1 什么是回调函数回调函数就是⼀个通过函数指针调用的函数。‘把一个函数当作参数传给另一个函数在合适的时机被 “回头调用”这个函数就叫回调函数。如果你把函数的指针地址作为参数传递给另⼀个函数当这个指针被用来调用其所指向的函数时被调用的函数就是回调函数。回调函数不是由该函数的实现直接调用而是在特定的事件或条件发生时由另外的一方调用的用于对该事件或条件进行响应。这里我们举个生活中的例子加以理解你去奶茶店点单你点奶茶主函数你跟店员说做好了喊我一声这就是回调函数你去玩手机主函数继续执行奶茶做好 → 店员喊你调用回调函数1.2 使用回调函数第13讲中我们写的计算机的实现的代码中红色框中的代码是重复出现的其中虽然执行计算的逻辑是区别的但是输入输出操作是冗余的有没有办法简化⼀些呢因为红色框中的代码只有调用函数的逻辑是有差异的我们可以把调用的函数的地址以参数的形式传递过去使用函数指针接收函数指针指向什么函数就调用什么函数这里其实使用的就是回调函数的功能如图实现voidmenu(){printf(--------- 计算器 ---------\n);printf(----- 1. add 2. sub ----\n);printf(----- 3. mul 4. div ----\n);printf(----- 0. exit ----\n);printf(---------------------------\n);}intAdd(intx,inty){returnxy;}intSub(intx,inty){returnx-y;}intMul(intx,inty){returnx*y;}intDiv(intx,inty){returnx/y;}//计算函数 - 根据参数的不同就能执行不同的运算voidcalc(int(*pf)(int,int)){intx0,y0;intr0;printf(请输入两个操作数:);scanf(%d %d,x,y);rpf(x,y);printf(%d\n,r);}intmain(){intinput0;do{menu();printf(选择:);scanf(%d,input);switch(input){case1:calc(Add);break;case2:calc(Sub);break;case3:calc(Mul);break;case4:calc(Div);break;case0:printf(退出计算器\n);break;default:printf(选择错误\n);![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/785781552e424c8eb64cd4f9e9a143e5.png#pic_center)break;}}while(input);return0;}二、qsort函数在C语言中也有一个函数qsort内部就使用了回调函数之前我们写的冒泡排序voidbubble_sort(intarr[],intsz)函数参数的类型为int 只能处理整型数组的排序显然这是有局限的我们如何优化呢恰好qsort函数可以排序任意类型的数据下面我们来学习qsort函数2.1 qsort基础头文件 函数原型#includestdlib.hvoidqsort(void*base,size_tnum,size_tsize,int(*cmp)(constvoid*,constvoid*));参数解析*void base要排序数组首地址万能指针能接收任意类型数组size_t num数组元素个数size_t size单个元素占用字节大小int (*cmp)(…)比较函数指针核心回调函数比较规则intcmp(constvoid*a,constvoid*b){// 1. 强制转成你要排序的类型// 2. 写比较逻辑}返回值返回负数a 放前面a b返回 0相等不动返回正数b 放前面a b升序*a - *b降序*b - *a原理qsort 内部是快速排序算法它不知道你排什么类型所以用 void* 接收排序时不知道怎么比大小所以必须让你传回调比较函数排序过程中反复调用你写的 cmp 函数判断先后顺序易错第三个参数必须写 sizeof(元素类型)不能乱写void* 必须强制类型转换才能取值浮点型禁止直接相减做返回值字符串数组是char**强转不是char*比较函数参数必须加 const 规范写法2.2 排序整形数据//测试qsort来排序整型数组//是用来比较p1和p2指向的两个整型值的//p1是指向一个整数的//p2是指向一个整数的#includestdlib.h#includestdio.hvoidprint_arr(intarr[],intsz){inti0;for(i0;isz;i){printf(%d ,arr[i]);}printf(\n);}intcmp_int(constvoid*p1,constvoid*p2){return*(int*)p1-*(int*)p2;//升序//降序return *(int*)p1 - * (int*)p2}voidtest1(){intarr[]{3,1,8,6,0,9,4,2,7,5};intszsizeof(arr)/sizeof(arr[0]);//默认是升序的排序qsort(arr,sz,sizeof(arr[0]),cmp_int);print_arr(arr,sz);}intmain(){test1();return0;}2.3 排序浮点型数据//浮点数测试intcmp_float(constvoid*p1,constvoid*p2){if(*(float*)p1*(float*)p2)return-1;elseif(*(float*)p1*(float*)p2)return1;elsereturn0;}//测试的qsort排序浮点型数据voidtest2(){floatarr[]{2.0,1.0,5.0,7.0,3.0};intszsizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_float);}2.4 排序结构数据//排序结构数据structStu{charname[20];intage;};intcmp_stu_by_age(constvoid*p1,constvoid*p2){return(*(structStu*)p1).age-(*(structStu*)p2).age;}//测试qsort函数来排序结构体数据voidtest3(){structStuarr[]{{zhangsan,18},{lisi,25},{wangwu,12}};intszsizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_age);}// 两个字符串比较大小的方法strcmp//strcmp(str1, str2)//str1 str2, 返回 0//str1 str2, 返回 0//str1 str2, 返回 0#includestring.hintcmp_stu_by_name(constvoid*p1,constvoid*p2){returnstrcmp(((structStu*)p1)-name,((structStu*)p2)-name);}voidtest4(){structStuarr[]{{zhangsan,18},{lisi,25},{wangwu,12}};intszsizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_name);}intmain(){//test1();//test2();//test3();test4();//struct Stu s { cuihua, 18 };////printf(%s\n, s.name);////printf(%d\n, s.age);////结构体变量.成员名////struct Stu* ps s;////- 结构体成员访问操作符////结构体指针-成员名//printf(%s\n, ps-name);//(*ps).name//printf(%d\n, ps-age);//(*ps).agereturn0;}重点结构体变量.成员名 -----访问struct Stu* ps s;- 结构体成员访问操作符结构体指针-成员名printf(%s\n, ps-name);//(*ps).nameprintf(%d\n, ps-age);//(*ps).age三qsort函数模拟实现使用回调函数模拟实现qsort采用冒泡的方式bubble_sort函数——只能排整型//qsort函数的模拟实现//使用回调函数模拟实现qsort采用冒泡的方式#includestdlib.h//void qsort(void* base,// size_t num,// size_t size,// int (*compar)(const void*, const void*));//提供一个函数,这个函数能够比较2个整型数据的大小intcmp_int(constvoid*e1,constvoid*e2){return*(int*)e1-*(int*)e2;}//*(int*)e1 *(int*)e2 -- 0//*(int*)e1 *(int*)e2 -- 0//*(int*)e1 - *(int*)e2 --- 0voidprint_arr(intarr[],intsz){inti0;for(i0;isz;i){printf(%d ,arr[i]);}printf(\n);}voidbubble_sort(intarr[],intsz){//躺输inti0;for(i0;isz-1;i){intflag1;//假设待排序的数据已经有序//一趟冒泡排序的过程intj0;for(j0;jsz-1-i;j){if(arr[j]arr[j1]){inttmparr[j];arr[j]arr[j1];arr[j1]tmp;flag0;}}if(flag1){break;}}}下面优化bubble_sort 使得可以排任意类型的数据我们要解决的问题1. 数据类型的通用性只能排整型直接用int*操作数组类型固定。 通用排序需要用 void*通用指针接收任意类型的数组首地址不能直接对void*做算术运算C 语言不允许必须强转成char*步长 1 字节来计算元素地址2. 元素大小宽度的适配只能排整型int大小固定通常 4 字节可以直接用arr[j1]取相邻元素。通用排序不同类型int/float/结构体的元素字节数不同必须额外传入单个元素的宽度width通过(char*)base j * width计算第j个元素的地址。3. 比较规则的自定义只能排整型直接用/比较数值大小逻辑写死在排序函数里。通用排序不同类型的比较逻辑不同比如浮点数、字符串、结构体成员必须通过函数指针传入自定义的比较函数比如写的cmp_int由调用者决定排序规则。4. 交换操作的通用性问题只能排整型直接用临时变量做int类型的交换代码简单。通用排序不能用固定类型交换必须实现按字节交换比如写的Swap函数逐字节拷贝元素的所有字节才能适配任意大小的类型。5. 类型安全与兼容性只能排整型类型单一不会出现类型不匹配。 通用排序需要用constvoid*保证指针的通用性同时在比较函数里正确强转成目标类型避免类型错误还要处理不同平台的字节序、对齐问题结构体场景6. 排序逻辑的解耦只能排整型排序逻辑 比较逻辑 交换逻辑都写死在一个函数里耦合度高。通用排序需要把排序流程冒泡 / 快排、比较逻辑、交换逻辑三者解耦排序函数只负责流程比较和交换由外部实现。1. 交换函数voidSwap(char*buf1,char*buf2,intwidth){inti0;for(i0;iwidth;i){chartmp*buf1;*buf1*buf2;*buf2tmp;buf1;buf2;}}这个函数实现按字节交换不管元素是int、float还是结构体都可以通过逐字节交换完成数据交换。width是元素的字节宽度循环width次就能完整交换两个元素的所有字节。2. 比较函数——cmp根据不同类型的数据自定义比较函数3. bubble_sort函数实现—排任意类型实现//默认:排成升序voidbubble_sort(void*base,intsz,intwidth,int(*cmp)(constvoid*e1,constvoid*e2)){//躺数inti0;for(i0;isz-1;i){intflag1;//假设待排序的数据已经有序//一趟冒泡排序的过程intj0;for(j0;jsz-1-i;j){//借助cmp指针指向的函数来比较arr[j] , arr[j 1]的大小 cmp函数是自定义的比较函数//传给给cmp函数的是arr[j] , arr[j 1]的地址if(cmp((char*)basej*width,(char*)base(j1)*width)0){Swap((char*)basej*width,(char*)base(j1)*width,width);flag0;}}if(flag1){break;}}}参数说明void* base待排序数组的首地址通用类型int sz数组元素个数int width单个元素的字节宽度int (cmp)(const voide1, const void* e2)比较函数指针用来定义排序规则核心逻辑用char强转base是因为char的步长是 1 字节方便通过j * width计算每个元素的地址。调用cmp函数比较相邻两个元素如果需要交换就调用Swap函数。flag是冒泡排序的优化如果某一轮没有发生交换说明数组已经有序直接跳出循环。qsort排序整形数据voidtest1(){intarr[]{1,3,5,7,9,2,4,6,8,0};intszsizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_int);//print_arr(arr,sz);}测试bubble_sort 排序整型数据voidtest2(){//写自己重新改造一下我们自己的bubble_sort()函数,来实现对任意类型数据的排序intarr[]{1,3,5,7,9,2,4,6,8,0};intszsizeof(arr)/sizeof(arr[0]);bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);//print_arr(arr,sz);}测试bubble_sort 排结构体数据#includestring.hstructStu{charname[20];intage;};intcmp_stu_by_name(constvoid*e1,constvoid*e2){returnstrcmp(((structStu*)e1)-name,((structStu*)e2)-name);}intcmp_stu_by_age(constvoid*e1,constvoid*e2){return((structStu*)e1)-age-((structStu*)e2)-age;}voidtest3(){structStuarr[]{{zhangsan,20},{lisi,25},{wangwu,18}};//intszsizeof(arr)/sizeof(arr[0]);//bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);bubble_sort(arr,sz,sizeof(arr[0]),cmp_stu_by_age);}主函数intmain(){test1();test2();test3();return0;}流程

相关文章:

C语言指针:从零掌握指针(5) 完结篇

文章目录C语言指针:从零掌握指针(5) 完结前言一、回调函数1.1 什么是回调函数?1.2 使用回调函数二、qsort函数2.1 qsort基础2.2 排序整形数据2.3 排序浮点型数据2.4 排序结构数据三,qsort函数模拟实现C语言指针&#x…...

ETS2LA:为《欧洲卡车模拟2》带来终极智能驾驶体验的5大核心功能

ETS2LA:为《欧洲卡车模拟2》带来终极智能驾驶体验的5大核心功能 【免费下载链接】Euro-Truck-Simulator-2-Lane-Assist Plugin based interface program for ETS2/ATS. 项目地址: https://gitcode.com/gh_mirrors/eur/Euro-Truck-Simulator-2-Lane-Assist 想…...

长期使用Taotoken的Token Plan套餐在项目开发成本控制上的实际感受

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 长期使用Taotoken的Token Plan套餐在项目开发成本控制上的实际感受 1. 从按需付费到计划用量的转变 在AI应用开发的早期阶段&…...

汽车后市场品牌营销路径:以奇正沐古和康明斯为例

在汽车后市场,很多品牌真正的难题并非没有技术、没有产品、没有资源,而是这些优势到了终端之后,无法变成司机、经销商和维修点愿意相信、愿意推荐、愿意购买的理由。康明斯发动机润滑油就是个典型例子,康明斯作为全球柴油发动机技…...

白嫖新网免费云主机,挂QQ机器人亲测可用

申请门槛低:只要手机号,不需要人脸识别,不想太麻烦就选择阿贝云 配置够用:1核1G 20G SSD,挂QQ机器人完全够 国内速度快:独立公网IP,延迟低,不掉线申请花了不到5分钟,装完…...

边缘计算中的机器学习能效优化与混合架构实践

1. 边缘计算中的机器学习能效革命在智能手表、健康监测设备等穿戴式设备中,实时运行机器学习模型一直是个棘手的问题。传统方案要么耗电太快导致续航崩溃,要么精度太低失去实用价值。我们团队最近实验的一组数据很能说明问题:在常见的运动识别…...

2026年5月PLC厂家:十大品牌专业评测解决工厂自动化选型难

摘要当制造业加速迈向智能化和柔性生产,PLC作为工业自动化的核心控制单元,其选型直接决定了产线效率、系统稳定性与长期运营成本。然而,面对众多品牌在技术路线、开放程度、生态兼容性上的显著分化,决策者常陷入“性能与成本如何平…...

Cortex-R52内存管理与实时性优化技术解析

1. Cortex-R52内存管理架构解析Cortex-R52作为Armv8-R架构的旗舰级实时处理器,其内存管理系统针对高可靠性场景进行了深度优化。与传统MMU不同,R52采用了增强型MPU(Memory Protection Unit)设计,通过16-24个可编程保护…...

【收藏】2026测试人必看!再不学大模型AI,真的要被行业淘汰了

最近和身边做测试的朋友闲聊,发现大家的焦虑感比往年更重了——有人做了3年功能测试,跳槽面试连初筛都过不了;有人深耕性能测试5年,薪资原地踏步,反而被刚入行、懂AI测试的新人弯道超车。 从ChatGPT横空出世引爆AI行业…...

LangGraph 持久化深度解析:Checkpoint 机制如何实现对话记忆和断点续跑

很多同学在第一次接入 LangGraph 时,会发现图默认是「无状态」的——每次 invoke,上一轮的消息就消失了。你以为加了 MessagesState 就有记忆了,结果测试一问,Agent 完全不知道「你叫什么名字」。 更惨的是什么?生产环…...

IGF-I Analog ;CYAAPLKPALSSC

一、基础信息多肽名称:IGF-I Analog 胰岛素样生长因子 I 类似物 三字母序列:Cys-Tyr-Ala-Ala-Pro-Leu-Lys-Pro-Ala-Lys-Ser-Cys 单字母序列:CYAAPLKPALSSC 氨基酸数量:12 aa 结构修饰:分子内二硫键 二硫键配对&#xf…...

冲突矿产法规合规:供应链尽责管理与ESG风险应对实战指南

1. 冲突矿产法规合规:一场被低估的供应链风暴如果你是一家电子、汽车或工业设备制造公司的供应链、法务或合规负责人,现在请立刻停下手中的工作,问自己一个问题:我们公司使用的锡、钽、钨、金(3TG)这四种金…...

换个角度思考【牛客tracker 每日一题】

换个角度思考 时间限制:1秒 空间限制:256M 知识点:线段树 网页链接 牛客tracker 牛客tracker & 每日一题,完成每日打卡,即可获得牛币。获得相应数量的牛币,能在【牛币兑换中心】,换取相…...

自治性、反应性、学习能力:AI Agent的关键特性

自治性、反应性、学习能力:AI Agent的关键特性——从蚂蚁觅食到通用智能体的进化之路 关键词 AI Agent, 自治性, 反应性, 强化学习, 记忆机制, 环境交互, 通用人工智能萌芽 摘要 想象一下:你有一个能自己帮你规划周末露营路线(自治性)、中途遇到暴雨自动切换到附近民宿…...

Claude Code 多项目 API 配置管理实践

背景 Claude Code 的项目级配置文件 .claude/settings.json 中包含 API 提供商相关的环境变量。当同时维护多个项目,每个项目使用不同的 API 提供商(Anthropic 直连、OpenRouter 代理、自建转发等)时,每次切换项目都需要手动修改…...

移动SoC设计演进:从骁龙600/400系列看芯片战略与体验竞争

1. 从一场发布会看移动芯片的十年演进2015年2月,巴塞罗那世界移动通信大会前夕,高通的一则新闻稿在业内激起了不小的涟漪。他们宣布了全新的骁龙600和400系列移动平台,其中最引人注目的,是首次将当时ARM最新的64位Cortex-A72核心引…...

硬件工程师显示器选购指南:从垂直分辨率到IPS面板的实战经验

1. 从“够用”到“爽用”:一个硬件工程师的显示器升级心路作为一名整天和代码、电路图、数据手册打交道的硬件工程师,我的工作台就是我的战场。而这块战场上最核心的装备,除了键盘鼠标,就是那块每天要盯着看至少八小时的显示器。几…...

2026AI大模型API聚合系统排行榜:四大主流中转API及特色玩家谁能脱颖而出?

随着AI技术大规模落地,AI大模型API聚合系统成为企业快速接入前沿智能能力、降低技术门槛的关键工具。目前市场上的服务商众多,企业在选择时往往会考虑稳定性、合规性、接入成本等因素。为了帮助企业解决这一难题,本文对当下主流的四大AI大模型…...

5个维度深度解析:如何实现高性能黑苹果系统的架构设计与优化策略

5个维度深度解析:如何实现高性能黑苹果系统的架构设计与优化策略 【免费下载链接】Hackintosh 国光的黑苹果安装教程:手把手教你配置 OpenCore 项目地址: https://gitcode.com/gh_mirrors/hac/Hackintosh 在传统PC硬件与macOS系统兼容性的技术挑战…...

从Gemini Nano到Orion Core:Google 2026 AI芯片级升级路线图(附17个真实POC性能基准数据)

更多请点击: https://intelliparadigm.com 第一章:Gemini Nano到Orion Core:Google 2026 AI芯片级演进全景图 Google 正在以空前的系统性节奏重构其AI硬件栈——从终端侧轻量模型推理引擎 Gemini Nano,到2026年即将量产的全栈自研…...

基于大语言模型与RAG的AI小说生成:从技术原理到工程实践

1. 项目概述:当AI开始“阅读”与“创作”最近在内容创作和小说爱好者圈子里,一个名为“auto-novel”的项目引起了我的注意。简单来说,这是一个利用人工智能技术,实现从“阅读”现有小说到“模仿创作”新内容的自动化工具。它的核心…...

AI技能统一管理:用Obsidian插件Agentfiles构建你的智能编码中枢

1. 项目概述:一个为AI编码时代打造的技能中枢 如果你和我一样,日常开发工作流里已经塞满了各种AI编码助手——Claude Code、Cursor、Codex、Windsurf……那么你一定也面临过同样的困境:每个工具都有自己的一套“技能”或“记忆”系统&#xf…...

FinFET与FD-SOI工艺下的IC可靠性验证关键技术

1. 集成电路可靠性验证的挑战与演进在28nm工艺节点之前,芯片设计工程师面临的选择相对简单——只需沿着摩尔定律的轨迹向下一个工艺节点迁移。但随着FinFET和FD-SOI等新型晶体管结构的出现,以及台积电、三星等代工厂推出的多样化工艺节点选项&#xff0c…...

Git Conflict Resolution

1. 这篇文章解决什么问题&#xff1f; Git 冲突不是异常情况&#xff0c;而是多人协作和分支开发里的正常现象。 常见问题包括&#xff1a; 1. 为什么会产生冲突&#xff1f; 2. 冲突文件里的 <<<<<<<、、>>>>>>> 是什么&#xff1f…...

2026年云端保姆级教程:如何搭建OpenClaw?Token Plan配置及大模型API Key接入

2026年云端保姆级教程&#xff1a;如何搭建OpenClaw&#xff1f;Token Plan配置及大模型API Key接入。OpenClaw是开源的个人AI助手&#xff0c;Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案…...

从手机闪光灯到汽车大灯:聊聊‘发光强度’(坎德拉)在硬件选型中的实际应用

从手机闪光灯到汽车大灯&#xff1a;发光强度&#xff08;坎德拉&#xff09;的硬件实战指南 当你在昏暗的停车场用手机闪光灯寻找钥匙时&#xff0c;是否想过为什么有些手机的补光能照亮整个车位&#xff0c;而有些却只能勉强看清手掌&#xff1f;这个差异背后&#xff0c;隐藏…...

2026盘古石取证初赛(APK取证)

APK取证1.分析方俊朗phone.E01检材&#xff0c;筛选优质客户应用将用户查询记录存储在一个加密的本地数据库中。请问该加密数据库的文件名是什么&#xff1f;[答案格式&#xff1a;12_abc.db]题目说了这边是筛选优质客户&#xff0c;其实和手机取证最后一题一样的&#xff0c;先…...

Go语言安全编码实践:常见漏洞与防护

Go语言安全编码实践&#xff1a;常见漏洞与防护 1. 安全编码原则 安全编码是防止漏洞的根本&#xff0c;包括输入验证、输出编码、最小权限等原则。 2. 安全工具 package securityimport ("regexp""strings" )type Validator struct {emailRegex *regexp.R…...

SQLite Having 子句详解

SQLite Having 子句详解 SQLite 是一款轻量级的数据库管理系统,广泛应用于移动应用、桌面应用以及各种嵌入式系统。在 SQLite 中,HAVING 子句是一个非常重要的特性,它用于对 GROUP BY 子句的查询结果进行过滤。本文将详细介绍 SQLite 的 HAVING 子句,包括其用法、语法以及…...

抖音图片怎么去水印?2026实测免费去水印方法全盘点,这几款工具真好用

抖音图片怎么去水印&#xff1f;2026实测免费去水印方法全盘点&#xff0c;这几款工具真好用 刷抖音的时候&#xff0c;你有没有遇到过这种情况&#xff1a;看到一张超好看的图片&#xff0c;点保存&#xff0c;结果发现角落里多了一行「用户名」或者一个抖音 Logo&#xff0c;…...