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;
}
相关推荐
笨蛋不要掉眼泪31 分钟前
Java测试题(上)
java·开发语言
东方佑36 分钟前
高效序列建模新突破:SamOut模型解读与21.79%损失改进
开发语言·python
峥无1 小时前
C语言分支与循环深度解析
c语言·开发语言
不过普通话一乙不改名1 小时前
第一章:Go语言基础入门之函数
开发语言·后端·golang
屁股割了还要学2 小时前
【C语言进阶】柔性数组
c语言·开发语言·数据结构·c++·学习·算法·柔性数组
草莓熊Lotso2 小时前
【LeetCode刷题指南】--有效的括号
c语言·数据结构·其他·算法·leetcode·刷题
☞下凡☜2 小时前
C语言(20250722)
linux·c语言·开发语言
whhhhhhhhhw2 小时前
Go语言-fmt包中Print、Println与Printf的区别
开发语言·后端·golang
坚持吧20212 小时前
【无标题】word 中的中文排序
开发语言·c#
魔力之心3 小时前
C study notes[3]
c语言