”回调函数与qsort函数及其模拟“宝典

hello,大家好,又见面啦,窝是脆皮炸鸡。这一节的内容是回调函数以及qsort的内容,真滴比之前的内容难好多,加油,不会就问。坚持就是胜利,不要放弃喔!!!

真的,慎入!!

ps:点赞+关注,追番不迷路。

在这里插入图片描述

1. 回调函数是什么?

简单来说,通过函数地址调用的函数,就是回调函数。

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

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数

回调函数不是由该函数的实现方直接调用(即不是写了这个函数,然后直接通过函数名调用),而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

在上节内容的结尾,比较麻烦的哪一个代码中,几乎是重复的,只有调用的函数不一样。
在这里插入图片描述

我们可以再自定义一个函数calc,将加减乘除的函数指针作为参数传给函数calc,用这个函数指针调用其所指向的函数(加减乘除函数)。

void calc(int (*pf)(int, int))
{
	printf("请输入两位操作数\n");
	int x, y, r = 0;
	scanf("%d %d", &x, &y);
	int r = pf(x, y);
	printf("计算结果是%d\n", r);
}

繁琐的那一块儿,改为:

case 1:
	calc(add);
case 2:
	calc(sub);
case 3:
	calc(mul); 
case 4:
	calc(div);

2. qsort使用举例(使用的是快速排序)

qsort是一个库函数,可以对任意类型的数据进行排序。(默认升序)
使用qsort需要包含头文件:#include<stdlib.h>

之前我们学过冒泡排序,但是它只可以对整数进行排序。(不能对浮点数,字符串,字符数组,结构体进行排序)

在这里插入图片描述

void qsort(void* base,  //指向待排序数组的第一个元素的指针(首元素地址)
           size_t num,  //(base指向的)数组的元素个数
           size_t size, //(base指向的)数组中的元素的字节大小
           int (*compar)(const void*, const void*)); //从*先和compar结合,可看出是指针。指向函数,且这个函数的返回类型是int。这里写的是函数地址
           //函数指针---给这个函数传递两个函数的指针(地址)      
               //compar这个指针指向两个指针:一个函数(比较两个元素的函数)
                        //别忘了,()里面是参数
void qsort(数组首元素指针,元素个数,元素大小,接收函数)

易错点:
比较整数,浮点数大小:可以用<.<=,>,>=,==,!=
比较字符串的大小:应该使用strcmp
比较结构体的大小:

当真正开始比较各种类型数据时,你会发现:其实比较的趟数,一趟比较多少对,这两个是不变的。(只是比较方式有差异)
那如何比较各种不同的数据嘞?如果你想利用qsort比较字符串,那你得写比较字符串的函数,然后传给qsort。(想比较什么,就给qsort函数传递比较什么的函数)

在这里插入图片描述

由上图可知:
如果p1指向的元素>p2指向的元素,返回的值>0
如果p1指向的元素=p2指向的元素,返回的值=0
如果p1指向的元素<p2指向的元素,返回的值<0

先给大家举个简单的例子:比较整数

#include<stdio.h>
#include<stdlib.h>
//函数的声明
int cmp_int(const void* p1, const* p2);
print(int* arr, int sz);

