六、回调函数与闭包
1 回调函数
1.1 C库函数-qsort()
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
参数
- base – 指向要排序的数组的第一个元素的指针。
- nitems – 由base指向的数组中元素的个数。
- size – 数组中每个元素的大小,以字节为单位。
- compar – 用来比较两个元素的函数。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
static int
str_compare(const void *s1, const void *s2)
{
char *str1 = *(char **)s1;
char *str2 = *(char **)s2;
printf("str1 = %s str2 = %s\n", str1, str2);
size_t l1 = strlen(str1);
size_t l2 = strlen(str2);
if(l1 > l2)
return 1;
else if(l1 == l2)
return 0;
else
return -1;
}
int
main(int argc, char const *argv[])
{
char *str_array[5] = {"da", "af", "daf", "d", "abcde"};
qsort(str_array, 5, sizeof(char *), str_compare);
for(int i = 0; i < 5; i++)
printf("%s ", str_array[i]);
printf("\n");
return 0;
}
分析 qsort函数根据二分法,依次两个两个变量传入到str_compare函数(用户自定义的比较函数)。具体实现步骤是先把空指针转换成需要比较数据类型指针,比较之后大于返回1,小于返回-1,这样是正排序。如果大于返回-1,小于返回1,这样是负排序。
1.2 闭包(Closure)概念
从上一节,我们通过函数指针向qsort函数传入了一个函数str_compare,这个函数被成为回调函数,但是它还有一个比较深奥的名字“闭包”。 所谓闭包,就是一个函数加上它所访问的所有非局部变量,而所谓”非局部变量“,表示这些变量对于那个函数而言既非局部变量,也非全局变量。 我们向qsort传入函数str_compare,它所接受排序数据集合中的2个元素,而且2个元素对于str_compare而言,即非全局变量,也非局部变量,因此str_compare与这2个参数形成了一个闭包。 在许多动态语言中,闭包通常也被昵称为”函数是第一类对象“,即函数与那些语言中基本类型具有相同的权利,例如函数可以存储在变量中,可以作为实参传递给其他函数,还可以作为其他函数的返回值。
1.3 C语言实现闭包
#include <stdio.h>
#include <math.h>
#include <string.h>
typedef int (*Func) (void *, void *);
static void
compare (void *a, void *b, Func callback)
{
int r = callback (a, b);
if (r == -1)
printf ("a < b\n");
else if (r == 0)
printf ("a = b\n");
else
printf ("a > b\n");
}
static int
float_compare (void *a, void *b)
{
float *f1 = (float *)a;
float *f2 = (float *)b;
if (*f1 > *f2)
return 1;
else if (fabs (*f1 - *f2) <= 10E-6)
return 0;
else
return -1;
}
static int
str_compare (void *a, void *b)
{
size_t len1 = strlen ((char *)a);
size_t len2 = strlen ((char *)b);
if (len1 > len2)
return 1;
else if (len1 == len2)
return 0;
else
return -1;
}
int
main (void)
{
float a = 123.567;
float b = 222.222;
Func func = float_compare;
compare (&a, &b, func);
char *s1 = "hello world!";
char *s2 = "hello!";
func = str_compare;
compare (s1, s2, func);
return 0;