C语言_回调函数和qsort

embedded/2025/1/11 14:26:58/

1. 回调函数

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

通俗易懂些讲就是把函数的指针作为参数传递给另一个函数,当在另一个函数中通过这个指针调用其所指向的函数时,那这个通过指针被调用的函数就叫做回调函数

先上一个模拟计算机的代码:

#include<stdio.h>
int add(int a, int b) {return a + b;
}
int sub(int a, int b) {return a - b;
}
int mul(int a, int b) {return a * b;
}
int div(int a, int b) {return a / b;
}int main() {int input = 0;int a, b;do {printf("___________________________\n");printf("______1.add     2.sub______\n");printf("______3.mul     4.div______\n");printf("______0.ret          ______\n");scanf("%d", &input);switch (input) {case 1:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", add(a, b));break;case 2:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", sub(a, b));break;case 3:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", mul(a, b));break;case 4:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", div(a, b));break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

这段代码中我们可以看到,case中的代码除了的调用的函数不同,其他成分总是反复出现,显得特别臃肿。这个时候我们就要使用回调函数了,再看以下改造后的代码:

#include<stdio.h>
int add(int a, int b) {return a + b;
}
int sub(int a, int b) {return a - b;
}
int mul(int a, int b) {return a * b;
}
int div(int a, int b) {return a / b;
}int cal(int(*pf)(int, int)) {int a, b;printf("输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", pf(a,b));
}int main() {int input = 0;int a, b;do {printf("___________________________\n");printf("______1.add     2.sub______\n");printf("______3.mul     4.div______\n");printf("______0.ret          ______\n");scanf("%d", &input);switch (input) {case 1:cal(add);break;case 2:cal(sub);break;case 3:cal(mul);break;case 4:cal(div);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

这段代码看起来是不是让人眼前一亮呢?将每个case中冗余的部分汇总到一个函数中,再通过函数指针调用所需要的函数。这就是回调函数的作用之一。

2. qsort函数

qsort函数是一个C标准库中的一个通用排序函数,用于对数组进行快速排序。

qsort函数的原型定义在<stdlib.h>头文件中。

下面是qsort函数调用的形式:

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

函数参数解析:

  • void *base:指向要排序数组首元素的指针。
  • size_t nmemb:数组中元素个数。
  • size_t size:数组中元素的类型大小。
  • int (\*cmp)(const void*,const void*):函数指针,指向比较两个元素的函数。(第一个元素小于第二个元素,返回负整数;两个元素相等,返回零;第一个元素大于第二个元素,返回正整数)。

2.1 qsort的使用

排序整形数据

#include<stdio.h>
#include<stdlib.h>
//要使用qsort函数需先实现一个比较函数
int int_cmp(const void* p1, const void* p2) {return (*(int*)p1 - *(int*)p2);
}int main() {int i = 0;int arr[10] = { 9,2,1,6,5,4,7,8,0,3 };qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), *int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {printf("%d\t", arr[i]);}return 0;
}

排序结构数据

#include<stdio.h>
#include<stdlib.h>
struct stu {char name[20];//名字int age;//年龄
};//比较名字
int cmp_name(const void* p1, const void* p2) {return strcmp(((struct stu*)p1)->name,((struct stu*)p2)->name);//strcmp 是一个库函数,专门用来比较两个字符串大小
}
//比较年龄
int cmp_age(const void* p1, const void* p2) {return ((struct stu*)p1)->age - ((struct stu*)p2)->age;
}//排序名字
void test1() {struct stu s[] = { {"wu",22},{"liu",20}, {"qi",18} };qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), *cmp_name);
}
//排序年龄
void test2() {struct stu s[] = { {"wu",22},{"liu",20}, {"qi",18} };qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), *cmp_age);
}int main() {test1();test2();return 0;
}

2.2 qsort的模拟实现

使用回调函数,用冒泡排序的方式模拟实现qsort

