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

深入理解指针(4)

  • 一、回调函数是什么?
  • 二、qsort使用举例
    • 2.1使用qsort函数排序整型数据
    • 2.2使用qsort排序结构数据
  • 三、qsort函数的模拟实现
  • 四、总结

一、回调函数是什么?

回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数
时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条
件发生时由另外的一方调用的,用于对该事件或条件进行响应。
上一篇文章我们实现了一个能够加减乘除和正常退出的计算器,阅读上篇文章:https://blog.csdn.net/2301_80179750/article/details/145286102?fromshare=blogdetail&sharetype=blogdetail&sharerId=145286102&sharerefer=PC&sharesource=2301_80179750&sharefrom=from_link
使用回调函数改造之前的代码:

#include <stdio.h>
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;
}
nemu()
{
 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;
int x = 0;
int y = 0;
int ret = 0;
//创建一个函数指针的数组
int(*pfArr[5])(int,int) = {NULL,Add,Sub,Mul,Div};
do 
{
nemu();
printf("请选择:");
scanf("%d",&input);//2
if(input >= 1 && input <= 4)
{
printf("请输入2个操作数:");
scanf("%d %d",&x,&y);
ret = pfArr[input](x,y);
printf("%d\n",ret);
}
else if(input == 0)
{
printf("退出计算器\n");
break;
}
else
{
printf("选择错误,重新选择\n");
}
}while(input);
return 0;
}

使用回调函数改造之后的代码:

