【C语言】回调函数(qsort)与模拟实现

这篇具有很好参考价值的文章主要介绍了【C语言】回调函数(qsort)与模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

何思何虑,居心当如止水;勿取勿忘,为学当如流水。— 出自《格言联璧·学问类》
解释:无思无虑,心境应当平静如水;不求冒进也不忘记,学业当如流水一般永无止境。

【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享


    这篇博客我们将会理解回调函数这个概念,以及借用qsort帮助理解,并且最终用qsort的思路来实现冒泡排序。
    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    回调函数🍀

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

    如果这样看你还是不太理解,我们可以举出一个简单的例子。

    void test2()
    {
    	printf("haha\n");
    
    }
    void test1(void (*p) ())
    {
    	p();
    }
    int main()
    {
    	test1(test2);
    
    	return 0;
    }
    

    这这段代码中:
    test1的实参是test2,而test1的形参也对应函数指针类型,

    {
    	p();
    }
    
    

    而p()就是借助p的存储的test2的地址调用test2,就相当于test2()

    归纳一下:
    在这个过程中谁是回调函数?
    答:test2,因为test2并不是直接调用,而是通过将test2的地址传递给test1的实参,然后通过形参的地址调用。
    现在我们已经理解了什么是回调函数。

    现在我们可以用一个简单的计算器来运用一下:

    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 menu()
    {
    
    	printf("**************************\n");
    	printf("****  1.add   2.sub   ****\n");
    	printf("****  3.mul   4.div   ****\n");
    	printf("****  0.exit          ****\n");
    	printf("**************************\n");
    
    }
    
    void  cal(int (*p) (int, int))
    {
    	int x = 0;
    	int y = 0;
    	scanf("%d %d", &x, &y);
    	printf("%d\n", p(x, y));
    }
    int main()
    {
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请输入");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 1:
    			cal(Add);
    			break;
    		case 2:
    			cal(Sub);
    			break; 
    		case 3:
    			cal(Mul);
    			break;
    		case 4:
    			cal(Div);
    			break;
    		case 0:
    			printf("退出计算机\n");
    			break;
    		default:
    			printf("输入错误请重新输入\n");
    		}
    
    
    
    	} while (input);
    
    }
    

    这就是用回调函数的一个运用方法,虽然没有转移表那么简洁,但是也是一种方法。

    qsort函数🤢

    我们先来看看这个函数的介绍。

    参数和返回值:
    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    这个函数的参数应该是算比较多的了。下面是参数的具体解释:

    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    这个函数的功能:
    qsort函数是C语言标准库中的一个排序函数,用于对数组进行快速排序(其实就是根据快排来实现的)。它的基本功能是将给定的数组(当然也包括结构体数组)按照指定的比较函数进行排序。

    头文件:
    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享
    那么是根据什么来判断要排序呢?

    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享
    实际上跟strcmp有点相似,比较两个元素的大小,根据回调函数(compar就是一个函数名,当qsort的参数里包含另一个函数的名字,就与我们说的回调函数相符)的返回值来判断是否需要排序。

    我们现在就来用用看:

    int cmp(const void* e1, const void* e2)
    {
    	//if (*(int*)e1 - *(int*)e2 > 0)
    	//	return 1;
    	//else if (*(int*)e1 - *(int*)e2 == 0)
    	//	return 0;
    	//else
    	//	return -1;
    	return (*(int*)e1 - *(int*)e2);
    		
    }
    int main()
    {
    	int arr[7] = { 8, 7, 4, 3, 6, 1, 2 };
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	qsort(arr, sz, sizeof(arr[0]), cmp);
    	for (int i = 0; i < 7; i++)
    	{
    		printf("%d ",arr[i]);
    	}
    
    
    	return 0;
    }
    

    我们简单的排序一个整型数组,【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    qsort这个函数能排序任何类型的数组的原因就是在于,
    cmp这个回调函数是由我们自己来实现的。
    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享
    介绍中也强调了这一点。那为什么是void * 类型的参数呢?
    因为void *类型能接收其他类型,所以才使得我们能排序所有类型的数组,
    但是cmp函数的实现也需要根据不同的类型进行不同的改动。

    接下来我们看看结构体数组元素的排序。

    typedef struct student
    {
    	char name[20];
    	int age;
    
    }student;
    void cmp(const void* e1, const void* e2)
    {
    	if ((*(student*)e1).age - (*(student*)e2).age > 0)
    	{
    		return 1;
    	}
    	else if ((*(student*)e1).age - (*(student*)e2).age == 0)
    	{
    		return 0;
    	}
    	else
    		return -1;
    		//return ((*(student*)e1).age - (*(student*)e2).age);简写
    }
    
    //void cmp(const void* e1, const void* e2)
    //{
    //	if (strcmp((*(student*)e1).name , (*(student*)e2).name)> 0 )
    //	{
    //		return 1;
    //	}
    //	else if (strcmp((*(student*)e1).name, (*(student*)e2).name) == 0)
    //	{
    //		return 0;
    //	}
    //	else
    //		return -1;
    //}
    int main()
    {
    	student s1[3] = { {"zhangxiaofan",20} ,{"shihao",18} ,{"fangyuan",25} };
    	qsort(s1, sizeof(s1) / sizeof(s1[0]), sizeof(s1[0]), cmp);
    	for (int i = 0; i < 3; i++)
    	{
    		printf(" %s is %d\n",s1[i].name, s1[i].age);
    	}
    	return 0;
    }
    

    分析(排序age)

    • 在排序结构体数组成员时,首先必须要有结构体数组,然后我们再进行初始化。
    • 当我们要排序的是int age;时,我们所创建的回调函数就与整型数组的排序有区别。
    • 区别首先在于强制类型转换,整型数组的元素类型是整型所以可以直接(int *),但是结构体数组的每个元素是结构体(所以用到student *),结构体的成员(int age)才是我们要排序的目标。
    • 在整型数组时我们直接讲e1,e2进行强制类型转换解引用然后相减,是因为e1,e2就直接表示的是整型元素,而结构体数组并不能和整型数组一样,因为结构体数组强制类型转换再解引用得到的是这个结构体,结构体怎么能和结构体相减呢?所以我们需要用到.去找到int age
      -【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    分析(排序名字)
    排序名字与排序年龄其实差不了太多,最重要的就是需要用到函数strcmp来比较字符的ASCII码,strcmp((*(student*)e1).name , (*(student*)e2).name)这样来判断就行了。

    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    我们已经学习完qsort函数了,我们知道qsort函数其实是用快速排序实现的,虽然我们没有学过快速排序,但是我们知道冒泡排序。下面我们就来自己用冒泡排序来实现一下吧。

    用冒泡实现qsort💥

    首先先简单的回顾一下冒泡排序。

    void bubble_sort(int* arr, int sz)
    {
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < sz - 1; i++)
    	{
    		for (j = 0; j < sz - 1 - i; j++)
    		{
    			int tmp = 0;
    			if (arr[j] > arr[j + 1])
    			{
    				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);
    	for (int i = 0; i < sz; i++)
    	{
    
    		printf("%d ", arr[i]);
    	}
    
    	return 0;
    }
    

    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享
    然后我们思考一下到底该如何能够排序任意的类型的数组呢?我们必须有个思路。

    • 就像qsort函数的创作者一样,他并不知道我们要排序什么样类型的数组,但是呢?他通过qsort函数的参数能够解决这个问题。
    • 也就是说我们给出数组的地址,元素多少,一个元素的大小,还有回调函数就能够实现排序的功能,那我们也需要想办法通过元素的多少和大小来实现我们自己的能排序各种类型数组的冒泡排序。当然我们可以自己试试看。

    下面是参考

    int cmp(const void* e1, const void* e2)
    {
    
    	return *(int*)e1 - *(int*)e2;
    }
    void swap(char* e1,char * e2,  int width)
    {
    	char tmp = 0;
    	while (width--)
    	{
    		tmp = *e1;
    		*e1 = *e2;
    		*e2 = tmp;
    		e1++;
    		e2++;
    	}
    
    }
    void my_bubble_sort(void *base, int size, int width,
    	int (*p)(const void*, const void*))
    {
    
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < size - 1; i++)
    	{
    		for (j = 0; j < size - 1 - i; j++)
    		{
    			char tmp = 0;
    			if (cmp((char *) base+j *width,(char *)base+(j+1)*width)> 0)
    			{
    				swap((char*)base + j * width, (char*)base + (j + 1) * width,
    				width);
    			}
    
    		}
    	}
    
    }
    int main()
    {
    	int arr[] = { 10, 9, 8, 7, 6 ,5, 4, 3, 2, 1 };
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	my_bubble_sort(arr, sz,sizeof(arr[0]),cmp);
    	for (int i = 0; i < sz; i++)
    	{
    
    		printf("%d ", arr[i]);
    	}
    
    	return 0;
    }
    

    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    如果想要排序逆序的数组,把 if 中的> 0 改成 < 0 就行了

    分析
    其实在自己实现的过程中最重要的就是my_bubble_sort这个函数,

    1. 首先我们要把参数写正确,

    void my_bubble_sort(void *base, int size, int width,
    	int (*p)(const void*, const void*))
    

    由于我们并不知道排序的类型所以我们将该数组的首地址放在void *,最后也要把函数指针写正确。

    1. 我们在冒泡中需要修改的就是if ()中的表达式,我们并不能直接判断大小,而是用cmp函数来判断。
      (char *) base+j *width,(char *)base+(j+1)*width
      我们先将base强转为char *类型,为什么呢?为什么不是int *,short *呢?
      我们知道内存中最小的单位是自己,而char *指针解引用只能访问一个字节,我并不需要知道具体是什么类型,我只需要知道数组一个元素的大小就行,通过(char *) base+j *width实际上找到了数组的一个元素width就是来表达大小的。
    2. swap函数
    swap((char*)base + j * width, (char*)base + (j + 1) * width,
    				width);
    

    我们需要传的参数其实就三个,元素1的地址,和元素2的地址,最后是元素的大小,为什么要这样做?

    void swap(char* e1,char * e2,  int width)
    {
    	char tmp = 0;
    	while (width--)
    	{
    		tmp = *e1;
    		*e1 = *e2;
    		*e2 = tmp;
    		e1++;
    		e2++;
    	}
    
    }`
    

    可以看到我们用char *来接收这两个地址,目的就是让字节让字节和字节交换,比如说一个结构体数组的一个元素的大小是20字节,那么我用字节为单位与另一个元素交换20次不就行了吗?这里的20不就相当于width吗?

    总结😈

    我们在这篇博客中从回调函数的概念到学会运用,再列举出qsort函数来帮助大家理解,并且也学会了这个强大的排序函数,最后我们还用冒泡排序来模拟出了一个可以排序任意类型数组的函数,可谓是收获颇多啊。
    完。
    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享

    【C语言】回调函数(qsort)与模拟实现,C语言,c语言,笔记,经验分享文章来源地址https://www.toymoban.com/news/detail-566397.html

    到了这里,关于【C语言】回调函数(qsort)与模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

    领支付宝红包 赞助服务器费用

    相关文章

    • C语言库函数之 qsort 讲解、使用及模拟实现

      我们在学习排序的时候,第一个接触到的应该都是冒泡排序,我们先来复习一下冒泡排序的代码,来作为一个铺垫和引入。 代码如下: 很简单的一种排序方法,但我们可以发现一个问题,那就是冒泡排序不够通用,它只能用于整型数组的排序,如果我要排序float类型,或者排

      2024年02月12日
      浏览(37)
    • C语言-指针进阶-qsort函数的学习与模拟实现(9.3)

      目录 思维导图: 回调函数 qsort函数介绍 模拟实现qsort 写在最后: 什么是回调函数? 回调函数是一个通过函数指针调用的函数。 将一个函数指针作为参数传递给一个函数,当这个指针被用来调用所指向函数时, 我们就将此称为回调函数。 在举例之前,我们先学习一个C语言

      2024年02月15日
      浏览(53)
    • 【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式

      目录 1、函数指针数组 1.1、函数指针数组是什么?  1.2、函数指针数组的用途:转移表 2、扩展:指向函数指针的数组的指针 3、回调函数 3.1、回调函数介绍  3.2、回调函数的案例:qsort函数 3.2.1、回顾冒泡排序  3.2.1、什么是qsort函数? 函数指针数组 是什么?首先主语是 数

      2024年02月07日
      浏览(43)
    • 冒泡排序模拟实现qsort()函数

      要模拟qsort()函数,我们首先要知道qsort()函数的特点: 使用快速排序的方法。 适用于任何数据类型的排序。 但由于部分学者还没有学习快速排序算法,所以本篇博客采用冒泡排序来模拟功能类似于qsort()的函数bubble_sort。 C库对qsort()函数解释: 我们得到的关于qsort()函数参

      2024年02月16日
      浏览(52)
    • qsort函数的应用以及模拟实现

      🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介::介绍库函数qsort函数的模拟实现和应用 金句分享: ✨追光的人,终会光芒万丈.✨ 库函数查询网站(建议使用 旧版本 查询) 头文件: stdlib.h 功能介绍: 使用函数 确定顺

      2024年02月02日
      浏览(35)
    • 【C】回调函数和qsort详解

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

      2024年02月13日
      浏览(35)
    • 模拟实现qsort函数(采用冒泡排序的方式)

      前言: 之前我在C语言:指针详解【进阶】后篇中提到了 qsort函数 , qsort函数 作为一个库函数,在我们日常的代码编写中可能会用到,在上面提到的文章中我们也进行使用了这个函数,大家也了解了一些这个函数的使用方法,但我们作为学习者,我们不仅要会用,还要知道这

      2024年02月05日
      浏览(41)
    • C语言——qsort()函数_学习笔记

      qsort()函数是一个库函数,包含在头文件 stdliib.h中,用来对数据进行排序操作的函数,它可以排序 任意类型的数据 !!! qsort()函数排序是 从小到大 排序,内部是采用 快速排序 思想排序数据的。qsort()函数有四个参数,解释如下: 第一个参数 void* base 。类型是 void* 类型的,

      2024年02月09日
      浏览(37)
    • c语言用冒泡排序模拟实现qsort排序

      1、简单介绍冒泡排序 冒泡排序就是两两相邻元素进行比较,如果不满足顺序就进行交换。现有一组整数,将其用冒泡排序实现排序为升序。 假设有这样一组整数:9 8 7 6 5    由此可知,如果一个整型数组有num个元素,则需走num-1趟,若走在第i趟,则在第i趟内需要比较num-1

      2024年02月15日
      浏览(45)
    • 【再识C进阶2(中)】详细介绍指针的进阶——函数指针数组、回调函数、qsort函数

      💓作者简介: 加油,旭杏,目前大二,正在学习 C++ , 数据结构 等👀 💓作者主页:加油,旭杏的主页👀 ⏩本文收录在:再识C进阶的专栏👀 🚚代码仓库:旭日东升 1👀 🌹欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖        在这一篇博客中,我们要认识并理解 函数指

      2024年02月09日
      浏览(44)

    觉得文章有用就打赏一下文章作者

    支付宝扫一扫打赏

    博客赞助

    微信扫一扫打赏

    请作者喝杯咖啡吧~博客赞助

    支付宝扫一扫领取红包,优惠每天领

    二维码1

    领取红包

    二维码2

    领红包