🚀前言
今天阿辉将为大家介绍库函数qsort的使用,还包括利用冒泡排序模拟实现qsort以及void*
类型的指针,关注阿辉不迷路哦 😘 ,内容干货满满😋,接下来就跟着阿辉一起学习吧👊
🚀void*类型指针
铁子们都知道一种指针只能接收同类型的地址,否则编译器就会报错,那有没有可以接收任意类型地址的指针呢?答案是有的,就是void*
类型的指针
例如:
int a = 10; char c = 'c'; float f = 1.2f; void*p = NULL; p = &a; p = &c; p = &f;
void*
类型指针可以接受任何类型的变量的地址,它就像一个“垃圾桶”一样,任何的地址都可以往里面“扔”,所以他也被称为泛型指针,但是void*
类型的指针也有它的局限性,因为void*
无具体类型,SOvoid*
类型的指针无法进行指针运算也无法进行解引用操作
既然如此,那void*
类型的指针有何应用场景,铁子们别急我们接着看👇
🚀库函数qsort的使用
铁子们,咱们今天的重点来了,qsort()
是C语言标准库提供的专门用来给数组排序的一个库函数
qsort()函数的声明
void qsort(void* base, size_t num, size_t size, int (*compar)(const void* p1, const void* p2)); 库函数qsort()有四个参数, 不返回 void* base 这个参数是指向数组首元素的指针 size_t num这个参数指的是数组中的元素个数 size_t size这个参数是数组中每个元素的大小,以字节为单位
对于库函数qsort()
的第四个参数int (*compar)(const void* ,const void*)
,是一个函数指针,要使用qsort()
得我们自己定义一个返回值为int
类型有两个const
修饰的void*
类型的指针的参数,并且返回值遵循如下规则的函数:
返回值< 0 第一个参数应在第二个参数前,无需交换 返回值> 0 第二个参数应在第一个参数前,需要交换 返回值= 0 谁在前无所谓,无去交换
qsort()
函数最厉害的就是它可以给任何数据排序,并且可以根据我们提供的比较函数实现升序或是降序,铁子们,我们来看看qsort()
是如何使用的👇
#include<stdio.h> #include<string.h> #include<stdlib.h> struct Stu { int age;//年龄 char name[20];//名字 }; //以结构体Stu成员age的数字大小排升序 int StuAgecomp(const void* p1, const void* p2) { return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age; } //以结构体Stu成员name利用库函数strcmp()给字符串排序 int StuNamecomp(const void* p1, const void* p2) { return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name); } //打印函数,打印排序后内容 void print(struct Stu arr[],int size) { for (int i = 0; i < size; i++) { printf("%d %s ", arr[i].age, arr[i].name); } printf("\n"); } int main() { struct Stu arr[] = { {19,"tangminghui"},{12,"tanzihao"},{30,"zenghongsen"} }; int size = sizeof(arr[0]);//数组每个元素的大小,单位字节 int num = sizeof(arr) / size;//数组的元素个数 qsort(arr, num, size, StuAgecomp); print(arr,num); qsort(arr, num, size, StuNamecomp); print(arr,num); return 0; }
输出:
🚀利用冒泡排序实现库函数qsort()
相信铁子们对冒泡排序并不感冒,库函数qsort()
的内核其实就是快排不过阿辉实力有限暂时还不会 😭,这里阿辉利用冒泡函数给大家徒手干一个
函数名就叫UpgradeBubbleSort
升级版冒泡排序 😜(以下简称冒泡函数)
我们的冒泡函数的参数与库函数qsort
一样,排序就是冒泡排序的皮,主要的问题是泛型参数如何交换,这里我们定义一个交换函数swp
来实现
下面是冒泡函数的具体实现,代码以及详解注释:
void UpgradeBubbleSort(void* base, size_t num, size_t size, int (*cmp)(const void* p1, const void* p2)) { for (int i = 0; i < num - 1; i++) { int flag = 0;//记录一趟下来是否发生交换 for (int j = 0; j < num - i - 1; j++) { //数据的大小这时就有用了,找到后一个数据的起始地址 char* p = (char*)base + j * size;//利用一个变量简化代码 //像下面注释这么写太挫了 //if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)) //冒泡排序的思想嘛,前一个数据和后一个比 if (cmp(p, p + size) > 0) { swp(p, size); flag = 1; } } if (flag == 0)//没有交换说明已有序无须继续,跳出循环 { break; } } }
为什么要把void*
指针强制转化为char*
类型,第一点,因为方便根据数据大小找到数据,char*
加减整数跳过该整数倍数的字节空间和数据大小size
结合使用,就能找到数据中每个元素;第二点,因为交换数据时把对应位置上的一个字节大小空间中的内容交换,即可交换两个数据的内容
给铁子们上图:
swp
函数的具体实现,代码以及详解注释:
//交换函数 void swp(char* p, int sz) { //有几个字节交换几次 //p+sz表示下一个数据 for (int i = 0; i < sz; i++) { //俩个数据对应位置的字节交换位置,完成交换 char tmp = *(p + i); *(p + i) = *(p + sz + i); *(p + sz + i) = tmp; } }
下面是完整的升级版冒泡排序函数 😘
//交换函数 void swp(char* p, int sz) { for (int i = 0; i < sz; i++) { //俩个数据对应位置的字节交换位置,完成交换 char tmp = *(p + i); *(p + i) = *(p + sz + i); *(p + sz + i) = tmp; } } //套着标准冒泡排序的皮 void UpgradeBubbleSort(void* base, size_t num, size_t size, int (*cmp)(const void* p1, const void* p2)) { for (int i = 0; i < num - 1; i++) { int flag = 0;//记录一趟下来是否发生交换 for (int j = 0; j < num - i - 1; j++) { char* p = (char*)base + j * size;//利用一个变量简化代码 //像下面注释这么写太挫了 //if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)) if (cmp(p, p + size) > 0) { swp(p, size); flag = 1; } } if (flag == 0)//没有交换说明已有序无须继续,跳出循环 { break; } } }
到这里,阿辉今天对于C语言中库函数qsort()的分享就结束了,希望这篇博客能让大家有所收获, 如果觉得阿辉写得不错的话,记得给个赞呗,你们的支持是我创作的最大动力🌹