#include<stdio.h>
#include<stdlib.h>
//比较函数
int int_cmp(const void* p1, const void* p2) {//使用const修饰指针,增强代码的可维护性。return *(int*)p1 - *(int*)p2;
}
//转换函数 - 实现排序时的元素调换
void _swap(void* p1, void* p2, int size) {int i = 0;for (i = 0; i < size; i++) {char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}
//使用回调函数,实现排序功能
void bubble(void* base, int count, int size, int(*cmp)(void*, void*)) {int i, j;for (i = 0; i < count - 1; i++) {for (j = 0; j < count - 1 - i; j++) {if ((cmp((char*)base + j * size, (char*)base + (j + 1) * size)) > 0) {_swap((char*)base+j*size,(char*)base+(j+1)*size,size);}}}
}int main() {int arr[10] = { 66,23,22,1,3,5,7,9,10,2 };bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), *int_cmp);int i;for (i = 0; i < 10; i++) {printf("%d\t", arr[i]);}return 0;
}

http://www.ppmy.cn/embedded/120108.html

相关文章

VMware ESXi 8.0U3 HPE (慧与) 定制版更新 OEM BIOS 2.7 支持 Windows Server 2025

VMware ESXi 8.0U3 HPE (慧与) 定制版更新 OEM BIOS 2.7 支持 Windows Server 2025 VMware ESXi 8.0U3 macOS Unlocker & OEM BIOS HPE (慧与) 定制版 ESXi 8.0U3 标准版&#xff0c;Dell (戴尔)、HPE (慧与)、Lenovo (联想)、Inspur (浪潮)、Cisco (思科)、Hitachi (日立…

目前最好用的爬虫软件是那个?

作为一名数据工程师&#xff0c;三天两头要采集数据&#xff0c;用过十几种爬虫软件&#xff0c;也用过Python爬虫库&#xff0c;还是建议新手使用现成的软件比较方便。 这里推荐3款不错的自动化爬虫工具&#xff0c;八爪鱼、亮数据、Web Scraper 1. 八爪鱼爬虫 八爪鱼爬虫是一…

【docker】debian中配置docker(2024年9月)

首先Follow了一下菜鸟教程&#xff0c;然后遇到了curl的问题。 curl存在的问题 参见这篇文章。其中用到了vim进行编辑&#xff0c;笔者的环境是windows10putty&#xff0c;vim的粘贴操作参考这篇文章。 修改之后的curl没有问题了&#xff0c;成功把脚本下载下来了。 但是在…

【Python】Copier:高效的项目模板化工具

Copier 是一个开源的 Python 工具&#xff0c;用于基于项目模板快速生成新项目。它通过灵活的模板化系统&#xff0c;使开发者可以快速创建、维护和更新项目模板&#xff0c;从而自动化项目的初始化流程。无论是简单的文件复制&#xff0c;还是复杂的项目结构配置&#xff0c;C…

灵当CRM index.php接口SQL注入漏洞复现 [附POC]

文章目录 灵当CRM index.php接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 灵当CRM index.php接口SQL注入漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技…

Linux:磁盘管理

一、静态分区管理 静态的分区方法不可以动态的增加或减少分区的容量。 1、磁盘分区-fdisk 该命令是用于查看磁盘分区情况&#xff0c;和分区管理的命令 命令格式&#xff1a;fdisk [选项] 设备文件名常用命令&#xff1a; -h&#xff1a;查看分区信息 fdisk系统常用命令&…

Ubuntu上安装Git:简单步骤指南

Git是目前世界上最流行的版本控制系统&#xff0c;广泛用于软件开发中。无论你是开发者还是版本控制的新手&#xff0c;Git都是你不可或缺的工具。本文将为你介绍如何在Ubuntu操作系统上安装Git。 什么是Git&#xff1f; Git是一个开源的分布式版本控制系统&#xff0c;由Lin…

Linux编译部署PHP环境

1.准备工作 安装前我们需要设置防护墙&#xff0c;开放端口&#xff0c;更新yum源 # 1.防火墙 systemctl status firewalld 看到active(running)就意味着防火墙打开了 systemctl stop firewalld 看到inactive(dead)就意味着防火墙关闭了 systemctl start fire…