【C语言指针五】转移表、回调函数、qsort、qsort函数的模拟实现

🎬 个人主页秦苒&
专栏传送门 :《C语言

🍀指尖燃热血,代码铸锋芒;以信仰破局,向顶峰生长


🍀秦苒&的简介:


前言:在【C语言指针四】数组指针变量、二维数组传参本质、函数指针变量、函数指针数组中我们学习了部分指针知识,接下来我们继续学习转移表、回调函数、qsort、qsort函数的模拟实现


文章目录


提示:以下是本篇文章正文内容,下面案例可供参考

1.转移表

函数指针数组的用途:转移表

(有需要回顾函数指针数组的小伙伴可以点击前言部分的链接快速浏览一遍)

计算器相信大家都补陌生,计算器背后是如何运行的呢?接下来我们一起学习了解!这里我们用计算器理解如何使用转移表:

如果不使用转移表该怎样完成呢?看这里:

c 复制代码
#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("*************************\n");
		printf(" 1:add 2:sub \n");
		printf(" 3:mul 4:div \n");
		printf(" 0:exit \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;
}

我们发现switch中有大量的重复函数,显得冗余,但是如果我们使用函数指针数组来实现的话呢,就大大提高了运行效率(这只是4种运算,如果是十多种呢?)

这里我们只需要把主调函数改一下,像这样:

还有一个不用函数指针数组就可以实现简化代码的方法(回调函数),坐下来听我慢慢说,我就觉得还挺神奇的哈哈

2.回调函数

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

如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的⼀方调用的,用于对该事件或条件进行响应。

就以本节第一个代码块为例吧,这些是修改部分,然后再加一个calc函数就完成啦

这个是使用回到函数改造后的完整代码:

c 复制代码
#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 x;
	int y;
	int ret = 0;
	printf("输入操作数:");
	scanf("%d %d", & x,& y);
	ret = pf(x,y);
	printf("ret = %d\n", ret);

}

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(" 0:exit \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;
}

就是这个思路:

3.qsort使用举例

3.1使用qsort函数排序整型数据

完整代码我给大家放到下面,接下来我们一一讲解!

c 复制代码
#include <stdio.h>
#include <stdlib.h>//qsort的头文件
//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;
}

我们看qsort这个函数在cpluspls网站中有详细介绍,其中这个大家要重点关注:

而这行代码

c 复制代码
return (*(int*)p1 - *(int*)p2);

也可以这么理解

3.2 使用qsort排序结构数据

我们看strcmp这个函数在strcmp网站中有详细介绍

strcmp是按照对应着字符串中的字符的ASCII码值比较的

c 复制代码
#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;
}

4.qsort函数的模拟实现

使用回调函数,模拟实现qsort(采用冒泡的方式)。

代码如下:

c 复制代码
#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;
}

总结

qsort的模拟实现看似复杂,拆解开来其实就是对指针和回调函数的灵活运用。编程的路上没有捷径,多敲代码、多思考底层逻辑,才能真正吃透知识点。希望这篇文章能给你带来一点启发,我们下次再见~

结尾

勇敢的寻宝者啊,这次旅途你挖掘到多少宝藏呢,苒苒很期待下次与您相遇!

结语:希望对寻找C语言相关内容的寻宝者有所帮助,不要忘记给博主"一键三连"哦!你的每一次鼓励都为我提供 了前行的动力!

小喵很期待与你再次寻宝奥 ᰔᩚ/•᷅•᷄\୭

相关推荐
superman超哥42 分钟前
Rust 异步错误处理最佳实践
开发语言·rust·编程语言·rust异步错误处理·rust最佳实践
脏脏a44 分钟前
C++ STL list 模拟实现:从底层链表到容器封装
开发语言·c++·stl·双链表
唐宋元明清21888 小时前
.NET 磁盘管理-技术方案选型
windows·c#·存储
故事不长丨8 小时前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
哈库纳玛塔塔8 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
你怎么知道我是队长9 小时前
C语言---typedef
c语言·c++·算法
phltxy9 小时前
从零入门JavaScript:基础语法全解析
开发语言·javascript
带土19 小时前
5. enum(枚举)关键字在C/C++中的作用
c语言·c++
天“码”行空10 小时前
java面向对象的三大特性之一多态
java·开发语言·jvm
odoo中国11 小时前
Odoo 19 模块结构概述
开发语言·python·module·odoo·核心组件·py文件按