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

C语言学习记录--深入理解指针(5)(qsort的练习)

     这一篇就是关于指针的最后一战了,主要是练习一个叫做  qsort   的C语言库函数

正文开始:

一.什么是qsort函数?

     qsort  就是 quick sort,也就是“快速排序”,意思就是说qsort就是一个排序函数,和之前写的冒泡排序不同,冒泡排序只能排序整型数据,而qsort可以排序任意类型的数据。

注意:使用qosrt需要包含头文件  #include<stdlib.h>

下面是我在cpulspuls 网站截到的图片,用来作qsort的说明:

 可以看到,这个函数的使用需要传递4个参数,分别是:

1.要排序的数组的首元素指针(即数组名)。

2.待排序数组中的元素个数。(可以用  sizeof(arr)/sizeof(arr[0])  )

3.待排序数组中每个元素的字节大小(即 sizeof(arr[0]  )

4.比较两个元素大小比较的函数的指针(即函数名)

   前面三个参数都很好理解,关键在于第四个,这是一个比较数组中元素大小的函数,根据这个函数的返回值决定元素的相对顺序。

二.qsort的应用

代码格式如下:

#include<stdlib.h>
void compare(const void* p1, const void* p2)
{}
int main()
{int arr[10] = { 9,0,5,7,3,2,4,1,8,6 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), compare);return 0;
}

然后来写函数:

void compare(const void* p1, const void* p2)
{if (*(int*)p1 > *(int*)p2)//因为void*类型不能解引用,所以这里使用(int*)来强制类型转换。{return 1;}else if (*(int*)p1 < *(int*)p2){return -1;   }else{return 0;}
}

返回大于0的数(1)和小于0的数(-1)来比较元素大小,

完整代码效果如下:

#include<stdlib.h>
void compare(const void* p1, const void* p2)
{if (*(int*)p1 > *(int*)p2){return 1;}else if (*(int*)p1 < *(int*)p2){return -1;   }else{return 0;}
}void print(int* arr, int sz)
{int i = 0;for (i = 0;i < sz;i++){printf("%d ", *(arr + i));}printf("\n");
}int main()
{int arr[10] = { 9,0,5,7,3,2,4,1,8,6 };int sz = sizeof(arr) / sizeof(arr[0]);printf("排序前:");print(arr, sz);qsort(arr, sz, sizeof(arr[0]), compare);printf("排序后:");print(arr, sz);return 0;
}

三.qosrt的其他应用举例

1. 字符串排序(按字典序)​

在处理文本数据时,我们经常需要对字符串进行排序,比如将单词按字典序排列。以下是使用qsort函数实现字符串排序的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 字符串比较函数(用于qsort)
int compare_strings(const void *a, const void *b) {// 将void指针转换为char**,再解引用得到char*return strcmp(*(const char **)a, *(const char **)b);
}int main() {const char *strings[] = {"banana", "apple", "cherry", "date", "elderberry"};int n = sizeof(strings) / sizeof(strings[0]);// 排序字符串数组qsort(strings, n, sizeof(const char *), compare_strings);// 输出排序结果printf("排序后的字符串:\n");for (int i = 0; i < n; i++) {printf("%s\n", strings[i]);}return 0;
}

运行结果:

2. 结构体排序(按学生成绩降序)​

当需要对自定义结构体数据进行排序时,qsort同样能发挥作用。假设我们有一个学生结构体,包含姓名和成绩信息,现在要按成绩从高到低对学生进行排序,代码如下:​

#include <stdio.h>
#include <stdlib.h>// 定义学生结构体
typedef struct {char name[50];int score;
} Student;// 学生比较函数(按成绩降序)
int compare_students(const void *a, const void *b) {// 将void指针转换为Student*const Student *student_a = (const Student *)a;const Student *student_b = (const Student *)b;// 降序排序:b - areturn student_b->score - student_a->score;
}int main() {Student students[] = {{"Alice", 85},{"Bob", 92},{"Charlie", 78},{"David", 92},{"Eve", 88}};int n = sizeof(students) / sizeof(students[0]);// 排序学生数组qsort(students, n, sizeof(Student), compare_students);// 输出排序结果printf("按成绩降序排列的学生:\n");for (int i = 0; i < n; i++) {printf("%s: %d分\n", students[i].name, students[i].score);}return 0;
}

运行结果:

四.使用冒泡排序的底层逻辑模拟qsort

  当我们学会了冒泡排序后,发现它只能排序整型数据,那么有办法让冒泡排序算法(Bubble_sort)也能够排序任意类型的数据吗?

有的兄弟,有的

