首页 > 其他分享 >深入理解指针(4)

深入理解指针(4)

时间:2024-09-15 16:51:52浏览次数:10  
标签:return int void ret 理解 深入 printf sizeof 指针

1. 回调函数是什么?

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 x, y;
	int input = 1;
	int ret = 0;
	do
	{
		printf("******************");
		printf(" 1:add ");
		printf(" 3:mul ");
		printf("******************");
		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;
}
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);
}
int main()
{
	int input = 1;
	do
	{
		printf("******************");
		printf(" 1:add ");
		printf(" 3:mul ");
		printf("******************");
		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. qsort使⽤举例 2.1  qsort函数的概念

2.1.1  函数原型

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

2.1.2  参数
        base:指向要排序的第一个对象的指针,并转换成(void*)
        num:元素的个数,size_t是无符号整型类型
        size:每个元素的大小(占几个字节),size_t是无符号整数类型                                                                compar:比较规则(可自定义)
2.1.3  返回值
        无返回值

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

#include <stdio.h>
#include<stdlib.h>
//qosrt函数的使⽤者得实现⼀个⽐较函数
int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
int main()
{
	int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	int i = 0;

	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}
2.3  使⽤qsort排序结构数据
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu //学⽣
{
	char name[20];//名字
	int age;//年龄
};
//假设按照年龄来⽐较
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//strcmp - 是库函数,是专⻔⽤来⽐较两个字符串的⼤⼩的
//假设按照名字来⽐较
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照年龄来排序
void test2()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
//按照名字来排序
void test3()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}

int main()
{
	test2();
	test3();
	return 0;
}

3. qsort函数的模拟实现

3. 使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)。 注意:用(void*)接收是因为我们也不清楚会传什么类型的值过来;用(void*)接收,之后强制类型转换成(char*)(因为这是最小的单位)这样就将数据分割成1bit大小的数据块了,再一个个进行交换,就完成了我们想要的换算了。
#include<stdio.h>
int int_cmp(const void* p1, const void* p2)
{
	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 = 0;
	int j = 0;
	for (i = 0; i < count - 1; i++)
	{
		for (j = 0; j < count - i - 1; 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[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	int i = 0;
	bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

标签:return,int,void,ret,理解,深入,printf,sizeof,指针
From: https://blog.csdn.net/Ripple12312/article/details/142284412

相关文章

  • 深入理解 Write-Ahead Logging (WAL) 及其应用
    在讨论数据库原理的时候,我们经常会听到一种技术-Write-AheadLogging(WAL),它保证了数据的持久性和一致性。WAL的基本思想非常简单,但它的应用范围非常广泛,从数据库到分布式系统,再到各种现代应用的开发中,都能看到它的影子。本文将深入剖析WAL的基本机制,并探讨其在不同应用场......
  • Nacos与Eureka的区别:深入解析微服务中的服务注册与发现
    在微服务架构中,服务注册与发现是确保各个服务之间高效通信与协调的重要机制。随着云原生应用的快速发展,服务治理的需求也在不断增长。在这一背景下,Nacos和Eureka作为两种主流的服务注册与发现工具,各具特色和优势。本文将深入分析Nacos与Eureka之间的区别,帮助开发者选择最适合自......
  • SQL查询技巧:深入解析学生选课系统数据库
            在大学的学生选课系统中,数据库的管理和查询是日常操作中的重要部分。本文通过一系列具体的SQL查询示例,深入解析如何高效地从数据库中获取所需信息,包括学生选课情况、成绩分析、教师课程管理等。系统数据库结构首先,我们有一个包含以下表的数据库:course -存......
  • 如何解决MySQL + 字段锁表问题|如何优化MySQL DDL操作以减少锁表时间|深入理解MySQL的On
    在日常的数据库操作中,MySQL数据库的表结构修改是不可避免的操作之一。例如,添加新字段是常见的需求之一。然而,在生产环境中对表结构进行更改时,特别是在大数据量的表中,容易出现锁表问题,导致业务系统的性能下降甚至完全卡顿。MySQL在进行表结构修改时会加表级锁,从而影响到其他的查询和......
  • 【二叉树的最大深度】带你理解递归奥妙!
    ......
  • 深入理解 C 语言中的结构体 —— 原理与实践
    引言在C语言中,结构体是一种非常强大的数据类型,用于组织不同类型的数据成员。通过结构体,我们可以创建复杂的数据结构,用于表示现实生活中的对象。本文将详细介绍C语言中结构体的基本概念、语法、使用方法以及一些高级主题,包括底层原理和具体应用。结构体基础知识定义......
  • 深入理解FastAPI中的root_path:提升API部署灵活性的关键配置
    在Web开发领域,FastAPI因其高性能、易于使用和类型提示功能而备受开发者喜爱。然而,当涉及到在生产环境中部署FastAPI应用程序时,我们常常需要面对一些挑战,比如如何正确处理代理服务器添加的路径前缀。这时,root_path配置就变得至关重要。本文将深入探讨FastAPI中的root_path,并......
  • 【时时三省】(C语言基础)指针进阶 例题7
    山不在高,有仙则名。水不在深,有龙则灵。              ----CSDN时时三省二维数组  第一个a因为它有12个元素每个元素占4个字节所以就打印48第二个a[0][0]表示是第一行第一个元素 所以它算的就是第一行第一个元素所占的大小所以就打印4第......
  • 【鸿蒙】HarmonyOS NEXT星河入门到实战4-ArkTS界面布局深入
    目录一、布局元素组成1.1内边距-padding1.2外边距margin1.3实战案例-QQ音乐-登录1.4边框border 二、设置组件圆角2.1基本圆角设置2.2特殊形状的圆角设置三、背景属性3.1背景图片-backgroundImage3.2背景图片位置-backgroundImagePosition3.3背景定位-......
  • 基于Python+数据可视化大屏+大数据爬虫的短视频内容理解与可视化推荐平台设计和实现(
    博主介绍:✌全网粉丝50W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、P......