(一)回调函数
我们把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。这句话是什么意思呢,回调函数又该如何去使用呢。
这里拿上一节完成的简单计算器代码说明,如下所示
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x – y;
}
int mlt(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}
void menu()
{
printf("…………………\\n");
printf("……1.Add………\\n");
printf("……2.Sub………\\n");
printf("……3.mlt……….\\n");
printf("……4.div……….\\n");
printf("……0.over……….\\n");
}
int main()
{
int a = 0;
int b = 0;
int input = 0;
int ret = 0;
do
{
menu();
printf("请选择:\\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = Add(a, b);
printf("%d\\n", ret);
break;
case 2:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = Sub(a, b);
printf("%d\\n", ret);
break;
case 3:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = mlt(a, b);
printf("%d\\n", ret);
break;
case 4:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = div(a, b);
printf("%d\\n", ret);
break;
case 0:
printf("退出游戏\\n");
break;
default:
printf("输入错误\\n");
break;
}
} while (input);
return 0;
}
我们之前就提到过,在switch语句中,有多个输入输出语句,这显的有点冗长多余,除了我们之前可以用函数指针数组来简化函数,我们这里也可以用回调函数来简化代码,这里我们需要创建一个新的函数Cal,将加减乘除运算函数的地址存入其中,当程序走到Cal函数时,我们需要选择我们所需要的运算,加减乘除分别对应,1,2,3,4,比如当我们在键盘上敲上1时,会调用加法函数来完成加法运算,而这时我们就可以把之前冗长重复的输入输出语句存放到Cal函数中,具体代码实现如下
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x – y;
}
int mlt(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}
void menu()
{
printf("…………………\\n");
printf("……1.Add………\\n");
printf("……2.Sub………\\n");
printf("……3.mlt……….\\n");
printf("……4.div……….\\n");
printf("……0.over……….\\n");
}
void Cal(int(*pf)(int,int))
{
int a = 0;
int b = 0;
int ret = 0;
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = pf(a, b);
printf("%d\\n", ret);
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:\\n");
scanf("%d", &input);
switch (input)
{
case 1:
Cal(Add);
break;
case 2:
Cal(Sub);
break;
case 3:
Cal(mlt);
break;
case 4:
Cal(div);
break;
case 0:
printf("退出游戏\\n");
break;
default:
printf("输入错误\\n");
break;
}
} while (input);
return 0;
}
(二)qsort函数
之前我们学过用冒泡排序来给一个数组里面的数字排列,但是有局限性,冒泡排序只能给整型变量排序,不能给字符或者其他变量排序,这时我们就可以学习一个新的函数,那就是qsort函数
qsort函数的使用一般格式包含4个部分,如下所示
int arr[] = { 1,2,7,4,3,8,3,1,9,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp);
//arr:指向待排序数组的第一个元素
//sizeof(arr):待排序数组的元素个数
//sizeof(arr[0]):每个元素的大小,单位是字节
//int_cmp:函数指针,指向的函数可以比较数组中的两个元素
所以在使用qsort函数时我们需要创建一个比较函数,比如我们要比较一个整型数组,创建一个int_cmp()比较函数,如下所示
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 – *(int*)p2);
}
int_cmp()里面的两个指针分别代表指向待排序的两个元素,用void类型是因为接受的变量有可能是整型,有可能是浮点型,也有可能是其他类型,所以用void来定义
如果p1<p2,那么返回<0的数
如果p1=p2,那么返回>0的数
如果p1>p2,那么返回>0的数
(int*)p代表强制类型转化,将p转化为整型类型,然后再*(int*),表示解引用,取到两个整型,将它们作对比,完整代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 – *(int*)p2);
}
int main()
{
int arr[] = { 1,2,7,4,3,8,3,1,9,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp);
//arr:指向待排序数组的第一个元素
//sizeof(arr):待排序数组的元素个数
//sizeof(arr[0]):每个元素的大小,单位是字节
//int_cmp:函数指针,指向的函数可以比较数组中的两个元素
for (i = 0; i < sz; i++)
{
//从小到大排序
printf("%d ", arr[i]);
}
}

