第十二讲:指针(4)

第十二讲:指针(4)

总结:该篇博客详细对以下两个内容进行讲解:

1.回调函数

2.qsort函数

1.回调函数

1.1什么是回调函数

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

如果我们将函数的地址作为参数传递给另一个函数,当通过这个指针被用来调用其指向的函数时,被调用的函数就是回调函数,回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外一方调用的,用于对该事件或条件进行响应

下面我们通过代码来理解什么是回调函数:

1.2深入理解并使用回调函数

我们写一个简易的计算器

1.2.1简单写法

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

这个方法写的十分冗余,下面我们来进行优化

1.2.2优化

c 复制代码
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 (*pa)(int, int)) //使用函数指针变量来接受函数指针
{
	printf("请输入两个操作数:\n");
	int x, y;
	x = 0;
	y = 0;
	scanf("%d %d", &x, &y);
	int set = pa(x, y);
	printf("%d\n", set);
}

int main()
{
	int input = 1;
	do
	{
		printf("*************************\n");
		printf(" 1:add 2:sub \n");
		printf(" 3:mul 4:div \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;
}

我们通过画图来理解回调函数:

2.qsort函数详解

2.1函数简单介绍

这是一个执行快速排序的函数,包含在<stdlib.h>库中

函数原型:

c 复制代码
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

对各个参数进行介绍如下:

1.base:指向要排序数组的首元素的地址

2.num:数组中的元素的个数

3.width:数组中每个元素的大小,单位是字节

4.int (__cdecl *compare )(const void *elem1, const void *elem2 ):

这是一个由编程者自己写的函数,将函数地址传入,函数的形式被规定,该函数定义了如何比较两个元素

对于自己定义的这个函数,通过其返回值决定所排序元素的顺序,遵循以下原则 :

2.3qsort函数使用举例

2.3.1qsort函数排序整形数据

c 复制代码
//使⽤qsort函数排序整型数据

int Sort1(const void* pa, const void* pb)
{
	return (*(int *)pa - *(int*)pb);
}

int main()
{
	int arr[] = { 2,3,4,5,1,6,7,9,10 };

	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), Sort1); //void qsort(void* base, 
	        //size_t num, 
			//size_t width, 
			//int(__cdecl * compare)(const void* elem1, const void* elem2));
	Print(arr, sz);
	return 0;
}

2.3.2qsort函数排序结构数据

c 复制代码
//使⽤qsort函数排序结构数据

//创建一个结构类型,假设为学生数据
struct Stu
{
	char name[20];
	int age;
};

//按照名字排序
int SortByName(const void* pa, const void* pb)
{
	return (strcmp(((struct Stu*)pa)->name, ((struct Stu*)pb)->name));
}

//按照年龄排序
int SortByAge(const void* pa, const void* pb)
{
	return (((struct Stu*)pa)->age - ((struct Stu*)pb)->age);
}

int main()
{
	//给定学生数据
	struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };

	int sz = sizeof(arr) / sizeof(arr[0]);
	//按照名字排序
	qsort(arr, sz, sizeof(arr[0]), SortByName); //void qsort(void* base, 
										   //size_t num, 
										   //size_t width, 
										   //int(__cdecl * compare)(const void* elem1, const void* elem2));
	//按照年龄排序
	qsort(arr, sz, sizeof(arr[0]), SortByAge); //void qsort(void* base, 
									       //size_t num, 
										   //size_t width, 
										   //int(__cdecl * compare)(const void* elem1, const void* elem2));

	return 0;
}

3.qsort函数的模拟实现

我们使用冒泡排序来进行qsort函数的模拟实现,首先先介绍一下什么是冒泡排序

3.1冒泡排序

目前的排序方式有很多,快速排序,希尔排序,冒泡排序,我们现在使用冒泡排序进行类比排序

c 复制代码
void BubbleSort(int* pa, int sz)
{
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - 1 - i; j++)
		{
			if (*(pa + j) > *(pa + j + 1))
			{
				int temp = *(pa + j);
				*(pa + j) = *(pa + 1 + j);
				*(pa + 1 + j) = temp;
			}
		}
	}
}

void Print(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", *(arr + i));
}

int main()
{
	int arr[] = { 2,3,4,5,1,6,7,9,10 };

	//冒泡排序
	int sz = sizeof(arr) / sizeof(arr[0]);
	BubbleSort(arr, sz);

	//进行打印
	Print(arr, sz);
	return 0;
}

3.2冒泡排序的改造

c 复制代码
//冒泡函数的改造
void Change(char* pa, char* pb, int sz)
{
	for(int i = 0; i<sz; i++)
	{
		char temp = *pa;
		*pa = *pb;
		*pb = temp;
		pa++;
		pb++;
	}
}

void BubbleSort(void* pa, size_t sz, size_t width, int(* compare)(const void* pa, const void* pb))
{
	for (int i = 0; i < sz - 1; i++)  //尽管是改造,但是这两个for循环是不用改变的
	{                                 //第一个for循环表示循环次数
		for (int j = 0; j < sz - 1 - i; j++) //第二个for循环是将两个数进行比较
		{
			//仍然是判断,如果compare函数返回值大于0,进行交换
			if (compare((char*)pa + j * width, (char*)pa + (j + 1) * width) > 0)
				Change((char*)pa + j * width, (char*)pa + (j + 1) * width, width); //进行交换,但是这个交换一次要交换数组类型个字节
		}
	}
}

int main()
{
	//给定学生数据
	struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };

	//冒泡排序
	int sz = sizeof(arr) / sizeof(arr[0]);
	BubbleSort(arr, sz, sizeof(arr[0]), SortByName);  //void qsort(void* base, 
										              //size_t num, 
										              //size_t width, 
										              //int(__cdecl * compare)(const void* elem1, const void* elem2));
	BubbleSort(arr, sz, sizeof(arr[0]), SortByAge);
	return 0;
}
相关推荐
Envyᥫᩣ2 分钟前
C#语言:从入门到精通
开发语言·c#
九圣残炎19 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
童先生23 分钟前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
lulu_gh_yu24 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!44 分钟前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚1 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
老秦包你会1 小时前
Qt第三课 ----------容器类控件
开发语言·qt
凤枭香1 小时前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
ULTRA??1 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
远望清一色1 小时前
基于MATLAB的实现垃圾分类Matlab源码
开发语言·matlab