C语言——回调函数的典型示例(分析详解)

🏡润下个人主页
🔥个人专栏 : 《C语言基础》

🏔️山高万仞,只登一步!



文章目录

一.什么是回调函数

回调函数是通过函数指针调用的函数

把函数的地址(指针)作为一个参数传递给另一个函数,当这个指针被用来调用所指的函数的时候,这个被调用的函数就是回调函数

回调函数不是在由该函数的实现方调用的,而是在特定的事件条件下由另一方调用的,用于对该事件或条件进行响应。

实例

c 复制代码
#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
void test(int(*pf)(int ,int))
{
	int r = pf(10, 20);
	printf("%d\n", r);
}
int main()
{
	test(Add);
	return 0;
}

这时Add()就是回调函数,没有直接调用Add( )由该函数的实现方调用(通过函数指针*pf调用Add()函数)。
直接调用的方式:Add(10,20)

回调函数的应用

以指针章节的转移表为例:🚀C语言------深入解析C语言指针:从基础到实践从入门到精通(四)

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 Menu()
{
	printf("**********************\n");
	printf("****1.Add  2.Sub******\n");
	printf("****3.Mul  4.Div******\n");
	printf("*****  0.exit  *******\n");
	printf("**********************\n");
}
int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	do
	{
	Menu();
	printf("请选择:\n");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		printf("请输入操作数:");
		scanf("%d %d", &x, &y);
		ret = Add(x, y);
		printf("%d\n", ret);
		break;
	case 2:
		printf("请输入操作数:");
		scanf("%d %d", &x, &y);
		ret = Sub(x, y);
		printf("%d\n", ret);
		break;
	case 3:
		printf("请输入操作数:");
		scanf("%d %d", &x, &y);
		ret = Mul(x, y);
		printf("%d\n", ret);
	case 4:
		printf("请输入操作数:");
		scanf("%d %d", &x, &y);
		ret = Div(x, y);
		printf("%d\n", ret);
		break;
	case 0:
		printf("退出\n");
		break;
	default:
		printf("输入错误,请重新输入\n");
		break;
	}
	} while (input);

	return 0;
}

会发现代码有许多冗长的部分,我们可以把冗长的代码用封装 成一个函数Calc,通过函数指针作为函数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 Menu()
{
	printf("**********************\n");
	printf("****1.Add  2.Sub******\n");
	printf("****3.Mul  4.Div******\n");
	printf("*****  0.exit  *******\n");
	printf("**********************\n");
}

void Calc(int (*pf)(int , int ))
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入操作数:");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("%d\n", ret);
}
int main()
{
	int input = 1;
	do
	{
		Menu();
		printf("请选择:\n");
		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;
}

图解 🤌:

接受的地址不同,调用的函数就不同,就能实现相对应的功能

二.qsort使用举例

在介绍qsort函数函数之前,之前讲解过冒泡排序,冒泡排序的方式是两个相邻元素逐个比较 ,但是冒泡排序只能进行整型间的排序 。冒泡排序还是有一些不便利的地方
qsort是C语言提供的一个排序函数,是基于快速排序算法思想的一种排序方式
优点

1.是现成的排序算法,可以直接使用
2.大部分情况下排序的效率比冒泡排序高
3.qsort函数可以排序任意类型的数据

冒泡排序代码实现: 🚀C语言------深入解析C语言指针:从基础到实践从入门到精通(三)

2.1qsort函数的介绍

通过cplusplus 网站查询qsort函数

qsort函数:

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*)):函数指针,指针指向的函数是用来比较排序数组的两个元素。这个函数是根据排序的标准自己编写的一个比较函数

这个比较函数的返回值是int类型的

当p1>p2时,返回>0

当p1=p2时,返回=0

当p1<p2时,返回<0

默认的排序是升序

官方网站上qsort函数的介绍

注:使用qsort要包含头文件

2.2qsort排序整型

以数组为例✍️

