萌新的学习笔记,写错了恳请斧正。
目录
回调函数
泛式编程
qsort
qsort是什么
比较函数怎么写
使用qsort排序各种数据
模仿qsort写一个万能冒泡排序
当一个函数a的参数含有函数指针时,这个函数指针在使用时所指向的函数b(被该函数调用的函数)就是回调函数。注意回调函数并不是由函数a决定调用的函数,而是在调用函数a时决定使用的函数。
比方说,上一篇笔记中的计算器如果不用转移表实现,也可以这样:
#include
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
void calc(int(*pf)(int, int))
{
int ret = 0;
int x, y;
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
int main()
{
int input = 1;
do
{
printf("************************");
printf("**1:add**2:sub**********");
printf("**3:mul**4:div**0:exit**");
printf("************************");
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
calc(add);
break;
case 2:
calc(sub);
break;
case 3:
calc(mul);
break;
case 4:
calc(div);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
上方的calc函数的参数就是函数指针,在实际调用calc函数时提供的指针指向的函数就是回调函数
泛式编程就是在编程的时候尽量减少对特定数据类型的依赖。
比方说我们要写一个冒泡排序的函数,如下:
void sortofup(int s[], int n)
{
_Bool flag = true;
while (flag)
{
flag = false;
for (int i = 0; i < n - 1; i++)
if (s[i] > s[i + 1])
{
s[i] ^= s[i + 1];
s[i + 1] ^= s[i];
s[i] ^= s[i + 1];
flag = true;
}
}
}
上面就是对一个长度为n的数组的冒泡排序的实现
但是这个数组只能是整型数组。如果我们需要对浮点型数组排序,就需要再写一个浮点型数组的冒泡排序;如果我们要对长整型数组排序,就需要再写一个长整型数组的冒泡排序。这就十分死板。
而在库函数中,有一个函数叫qsort,它能对任意类型的数据进行快速排序,十分灵活
这就是泛式编程的应用,那么具体是怎么实现的呢?不急,待会讲。
qsort是stdlib.h(或search.h)头文件中定义的一种排序函数
qsort没有返回值(void),而其参数有4个:
在使用qsort时,我们需要排序某种类型的数据,就先写一个对该类型数据的比较函数。这个函数的参数是两个泛型指针,返回值是整型,而返回值的正负或零代表了比较的结果是大于小于或等于(第一个参数更大时返回正数则递增排序,反之则为递减排序,如果有其他比较排序规则也可以自行添加,比如奇偶交叉等)。比方说,比较两个整型数据,我们可以这么写:
int Comp_int(const void* a, const void* b)
{
int ia = *(int*)a;
int ib = *(int*)b;
if (ia > ib)
return 1;
if (ia < ib)
return -1;
else
return 0;
}
上方代码我们将a与b强制类型转换为整型指针并解引用,这样我们就得到了整型a与b的值,并可以加以比较。
注意如果指针传参时我们不希望原值被改变,无论函数中有没有会对原值产生影响的内容,我们都最好在参数前加一个const进行限制,这是一个好习惯。
我们也可以进一步根据实际情况简化比较函数:
int Comp_int(void* a, void* b)
{
return *(int*)a - *(int*)b;
}
#include
#include
#include
#include
struct Stu
{
char Name[20];
short ID;
};
int Comp_int(void* a, void* b)
{
return *(int*)a - *(int*)b;
}
int Comp_flt(void* a, void* b)
{
int c = 0;
if ((c = *(float*)a - *(float*)b) == 0)
return 0;
return c > 0 ? 1 : -1;
}
int Comp_struct_by_ID(void* a, void* b)
{
return ((struct Stu*)a)->ID - ((struct Stu*)b)->ID;
}
int main()
{
//@@@@@排序整型数组并打印@@@@@
int arr_int[] = { 2,5,78,3,31,6,7865,34,1,7,8,132,4,7,5 };
size_t len_int = sizeof arr_int / sizeof arr_int[0];
qsort(arr_int, len_int, sizeof arr_int[0], Comp_int);
for (int i = 0; i < len_int; i++)
printf("%d ", arr_int[i]);
printf("\n");
//@@@@@排序浮点型数组并打印@@@@@
float arr_flt[] = { 12.5,3.5,6.2,9,1.1,98.2,0.4,-9.3,14.7 };
size_t len_flt = sizeof arr_flt / sizeof arr_flt[0];
qsort(arr_flt, len_flt, sizeof arr_flt[0], Comp_flt);
for (int i = 0; i < len_flt; i++)
printf("%.2f ", arr_flt[i]);
printf("\n");
//@@@@@排序结构体数组并打印@@@@@
struct Stu arr_struct[] = { {"zhangsan",2},{"lisi",1},{"wangwu",3} };
size_t len_struct = sizeof arr_struct / sizeof arr_struct[0];
//按id排序
qsort(arr_struct, len_struct, sizeof arr_struct[0], Comp_struct_by_ID);
for (int i = 0; i < len_struct; i++)
printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
printf("\n");
//按首字母排序
qsort(arr_struct, len_struct, sizeof arr_struct[0], strcmp);
for (int i = 0; i < len_struct; i++)
printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
printf("\n");
return 0;
}
上方代码按首字母排序的strcmp函数后面笔记会讲,是string.h提供的函数
我们可以模仿qsort来实现一个万能的冒泡排序
只需要做三件事:
具体实现如下:
#include
#include
#include
struct Stu
{
char Name[20];
short ID;
};
int Comp_int(void* a, void* b)
{
return *(int*)a - *(int*)b;
}
int Comp_flt(void* a, void* b)
{
int c = 0;
if ((c = *(float*)a - *(float*)b) == 0)
return 0;
return c > 0 ? 1 : -1;
}
int Comp_struct_by_ID(void* a, void* b)
{
return ((struct Stu*)a)->ID - ((struct Stu*)b)->ID;
}
void bsort(void* base, size_t count, size_t size, int(*comp_f)(void*, void*))
{
int flag = 1;
for (int k = 0; k < count; k++)
{
flag = 1;
for (int i = 0; i < count - k - 1; i++)
{
if (comp_f((char*)base + size * i, (char*)base + size * (i + 1)) > 0)
{
for (int j = 0; j < size; j++)
{
char* a = (char*)base + size * i + j;
char* b = (char*)base + size * (i + 1) + j;
char c;
c = *a, *a = *b, *b = c;
}
flag = 0;
}
}
if (flag)
break;
}
}
int main()
{
int arr_int[] = { 2,5,78,3,31,6,7865,34,1,7,8,132,4,7,5 };
size_t len_int = sizeof arr_int / sizeof arr_int[0];
bsort(arr_int, len_int, sizeof arr_int[0], Comp_int);
for (int i = 0; i < len_int; i++)
printf("%d ", arr_int[i]);
printf("\n");
float arr_flt[] = { 12.5,3.5,6.2,9,1.1,98.2,0.4,-9.3,14.7 };
size_t len_flt = sizeof arr_flt / sizeof arr_flt[0];
bsort(arr_flt, len_flt, sizeof arr_flt[0], Comp_flt);
for (int i = 0; i < len_flt; i++)
printf("%.2f ", arr_flt[i]);
printf("\n");
struct Stu arr_struct[] = { {"zhangsan",2},{"lisi",1},{"wangwu",3} };
size_t len_struct = sizeof arr_struct / sizeof arr_struct[0];
bsort(arr_struct, len_struct, sizeof arr_struct[0], Comp_struct_by_ID);
for (int i = 0; i < len_struct; i++)
printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
printf("\n");
bsort(arr_struct, len_struct, sizeof arr_struct[0], strcmp);
for (int i = 0; i < len_struct; i++)
printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
printf("\n");
return 0;
}