【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语言相关内容的寻宝者有所帮助,不要忘记给博主"一键三连"哦!你的每一次鼓励都为我提供 了前行的动力!

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

相关推荐
helloworddm2 小时前
GetDirectoryReference 远程代理创建机制详解
服务器·架构·c#
棒棒的唐2 小时前
Avue2图片上传使用object对象模式时,axios的请求模式用post还是get?
开发语言·前端·javascript·avue
秋邱2 小时前
Java 运算符与流程控制:全类型运算符用法 + 分支 / 循环语句实战
java·开发语言
旧梦吟2 小时前
脚本网页 C与汇编详解
c语言·css3·html5
万邦科技Lafite2 小时前
淘宝开放API批量上架商品操作指南(2025年最新版)
开发语言·数据库·python·开放api·电商开放平台·淘宝开放平台
缺点内向2 小时前
C#:轻松实现Excel到TXT的转换
后端·c#·.net·excel
Chase_______2 小时前
【JAVA基础指南(二)】快速掌握流程控制
java·开发语言
Slow菜鸟2 小时前
Java基础架构设计(四)| 通用响应与异常处理(单体/分布式通用增强方案)
java·开发语言·分布式
世转神风-2 小时前
qt-初步编译运行报错-When executing step “Make“-无法启动进程“make“
开发语言·qt