//主函数
int main()
{
	int arr[] = { 1,3,5,8,0,99,95,33 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//写一个qsort函数用来比较元素
	qsort(arr, sz,   sizeof(arr[0]),   cmp_int);
	             //第一个元素的字节大小
	//写一个print函数将排好序的数组打印出来
	print(arr, sz);
	return 0;
} 


//两个函数的定义
int cmp_int(const void* p1, const* p2)//是在比较什么呢?比较p1,p2指向的元素
            //参数要完全按照要求来写
{
	//此处不能直接解引用p1和p2,因为void*不能接引用
	//p1原本的类型是void*,我们可以强制类型转换,将p1的类型强制转换为int*
	//想比较哪种类型,就将它强制转换为哪种类型
	if ((*(int*)p1) > (*(int*)p2))  //切记:先将指针类型转换,再解引用
		return 1; //返回的数字>0即可
	else if ((*(int*)p1) < (*(int*)p2))
		return -1;
	else if ((*(int*)p1) = (*(int*)p2))
		return 0;
}
print(int* arr, int sz)
{
	int index = 0;
	for (index = 0; index < sz; index++)
	{
		printf("%d ", arr[index]);
	}
}

再给大家举一个例子:比较字符大小(这一次没有注释,很清晰)

#include<stdio.h>
#include<stdlib.h>
int cmp_int(const void* p1, const* p2);
void print(int* arr, int sz);

int main()
{
	char arr[] = "gfedcba";
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int); //函数
	print(arr, sz); //函数
	return 0;
}


#include<string.h>
int cmp_int(const void* p1, const* p2)
{
    return (  ((char*)p1))
	return strcmp(((char*)p1), ((char*)p2));
	               字符串大小用strcmp比较
	//如果p1指向的元素<p2指向的,返回值<0
	//如果p1指向的元素>p2指向的,返回值>0
	//如果p1指向的元素=p2指向的,返回值=0
}
void print(char* arr, int sz)
{
	int index = 0;
	for (index = 0; index < sz; index++)
	{
		printf("%c ", arr[index]);
	}
}

比较结构体的例子(有名字,有数字,看你自己想比较什么)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//演示比较字符吧

struct jiegou
{
	char name[20];
	int age;
};
int cmp(const void* p1, const void* p2)
{
	return (strcmp(((struct jiegou *)p1)->name, ((struct jiegou *)p2)->name));
}
void print(struct jiegou* sss, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s ", sss[i].name);
	}
}


int main()
{
	struct jiegou sss[] = { {"wang",20},{"hou",21},{"yao",99} };
	int sz = sizeof(sss) / sizeof(sss[0]);
	qsort(sss, sz, sizeof(sss[0]), cmp);
	print(sss, sz);
}

3. qsort函数的模拟实现

我们可以尝试将最初的bubble冒泡排序模拟成qsort函数

在这里插入图片描述

接下来修改if语句
在这里插入图片描述
最终修改为:

if( (  cmp(((char*)base)+j*width,((char*)base)+(j+1)*width )  ) >0)

整个代码是这样的:(比较难的部分会有注释的)

#include<stdio.h>
#include<stdlib.h>
void swap(char* buf1, char* buf2);
void bubble_moni(void* basz, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2));
void print(int* arr, int sz);
int cmp_char(const void* p1, const void* p2);
int main()
{
	char arr[] = "gfedcba";
	int sz = sizeof(arr) / sizeof(arr[0]);
	//通过bubble_char来将字符排序
	bubble_moni(arr, sz, sizeof(arr[0]), cmp_char);
	//通过print函数打印出排序好的数组
	print(arr, sz);
}
int cmp_char(const void* p1, const void* p2)
{

	return (        (*((char*)p1)) - (*((char*)p2))              );
}

void bubble_moni(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
          //接收不明类型的数组  元素个数    元素大小        函数指针
{
	//比较的趟数
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - 1 - i; j++)
		{
			if ((cmp(((char*)base) + j * width, ((char*)base) + (j + 1) * width)) > 0  ) //比较两元素
			cmp()是一个函数,括号内只是放了两个元素的地址,通过返回值判断是否进入if
			{
			//进入if后,通过swap函数交换两个值
				swap(((char*)base) + j * width, ((char*)base) + (j + 1) * width,width);//将其交换
			}
		}
	}
}
void swap(char* buf1, char* buf2,size_t width)
{         //           //
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char temp = 0;
		//
		temp = *buf1;
		*buf1 = *buf2;
		*buf2 = temp;
		buf1++;
		buf2++;
	}
}
void print(char* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%c ", arr[i]);
	}
}
  • 39
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值