上面是升序排序,如果想要降序排序只需将int_cmp函数里的p1,p2调换位置即可
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p2 – *(int*)p1);
}
int main()
{
int arr[] = { 1,2,7,4,3,8,3,1,9,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp);
//arr:指向待排序数组的第一个元素
//sizeof(arr):待排序数组的元素个数
//sizeof(arr[0]):每个元素的大小,单位是字节
//int_cmp:函数指针,指向的函数可以比较数组中的两个元素
for (i = 0; i < sz; i++)
{
//从小到大排序
printf("%d ", arr[i]);
}
}
我们再比较浮点数的大小,主函数部分和上述代码一样,但是比较函数float_cmp()部分与比较整型部分不同,我们不能直接将两个代比较的数相减,因为比如1-0.5,应该是返回0.5,也就是>0的数,但是浮点数转化成整数时会舍弃小数点后面的数字,直接返回0,所以我们用if比较大小,如果p1>p2,返回1,也就是>0的数,依次类推
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int float_cmp(const void*p1,const void*p2)
{
if (*(float*)p1 > *(float*)p2)
return 1;
else if (*(float*)p1 < *(float*)p2)
return -1;
else
return 0;
}
int main()
{
int i = 0;
float arr2[] = { 0,1.0,6.0,3.0,5.0,9.0 };
int sz = sizeof(arr2) / sizeof(arr2[0]);
qsort(arr2, sz, 4, float_cmp);
for (i = 0; i < sz; i++)
{
printf("%.2f ", arr2[i]);
}
return 0;
}

qsort函数也可以用来比较结构体中的内容,比如创建一个结构体如下
struct Stu
{
char name[20];
int age;
};
我们如果要比较结构体中的内容,我们需要选定一个要比较的类型,比如上述结构体中,我们可以分别按照年龄排序或者按照名字排序,比较名字大小就是比较字符串的长度,首先,我们选择按照年龄排序
1.比较函数:
int age_cmp(const void* p1, const void* p2)
{
return (*(struct Stu*)p1).age – (*(struct Stu*)p2).age;
}
2.主函数:
int main()
{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), age_cmp);
return 0;
}
3.完整代码:
struct Stu
{
char name[20];
int age;
};
int age_cmp(const void* p1, const void* p2)
{
return (*(struct Stu*)p1).age – (*(struct Stu*)p2).age;
}
int main()
{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), age_cmp);
return 0;
}
通过调试可以发现数组中的内容按照年龄从小到大排序:
其次,我们再选择按照姓名排序
按照姓名排序就是比较字符串大小,比较字符串大小我们用到strcmp函数,它需要头文件<string.h>,它的使用方法如下所示
#include <stdio.h>
#include <string.h>
int main() {
char s1[] = "abc";
char s2[] = "abd";
char s3[] = "abc";
int res1 = strcmp(s1, s2); // c < d → 返回负数
int res2 = strcmp(s1, s3); // 完全相等 → 返回0
printf("res1 = %d\\n", res1);
printf("res2 = %d\\n", res2);
return 0;
}
将两个字符串用逗号隔开,如果第一个字符串>第二个,返回>0的数,如果相等,则返回0,如果小于,则返回小于0的数
字符串大小比较的规则:
1.从左到右逐个字符对比,找到第一个不相等的字符就停止比较,后续字符不再参与
2.比较依据:单个字符的 ASCII 数值大小。
若当前字符 str1[i] > str2[i] → 字符串 1 更大
若当前字符 str1[i] < str2[i] → 字符串 2 更大
3.前面所有字符全都相等时,再比较字符串长度:
短字符串先遇到结束符 \\0,则短的更小。
例:"app" < "apple"
数字(48~57) < 大写字母A~Z(65~90) < 小写字母a~z(97~122)
了解到字符串大小比较规则,和strcmp的使用后,我们来完成按照姓名顺序的排序
1..比较函数:
int name_cmp(const void* p1, const void* p2)
{
return strcmp((*(struct Stu*)p1).name, (*(struct Stu*)p2).name);
}
2.主函数:
int main()
{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), name_cmp);
return 0;
}
3.完整代码:
struct Stu
{
char name[20];
int age;
};
int name_cmp(const void* p1, const void* p2)
{
return strcmp((*(struct Stu*)p1).name, (*(struct Stu*)p2).name);
}
int main()
{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), name_cmp);
return 0;
}
通过调试可以发现数组中的内容按照姓名从小到大排序:



