指针还是学不会?跟着小代老师学,进入深入理解指针(4)

指针还是学不会?跟着小代老师学,进入深入理解指针(4)

  • 1回调函数
  • 2qsort使用举例
    • 2.1使用qsort函数排序整行数据
    • 2.2使用qsort排序结构体数据
  • 3qsort函数的模拟实现

1回调函数

回调函数就是一个通过函数指针调用的函数
如果你把函数的指针(地址)作为一个参数传递给另外一个函数,当这个指针被用来调用其所指向的函数,被调用的函数就被称为回调函数。回调函数不是有函数的实现方直接调用的,而是在特定的事件或者条件发生时候由另一方调用,用来对该事件或者条件进行相应。
深入理解指针(3)讲中我们写的计算机的实现的代码中,红⾊框中的代码是重复出现的,其中虽然执⾏计算的逻辑
是区别的,但是输⼊输出操作是冗余的,有没有办法,简化⼀些呢?
因为红⾊框中的代码,只有调⽤函数的逻辑是有差异的,我们可以把调⽤的函数的地址以参数的形式
传递过去,使⽤函数指针接收,函数指针指向什么函数就调⽤什么函数,这⾥其实使⽤的就是回调函
数的功能。

未使用回调函数前:
#include<stdio.h>
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}int mul(int x, int y)
{
	return x * y;
}int div(int x, int y)
{
	return x / y;
}
void meun()
{
	printf("********************\n");
	printf("***1.add***2.sub****\n");
	printf("***3.mul***4.div****\n");
	printf("***   0.exit    ****\n");
	printf("********************\n");
}
int main()
{
	int x = 0;
	int y = 0;
	int input = 0;
	int ret = 0;
	do
	{
		meun();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入两个数:");
			scanf("%d %d",& x,& y);
			ret=add(x, y);
			printf("%d", ret);
			break;
		case 2:
			printf("请输入两个数:");
			scanf("%d %d", &x,& y);
			 ret = sub(x, y);
			printf("%d", ret);
			break;
		case 3:
			printf("请输入两个数:");
			scanf("%d %d", &x,& y);
		    ret = mul(x, y);
			printf("%d", ret);
			break;
		case 4:
			printf("请输入两个数:");
			scanf("%d %d",& x,& y);
			ret = div(x, y);
			printf("%d", ret);
			break;
		case 0:printf("退出计算器"); break;
		default: printf("输入错误,请重新输入");break;
		}
	} while (input);
}
使用回调后
#include<stdio.h>
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}int mul(int x, int y)
{
	return x * y;
}int div(int x, int y)
{
	return x / y;
}
void cual (int(*pf)(int, int))
{
	int x = 0;
	int y = 0;
	printf("请输入两个数:");
	scanf("%d %d", &x, &y);
	int ret = pf(x, y);
	printf("%d", ret);
}
void meun()
{
	printf("********************\n");
	printf("***1.add***2.sub****\n");
	printf("***3.mul***4.div****\n");
	printf("***   0.exit    ****\n");
	printf("********************\n");
}
int main()
{
	int input = 0;
	do
	{
		meun();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			cual(add);
			break;
		case 2:
			cual(sub);
			break;
		case 3:
			cual(mul);
			break;
		case 4:
			cual(div);
			break;
		case 0:printf("退出计算器"); break;
		default: printf("输入错误,请重新输入");break;
		}
	} while (input);

2qsort使用举例

让我们先了解下qsort在这里插入图片描述
在这里插入图片描述

2.1使用qsort函数排序整行数据


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

这边需要注意几个点,首先是qsort四个参数,最后一个参数是函数指针,指针也是地址,函数名本身就是一种地址。然后qsort默认是升序排序。

2.2使用qsort排序结构体数据

#include<stdio.h>
struct stu
{
	char name[20];
	int age;
};

int cmp(const void* p1, const void*p2)
{
	return ((struct stu*)p1)->age - ((struct stu*)p2)->age;
}

int main()
{
	
	struct stu arr[3] = { {"wang",192},{"zhang",16},{"li",18} };
	int num = sizeof(arr) / sizeof(arr[0]);
	
	qsort(arr, num, sizeof(arr[0]), cmp);
	for (int i = 0; i <3 ; i++)
	{
		printf("%s,%d", arr[i].name,arr[i].age);
	}
	return 0;
}

这里总结下我出现的程序问题:
1.当我把结构体放在mian函数当中当作局部变量,编译会出现错误,当把他变为全局变量错误消失
在这里插入图片描述
在这里插入图片描述
2.我们对比下面两张部分代码
在这里插入图片描述
在这里插入图片描述
我们发现结构体强转时候需要把强转和指针变量再用括号包装一下,给的解释是结构体变量是临时的所以要再用括号包装一下啊,否则用不了。
而向int就可以直接强转。
3.还可以这样访问结构体成员
在这里插入图片描述

3qsort函数的模拟实现

使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)。
注意:这⾥第⼀次使⽤ void* 的指针,讲解 void* 的作⽤。

#include<stdio.h>