接下来就是本篇的重点了,即使用冒泡排序的底层逻辑模拟qsort。

  我这里直接先把代码端上来吧:

#include<stdio.h>
void swap(char* bf1, char* bf2, size_t width)
{int i = 0;char tmp = 0;for (i = 0;i < width;i++){tmp = *bf1;*bf1 = *bf2;*bf2 = tmp;bf1++;bf2++;}
}int cmp(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}void print(int arr[10], int sz)
{int i = 0;for (i = 0;i < sz;i++){printf("%d ", *(arr + i));}printf("\n");
}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);}}}
}int main()
{int arr[10] = { 10,9,8,7,6,5,4,3,2,1 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp);print(arr, sz);return 0;
}

这段代码实现了一个通用的冒泡排序算法,它能够对任意类型的数据进行排序,具体功能包括:

  1. 内存交换函数swap函数用于交换两个内存块的内容
  2. 比较函数cmp函数用于定义元素之间的比较规则
  3. 打印函数print函数用于输出排序结果
  4. 通用冒泡排序bubble_sort函数实现核心排序逻辑
  5. 主函数:演示如何使用上述功能对整数数组进行排序

我想写更清楚一点儿的解释,可奈何有点力不从心(说白了现在还没有能力用文字把所有代码解释清楚)

主要难点在于这两个地方:

  1. 内存交换函数swap函数用于交换两个内存块的内容
  2. 比较函数cmp函数用于定义元素之间的比较规则

swap函数是实现元素交换的核心:

void swap(char* bf1, char* bf2, size_t width)
{int i = 0;char tmp = 0;for (i = 0; i < width; i++){tmp = *bf1;*bf1 = *bf2;*bf2 = tmp;bf1++;bf2++;}
}

这个函数通过逐字节交换两个内存块的内容来实现元素交换。由于使用了char*指针,每次只能访问一个字节,因此需要循环width次,确保交换整个元素的内容。

比较函数cmp是定义排序规则的关键:

int cmp(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}

比较函数的设计遵循以下原则:

  • 接受两个const void*类型的参数
  • 将参数转换为实际数据类型的指针
  • 根据比较结果返回负值、零或正值

其他的点在熟悉C语言指针的情况下是很容易理解的。

OK!指针的内容我也终于学完了,真是一场盛大得知识盛宴啊。

学习过程终归有些枯燥和乏味,但想起来最终目标还很远,所以还是要砥砺前行,感觉把自己说的有点高大上了,算了……一步步来。

指针到此结束,感谢各位的阅读!

http://www.xdnf.cn/news/489943.html

相关文章:

  • Linux基础开发工具大全
  • 连续隐马尔可夫离散隐马尔科夫模型的MATLAB实现
  • falsk-ORM的使用-数据库表的创建
  • 【Linux】动静态库链接原理
  • nnUNet V2代码——图像增强(三)
  • 【数据结构】线性表--栈
  • 金属加工液展|切削液展|2025上海金属加工液展览会
  • 使用unsloth对Qwen3在本地进行微调
  • 一个批量文件Dos2Unix程序(Microsoft Store,开源)1.1.0 编码检测和预览
  • 淘宝扭蛋机系统开发前景分析:解锁电商娱乐化新蓝海
  • HOW - React NextJS 的同构机制
  • Dify中使用插件LocalAI配置模型供应商报错
  • Spring Cloud深度实践:从服务发现到弹性智能API网关全景解析
  • Day29 -JS开发02 -两个实例:dom树(存在dom-xss) 加密及基础的js逆向(明文加密)
  • SAP-ABAP:SAP DMS(文档管理系统)的详细说明,涵盖其核心功能、架构、配置及实际应用
  • spring学习->sprintboot
  • Room数据库
  • Matrix-Game:键鼠实时控制、实时生成的游戏生成模型(论文代码详细解读)
  • Java并发编程-线程池(四)
  • Reth(冗余以太网接口) 和Bridge-Aggregation(链路聚合接口)区别
  • 一个进程中可以有多个 WebView2 控件,它们各自有独立的用户数据目录,COOKIE共享
  • 内存泄漏系列专题分析之十六:高通相机CamX内存泄漏内存占用分析--chi-cdk部分ION内存拆解方法
  • 跳转传参的使用
  • Java生产环境设限参数教学
  • 第六章 进阶10 实习生的焦虑
  • 一文讲透面向对象编程OOP特点及应用场景
  • 深入探索Java微服务架构:Spring Cloud与Kubernetes的整合实践
  • 敏感数据加密和模糊匹配
  • 使用CherryStudio +SiliconFlow 部署独立的deepseek+知识库
  • 文本数据词汇级增强