C语言:深入理解指针(5)

1.回调函数

回调函数就是⼀个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被用来调⽤其所指向的函数 时,被调⽤的函数就是回调函数。在上一讲中我们说过在学习指针函数前我们可以通过 switch 语句来写这个问题,但是这样 case 语句中就会有很多冗余的内容,通过回调函数我们就可以解决这个问题,代码和执行结果如下:

复制代码
#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 Print()
{
	printf("******************************\n");
	printf("******1.加法****2.减法********\n");
	printf("******3.乘法****4.除法********\n");
	printf("************0.退出************\n");
	printf("******************************\n");
	printf("请选择:");
}
int calcu(int(*p)(int, int))
{
	printf("输入操作数:");
	int ans = 0;
	int x, y;
	scanf("%d %d", &x, &y);
	ans = p(x, y);
	printf("%d\n", ans);
}
int main()
{
	int input = 0;
	do
	{
		Print();
		scanf("%d", &input);
		switch (input)
		{
		case 1:calcu(add);break;
		case 2:calcu(sub);break;
		case 3:calcu(mul);break;
		case 4:calcu(div);break;
		case 0:printf("退出计算器");break;
		default:printf("输入错误,重新输入\n");break;
		}
	} while (input);
		return 0;
}

区别是我们多了一个 calcu 函数,我们把调⽤的函数的地址以参数的形式传递过去,使⽤函数指针接收,函数指针指向什么函数就调用什么函数,这⾥其实使⽤的就是回调函数的功能。

2. qsort 使用举例

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

qsort函数是一个库函数,这个库函数是用来排序的,是基于快速排序算法实现的一个库函数,这个函数可以用来排序任意类型的数据。

之前的学习中我们学习了冒泡排序算法,但之前写的那个算法是用来排序整型数组的,但却不能用来排序浮点型和结构体数据,而是只能排序固定类型的数据。下来让我们来学习一下 qsort 函数。

复制代码
void qsort(void *base,    //指向待排序数组的第一个元素,可以接受任意类型的数据
           size_t num,    //待排序数组的元素个数
           size_t size,   //待排序数组中元素的大小,单位是字节
           int (*compar)(const void *p1, const void *p2)
           //compar是一个函数指针,这个指针可以接受一个函数地址
           //这个函数是使用qsort函数的人设计的,这个函数用来比较两个数组元素的大小
          );

在这里我们约定当 p1 指向的元素大于 p2 指向的元素时,因该返回一个大于 0 的数字;当 p1 指向的元素等于 p2 指向的元素时,返回 0,当 p1 指向的元素小于 p2 指向的元素时,返回一个小于 0 的数字。

如图就是一个通过 qsort 函数实现排序的过程。 注意:qsort 默认是升序的。

2.2 使用 qsort 函数排序结构数据

注意,两个字符转比较大小不是比长度,而是比较对应位置上字符的大小。

3. qsort 函数的模拟实现

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

代码和执行结果如下:

复制代码
#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,2,4,5,7,6,8,9,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;
}
相关推荐
人工干智能4 小时前
科普:Python 中,字典的“动态创建键”特性
开发语言·python
LGL6030A4 小时前
算法题实战积累(3)——方块转换(C语言)
c语言·算法
初听于你5 小时前
缓存技术揭秘
java·运维·服务器·开发语言·spring·缓存
长路归期无望7 小时前
C语言小白实现多功能计算器的艰难历程
c语言·开发语言·数据结构·笔记·学习·算法
是大强8 小时前
stm32摇杆adc数据分析
开发语言
口嗨农民工8 小时前
win10默认搜索APP和window设置控制命板
linux·服务器·c语言
蓝莓味的口香糖9 小时前
【JS】什么是单例模式
开发语言·javascript·单例模式
linux kernel9 小时前
第二十三讲:特殊类和类型转换
开发语言·c++
笨蛋少年派9 小时前
JAVA基础语法
java·开发语言
渡我白衣9 小时前
深入剖析:boost::intrusive_ptr 与 std::shared_ptr 的性能边界和实现哲学
开发语言·c++·spring