int comp(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}
void swap( int with,char* p1, char* p2)
{
	for (int i = 0; i < with; i++)
	{
		char temp = *p1;
		*p1 = *p2;
		*p2 = temp;
		*p1++;
		*p2++;
	}
}
void my_qsort_bubble_sort(void* base, int num, int with, int (*p_com)(const void*p1, const void*p2))
{
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (p_com( (char*) base + j * with , (char*)base + (j + 1) * with)>0)
		    {
				swap(with,(char*)base + j * with, (char*)base + (j + 1) * with);
		    }
		}
	}
}
int main()
{
	int arr[10] = { 2,3,45,21,4,5,9,0,3,20 };
	int num = sizeof(arr) / sizeof(arr[0]);
	int with = sizeof(arr[0]);
	my_qsort_bubble_sort(arr, num, with, comp);
	for (int i = 0; i < num; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

这里总结一下:当时敲完代码运行时候发现没有交换,结果检查发现是swap函数有了问题忘记给p1++,p2++了,做题关键思想是用回调函数,然后数值之间哪些要用指针来实现。

在这里插入图片描述在这里插入图片描述
这个是用模拟qsort来实现结构体排序。

#include<stdio.h>
struct stu
	{
		char name[20];
		int age;
	};
int comp(const void* p1, const void* p2)
{
	return ((struct stu*)p1)->age - ((struct stu*)p2)->age;
}
void swap( int with,char* p1, char* p2)
{
	for (int i = 0; i < with; i++)
	{
		char temp = *p1;
		*p1 = *p2;
		*p2 = temp;
		*p1++;
		*p2++;
	}
}
void my_qsort_bubble_sort(void* base, int num, int with, int (*p_com)(const void*p1, const void*p2))
{
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (p_com( (char*) base + j * with , (char*)base + (j + 1) * with)>0)
		    {
				swap(with,(char*)base + j * with, (char*)base + (j + 1) * with);
		    }
		}
	}
}
int main()
{
	struct stu  arr[] = { {"man",20},{"fyy",30},{"xyy",10} };
	int num = sizeof(arr) / sizeof(arr[0]);
	int with = sizeof(arr[0]);
	my_qsort_bubble_sort(arr, num, with, comp);
	for (int i = 0; i < num; i++)
	{
		printf("%s %d ", arr[i].name,arr[i].age);
		printf("\n");
	}
	return 0;
}

总结一下:
当时写好结构体时候,怎么找结构体成员都找不到,结果发现自己强转错误了。这里要注意下,我们强转时候一定要明白我们比较的类型是什么。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【窗口函数的详细使用】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;今天主要和大家分享一下可MySQL中的窗口函数的概念&#xff0c;语法以及常用的窗口函数,希望对大家有所帮助。感谢大家关注点赞。 &#x1f49e;&#x1f49e;前路漫漫&#xff0c;希望大…

【TS】进阶

一、类型别名 类型别名用来给一个类型起个新名字。 type s string; let str: s "123";type NameResolver () > string;: // 定义了一个类型别名NameResolver&#xff0c;它是一个函数类型。这个函数没有参数&#xff0c;返回值类型为string。这意味着任何被…

【轻量化】YOLOv10: Real-Time End-to-End Object Detection

论文题目&#xff1a;YOLOv10: Real-Time End-to-End Object Detection 研究单位&#xff1a;清华大学 论文链接&#xff1a;http://arxiv.org/abs/2405.14458 代码链接&#xff1a;https://github.com/THU-MIG/yolov10 推荐测试博客&#xff1a;YOLOv10最全使用教程&#xff0…

一个月速刷leetcodeHOT100 day14 彻底搞懂二分搜索 以及相关题目

二分查找算法&#xff08;Binary Search Algorithm&#xff09; 是一种用于在已排序数组中查找特定元素的高效算法。它的基本思想是每次将待查找的区间分成两部分&#xff0c;并确定目标元素位于哪一部分中&#xff0c;然后只在目标区间中继续查找&#xff0c;直到找到目标元素…

水经微图IOS版5.3.0发布

随时随地&#xff0c;微图一下&#xff01; 水经微图&#xff08;以下简称“微图”&#xff09;IOS版&#xff0c;新版已上线。 当前版本 当前版本号为&#xff1a;5.3.0-beta 如果你发现该版本中存在问题&#xff0c;请及时反馈给我们修订。 关于我们产品的版本控制&…

国产工业级实时数据库

项目功能描述 Mars数据库的核心功能在于其能够高效地处理来自工业现场的大量传感器数据。它通过简化的可视化配置&#xff0c;允许用户轻松接入各种传感器&#xff0c;并进行数据记录和逻辑处理。Mars数据库在单机模式下支持高达120万个传感器信号的接入&#xff0c;而其分布式…

【文末附gpt升级秘笈】埃隆·马斯克芯片调配策略对特斯拉股价的影响分析

埃隆马斯克芯片调配策略对特斯拉股价的影响分析 一、引言 在现代商业环境中&#xff0c;企业间的资源调配与策略布局往往对其股价产生深远影响。据外媒CNBC报道&#xff0c;埃隆马斯克在芯片资源分配上的决策引起了业界的广泛关注。他秘密要求英伟达将原本预留给特斯拉的高端…

