一、作者声明:
标题中的可爱纯纯是用来凑字数,没有特殊含义,因为可爱的平台不让用四个字作为标题!
如果平台允许我甚至想用两个字作为标题——《回调》!或者直接一个字——《调》!
二、什么回调函数?
通过函数指针调用的函数就是回调函数。
如果把函数的指针(地址)作为参数传给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外一方调用的,用于对该事件或条件的响应。
三、库函数qsort为例,讲解回调函数
qsort函数:快速排序函数
qsort是一个库函数,底层使用的是快速排序的方式,对数据进行排序。该函数可以直接使用,能对任意类型的数据进行排序。
包含于头文件:
#include<stdlib.h>
函数原型:
void qsort (void* base, size_t num, size_t size, int (*compar)(const void* e1,const void* e2))
参数解析:
void *base是待排序数组第一个元素的地址(起始地址)
size_t num是待排序数组的大小(元素个数)
size_t num是待排序数组元素的大小(每一个元素的字节大小)
int (*compar)(const void* e1,const void* e2)是函数指针,指向比较函数(不同类型数据的比较方法不同,因此需要自定义比较方法),该函数返回值为int类型,参数为e1,e2,分别是待比较两个元素的地址。返回值要求:
若e1指向的元素大于e2指向的元素,则返回大于0的数字;若相等,则返回0;若小于,则返回小于0的数字。
(注1:正是因为有了compar比较函数,qsort函数才能排序任意类型的数据)
(注2:void *类型指针不能直接解引用,也不能加减整数,它是用来存放任意类型数据的地址,使用时需要强制类型转换)
实例代码1(排序整型数据):
void Printnums(int* nums, size_t size)//打印整型数组函数 { int i = 0; for (i = 0; i < size; i++) { printf("%d ", nums[i]); } } int cmp_int(const void* e1, const void* e2)//整形数据的比较函数 { return *(int*)e1 - *(int*)e2;//无具体类型指针先强制类型转换,再解引用 } int main() { int nums[10] = { 10,9,8,7,6,5,4,3,2,1 }; qsort(nums, sizeof(nums) / sizeof(nums[0]), sizeof(nums[0]), cmp_int); //待排序数组起始地址;待排序数组元素个数;待排序数组每个元素的字节大小;数据比较函数 Printnums(nums, sizeof(nums) / sizeof(nums[0])); return 0; }
实例代码2(按年龄大小排序结构体数组):
struct stu { char name[20]; int age; }; void Print_struct_age(struct stu* arr,size_t size)//打印结构体数组中结构体成员变量—年龄 { for (int i = 0; i < size; i++) { printf("%d ", arr[i].age); } printf("\n"); } int cmp_struct_age(const void* e1, const void* e2)//按照年龄比较排序 { return ((struct stu*)e1)->age - ((struct stu*)e2)->age;//强制类型转换为结构体指针类型,不解引用利用->也可以访问成员变量 } int main() { struct stu s1 = { "Tom",29 };//结构体变量 struct stu s2 = { "Jerry",20 }; struct stu s3 = { "David",26 }; struct stu arr[] = { s1,s2,s3 };//结构体数组 Print_struct_age(arr, sizeof(arr) / sizeof(arr[0]));//打印年龄 qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), cmp_struct_age);//按年龄排序 Print_struct_age(arr, sizeof(arr) / sizeof(arr[0]));//打印年龄 return 0; }
实例代码3(按姓名首字母排序结构体数组):
struct stu { char name[20]; int age; }; void Print_struct_name(struct stu* arr,size_t size)//打印结构体数组中结构体成员变量—姓名 { for (int i = 0; i < size; i++) { printf("%s ", arr[i].name); } printf("\n"); } int cmp_struct_name(const void* e1, const void* e2) { return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);//利用strcmp字符串比较函数,该函数的返回值要求和qsort中compar比较函数的返回值要求相同 } int main() { struct stu s1 = { "Tom",29 };//结构体变量 struct stu s2 = { "Siri",20 }; struct stu s3 = { "David",26 }; struct stu arr[] = { s1,s2,s3 };//结构体数组 Print_struct_name(arr, sizeof(arr) / sizeof(arr[0]));//打印姓名 qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), cmp_struct_name);//按姓名首字母排序 Print_struct_name(arr, sizeof(arr) / sizeof(arr[0]));//打印姓名 return 0; }
以上所有实例都是利用qsort快速排序函数对各种类型的数据排序,当我们向qsort函数参数传入比较函数compar地址时,该函数在qsort函数中通过其函数指针被调用,就是回调函数。