1.回调函数
回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数
时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。我们在上一讲的calc函数就是回调函数,因为我们在计算器的模拟实现中有些代码时重复的,所以我们将其包装成一个函数,让其每次使用时进行调用。
2.qsort排序
我们在之前学过冒泡排序,但是我们的冒泡排序只能排序整型数据,而这个qsort可以排序任意函数。
1.qsort的参数
有四个参数,第一个参数是指向需要排序的指针也就是数组的首元素地址,第二个参数是需要排序元素的个数,第三个参数是每个元素的大小,最有一个参数是我们给定一个排序方式,且这个排序方式的返回值为大于0、小于0,或等于0.
2.qsort头文件
qsort的头文件为<stdlib.h>
3.qsort排序演示
#include<stdio.h>
#include<stdlib.h>
int sort(const void* p1, const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
void print(int* pt, int num)
{
for (int i = 0; i < num; i++)
{
printf("%d ", pt[i]);
}
printf("\n");
}
int main()
{
int arr[5] = { 5,3,4,1,2 };
size_t num = sizeof(arr) / sizeof(arr[0]);
print(arr, num);
qsort(arr, num, sizeof(arr[0]), sort);
print(arr,num);
return 0;
}
我们的sort函数就是我们给定的排序规则,void*的指针不能直接解引用,所以我们将其强制类型转换为int* 这样我们就可以找到数组的元素了,p1>p2返回大于0的值,p1=p2返回0,p1<p2返回小于0的值。为了方便观察我们在排序前和排序后都对arr进行打印,究竟排序成功了吗?
我们来看看结果:
这个地方我们是以升序排序的,那怎么降序排序呢?其实只要在我们给定的规则上改动即可,我们的sort函数的指针位置调换即可。
我们再次运行试试看:
因为qsort库函数的参数是viod*的指针,所以我们可以传任意指针。那么如果我们想排序结构体是否可以用qsort排序呢?
4.qosrt排序结构体
在这之前我们先来学习一个库函数strcmp,他是用来专门比较字符串的,比较规则是字符所对应的ASCLL码值进行比较的。
它有两个参数都是char*,所以我们只需要给它喜欢传参即可,这个指针也就指向要比较字符串的指针,一般为我们用其数组名。const作为它的参数的原因是为了增加代码的安全性,我们只是为了比较,并不想改变字符串的内容,所以我们加上const,这样我们如果写错了要改变字符串的内容,编译器就会报错。它的头文件为<string.h>。
它的返回值也刚刚好满足qsort的第四参数的规则。
演示如下:
struct Stu
{
char name[15];
int age;
};
int sort(const void* p1, const void* p2)
{
return strcmp( (char*) p1, (char*) p2);
}
void print(struct Stu *pt,size_t num)
{
for (int i = 0; i < num; i++)
{
printf("%s %d ", pt->name, pt->age);
pt++;
}
printf("\n");
}
int main()
{
struct Stu s[] = { {"zhang",13},{"chen",19},{"qing",17} };
size_t num = sizeof(s) / sizeof(s[0]);
print(&s, num);
qsort(s, num, sizeof(s[0]), sort);
print(&s,num);
return 0;
}
结构体指针是不需要解引用的,直接->就可以找到对应成员。我们为了好观察排序前排序后都进行打印。
结果如下:
我们可以看到确实是按照ASCLL码值的大小来排序的,z的ASCLL码值大于c、q的ASCLL码值。
我们可以思考下怎样将冒泡排序进行改进,让其能够排序任意类型的数据。