【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式

2024-02-27 1153阅读

温馨提示:这篇文章已超过445天没有更新,请注意相关的内容是否还可用!

目录

1、函数指针数组

1.1、函数指针数组是什么?

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

2、扩展:指向函数指针的数组的指针

3、回调函数

3.1、回调函数介绍

 3.2、回调函数的案例:qsort函数

3.2.1、回顾冒泡排序

 3.2.1、什么是qsort函数?


1、函数指针数组

1.1、函数指针数组是什么?

函数指针数组是什么?首先主语是数组,数组是一个存放相同类型数据的存储空间。那我们已经学习了指针数组,比如:

char* arr[5]  ———— 字符指针数组,它是一个数组,存放的是字符指针。

int* arr[5]     ———— 整型指针数组,它是一个数组,存放的是整型指针。

假设有这么一个使用场景,我需要将几个函数的地址存放到一个数组中,那应该怎么存?下面给大家介绍一下:函数指针数组

int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int main()
{
	int (*pf1)(int, int) = &Add;  //pf1和pf2是函数指针
	int (*pf2)(int, int) = ⋐
	//数组中存放类型相同的多个数组
	int (*pfArr[4])(int, int) = { &Add,&Sub };  //pfArr就是函数指针数组
	return 0;
}

函数指针数组的写法与函数指针非常相似,只需要在名字后加个方括号[ ]就可以了。

注意:因为数组是一个存放相同类型数据的存储空间,所以函数指针数组只能够存放返回类型和参数类型都一致的函数的函数地址。

 1.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 menu()
{
	printf("*******************************\n");
	printf("******   1.add   2.sub    *****\n");
	printf("******   3.mul   4.div    *****\n");
	printf("******   0.exit           *****\n");
	printf("*******************************\n");
}
int main()
{
	int input = 0;
	int a = 0;
	int b = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入2个操作数:");
			scanf("%d %d", &a, &b);
			ret = add(a, b);
			printf("%d\n", ret);
			break;
		case 2:
			printf("请输入2个操作数:");
			scanf("%d %d", &a, &b);
			ret = sub(a, b);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入2个操作数:");
			scanf("%d %d", &a, &b);
			ret = mul(a, b);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入2个操作数:");
			scanf("%d %d", &a, &b);
			ret = div(a, b);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式

    上面的代码虽然能实现一个计算器功能,但是可以发现,这个代码特别地冗余,重复的部分非常多,并且如果需要添加多一个功能是,又需要再添加多一个case,导致代码越来越长,重复部分也越来越多,这是非常不好的代码习惯,那有什么办法能够解决呢?

    其实我们通过观察可以发现,这些函数有一些特点,就是除了函数名不同之外,返回类型以及参数类型都是一致的。

    既然除了函数名不同之外其余都相同,那么是否就可以使用函数指针数组来改造一下代码?

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 input = 0;
	int a = 0;
	int b = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		//创建一个函数指针数组
		int (*pfArr[])(int, int) = { NULL,add,sub,mul,div };
						    //为了使数组下标与菜单序号对应起来,在0下标处放置一个NULL
		if (input == 0)
		{
			printf("退出计算器\n");
		}
		else if (input >= 1 && input  arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	int i = 0;
	for ( i = 0; i  
 
 

上面就是冒泡排序的实现,但是可以看到,这个冒泡排序其实是有缺陷的,它的参数是int类型,限制了它只能够排序整型数据!而这里即将讲到的qsort函数就是一个可以用来排序任意类型数据的函数。

 3.2.1、什么是qsort函数?

qsort是一个库函数,底层使用的是快速排序的方式对数据进行排序。头文件:

这个函数可以直接使用用来排序任意类型的数据。

当然除了快速排序,还有很多排序,例如:冒泡排序、选择排序,希尔排序,归并排序等等

【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式

qsort函数定义原型:

void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));

  • void* base:待排序数组的第一个元素的地址
  • size_t num:待排序数组的元素个数
  • size_t size:以字节为单位,待排序数组中一个元素的大小。
  • int (*compar)(const void*,const void*):函数指针,指向一个函数,用来比较两个元素,由用户自行创建并封装。

     比较函数的形参中为什么用的是void*:

    void* 是无具体类型的指针,不能进行解引用操作符,也不能进行+-整数的操作,它是用来存放任意类型数据的地址(可以理解为垃圾桶,什么都能装,当需要用时再强制类型转换为需要的类型)。只有void*被允许存放任意类型数据的地址,如果是其他类型的指针编译器会报错。正是因为定义qsort函数时用的是void*,qsort函数才可以排序任意类型的数据。

    使用qsort函数最重要的就是最后一个参数,这个参数决定了qsort函数比较两个元素的规则。这里先写一个用于排序整型数据的比较函数cmp_int:

    int cmp_int(const void* e1, const void* e2)
    {
    	return *(int*)e1 - *(int*)e2;
    }

     比较函数的要求:

    • 当p1指向的元素大于p2指向的元素时,返回大于0的数
    • 当p1指向的元素等于p2指向的元素时,返回0
    • 当p1指向的元素小于p2指向的元素时,返回小于0的数

      【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式

       【完整代码】

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

      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  
       
       

      同理,qsort函数排序结构体类型数据(下面例子以结构体中的年龄来排序):

      struct Stu
      {
      	char name[20];
      	int age;
      };
      int cmp_struct(const void* e1, const void* e2)
      {
      	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
      }
      int main()
      {
      	struct Stu arr[] = { {"zhangsan",20},{"lisi",21},{"wangwu",22} };
      	int sz = sizeof(arr) / sizeof(arr[0]);
      	qsort(arr, sz, sizeof(arr[0]), cmp_struct);
      	return 0;
      }

       【运行结果】

      可以发现确实是完成了按年龄排序。

      【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式


      如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

      如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

      如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]