TMS320F280049学习3:烧录

TMS320F280049学习3&#xff1a;烧录 文章目录 TMS320F280049学习3&#xff1a;烧录前言一、烧录RAM二、烧录FLASH总结 前言 DSP的烧录分为两种&#xff0c;一种是将程序烧录到RAM中&#xff0c;一种是烧录到FLASH中&#xff0c;烧录ARM中的程序&#xff0c;只要未掉电&#x…

Vue3项目准备:utils工具插件文件夹中封装request.js配置axios请求基地址及超时时间、请求拦截器、响应拦截器

token介绍 概念&#xff1a;访问权限的令牌&#xff0c;本质上是一串字符串 创建&#xff1a;正确登录后&#xff0c;由后端签发并返回 作用&#xff1a;判断是否有登录状态等&#xff0c;控制访问权限 注意&#xff1a;前端只能判断token有无&#xff0c;而后端才能判断tok…

Camtasia Studio2024永久免费版及最新版本功能讲解

在当前数字化时代&#xff0c;视频内容的制作与编辑变得愈发重要。无论是企业宣传、在线教育还是个人Vlog制作&#xff0c;一款功能强大且易于上手的视频编辑软件成为了刚需。Camtasia Studio作为市场上备受欢迎的视频编辑与屏幕录像工具&#xff0c;凭借其强大的功能与用户友好…

在线标注流程

文章目录 在线标注流程标注方法 在线标注流程 登录地址&#xff1a;http://7a27c5e078f644a2a9b734603913c65e.login.bce.baidu.com 出现页面&#xff1a; 登录名&#xff1a; 三个中任意一个 密码&#xff1a;ZNSJ123a 登录之后叉掉。再打开这个网站&#xff1a;https://…

2938. 区分黑球与白球

题目 桌子上有 n 个球&#xff0c;每个球的颜色不是黑色&#xff0c;就是白色。 给你一个长度为 n 、下标从 0 开始的二进制字符串 s&#xff0c;其中 1 和 0 分别代表黑色和白色的球。 在每一步中&#xff0c;你可以选择两个相邻的球并交换它们。 返回「将所有黑色球都移到…

Leetcode:电话号码的字母组合

题目链接&#xff1a;17. 电话号码的字母组合 - 力扣&#xff08;LeetCode&#xff09; 普通版本&#xff08;回溯&#xff09; class Solution { public:string tmp;//临时存放尾插内容vector<string> res;//将尾插好的字符串成组尾插给resvector<string> board{…

⌈ 传知代码 ⌋ AI驱动食物图像识别

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

【数据结构】平衡二叉树(AVL树)

目录 前言 一、AVL树概念 二、AVL树节点定义 三、AVL树插入 1. 按照二叉搜索树的方式插入新节点 2. 维护节点的平衡因子与调整树的结构 a. 新节点插入较高左子树的左侧---左左&#xff1a;右单旋 b. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋 c. 新节点插入…

前端面试项目细节重难点(已工作|做分享)想(八)

面试官&#xff1a;请你讲讲你在该项目中遇到的印象深刻的问题是什么&#xff1f; 答&#xff1a;我的回答&#xff1a;该项目的实现过程中我确实遇到了问题&#xff1a;【我会给大家整理回答思路和角度&#xff0c;那那么遇到这样的问题也可借鉴这种思路进行阐述】 第一层面…

RocketMQ教程(五):RocketMQ的工作原理2

工作原理 RocketMQ 是一个高性能、高吞吐量的分布式消息和流计算平台,它基于发布-订阅模式工作。其核心设计理念是确保消息传递的高效性、稳定性和可扩展性。RocketMQ 的工作原理主要可以分为以下几个部分: 1. 消息流程 消息发布: Producer 首先向 NameServer 查询目标 Top…

二重,三重积分和曲面,曲线积分的关系和区别

这是我在学习完曲面曲线积分概念后容易和二重三重积分混淆而大概总结和区分了一下&#xff0c;如果有错误请大佬指出&#xff0c;多谢&#xff01;&#xff01;&#xff01;

shell(一)

shell 既是脚本语言又是应用程序 查看自己linux系统的默认解析&#xff1a;echo $SHELL 创建第一个shell 文件 touch 01.sh编辑 vi 01.sh01.sh 文件内容 #!/bin/bash echo felicia保存 按Esc 然后输入:wq 定义以开头&#xff1a;#!/bin/bash #!用来声明脚本由什么shell解释…

无线麦克风什么牌子的音质效果好?一文揭秘领夹麦克风哪个品牌好

​近年来&#xff0c;无线领夹麦克风在各个领域都大放异彩&#xff0c;无论是直播、采访还是上课&#xff0c;都能看到它的身影。这款小小的无线麦克风&#xff0c;蕴含着巨大的能量&#xff0c;为媒体人的创作提供了强大的支持。对于想要更新设备的媒体人来说&#xff0c;现在…