#include <stdio.h>
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 nemu()
{
 printf("*************************\n");
 printf("  1:add           2:sub  \n");
 printf("  3:mul           4:div  \n");
 printf("  0:exit                 \n");
 printf("*************************\n");
}
void Calc(int(*pf)(int,int))
{
int x = 0;
int y = 0;
int ret = 0;
printf("请输入2个操作数:");
scanf("%d %d",&x,&y);
ret = pf(x,y);
printf("%d\n",ret);
}
int main()
{
int input = 0;
do
{
nemu();
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;
}

通过观察上述代码我们可以得出结论:我们可以把调用的函数的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这里其实使用的就是回调函数的功能。

二、qsort使用举例

2.1使用qsort函数排序整型数据

qsort —— 用来排序的,库函数,直接可以用来排序数据,底层使用的是快速排序的方式。
注:qsort是库函数需要包含头文件<stdlib.h>
函数形式如下:

void qsort(void*base,//指针,指向的是待排序的数组的第一个元素
		   size_t num,//是base指向的待排序数组的元素个数
		   size_t size,//base指向的待排序数组的元素大小
		   int(*compar)(const void*,const void*)//函数指针 —— 指向的是两个元素的比较函数
		   );

官网如图:
在这里插入图片描述
在这里插入图片描述
官网链接:https://legacy.cplusplus.com/reference/cstdlib/qsort/?kw=qsort
qsort函数有实现者;qsort函数的使用者 —— 明确的知道要排序的是什么数据,这些数据应该如何比较,所以提供两个元素的比较函数。
使用qsort函数排序整型数据,代码如下:

#include <stdio.h>
#include <stdlib.h>
void print_arr(int arr[],int sz)
{
int i = 0;
for(i = 0;i < sz;i++)
{
printf("%d",arr[i]);
}
printf("\n");
}
int cmp_int(const void*p1,const void*p2)
{
return*(int*)p1 - *(int*)p2;//可以调节降序
}// > ——> >0	//< ——> <0	//== ——> ==0
void test1()
{
int arr[] = {3,1,7,8,5,2,4,9,0,6};
int sz = sizeof(arr)/sizeof(arr[0]);
qsort(arr,sz,sizeof(arr[0]),cmp_int);
print_arr(arr,sz);
}
int main()
{
//写一段代码使qsort排序整型数据
test1();
return 0;
}

运行结果如下图:
在这里插入图片描述

2.2使用qsort排序结构数据

strcmp是按照对应着字符串中的字符的ASCII码值比值(是专门用来比较两个字符串的大小的),是库函数。
注:必须包含头文件<string.h>。
在这里插入图片描述
结构体访问成员操作符:

. ->

结构体变量.成员名
结构体指针->成员名
结构体访问操作符如何使用,代码如下:

#include <stdio.h>
struct Stu
{
char name[20];
int age;
};
void print(struct Stu*ps)
{
//printf("%s %d\n",(*ps).name,(*ps).age);
printf("%s %d\n",ps -> name,ps -> age);
}
//->结构体成员的间接访问操作
//结构体指针->成员名
int main()
{
struct Stu s = {"zhangsan",18};
print(&s);
return 0;
}

使用qsort排序结构数据,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//struct Stu
//{
//	char name[20];
//	int age;
//}s, s1, s2;//s1,s2,s是结构体变量
//typedef struct Stu
//{
//	char name[20];
//	int age;
//}stu;//stu是类型名
struct Stu
{
	char name[20];
	int age;
};
//这里的两个结构体元素怎么比较大小?
//1.按照名字比较 —— 字符串比较 —— strcmp
//2.按照年龄比较 —— 整型比较
int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
int cmp_stu_by_age(const void* p1, const void* p2)
{
	return((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void test2()
{
	struct Stu arr[3] = { {"zhangsan",20},{"lisi",35},{"wangwu",18} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_name);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}
int main()
{
	test2();
	return 0;
}

调试如下图:
在这里插入图片描述
通过调试,我们可以看出来qsort对结构体进行排序了。

三、qsort函数的模拟实现

使用回调函数,模拟实现qsort(采用冒泡的方式)。
qsort函数的模拟实现,代码如下:

#include <stdio.h>
void print_arr(int arr[],int sz)
{
int i = 0;
for(i = 0;i < sz;i++)
{
printf("%d",arr[i]);
}
printf("\n");
}
int cmp_int(const void*p1,const void*p2)
{
return *(int*)p1 - *(int*)p2;
}
void Swap(char*buf1,char*buf2,size_t width)
{
int i = 0;
for(i = 0;i < width;i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void*base,size_t sz,size_t width,int(*cmp)(const void*p1,const void*p2))
{
//趟数
int i = 0;
for(i = 0;i < sz-1;i++)
{
//一趟内部的两两比较
int j = 0;
for(j = 0;j < sz-1-i;j++)
{
//比较
if(cmp((char*)base + j * width,(char*)base + (j + 1)*width) > 0)//改变
{
//交换两个元素
Swap((char*)base + j * width,(char*)base + (j + 1)*width,width);
}
}
}
}
//测试的是bubble_sort排序整型数据
void test1()
{
int arr[] = {3,1,7,8,5,2,4,9,0,6};
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);
print_arr(arr,sz);
}
int main()
{
test1();
return 0;
}

运行结果如下图:
在这里插入图片描述

四、总结

这篇文章详细介绍了C语言中的回调函数和qsort函数的使用,通过具体的代码示例展示了如何利用这些技术实现灵活的函数调用和数据排序。
回调函数
回调函数是一种通过函数指针调用的函数。在C语言中,函数指针允许我们将函数的地址作为参数传递给另一个函数,从而在特定的事件或条件下调用这些函数。文章通过一个简单的计算器程序展示了回调函数的使用。原始代码中,通过一个函数指针数组来选择不同的运算函数。改造后的代码中,使用了回调函数,将运算函数的地址作为参数传递给Calc函数,从而实现了更灵活的函数调用。这种改造不仅提高了代码的可读性,还增强了程序的灵活性和可扩展性。
qsort函数
qsort是C标准库中的一个通用排序函数,可以对任意类型的数据进行排序。文章首先介绍了qsort函数的基本用法,包括其参数的含义和如何定义比较函数。通过一个整型数组的排序示例,展示了如何使用qsort对整型数据进行排序。接着,文章进一步介绍了如何使用qsort对结构体数组进行排序。通过定义不同的比较函数,可以按照结构体中的不同成员进行排序,如按名字或年龄排序。这些示例展示了qsort函数的强大功能和灵活性。
qsort函数的模拟实现
文章最后通过一个冒泡排序的实现,模拟了qsort函数的行为。这个模拟实现使用了回调函数来比较元素,从而实现了对不同类型数据的排序。通过这个模拟实现,读者可以更好地理解qsort函数的内部工作机制,以及如何通过回调函数实现灵活的数据比较。
这篇文章通过具体的代码示例,详细介绍了C语言中的回调函数和qsort函数的使用。通过回调函数,可以实现更灵活的函数调用,提高代码的可读性和可扩展性。qsort函数则提供了一种通用的排序方法,可以对任意类型的数据进行排序。通过这些技术,读者可以更好地理解和应用C语言中的函数指针和排序算法。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

零售业革命:改变行业的顶级物联网用例

mpro5 产品负责人Ruby Whipp表示&#xff0c;技术进步持续重塑零售业&#xff0c;其中物联网&#xff08;IoT&#xff09;正引领这一变革潮流。 研究表明&#xff0c;零售商们正在采用物联网解决方案&#xff0c;以提升运营效率并改善顾客体验。这些技术能够监控运营的各个方面…

macos的图标过大,这是因为有自己的设计规范

苹果官方链接&#xff1a;App 图标 | Apple Developer Documentation 这个在官方文档里有说明&#xff0c;并且提供了sketch 和 ps 的模板。 figma还提供了模板&#xff1a; Figma

【从零到一,C++项目实战】CineShare++(基于C++的视频点播系统)

&#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系列 &#x1f308;Linux学习专栏&#xff1a; 南桥谈Linux &#x1f308;数据结构学习专栏&#xff1a; 数据结构杂谈 &#x1f308;数据…

【leetcode100】从前序与中序遍历序列构造二叉树

1、题目描述 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,9,20,nul…

免费GPU算力,不花钱部署DeepSeek-R1

在人工智能和大模型技术飞速发展的今天&#xff0c;越来越多的开发者和研究者希望能够亲自体验和微调大模型&#xff0c;以便更好地理解和应用这些先进的技术。然而&#xff0c;高昂的GPU算力成本往往成为了阻碍大家探索的瓶颈。幸运的是&#xff0c;腾讯云Cloud Studio提供了免…

window保存好看的桌面壁纸

1、按下【WINR】快捷键调出“运行”窗口&#xff0c;输入以下命令后回车。 %localappdata%\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets 2、依次点击【查看】【显示】&#xff0c;勾选【隐藏的项目】&#xff0c;然后按【CtrlA】全部…

android 的aab包

什么是 AAB (Android App Bundle)&#xff1f; AAB (Android App Bundle) 是 Google 推出的新一代 Android 应用发布格式&#xff0c;用于取代传统的 APK 格式。AAB 的全称是 Android App Bundle&#xff0c;扩展名为 .aab&#xff0c;它并不是直接可以安装的文件&#xff0c;…

【25考研】中科院软件考研复试难度分析!

中科院软件复试不需要上机&#xff01;且对专业综合能力要求较高&#xff01;提醒同学一定要认真复习&#xff01; 一、复试内容 二、参考书目 官方并未明确给出&#xff0c;建议同学参考初试书目&#xff1a; 1&#xff09;《数据结构&#xff08;C语言版&#xff09;》严蔚…

2014年蓝桥杯第五届CC++大学B组真题及代码

目录 1A&#xff1a;啤酒和饮料&#xff08;填空&#xff09;&#xff08;枚举&#xff09; 2B&#xff1a;切面条&#xff08;填空&#xff09; 3C&#xff1a;李白打酒&#xff08;填空&#xff09;&#xff08;dfs&#xff09; 4D&#xff1a;史丰收速算&#xff08;代码…

目标跟踪之sort算法(3)

这里写目录标题 1 流程1 预处理2 跟踪 2 代码 参考&#xff1a;sort代码 https://github.com/abewley/sort 1 流程 1 预处理 1.1 获取离线检测数据。1.2 实例化跟踪器。2 跟踪 2.1 轨迹处理。根据上一帧的轨迹预测当前帧的轨迹&#xff0c;剔除到当前轨迹中为空的轨迹得到当前…

单片机基础模块学习——DS18B20温度传感器芯片

不知道该往哪走的时候&#xff0c;就往前走。 一、DS18B20芯片原理图 该芯片共有三个引脚&#xff0c;分别为 GND——接地引脚DQ——数据通信引脚VDD——正电源 数据通信用到的是1-Wier协议 优点&#xff1a;占用端口少&#xff0c;电路设计方便 同时该协议要求通过上拉电阻…

【精选】基于数据挖掘的招聘信息分析与市场需求预测系统 职位分析、求职者趋势分析 职位匹配、人才趋势、市场需求分析数据挖掘技术 职位需求分析、人才市场趋势预测

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

文献阅读 250125-Accurate predictions on small data with a tabular foundation model

Accurate predictions on small data with a tabular foundation model Accurate predictions on small data with a tabular foundation model | Nature 使用一种基于表格的模型来对小型数据实现准确预测 ## Abstract: 基于其他列来填充标签列中缺失值的基本预测任务对于各种应…

shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。

文章目录 前言1. 直接上代码最后在讲解1.1 新增的pom依赖1.2 RedisCache.java1.3 RedisCacheManager.java1.4 jwt的三个类1.5 ShiroConfig.java新增Bean 2. 源码讲解。2.1 shiro 缓存的代码流程。2.2 缓存流程2.2.1 认证和授权简述2.2.2 AuthenticatingRealm.getAuthentication…

【QT】 控件 -- 显示类

&#x1f525; 目录 [TOC]( &#x1f525; 目录) 1. 前言 2. 显示类控件2.1 Label 1、显示不同文本2、显示图片3、文本对齐、自动换行、缩进、边距4、设置伙伴 3.2 LCD Number 3.3 ProgressBar 3.4 Calendar Widget 3. 共勉 &#x1f525; 1. 前言 之前我在上一篇文章【QT】…

location的使用规则

1、基于URL的location 负责均衡配置 后端集群中的web服务器&#xff0c;必须要有对应的目录和文件才能被访问到 http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;upstream default_pool {server 10.0.0.7:…

如何制作浪漫风格的壁纸

制作浪漫风格的壁纸需要营造出温馨、柔和、梦幻的氛围&#xff0c;通过色彩、元素和构图来传达浪漫的情感。以下是一个详细的步骤指南&#xff0c;帮助你制作浪漫风格的壁纸&#xff1a; 一、明确设计目标 确定用途&#xff1a; 个人使用&#xff1a;如果是为了个人设备&#…

SpringBoot支持动态更新配置文件参数

前言 博主介绍&#xff1a;✌目前全网粉丝3W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技术内容&#xff1a;Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。 博主所有博客文件…

题海拾贝:P2085 最小函数值

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…

企业微信SCRM开创客户管理新纪元推动私域流量高效转化

内容概要 在当今瞬息万变的数字化时代&#xff0c;企业面临着前所未有的客户管理挑战。消费者的需求日益多样化&#xff0c;他们希望能够随时随地与品牌沟通。因此&#xff0c;越来越多的企业意识到&#xff0c;传统的客户管理方式已无法满足市场的需求。在这样的背景下&#…