网站建设的系统分析,网络哪个公司便宜又好,团购网站建设报价,怎么查看网站备案信息文章目录 一、回调函数是什么二、qsort使用举例三、qsort函数的模拟实现 一、回调函数是什么 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针#xff08;地址#xff09;作为参数传递给另⼀个函数#xff0c;当这个指针被⽤来调⽤其所指向的函数 时#x… 文章目录 一、回调函数是什么二、qsort使用举例三、qsort函数的模拟实现 一、回调函数是什么 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针地址作为参数传递给另⼀个函数当这个指针被⽤来调⽤其所指向的函数 时被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的⽤于对该事件或条件进⾏响应。 第指针4中我们写的计算机的实现的代码中 switch 语句代码是重复出现的其中虽然执⾏计算的逻辑是区别的但是输⼊输出操作是冗余的有没有办法简化⼀些呢 int main()
{int input 0;int x 0;int y 0;int ret 0;do{menu();printf(请选择:);scanf(%d, input);switch (input){case 1:printf(请输入两个整数\n);scanf(%d %d, x, y);ret Add(x, y);printf(%d\n, ret);break;case 2:printf(请输入两个整数\n);scanf(%d %d, x, y);ret Sub(x, y);printf(%d\n, ret);break;case 3:printf(请输入两个整数\n);scanf(%d %d, x, y);ret Mul(x, y);printf(%d\n, ret);break;case 4:printf(请输入两个整数\n);scanf(%d %d, x, y);ret Div(x, y);printf(%d\n, ret);break;case 0:printf(退出游戏\n);break;default:printf(选择错误请重新选择\n);}}while (input);return 0;
} 因为 switch 语句的代码只有调⽤函数的逻辑是有差异的我们可以把调⽤的函数的地址以参数的形式传递过去使⽤函数指针接收函数指针指向什么函数就调⽤什么函数这⾥其实使⽤的就是回调函数的功能。 那具体怎么简化这段代码呢 能不能把这四段代码分装成一个函数把四个问题都解决。 设计一个 “中间商” 函数Calc void Calc(int(*pf)(int, int))
{int x 0;int y 0;int ret 0;printf(请输入两个整数\n);scanf(%d %d, x, y);ret pf(x, y);printf(%d\n, ret);
} 最后改造后的结果 int Add(int x, int y)
{return x y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}void menu()
{printf(********************************\n);printf(****** 1. add 2. sub *****\n);printf(****** 3. mul 4. div *****\n);printf(****** 0. exit *****\n);printf(********************************\n);
}void Calc(int(*pf)(int, int))
{int x 0;int y 0;int ret 0;printf(请输入两个整数\n);scanf(%d %d, x, y);ret pf(x, y);printf(%d\n, ret);
}int main()
{int input 0;do{menu();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);}} while (input);return 0;
} 简单来说把一个函数的地址传递给了函数指针在这个函数内部通过函数指针去调用他所指向的函数这种通过函数指针调用函数的方式被调用的函数就是回调函数。 二、qsort使用举例 qsort是C语言中的一个库函数这个函数是用来对数据进行排序的对任意类型的数据都能进行排序。quiick sort 底层使用的快速排序的思想 void qsort(void* base, //指向待排序数组的第一个元素的指针size_t num, //base指向数组中的元素个数size_t size,//base指向的数组中一个元素的大小单位是字节int (*cmp)(const void*, const void*) //函数指针 - 传递函数的地址//); 而在 compar 函数中的实现结果如下 int compareMyType (const void * a, const void * b)
{if ( *(MyType*)a *(MyType*)b ) return -1;if ( *(MyType*)a *(MyType*)b ) return 0;if ( *(MyType*)a *(MyType*)b ) return 1;
} 2.1 使用qsort函数排序整型数据 如果想使用 qsort 函数排序整型类型数据就得提供一个比较 2 个整型的比较函数 int cmp_int(const void* p1, const* p2)
{return(*(int*)p1 - *(int*) p2);
}int main()
{int arr[10] { 3,1,5,6,9,8,7,2,4,10 };int sz sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_int);for (int i 0; i sz; i){printf(%d , arr[i]);}return 0;
} 意思是如果想要比较两个“字符串”两个“结构体”等就提供相应的比较函数这样qsort就实现了可以比较任何类型数据的功能了。 再举个例子 2.2 使用qsort排序结构数据 首先创建一个结构体 #includestdio.h
#includestring.hstruct Stu //学⽣
{char name[20];//名字int age;//年龄
};int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)-name, ((struct Stu*)p2)-name);}int cmp_stu_by_age(const void* p1, const void* p2)
{ return ((struct Stu*)p1)-age - ((struct Stu*)p2)-age;
}void Swap(char* buf1, char* buf2, size_t width)
{int i 0;char tmp 0;for (i 0; i width; i){tmp *buf1;*buf1 *buf2;*buf2 tmp;buf1;buf2;}
}void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{int i 0;for (i 0; i sz - 1; i){int j 0;for (j 0; j sz - 1 - i; j){//if (arr[j] arr[j 1])if (cmp((char*)base j * width, (char*)base (j 1) * width) 0){Swap((char*)base j * width, (char*)base (j 1) * width, width);}}}
}void test3()
{struct Stu arr[] { {zhangsan, 20},{lisi,35},{wangwu, 18} };int sz sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);}void test4()
{struct Stu arr[] { {zhangsan, 20},{lisi,35},{wangwu, 18} };int sz sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);}int main()
{test3();test4();return 0;
}struct stu
{char name[20];int age;
}; 1. 假设按照姓名来比较 int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)-name, ((struct Stu*)p2)-name);//因为 p1 的类型是 void*所以我们要把它强制类型转换成struct Stu*注意这个转换是临时的所以要用括号括起来struct Stu*p1-name。
}void test1()
{struct Stu arr[] { {zhangsan, 20},{lisi,35},{wangwu, 18} };int sz sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);} 2. 假设按照年龄来比较 int cmp_stu_by_age(const void* p1, const void* p2)
{ return ((struct Stu*)p1)-age - ((struct Stu*)p2)-age;
}void test1()
{struct Stu arr[] { {zhangsan, 20},{lisi,35},{wangwu, 18} };int sz sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);} 最后进入主函数调试分别对 arr 进行监控 int main()
{test1();test2();return 0;
} 注意strcmp比较的不是字符串长度而是对应位置上字符的大小 三、qsort函数的模拟实现 在指针3的讲解中我们了解到冒泡排序的算法及引用并定义了代码 bubble_sort 函数。而了解了qsort这个库函数后我们能否可以将 buble_sort 函数改造成通用的算法可以排序任意类型的数据 答案肯定是可以的可以通过 qsort 的模仿实现。 前面讲到 qsort 是底层使用的快速排序而我们自己定义的 bubble_sort 是通过冒泡排序的思路实现排序不会有冲突。 代码如下 void Swap(char*buf1, char*buf2, size_t width)
{int i 0;char tmp 0;for (i 0; i width; i){tmp *buf1;*buf1 *buf2;*buf2 tmp;buf1;buf2;}
}void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{//趟数int i 0;for (i 0; i sz - 1; i){//一趟内部的两两比较int j 0;for (j 0; j sz-1-i; j){//if (arr[j] arr[j 1])//比较两个元素if(cmp((char*)basej*width, (char*)base(j1)*width)0){//交换两个元素Swap((char*)base j * width, (char*)base (j 1) * width, width);}}}
}接下里我们逐步分析 在 bubble_sort 的形参描写的过程 1.不清楚要排序的数据的类型所以用 void *base接收 2.base指向的数组的大小单位是字节用 size_t(无符号整型) 接收 3.base指向的数组中一个元素的大小单位是字节但是我们不清楚将来的数据类型是什么所以我们可以用宽度 width 接收 4.void*类型指针可以接受任何类型的地址可以写成 (*cmp)(const void* p1, const void* p2)) 返回类型是 int。 bubble_sort 中的逻辑算法 1.首先我们清楚在冒泡排序中的趟数和每一趟中所需要两两对比的对数是不会改变的不论数据类型是怎么样都是采取这种对比过程。 2.1需要改变就是 if ( ) 中的条件和交换过程 利用 cmp 的返回值是否大于零如果大于零说明前者大于后者则进行交换假设是升序排列。如果我们要使用冒泡排序的思路就要解决 arr[j] 和 arr[j 1] 这两个元素的地址传达。 2而我们只知道首元素 base 的地址以及一个元素的宽度 width但具体的大小不清楚。假设是一组整型数组 int arr[10] { 3,1,5,6,9,8,7,2,4,10 } ,width 就等于 4所以我们可以把 base 强制类型转换成 char*base当指向首元素地址 3时为 char*base0指向下个元素地址 1时为char*basewidth*(01)那么就可以写成 if(cmp((char*)basej*width, (char*)base(j1)*width)0) 3接下里就进入交换 Swap((char*)base j * width, (char*)base (j 1) * width, width) buf1 和 buf2相差的是一个 width4个字节那交换的时候是否就可以创建一个 int tmp 0 进行交换呢在void Swap函数中并不知道buf1.2是什么类型只知道两者之间相差一个元素是 4 个字节所以只能一个字节一个字节得交换四对字节分别交换两个整型就交换成功了。 最后我们把上述的结构体数据利用 bubble_sort 排序看是否成功 #includestdio.h
#includestring.hstruct Stu //学⽣
{char name[20];//名字int age;//年龄
};int cmp_stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)-name, ((struct Stu*)p2)-name);}int cmp_stu_by_age(const void* p1, const void* p2)
{return ((struct Stu*)p1)-age - ((struct Stu*)p2)-age;
}void Swap(char* buf1, char* buf2, size_t width)
{int i 0;char tmp 0;for (i 0; i width; i){tmp *buf1;*buf1 *buf2;*buf2 tmp;buf1;buf2;}
}void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{int i 0;for (i 0; i sz - 1; i){int j 0;for (j 0; j sz - 1 - i; j){//if (arr[j] arr[j 1])if (cmp((char*)base j * width, (char*)base (j 1) * width) 0){Swap((char*)base j * width, (char*)base (j 1) * width, width);}}}
}
void test3()
{struct Stu arr[] { {zhangsan, 20},{lisi,35},{wangwu, 18} };int sz sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);}void test4()
{struct Stu arr[] { {zhangsan, 20},{lisi,35},{wangwu, 18} };int sz sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);}int main()
{test3();test4();return 0;
}最终监视一下 arr 中的地址内容 1.按姓名排序 2.按年龄排序 未完待续~~