栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C指针进阶2-->函数指针数组 回调函数简化计算器代码,基于回调函数模拟实现qsort函数

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C指针进阶2-->函数指针数组 回调函数简化计算器代码,基于回调函数模拟实现qsort函数

指针进阶
  • 函数指针数组
    • 函数指针数组的用途:转移表
  • 回调函数
    • 用回调函数简化计算器
    • 基于回调函数模拟实现qsort函数
      • 演示qsort函数的使用
        • 对一组整形数组进行升序排序
        • 使用qsort来排升序结构数据
      • 用冒泡排序模拟实现qsort函数

函数指针数组

函数指针数组是一个数组,数组元素是函数指针。
函数指针数组的形式:int (*parr[10])();
parr 先和[] 结合,说明 parr是数组,数组的内容是什么呢?
是 int(*)() 类型的函数指针。

函数指针数组的用途:转移表

例子写一个计算器:
要求:有加法,减法,乘法,除法。
我们以往的代码实现:

#include
void menu()
{
	printf("***************************n");
	printf("******  1.add 2.sub  ******n");
	printf("******  3.mul 4.div  ******n");
	printf("******     0.exit    ******n");
	printf("***************************n");
}
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;
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		int x = 0;
		int y = 0;
		int ret = 0;
		switch (input)
		{
		case 1:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("%dn", ret);
			break;
		case 2:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("%dn", ret);
			break;
		case 3:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			printf("%dn", ret);
			break;
		case 4:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("%dn", ret);
			break;
		case 0:
			printf("退出计算器n");
			break;
		default:
			printf("选择错误n");
			break;
		}
	} while (input != 0);
	return 0;
}

发现上面的代码主函数部分过于累赘,有很多重复的部分。

每个case语句内蓝框都是重复的部分,那我们如何把这些重复的部分用函数指针数组来解决?

#include
void menu()
{
	printf("***************************n");
	printf("******  1.add 2.sub  ******n");
	printf("******  3.mul 4.div  ******n");
	printf("******     0.exit    ******n");
	printf("***************************n");
}
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;
}


int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		int x = 0;
		int y = 0;
		int ret = 0;
		int (*arr[5])(int, int) = { NULL, Add, Sub, Mul, Div };
		if (input == 0)
		{
			printf("退出计算器n");

		}
		else if(input>0&&input<5)
		{
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);

			ret = arr[input](x, y);
			printf("%dn", ret);
		}
		else
		{
			printf("选择错误n");
		}
			
	} while (input != 0);
	return 0;
}
回调函数

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

用回调函数简化计算器
#include
void menu()
{
	printf("***************************n");
	printf("******  1.add 2.sub  ******n");
	printf("******  3.mul 4.div  ******n");
	printf("******     0.exit    ******n");
	printf("***************************n");
}
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 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("%dn", ret);
}


int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			printf("退出计算器n");
			break;
		case 1:
			calc(Add);
			break;
		case 2:
			calc(Sub);
			break;
		case 3:
			calc(Mul);
			break;
		case 4:
			calc(Div);
			break;
		default:
			printf("选择错误n");
			break;
		}
	} while (input != 0);
	return 0;
}
基于回调函数模拟实现qsort函数 演示qsort函数的使用

qsort - 这个函数可以排序任意类型的数据

  • void qsort(void* base,//你要排序的数据的起始位置
    size_t num,//待排序的数据元素的个数
    size_t width,//待排序的数据元素的大小(单位是字节)
    int(* cmp)(const void* e1, const void* e2)//函数指针-比较函数
    );—>MSDN搜索得到的。
    头文件--
对一组整形数组进行升序排序
#include
#include

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}
int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}
使用qsort来排升序结构数据
#include
#include

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}
struct Stu
{
	char name[20];
	int age;
};
int cmp_stu_by_name(const void* e1, const void* e2)//比较name
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_stu_by_age(const void* e1, const void* e2)//比较age
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

int main()
{
	struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);//对name升序
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s %dn", s[i].name, s[i].age);
	}
	printf("n");
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);//对age升序
	for (i = 0; i < sz; i++)
	{
		printf("%s %dn", s[i].name, s[i].age);
	}
	printf("n");
	return 0;
}

用冒泡排序模拟实现qsort函数

qsort函数本来是用快速排序来进行排序的,但是快速排序是在数据结构学习的,所以在C语言还未学习到数据结构时先用已经学过的冒泡排序来模拟。

void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//假设数组是排好序的
		//一趟冒泡排序的过程
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j+1) * width))
			{
				//交换
				Swap((char*)base + j * width, (char*)base + (j+1) * width, width);
				flag = 0;
			}
		}
		if (flag == 1)//判断一次冒泡排序后是否进行交换,未进行交换则有序,退出循环
		{
			break;
		}
	}
}

这个模拟sqort函数中与以前冒泡排序函数不同的是(char*)base + j * width,和(char*)base + j * width是什么意思呢?为啥必须要强制转换为(char*)呢?

实现Swap函数

void Swap(char* buf1, char* buf2, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		++buf1;
		++buf2;
	}
}

该Swap函数第一个参数和第二个参数是需要交换两个数据的首地址。sz是需要交换的两个数据的大小。
对两个数据的每个字节的数据依次进行交换,最终完成两个数据的交换。

对上面的qsort函数的使用几个案例,qsort函数用bubble_sort函数代替可以依次验证模拟实现函数的准确性

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/994036.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号