【C语言进阶】回调函数
文章目录
八、回调函数
1 介绍
回调函数就是一个通过函数指针调用的函数。(函数指针实现回调函数)
如果把函数的地址作为参数传递给另一个函数,当这个函数指针被用来调用其所指向的函数时,就说这是回调函数。
回调函数不是由该函数的实现方法直接调用,而是在特定的的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行相应。
示例:
A <------> B(*pfA)
//将A函数的地址传递给B函数,在B函数内部通过函数指针调用A函数,那么B函数就被称为回调函数。
2 qsort()
函数
qsort()
是C语言的一个标准库函数,定义在<stdlib.h>
头文件中。
qsort()
函数用于对数组进行快速排序,它是一个通用的排序函数,支持对不同类型的元素进行排序。
2.1 函数原型
void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
2.2 功能
-
对长度为
num
的数组的元素进行排序,每个元素的字节长度为size
。 -
此函数使用的排序算法通过调用指定的函数
compar
来比较元素对,并将指向它们(元素)的指针作为参数。 -
该函数不返回任何值,而是通过重新排序其元素来修改指向的数组的内容。
2.3 函数参数
① base
指向要排序的数组的第一个元素的地址。
② num
指向的数组中的元素个数。是无符号整数类型(size_t <–> unsigned)。
③ size
数组中每个元素的大小(以字节为单位)。是无符号整数类型(size_t <–> unsigned)。
④ compar
指向函数的指针,用于自定义排序规则。指针指向比较两个元素的函数。函数原型:
int compar (const void* p1, const void* p2);
compar()
函数通过返回值来确定当前比较的两个数据的顺序,如下表所示。
返回值 | 意义 |
---|---|
<0 | p1 指向的元素位于 p2 指向的元素之前 |
0 | p1 指向的元素等同于 p2 指向的元素 |
>0 | p1 指向的元素在 p2 指向的元素之后 |
2.4 返回值
无,qsort()
函数没有返回值,函数执行完成后,base
数组中存储的就是有序序列。
2.5 qsort()
函数的使用
代码示例:
#include<stdio.h>
#include<stdlib.h>
//qsort函数在使用前必须先实现一个比较函数
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);//先强制类型转换,然后再进行解引用,最后相减比大小
}
int main()
{
int arr[10] = { 1,3,5,7,9,2,4,6,8,10 };
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);//回调函数
int i = 0;
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);//1 2 3 4 5 6 7 8 9 10
}
printf("\n");
return 0;
}
解释说明:
1 qsort()
是C语言的一个标准库函数,定义在 <stdlib.h>
头文件中。
2 void*
类型的指针,不能直接进行解引用或者进行指针运算;但是却可以接收任意类型的地址。
3 模拟 qsort()
函数实现冒泡排序
使用回调函数,模拟实现 qsort
函数,采用冒泡排序的方式。
代码示例:
#include<stdio.h>
//自定义比较函数
int int_cmp(const void* p1, const void* p2)
{
//返回两数之差
return *((int*)p1) - *((int*)p2);//void*指针不能直接解引用
}
//字节大小为size的两个元素进行交换的函数
void my_swap(char* p1, char* p2, size_t size)
{
int i = 0;
for (i = 0; i < size; i++)//每次交换一个数
{
//一个字节一个字节进行交换,大小端存储不影响
char temp = *(p1 + i);
*(p1 + i) = *(p2 + i);
*(p2 + i) = temp;
}
}
//qsort()函数以冒泡排序的方式实现
void my_bubble(void* base, size_t num, size_t size, int(*cmp)(const void*, const void*))
{
int i = 0;
for (i = 0; i < num - 1; i++)//排序躺数
{
int j = 0;
for (j = 0; j < num - 1 - i; j++)//每趟排序对数
{
//交换成升序序列
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
{
//如果 下标为j的元素 > 下标为j+1的元素,就发生交换
my_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
int main()
{
//模拟实现qsort()函数,采用冒泡排序的方式
int arr[10] = { 1,3,5,7,9,2,4,6,8,10 };
my_bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
//打印排序后的数组元素
int i = 0;
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
解释说明:
1 (char*)base + j * size
base
为 void
类型的指针,不能直接解引用或直接进行指针运算,所以必须先强制类型转换为 char
类型的指针;类型决定指针解引用访问多少字节的空间,一个 char
类型的指针进行解引用能访问内存中一个内存单元。
j * size
表示在 (char*)base
的基础上,跳过 j
个字节的空间(+ 表示向后)。
2 函数原型说明:
//比较两个数的大小,返回的是两个数的差值
int int_cmp(const void* p1, const void* p2);
//交换字节大小为size的两个数,一次交换一个字节大小()函数以
void my_swap(void* p1, void* p2, int size);
//模拟qsort()函数以bubble冒泡排序的形式实现
void my_bubble(void* base, int count, int size, int(*cmp)(void*, void*));
// 数组名 数组长度 元素类型 比较函数的地址(函数指针实现回调函数)
3 交换函数:
逐字节交换任意类型的两个数,一次交换一个内存空间的内容。
比如:int
类型占4个内存空间,那就交换4次。
总结:
本节介绍了什么是回调函数;给出了 qsort()
函数的使用;最后通过模拟 qsort()
函数实现了冒泡排序。
感谢您的阅读!如有任何错误,欢迎您的批评指正!