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

C语言:指针(4)

1. 回调函数

回调函数就是指通过函数指针调用的函数。

如果将函数指针作为参数传递给另一个函数,另一个函数根据指针来调这个函数,那么被调用的函数就是回调函数。回调函数不是由这个函数的实现方直接调用,而是在特定的条件下由另一方调用的。

例如在指针(3)中,我们将多个函数的地址放在函数指针数组中,根据不同的选择来对输入的x和y执行相应的计算,这里就是采用的就是回调函数的功能。

2. qsort使用举例

2.1 qsort函数

在 C 语言中,qsort是标准库<stdlib.h>提供的快速排序函数,用于对数组进行排序。其函数原型如下:

void qsort(void *base, size_t nmemb, size_t size,int (*compar)(const void *, const void *));

其中:

base是要排序的数组首元素的地址

nmemb是数组中元素的个数

size是每个元素的大小,单位为字节

compar是指比较函数的指针,用来定义排序规则

2.2 利用qsort函数排序整型数据

qsort会根据传递的函数指针所指向的那个函数的返回值来排序,例如两个值a,b进行比较:

当返回值为负时,a就会排在b前面;返回值为正时,a排在b后面;返回值为0时,qsort会将这两个值视为相等,但并不会保证相等元素排序与原始排序相同,例如:原始排序是 a  b,a在前,而qsort排序后可能会是b  a,即相等的元素排序后的相对位置不一定与原始位置相同。

知道这些我们可以利用qsort函数做一个简单的排序,让一个数组中的元素按升序排序:

#include <stdio.h>
#include <stdlib.h>
int i;int cmp(const void* p1,const void* p2)
{return (*(int *)p1 - *(int *)p2);
}
int main()
{int arr[] = {1,4,3,6,8,9,7,2,5,0};int num = sizeof(arr)/ sizeof(arr[0]);int sz = sizeof(arr[0]);qsort(arr,num,sz,cmp);for(i = 0;i < num;i++){printf("%d ",arr[i]);}return 0;
}
0 1 2 3 4 5 6 7 8 9 

我们可以看到输出结果与预期一致,qsort正确得进行了排序。

另外,我们可以看到我们定义的cmp函数中,在进行运算前前面先将指针p1与p2的类型先强制转换为了int *,这是因为void *虽然可以接受各种类型的指针,但是却不能直接使用,必须先进行强制类型转换。这里因为我们希望是升序,所以返回p1减去p2的值。若p1 < p2,返回值为负,p1排在p2前;若p1 > p2,返回值为正,p1排在p2后。如果我们想要实现降序,只需要将cmp函数体内p1与p2的位置互换或者是在计算表达式前加上 - ,改变正负即可。

2.3 使用qsort排序结构数据

现在我们尝试利用qsort函数来对结构数据进行排序,例如:

#include <stdio.h>
#include <stdlib.h>
int i;
struct Stu
{char name[10];int age;
};
int cmp_by_name(const void *p1,const void *p2)
{return strcmp(((struct Stu*)p1)->name,((struct Stu*)p2)->name);
}int main()
{struct Stu s[] = {{"zhangsan",20},{"lisi",23},{"wangwu",19}};int len = sizeof(s)/ sizeof(s[0]);int sz = sizeof(s[0]);qsort(s,len,sz,cmp_by_name);for(i = 0;i < len;i++){printf("%s\n",s[i].name);}return 0;
}
lisi
wangwu
zhangsan

根据打印结果,我们发现,qsort成功按照字母顺序进行了排序。同样的,我们也可以写出cmp_by_age函数,让qsort按照年龄来进行排序。

另外,我在定义函数cmp_by_name时,在函数体内部用 -> 来访问结构中的name,而在打印时使用的是 . 。这是因为,我在定义函数的返回值时,这里的数据是指针类型,只能用->来访问,而在打印时则是直接访问结构,所以要使用 . 来访问结构中数据。因此,如果我们不想使用->,也可以先对指针进行解引用操作然后再使用 . 来访问数据。

3. qsort函数的模拟实现

学习了qsort函数的使用方法后,我们现在尝试自己写代码来模拟实现qsort函数。

例如,我们用冒泡排序的方法法来模拟qsort函数。

那么。根据上面的代码的经验,我们可以得到下面的代码:

#include <stdio.h>int cmp(const void *p1,const void *p2)
{return (*(int*)p1 - *(int*)p2);
}
void swap(void *p1,void *p2,int sz)
{int i;char temp;for(i = 0;i < sz;i++){temp = *((char *)p1 + i);*((char *)p1 + i) = *((char *)p2 + i);*((char *)p2 + i) = temp;}
}void bubble(void* base,int num,int sz,int (*cmp)(const void *p1,const void *p2))
{int i,j;for(i = 0;i < num - 1;i++){for(j = 0;j < num - 1 - i;j++){if(cmp(base + j * sz,base + (j + 1) * sz) < 0){swap(base + j * sz,base + (j + 1) * sz,sz);}}}
}
int main()
{int i;int arr[] = {1,5,3,7,9,4,0,2,6,8};int num = sizeof(arr)/ sizeof(arr[0]);int sz = sizeof(arr[0]);bubble(arr,num,sz,cmp);for(i = 0;i < num;i++){printf("%d ",arr[i]);}return 0;
}
9 8 7 6 5 4 3 2 1 0 

这里主体的逻辑和上面的代码一样,值得一提的是swap这个函数。

在定义这个函数的时候我们是将指针类型强制转换为char * 类型,这样处理的好处是:我们为了模拟qsort函数实现通用设计,在不知道接受的数据类型的前提下,将指针类型强制转换为char *类型,而char *类型指针和 i 相加时只会跳过 i 个字节,这样能够充分交换每一个字节中的数据,防止遗漏,保证了数据的准确性。         

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

相关文章:

  • QT(事件)
  • 网络安全合规6--服务器安全检测和防御技术
  • MyBatis针对MySQL模糊查询中特殊字符(%和_)的处理方案
  • BGE:智源研究院的通用嵌入模型家族——从文本到多模态的语义检索革命
  • 模型驱动的自动驾驶AI系统全生命周期安全保障
  • C++入门自学Day10-- Vector类的自实现
  • Nginx学习与安装
  • Docker(springcloud笔记第三期)
  • docker 将本地python环境(有系统依赖)进行打包移到另一个服务器进行部署
  • 飞算AI:企业智能化转型的新引擎——零代码重塑生产力
  • sql查询优化方式常见情况总结
  • TLSv1.2协议与TCP/UDP协议传输数据内容差异
  • 【Redis】Sentinel (哨兵)
  • 深度学习实战114-基于大模型的深度研究(DeepResearch)架构:从自主信息探索到洞察生成的革命
  • games101 第三讲 Transformation(变换)
  • RK3568项目(十五)--linux驱动开发之进阶驱动
  • Linux应用层开发--进程处理
  • 【完整源码+数据集+部署教程】医学报告图像分割系统源码和数据集:改进yolo11-HGNetV2
  • @Linux进程管理工具 - PM2全面指南
  • 理财 - 基金
  • 【React】use-immer vs 原生 Hook:谁更胜一筹?
  • PromptPilot — AI 自动化任务的下一个环节
  • 云蝠智能 Voice Agent 多模型接入技术架构与实践
  • 微信小程序实现导航至目的地
  • 腾讯位置商业授权微信小程序关键词输入提示
  • python自学笔记7 可视化初步
  • 并发编程(八股)
  • epoll模型解析
  • 数据科学与计算:从基础到实践的全面探索
  • 深度学习(6):参数初始化