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

指针深入第三弹--回调函数,qsort函数使用的运用

目录

回调函数是什么?

qsort使用

使用qsort函数排序整型数据

排序结构体数据

qsort函数的模拟实现

总结

回调函数是什么?

回调函数就是⼀个通过函数指针调⽤的函数。

如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数 时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条 件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。

我们利用函数指针修改一下指针深入第二弹里的计算器

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 cacl(int (*pf)(int, int))
{int x, y,ret;printf("请输入两个操作数\n");scanf("%d %d", &x, &y);ret = pf(x, y);printf("结果是:%d\n", ret);
}
int main()
{int x, y;int input = 1;int ret = 0;int (*p[5])(int x, int y) = { 0,Add,Sub,Mul,Div };do{printf("*******************\n");printf("****1:Add   2.Sub**\n");printf("****3.Mul   4.Div**\n");printf("*******0.exit******\n");printf("请选择:\n");scanf("%d", &input);switch (input){case 1:cacl(Add);break;case 2:cacl(Sub);break;case 3:cacl(Mul);break;case 4:cacl(Div);break;case 0:printf("退出\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}

主调函数

int main()
{int x, y;int input = 1;int ret = 0;int (*p[5])(int x, int y) = { 0,Add,Sub,Mul,Div };do{printf("*******************\n");printf("****1:Add   2.Sub**\n");printf("****3.Mul   4.Div**\n");printf("*******0.exit******\n");printf("请选择:\n");scanf("%d", &input);switch (input){case 1:cacl(Add);break;case 2:cacl(Sub);break;case 3:cacl(Mul);break;case 4:cacl(Div);break;case 0:printf("退出\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}

回调函数

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

有了函数指针后,函数的调用,可以用函数名调用,也可以使用函数指针调用

qsort使用

使用qsort函数排序整型数据

排序方式有:选择排序,插入排序,冒泡排序,快速排序,希尔排序等

下面我们来写一个冒泡排序的数组,对一组整型数据进行排序,排序为升序

void bubble_sort(int arr[5], int sz)
{int t;for (int i = 0; i < sz - 1; i++){for (int j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1]){t = arr[j];arr[j] = arr[j + 1];arr[j + 1] = t;}}}
}
void print(int arr[5],int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int arr[5] = { 5,9,6,4,2};int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr,sz);print(arr,sz);return 0;
}

这个函数只能排序整形数据

假设我要改造这个函数,让这个函数能排序其他类型的数据,需要改造的地方:

  • 两个整形元素可以直接用>比较,但是两个字符串,两个结构体元素不能使用>比较!!

把两个元素的比较方法,封装成函数,然后把函数的地址传给排序函数

我们来看一下qsort,根据这个函数来改造

qsort--用来排序的库函数,直接可以用来排序数据,底层使用的是快速排序的方式

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

void* 类型的指针是无具体类型的指针,这种类型的指针不能直接解引用,也不能进行+-整数的运算

qsort函数的使用者,明确的知道要排序的是什么类型的数据,这些数据要如何比较,所以提供两个元素的比较函数

写一下这个比较函数

//int类型的数据
int cmp_int(const void* p1, const void* p2)
{if (*(int*)p1 > *(int*)p2)return 1;else if (*(int*)p1 == *(int*)p2)return 0;elsereturn -1;
}

精进一下

//int类型的数据
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - * (int*)p2;//为升序
}

字符串的比较用strcmp,strcmp是按照着字符中的字符对应这ASCII码值比较的,比的不是长度,是ASCII码值的大小

排序结构体数据

“ -> ”  是结构体成员操作符,为结构体成员的间接访问操作

  • 结构体变量.成员名
  • 结构体指针.成员名
  • 结构体指针->成员名
struct Stu
{char name[20];int age;
}s,s1,s2;//s1,s2,s是结构体变量
typedef struct Stu
{char name[20];int age;
}stu;//stu是类型名

这里的两个结构体怎么比较大小

  1. 按照名字比较--字符串比较--strcmp
  2. 按照年龄比较--整型比较
int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p1)->age);
}

(struct Stu*)p1:将指针 p1 强制转换为 struct Stu* 类型

完整代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//int类型的数据
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 >-* (int*)p2;
}
struct Stu
{char name[20];int age;
};int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p1)->name);
}
void test()
{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);
}
int main()
{test();return 0;
}

结果按照字符串的大小排序的

qsort函数的模拟实现

使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)

base==arr[0]

(char*)base+4==arr[1]

arr[j]==(char*)base+j*width

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 t = *buf1;*buf1 = *buf2;*buf2 = t;buf1++;buf2++;}
}
void bubble_sort(void* base,size_t sz,size_t width,int(*cmp)(const void* p1,const void* p2))
{for (int i = 0; i < sz - 1; i++){for (int 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);}}}
}
void print(int arr[5],int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
void test()
{int arr[] = { 5,6,3,8,4,2,9,1,7,10 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);print(arr, sz);
}
int main()
{test();return 0;
}

总结

# 文章总结

通过本文的学习,我们深入理解了回调函数的概念及其在C语言中的重要应用。回调函数作为一种函数指针的应用,为我们提供了极大的编程灵活性,特别是在qsort这样的标准库函数中体现得淋漓尽致。

我们从基础的整型数据排序开始,逐步过渡到更复杂的结构体数据排序,掌握了qsort函数的使用方法和比较函数的编写技巧。通过模拟实现qsort函数,我们不仅加深了对回调函数工作原理的理解,也提升了算法实现的能力。

回调函数的魅力在于它能够让代码更加模块化、可扩展,是C语言中实现多态性的重要手段。掌握回调函数和qsort的使用,不仅能帮助我们更好地处理排序问题,也为理解更高级的编程概念打下了坚实基础。

希望本文的内容对您有所帮助,欢迎在评论区交流讨论,共同进步!

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

相关文章:

  • 微网站分享功能推广新网站
  • 酒店电子商务网站建设阿德莱德做网站
  • 最新网站建设网站策划做啥
  • 原创文章网站开发教程网络哪家公司比较好
  • 网站备案 新网永久新域名225222
  • 网络营销导向企业网站建设的一般原则是什么?动画制作培训学院
  • 仿冒网站制作eclipse 网站开发源码
  • 网站制作学校百度大数据中心
  • 网站开发的岗位it运维方案
  • 宁波专业建设网站建站公司wordpress 歌
  • swiper做的网站南水北调建设管理局网站
  • sql server做网站wordpress留言标签
  • 高密网站开发网站备案ip地址
  • 网站改版建设,有哪些内容滕州英文网站建设
  • 最好的锦州网站建设开源网站程序
  • 网站公司怎么做网站制作公司高端
  • 视频网站不赚钱为什么还做百度关键词搜索指数查询
  • 宿州金融网站建设电商网站开发文档
  • 北京网站建设联系兴田德润数字广东网络建设有限公司总经理
  • 做的比较好的法律实务培训网站网站开发摊销期多少年
  • 网站设计博客建站重庆
  • MediSam信息统计表格
  • 滨州网站建设铭盛信息做牙网站
  • 免费外国网站浏览器外包服务属于什么行业
  • 没有公司怎么做网站明薇通网站建设哪家好
  • lerobot框架部署diffusion policy模型
  • 网站建设l临沂网站建设与架构男友实验
  • 莱芜做网站的公司中国建设银行手机银行网站
  • 表格在网站后台是居中可到前台为什么不居中兖州城乡建设局网站
  • 做网站,用什么做数据库最好自学网站建设 难吗