深入理解C语言指针(四):回调函数与qsort 1. 什么是回调函数 回调函数是通过函数指针传递给另一个函数,并在合适时机被调用的函数。它把“固定流程”和“可变行为”分离开。
1 2 3 4 5 6 7 int add (int x, int y) { return x + y; }int sub (int x, int y) { return x - y; }int calculate (int x, int y, int (*operation)(int , int )) { return operation(x, y); }
调用:
1 2 int a = calculate(10 , 5 , add);int b = calculate(10 , 5 , sub);
calculate 不关心具体运算,只负责组织调用过程。
2. qsort函数 qsort 声明在 <stdlib.h> 中:
1 2 void qsort (void *base, size_t count, size_t size, int (*compare)(const void *, const void *)) ;
参数含义:
base:待排序数据首地址;
count:元素个数;
size:每个元素的字节数;
compare:比较函数。
比较函数返回值约定:小于0表示第一个元素应在前;等于0表示相等;大于0表示第二个元素应在前。
3. 整数排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <stdlib.h> int compare_int (const void *left, const void *right) { int a = *(const int *)left; int b = *(const int *)right; return (a > b) - (a < b); } int main (void ) { int arr[] = {9 , 1 , 5 , 3 , 7 }; size_t count = sizeof (arr) / sizeof (arr[0 ]); qsort(arr, count, sizeof (arr[0 ]), compare_int); for (size_t i = 0 ; i < count; ++i) printf ("%d " , arr[i]); return 0 ; }
不建议直接 return a - b;,因为极端值相减可能发生有符号整数溢出。
4. 结构体排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <string.h> struct Student { char name[20 ]; int age; }; int compare_age (const void *left, const void *right) { const struct Student *a = left; const struct Student *b = right; return (a->age > b->age) - (a->age < b->age); } int compare_name (const void *left, const void *right) { const struct Student *a = left; const struct Student *b = right; return strcmp (a->name, b->name); }
同一批数据只需更换比较函数,即可按不同字段排序。
5. 模拟通用排序的关键 通用排序不知道元素类型,因此使用 char * 按字节移动,通过 size 定位元素:
1 2 3 4 5 6 7 8 9 10 11 static void swap_bytes (void *a, void *b, size_t size) { unsigned char *x = a; unsigned char *y = b; while (size--) { unsigned char tmp = *x; *x++ = *y; *y++ = tmp; } }
1 2 3 4 5 6 7 8 9 void generic_bubble_sort (void *base, size_t count, size_t size, int (*compare)(const void *, const void *)) { char *data = base; for (size_t end = count; end > 1 ; --end) for (size_t i = 0 ; i + 1 < end; ++i) if (compare(data + i * size, data + (i + 1 ) * size) > 0 ) swap_bytes(data + i * size, data + (i + 1 ) * size, size); }
6. 总结 回调的本质是把行为当作参数传递。qsort 通过 void *、元素大小和比较回调实现类型无关的排序,这也是C语言实现泛型接口的重要方式。
Lichermione
天行健,君子以自强不息;
地势坤,君子以厚德载物。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 LichermioneX 的博客 !