c 复制代码
#include<stdio.h>
#include<stdlib.h>
void print_arr(int arr[], int sz)
{
	int i = 0;
	for ( i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int cmp_arr(const void* p1, const void* p2)
{
	if (*(int*)p1 > *(int*)p2)
	{
		return 1;
	}
	else if (*(int*)p1 < *(int*)p2)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}
int main()
{
	int arr[10] = { 2,4,1,7,6,8,9,5,3,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_arr);
	print_arr(arr, sz);
	return 0;
}


com_arr可以直接写成:

c 复制代码
int cmp_arr(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
	
}

如果想要进行降序排列:

c 复制代码
int cmp_arr(const void* p1, const void* p2)
{
	if (*(int*)p1 < *(int*)p2)
	{
		return 1;
	}
	else if (*(int*)p1 > *(int*)p2)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}
return (*(int*)p2 - *(int*)p1);//等价

2.3qsort排序结构数据

结构体成员访问的方式

c 复制代码
struct stu 
{
	char name[20];
	int age;
};
void test(struct stu *s)
{
	printf("%d\n", s->age);
	printf("%s\n", s->name);
	printf("%d\n", (*s).age);
	printf("%s\n", (*s).name);
}
int main()
{
	struct stu s = { "zhangsan",20 };
	test(&s);
	return 0;
}


用qsort函数排序结构体变量

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stu
{
	char name[30];
	int age;
};

void print_arr(struct stu s[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s:%d ", s[i].name,s[i].age);
	}
	printf("\n");
}
int cmp_age(const void* p1, const void* p2)
{
	return (*(struct stu*)p1).age -(*(struct stu*)p2).age;
}
void test1()
{
	struct stu s[] = {{"zhangsan",19},{"wangli",20},{"xiaoming",18}};
	int sz = sizeof(s) / sizeof(s[0]);
	print_arr(s, sz);
	qsort(s, sz, sizeof(s[0]), cmp_age);
	print_arr(s, sz);
}
int cmp_name(const void* p1, const void* p2)
{
	return strcmp(((struct stu*)p1)->name , ((struct stu*)p2)->name);
}
void test2()
{
	struct stu s[] = { {"zhangsan",19},{"wangli",20},{"xiaoming",18} };
	int sz = sizeof(s) / sizeof(s[0]);
	print_arr(s, sz);
	qsort(s, sz, sizeof(s[0]), cmp_name);
	print_arr(s, sz);
}
int main()
{
	printf("按年龄打印\n");
	test1();
	printf("按名字打印\n");
	test2();
	return 0;
}

三.qsort函数的模拟实现

使用回到函数,模拟实现qsort函数(使用冒泡排序的方式)

c 复制代码
#include<stdio.h>
int cmp_int(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
void Swap(char*buff1,char*buff2,size_t width)
{
	int i = 0;
	for ( i = 0; i < width; i++)
	{
		int tmp = *buff1;
		*buff1 = *buff2;
		*buff2 = tmp;
		buff1++;
		buff2++;
	}
}
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(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 (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}
void test()
{
	int arr[] = { 2,4,1,7,6,8,9,5,3,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_arr(arr, sz);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}
int main()
{
	test();
	return 0;
}


任意类型的数据

c 复制代码
struct stu
	{
		char name[20];
		int age;
	};
void Swap(char*buff1,char*buff2,size_t width)
{
	int i = 0;
	for ( i = 0; i < width; i++)
	{
		int tmp = *buff1;
		*buff1 = *buff2;
		*buff2 = tmp;
		buff1++;
		buff2++;
	}
}

void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(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 (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}
int cmp_age(const void* p1, const void* p2)
{
	return (*(struct stu*)p1).age -(*(struct stu*)p2).age;
}
int cmp_name(const void* p1, const void* p2)
{
	return strcmp(((struct stu*)p1)->name , ((struct stu*)p2)->name);
}
void print_arr2(struct stu s[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s:%d ", s[i].name, s[i].age);
	}
	printf("\n");
}
void test2()
{
	struct stu s[] = { {"zhangsan",19},{"wangli",20},{"xiaoming",18} };
	int sz = sizeof(s) / sizeof(s[0]);
	
	printf("按名字排序\n");
	bubble_sort(s, sz, sizeof(s[0]), cmp_name);
	print_arr2(s, sz);
	printf("按年龄排序\n");
	bubble_sort(s, sz, sizeof(s[0]), cmp_age);
	print_arr2(s, sz);
}
	
int main()
{
	test2();
	return 0;
}

swap函数实现原理


紫色框是编写者自己写的比较函数
棕色框是是实现库函数的人(厂商)规定的

相关推荐
朝新_3 小时前
【EE初阶 - 网络原理】传输层协议
java·开发语言·网络·笔记·javaee
koo3643 小时前
李宏毅机器学习笔记27
人工智能·笔记·机器学习
weixin_448119943 小时前
Datawhale人工智能的数学基础 202510第3次作业
人工智能·算法
前端架构师-老李3 小时前
Java开发—JDK的安装和版本管理(macOS)
java·开发语言·macos
文火冰糖的硅基工坊3 小时前
[人工智能-大模型-9]:大模型十大应用场景和对应的代表性的产品?
服务器·人工智能·大模型
木建隶3 小时前
AI 食用指南--更好的用AI编程
人工智能·ai编程
亚马逊云开发者3 小时前
GenDev 智能开发:Amazon Q Developer CLI 赋能Amazon Code Family实现代码审核
人工智能
weixin_377634843 小时前
【强化学习】RLMT强制 CoT提升训练效果
人工智能·算法·机器学习
懂得节能嘛.3 小时前
【动态配置中心】Java+Redis构建动态配置中心
java·开发语言·redis