目录
[1 回调函数是什么?](#1 回调函数是什么?)
[2 qsort 使⽤举例](#2 qsort 使⽤举例)
[2.1 使⽤qsort函数排序整型数据](#2.1 使⽤qsort函数排序整型数据)
[2.2 使⽤qsort排序结构数据](#2.2 使⽤qsort排序结构数据)
[3 qsort函数的模拟实现](#3 qsort函数的模拟实现)
1 回调函数是什么?
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
//回调函数int Add(int x, int y)
{
return x + y;
}void test(int (*pf)(int, int))
{
int r = pf(10, 20);
printf("%d\n", r);
}int main()
{
test(Add);return 0;
}

改写计算器代码
void menu()
{
printf("****************************\n");
printf("****** 1. add 2. sub ******\n");
printf("****** 3. mul 4. div ******\n");
printf("****** 0. exit ******\n");
printf("****************************\n");
}
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 Calc(int (*pf)(int, int))
{
int x = 0;
int y = 0;
int r = 0;
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
//r = (*pf)(x, y);
r = pf(x, y);
printf("%d\n", r);
}
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");
break;
}
} while (input);
return 0;
}



2 qsort 使⽤举例
2.1 使⽤qsort函数排序整型数据
qsort是c语言中提供的一个排序函数
quick sort是基于快速排序算法思想的一种排序算法
qsort的好处:
1.现成的排序算法,学会了直接就能使用 ,不需要自己实现了
2.大部分的情况下效率都比冒泡排序高的
- qsort函数可以排序任意类型的数据
我们自己实现过的冒泡排序函数,只能排序整型
利用冒泡排序来演示
冒泡排序
void bubble_sort(int arr[], int sz)
{
//1. 趟数
//2. 一趟内部的比较:比较的对数
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]) //交换
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test1()
{
int arr[] = { 3,1,5,8,7,9,2,4,6,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
bubble_sort(arr, sz);
print_arr(arr, sz);
}
int main()
{
test1();
return 0;
}

使用qsort函数排序整型数据
void qsort(void* base, //是指针,指向了被排序数组的第一个元素
size_t num, //base指向的被排序数组的元素个数
size_t size, //base指向的被排序数组的元素的大小(长度),单位是字节
int (*compar)(const void*, const void*)//是什么?函数指针,指针指向的函数是用来比较被排序数组中的两个元素的
);
//cmp_int函数是用来比较两个整型数据的大小的
//p1指向了一个整型数据
//p2指向了一个整型数据
//升序
//int cmp_int(const void* p1, const void*p2)
//{
// if (*(int*)p1 > *(int*)p2)
// return 1;
// else if (*(int*)p1 < *(int*)p2)
// return -1;
// else
// return 0;
//}//降序
//int cmp_int(const void* p1, const void* p2)
//{
// if (*(int*)p2 > *(int*)p1)
// return 1;
// else if (*(int*)p2 < *(int*)p1)
// return -1;
// else
// return 0;
//}//升序
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
//降序
//int cmp_int(const void* p1, const void* p2)
//{
// return (*(int*)p2 - *(int*)p1);
//}#include <stdlib.h>//qsort函数的头文件
//打印
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
//测试qsort函数,排序整型数组
void test2()
{
int arr[] = { 3,1,5,8,7,9,2,4,6,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
//排序
//使用qsort函数的程序员,就得自己写一个比较函数,来比较两个整型数据的大小
qsort(arr, sz, sizeof(arr[0]), cmp_int);
print_arr(arr, sz);
}
int main()
{
test2();
return 0;
}

2.2 使⽤qsort排序结构数据
介绍结构指针和结构体成员访问操作符 -> ;
//一
struct Stu
{
char name[30];
int age;
};
void test(struct Stu* ps)
{
//printf("%s\n", (*ps).name);
//printf("%d\n", (*ps).age);printf("%s\n", ps->name);//结构体成员访问操作符:-> 结构体指针->成员名
printf("%d\n", ps->age);
}
void test3()
{
struct Stu s = { "zhangsan", 20 };
//printf("%s\n", s.name);
//printf("%d\n", s.age);test(&s);
}
int main()
{
test3();
return 0;
}

//二
//年龄
struct Stu
{
char name[30];
int age;
};
//按照年龄来比较
//p1指向了一个结构体变量
//p2指向了一个结构体变量
//int cmp_stu_by_age(const void* p1, const void* p2)
//{
// return (*(struct Stu*)p1).age - (*(struct Stu*)p2).age;
//}int cmp_stu_by_age(const void* p1, const void* p2)
{
return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);
}
//打印
void print_stu(struct Stu arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s: %d\n", arr[i].name, arr[i].age);
}
printf("\n");
}
//测试qsort函数排序结构体数据
void test4()
{
struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
print_stu(arr, sz);
}
int main()
{
test4();
return 0;
}

//三
//名字
//strcmp的头文件#include <string.h>
struct Stu
{
char name[30];
int age;
};
//两个字符串在比较大小的时候,不能使用> >= < <= == !=
//应该使用strcmp()
int cmp_stu_by_name(const void* p1, const void* p2)
{
//return strcmp(((struct Stu*)p2)->name, ((struct Stu*)p1)->name);//降序
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);//升序
}
//打印
void print_stu(struct Stu arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s: %d\n", arr[i].name, arr[i].age);
}
printf("\n");
}
//测试qsort函数排序结构体数据
void test5()
{
struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
print_stu(arr, sz);
}
int main()
{
test5();
return 0;
}

3 qsort函数的模拟实现
使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)。
//一
//升序
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}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_sort2(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{
//1. 趟数
//2. 一趟内部的比较:比较的对数
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)
{
//交换arr[j], arr[j + 1]
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
//打印
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test6()
{
int arr[] = { 3,1,5,8,7,9,2,4,6,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
bubble_sort2(arr, sz, sizeof(arr[0]), cmp_int);
print_arr(arr, sz);
}
int main()
{
test6();
return 0;
}



//二
//年龄
struct Stu
{
char name[30];
int 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++;
}
}
int cmp_stu_by_age(const void* p1, const void* p2)
{
return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);
}
//排序任意类型的数据 - 泛型编程
//但是底层还是冒泡排序的算法思想
void bubble_sort2(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{
//1. 趟数
//2. 一趟内部的比较:比较的对数
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)
{
//交换arr[j], arr[j + 1]
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
//打印
void print_stu(struct Stu arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s: %d\n", arr[i].name, arr[i].age);
}
printf("\n");
}
void test7()
{
struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort2(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
print_stu(arr, sz);
}
int main()
{
test7();
return 0;
}


//三
//名字
struct Stu
{
char name[30];
int 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++;
}
}
//两个字符串在比较大小的时候,不能使用> >= < <= == !=
//应该使用strcmp()
int cmp_stu_by_name(const void* p1, const void* p2)
{
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
//排序任意类型的数据 - 泛型编程
//但是底层还是冒泡排序的算法思想
void bubble_sort2(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{
//1. 趟数
//2. 一趟内部的比较:比较的对数
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)
{
//交换arr[j], arr[j + 1]
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
//打印
void print_stu(struct Stu arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s: %d\n", arr[i].name, arr[i].age);
}
printf("\n");
}
void test8()
{
struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort2(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
print_stu(arr, sz);
}
int main()
{
test8();
return 0;
}
