【C语言】10.C语言指针(4)

文章目录

  • 1.回调函数是什么?
  • 2.qsort 使⽤举例
    • 2.1 使⽤qsort函数排序整型数据
    • 2.2 使⽤qsort排序结构数据
  • 3.qsort函数的模拟实现


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;
}
/*****************************************************main函数******************************************************/
int main(){int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输入操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输入操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输入操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输入操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

使用回调函数改造后:

#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;
}/*****************************************************calc函数******************************************************/
void calc(int(*pf)(int, int)){int ret = 0;int x, y;printf("输入操作数:");scanf("%d %d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}/*****************************************************main函数******************************************************/
int main(){int input = 1;do{printf("*************************\n");printf(" 1:add  2:sub \n");printf(" 3:mul  4:div \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:calc(add);break;case 2:calc(sub);break;case 3:calc(mul);break;case 4:calc(div);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

2.qsort 使⽤举例

2.1 使⽤qsort函数排序整型数据

qsort是C语言中的一个库函数。

使用qsort函数要包含一个头文件:#include <stdlib.h>

这个函数是用来对数据进行排序的,对任意类型的数据都能进行排序

就比方下面的冒泡排序:

void bubble_sort(int arr[], int sz) {//趟数int i = 0;for (i = 0; i < sz - 1; i++) {//一趟内部的两两比较int j = 0;for (j = 0; j < sz - i - 1; j++) {if (arr[j] > arr[j + 1]) {int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}

这个程序排序整型数据是没问题的,但是能排序字符数组吗?能排序字符串吗?能排序浮点数吗?能排序结构体吗?

这个排序算法只能排序整型。

我们来看一下qsort函数的定义:

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

我们把这个代码划分一下:

void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*)//函数指针,传递函数的地址);

void* base:指向待排序数组的第一个元素的指针。

size_t num:base指向数组元素中元素的个数。

size_t size:base指向的数组元素中一个元素的大小,单位是字节。

int (*compar)(const void*,const void*):函数指针,传递函数的地址

字符串的大小比较大小不能使用>>=<<===!=

应该使用strcmp函数。

比较两个结构体呢?

也不能用>>=<<===!=比吧?

qsort函数能够实现排序,是因为它很聪明。

既然不同元素代码的比较不同,那么就把他抽离出来。谁要调用这个qsort函数进行比较,那么谁就来提供比较函数。

这也就是为什么会有个函数指针的原因。

#include <stdio.h>
#include <stdlib.h>
/*
cmp_int函数对函数的返回值有要求
p1指向的元素比p2指向的元素小的时候,返回一个小于0的数字
p1指向的元素和p2指向的元素一样的时候,返回一个等于0的数字
p1指向的元素比p2指向的元素大的时候,返回一个大于0的数字
*/
int cmp_int(const void* p1, const void* p2) {if (*(int*)p1 > *(int*)p2) {// 将指针 p1 和 p2 强制转换为指向 int 的指针,然后通过解引用获取指针指向的整数值return 1;}else if (*(int*)p1 < *(int*)p2) {return -1;}else {return 0;}
}
//当然上面也可以直接返回:
//return *(int*)p1 - *(int*)p2;void print_arr(int arr[], int sz) {int i = 0;for (i = 0; i < sz; i++) {printf("%d ", arr[i]);}
}void test1() {int arr[] = { 3,1,7,9,4,2,6,5,8,0 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_int);print_arr(arr, sz);
}int main() {test1();return 0;
}

打印:

0 1 2 3 4 5 6 7 8 9

2.2 使⽤qsort排序结构数据

我们先看一下打印结构体的操作:

struct Stu {char name[20];int age;
};/*结构体成员访问操作符:
. :结构体变量.成员名
->:结构体指针->成员名
*/
int main() {struct Stu s = { "zhangsan",20 };printf("%s %d\n", s.name, s.age);struct Stu* ps = &s;//struct Stu*是结构体指针类型,指针名是psprintf("%s %d\n", (*ps).name, (*ps).age);printf("%s %d\n", ps->name, ps->age);return 0;
}

打印:

zhangsan 20
zhangsan 20
zhangsan 20

下面的代码中有关于strcmp函数的使用,如果不记得的可以看之前的这篇博客:

【C语言】strcmp函数讲解

通过qsort函数,按照名字比较结构体数据大小:

#include <string.h>
#include <stdlib.h>struct Stu {char name[20];int age;
};//按照名字比较两个结构体数据
//名字是字符串,字符串比较是用strcmp函数的
int cmp_stu_by_name(const void* p1, const void* p2) {return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}//测试qsort函数来排序结构体数据
void test2() {struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}
int main() {test2();return 0;
}

通过qsort函数,按照年龄比较结构体数据大小:

#include <string.h>
#include <stdlib.h>struct Stu {char name[20];int age;
};//按照年龄比较两个结构体数据
int cmp_stu_by_age(const void* p1, const void* p2) {return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}//想逆序的话就这么写:
//return ((struct Stu*)p2)->age - ((struct Stu*)p1)->age;
//其实就是把p1和p2换个位置。void test3() {struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}int main() {test3();return 0;
}

3.qsort函数的模拟实现

刚刚我们一开始用的是冒泡排序,那么我们能不能把冒泡排序改造一下呢?改造成和qsort函数一样,可以接受任意类型的数据呢?

在这里插入图片描述

这里(char*)base+4就是加了4个字节。也就是一个数组位。因为这里是整型数组,一位4字节。

如果不是整形数组,那就是加了width个字节。

从9到8是:(char*)base+0(char*)base+4

从8到7是:(char*)base+4(char*)base+8

中间差的就是位数乘上width

(改版)冒泡排序测试整型:

#include <stdlib.h>int cmp_int(const void* p1, const void* p2) {if (*(int*)p1 > *(int*)p2) {// 将指针 p1 和 p2 强制转换为指向 int 的指针,然后通过解引用获取指针指向的整数值return 1;}else if (*(int*)p1 < *(int*)p2) {return -1;}else {return 0;}
}void print_arr(int arr[], int sz) {int i = 0;for (i = 0; i < sz; i++) {printf("%d ", arr[i]);}
}void Swap(char* buf1, char* buf2, size_t width) {int i = 0;char tmp = 0;for (i = 0; i < width; i++) {tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}void bubble_sort(void* base, size_t sz, size_t width, int (*compar)(const void* p1, const void* p2)) {//趟数int i = 0;for (i = 0; i < sz - 1; i++) {//一趟内部的两两比较int j = 0;for (j = 0; j < sz - i - 1; j++) {//比较两个元素if (compar((char*)base + j * width, (char*)base + (j + 1) * width) > 0) {//交换两个元素Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}void test4() {int arr[] = { 3,1,7,9,4,2,6,5,8,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);print_arr(arr, sz);
}int main() {test4();return 0;
}

打印:

0 1 2 3 4 5 6 7 8 9

(改版)冒泡排序测试结构体:

比较名字

struct Stu {char name[20];int age;
};//按照名字比较两个结构体数据
//名字是字符串,字符串比较是用strcmp函数的
int cmp_stu_by_name(const void* p1, const void* p2) {return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}void Swap(char* buf1, char* buf2, size_t width) {int i = 0;char tmp = 0;for (i = 0; i < width; i++) {tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}void bubble_sort(void* base, size_t sz, size_t width, int (*compar)(const void* p1, const void* p2)) {//趟数int i = 0;for (i = 0; i < sz - 1; i++) {//一趟内部的两两比较int j = 0;for (j = 0; j < sz - i - 1; j++) {//比较两个元素if (compar((char*)base + j * width, (char*)base + (j + 1) * width) > 0) {//交换两个元素Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}//测试qsort函数来排序结构体数据
void test5() {struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}int main() {test5();return 0;
}

比较年龄

struct Stu {char name[20];int age;
};//按照年龄比较两个结构体数据
int cmp_stu_by_age(const void* p1, const void* p2) {return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}//想逆序的话就这么写:
//return ((struct Stu*)p2)->age - ((struct Stu*)p1)->age;
//其实就是把p1和p2换个位置。void Swap(char* buf1, char* buf2, size_t width) {int i = 0;char tmp = 0;for (i = 0; i < width; i++) {tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}void bubble_sort(void* base, size_t sz, size_t width, int (*compar)(const void* p1, const void* p2)) {//趟数int i = 0;for (i = 0; i < sz - 1; i++) {//一趟内部的两两比较int j = 0;for (j = 0; j < sz - i - 1; j++) {//比较两个元素if (compar((char*)base + j * width, (char*)base + (j + 1) * width) > 0) {//交换两个元素Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}void test6() {struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}int main() {test6();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/342221.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka-消费者-指定offset消费(SpringBoot整合Kafka)

文章目录 1、指定offset消费1.1、创建消费者监听器‘1.2、application.yml配置1.3、使用 Java代码 创建 主题 my_topic1 并建立3个分区并给每个分区建立3个副本1.4、创建生产者发送消息1.4.1、分区0中的数据 1.5、创建SpringBoot启动类1.6、屏蔽 kafka debug 日志 logback.xml1…

服务器数据恢复—EqualLogic存储硬盘灯亮黄色的数据恢复案例

服务器数据恢复环境&#xff1a; 一台某品牌EqualLogic PS 6011型号存储&#xff0c;底层有一组由16块SAS硬盘组建的RAID5阵列&#xff0c;上层存储空间划分了4个卷&#xff0c;格式化为VMFS文件系统&#xff0c;存放虚拟机文件。 服务器故障&#xff1a; 存储设备上两块硬盘指…

基于STC89C52单片机空气PM2.5系统设计资料

#include <reg52.h>#include <intrins.h>#define uint unsigned int#define uchar unsigned char //宏定义sbit RSP1^6;//液晶接口sbit ENP1^7;sbit LED P2^0;//粉尘传感器控制接口sbit ADCS P3^7;//AD0832接口sbit ADCLK P3^5;sbit ADDI P3^6;sbit ADDO P3^6;…

【大模型】基于Hugging Face调用及微调大模型(1)

文章目录 一、前言二、Transformer三、Hugging Face3.1 Hugging Face Dataset3. 2 Hugging Face Tokenizer3.3 Hugging Face Transformer3.4 Hugging Face Accelerate 四、基于Hugging Face调用模型4.1 调用示例4.2 调用流程概述4.2.1 Tokenizer4.2.2 模型的加载4.2.3 模型基本…

# RocketMQ 实战:模拟电商网站场景综合案例(二)

RocketMQ 实战&#xff1a;模拟电商网站场景综合案例&#xff08;二&#xff09; 一、SpringBoot 整合 Dubbo &#xff1a;dubbo 概述 1、dubbo 概述 Dubbo &#xff1a;是阿里巴巴公司开源的一款高性能、轻量级的 Java RPC 框架&#xff0c;它提供了三大核心能力&#xff1a…

【WP】猿人学15_备周则意怠_常见则不疑

https://match.yuanrenxue.cn/match/15 抓包分析 抓包分析有一个m参数&#xff0c;三个数字组成 追栈/扣代码 根据启动器顺序追栈&#xff0c;一般优先跳过 jQuery 直接能找到加密函数 每次获取的数字都不一样 window.m function() { t1 parseInt(Date.parse(new Date(…

【全开源】Java共享茶室棋牌室无人系统支持微信小程序+微信公众号

打造智能化休闲新体验 一、引言&#xff1a;智能化休闲时代的来临 随着科技的飞速发展&#xff0c;智能化、无人化服务逐渐渗透到我们生活的各个领域。在休闲娱乐行业&#xff0c;共享茶室棋牌室无人系统源码的出现&#xff0c;不仅革新了传统的休闲方式&#xff0c;更为消费…

Marin说PCB之如何在主板上补偿链路中的走线的等长误差?

一场雨把我困在这里&#xff0c;你冷漠地看我没有穿雨衣淋成落汤鸡。今天刚刚出门时候看天气预报没有雨&#xff0c;于是我就没有带雨衣骑电动车去公司了&#xff0c;谁知道回来的路上被淋成狗了。天气预报就像是女人的脾气那样&#xff0c;不能完全相信的。 好了&#xff0c;我…

什么是视频号招商团长?如何加入成为视频号招商团长

视频号招商团长&#xff0c;是通过微信视频号平台的线上和线下活动&#xff0c;撮合商家和达人进行合作&#xff0c;帮助商家、达人在视频号成长发展&#xff1b;同时还可以通过邀请内容创作者入驻微信视频号并为其提供支持&#xff1b;从而获取佣金收益的&#xff0c;而其作用…

【LeetCode算法】第100题:相同的树

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;二叉树的先序遍历。采用递归的先序遍历方法&#xff0c;首先访问根节点若不同则返回false&#xff0c;其次访问左子树和右子树。在访问左右子树时&#xff0c;需要注意…

CAN总线学习笔记-CAN帧结构

数据帧 数据帧&#xff1a;发送设备主动发送数据&#xff08;广播式&#xff09; 标准格式的11ID不够用了&#xff0c;由此产生了扩展格式 SOF&#xff1a;帧起始&#xff0c;表示后面一段波形为传输的数据位 ID&#xff1a;标识符&#xff0c;区分功能&#xff0c;同时决定优…

【qt】项目移植

项目移植 一.前言二.同名问题三.具体操作1.修改文件名2.修改类名3.修改一些不能自动改的名4.修改.ui文件5.删除原来自动生成的ui_xxx.h文件6.修改头文件 四.导入项目五.使用导入的项目六.项目建议 一.前言 终于概率论考完了,有时间了,接着上个项目,我们继续来完成我们的多窗口开…

探索 LLM 预训练的挑战,GPU 集群架构实战

万卡 GPU 集群实战&#xff1a;探索 LLM 预训练的挑战 一、背景 在过往的文章中&#xff0c;我们详细阐述了LLM预训练的数据集、清洗流程、索引格式&#xff0c;以及微调、推理和RAG技术&#xff0c;并介绍了GPU及万卡集群的构建。然而&#xff0c;LLM预训练的具体细节尚待进一…

Qt——升级系列(Level Two):Hello Qt 程序实现、项目文件解析、Qt 编程注意事项

Hello Qt 程序实现 使用“按钮”实现 纯代码方式实现&#xff1a; // Widget构造函数的实现 Widget::Widget(QWidget *parent): QWidget(parent) // 使用父类构造函数初始化QWidget&#xff0c;传入父窗口指针, ui(new Ui::Widget) // 创建Ui::Widget类的实例&#xff0c;并…

YOLOv8_obb预测流程-原理解析[旋转目标检测理论篇]

YOLOv8_obb的预测流程,主要分预处理模块、推理模块和后处理模块。这里面有很多内容是和目标检测预测流程是重合的,主要区别在于Angle分支、NMS后处理以及regularize_rboxes部分。本文也主要介绍一下这三个模块,其他模块可以结合YOLOv8预测流程-原理解析[目标检测理论篇]一起…

Ffmpeg安装和简单使用

Ffmpeg安装 下载并解压 进入官网 (https://ffmpeg.org/download.html)&#xff0c;选择 Window 然后再打开的页面中下滑找到 release builds&#xff0c;点击 zip 文件下载 环境变量配置 下载好之后解压&#xff0c;找到 bin 文件夹&#xff0c;里面有3个 .exe 文件 然后复制…

Zookeeper复习

一、入门 1、概念 zookeeper文件系统通知机制 2.特点 1&#xff09;、一个领导者&#xff0c;多个跟随者组成的集群。 2&#xff09;、集群中只要有半数以上存活机制&#xff0c;zookeeper集群能正产服务。zk适合安装奇数台。 3&#xff09;、全局数据一致&#xff1a;每…

量化投资分析平台 迅投 QMT(四)获取标的期权的代码

量化投资分析平台 迅投 QMT [迅投 QMT](https://www.xuntou.net/?user_code7NYs7O)我目前在使用有了底层标的如何获取期权的交易代码呢&#xff1f;上代码历史帖子 迅投 QMT 我目前在使用 两个月前&#xff08;2024年4月&#xff09;迅投和CQF有一个互动的活动&#xff0c;进…

5G+北斗智能手持终端在哪些行业中发挥作用

在当今科技融合发展的浪潮中&#xff0c;5G北斗智能手持终端正逐步成为驱动各行各业智能化升级的关键力量。这一融合创新技术不仅重塑了传统的通信与定位方式&#xff0c;而且在多个核心领域展现了其变革性的应用价值。 5G北斗智能手持终端因其独特的技术组合&#xff0c;在多个…