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]);
}
}