第十二讲:指针(4)
- 1.回调函数
- 1.1什么是回调函数
- 1.2深入理解并使用回调函数
- 1.2.1简单写法
- 1.2.2优化
- 2.qsort函数详解
- 2.1函数简单介绍
- 2.3qsort函数使用举例
- 2.3.1qsort函数排序整形数据
- 2.3.2qsort函数排序结构数据
- 3.qsort函数的模拟实现
- 3.1冒泡排序
- 3.2冒泡排序的改造
总结:该篇博客详细对以下两个内容进行讲解:
1.回调函数
2.qsort函数
1.回调函数
1.1什么是回调函数
回调函数就是一个通过函数指针调用的函数
如果我们将函数的地址作为参数传递给另一个函数,当通过这个指针被用来调用其指向的函数时,被调用的函数就是回调函数,回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外一方调用的,用于对该事件或条件进行响应
下面我们通过代码来理解什么是回调函数:
1.2深入理解并使用回调函数
我们写一个简易的计算器
1.2.1简单写法
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;
}
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}
这个方法写的十分冗余,下面我们来进行优化
1.2.2优化
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 (*pa)(int, int)) //使用函数指针变量来接受函数指针
{printf("请输入两个操作数:\n");int x, y;x = 0;y = 0;scanf("%d %d", &x, &y);int set = pa(x, y);printf("%d\n", set);
}int main()
{int input = 1;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf("*************************\n");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函数简单介绍
这是一个执行快速排序的函数,包含在<stdlib.h>库中
函数原型:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
对各个参数进行介绍如下:
1.base:指向要排序数组的首元素的地址
2.num:数组中的元素的个数
3.width:数组中每个元素的大小,单位是字节
4.int (__cdecl *compare )(const void *elem1, const void *elem2 ):
这是一个由编程者自己写的函数,将函数地址传入,函数的形式被规定,该函数定义了如何比较两个元素
对于自己定义的这个函数,通过其返回值决定所排序元素的顺序,遵循以下原则 :
2.3qsort函数使用举例
2.3.1qsort函数排序整形数据
//使⽤qsort函数排序整型数据int Sort1(const void* pa, const void* pb)
{return (*(int *)pa - *(int*)pb);
}int main()
{int arr[] = { 2,3,4,5,1,6,7,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), Sort1); //void qsort(void* base, //size_t num, //size_t width, //int(__cdecl * compare)(const void* elem1, const void* elem2));Print(arr, sz);return 0;
}
2.3.2qsort函数排序结构数据
//使⽤qsort函数排序结构数据//创建一个结构类型,假设为学生数据
struct Stu
{char name[20];int age;
};//按照名字排序
int SortByName(const void* pa, const void* pb)
{return (strcmp(((struct Stu*)pa)->name, ((struct Stu*)pb)->name));
}//按照年龄排序
int SortByAge(const void* pa, const void* pb)
{return (((struct Stu*)pa)->age - ((struct Stu*)pb)->age);
}int main()
{//给定学生数据struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]);//按照名字排序qsort(arr, sz, sizeof(arr[0]), SortByName); //void qsort(void* base, //size_t num, //size_t width, //int(__cdecl * compare)(const void* elem1, const void* elem2));//按照年龄排序qsort(arr, sz, sizeof(arr[0]), SortByAge); //void qsort(void* base, //size_t num, //size_t width, //int(__cdecl * compare)(const void* elem1, const void* elem2));return 0;
}
3.qsort函数的模拟实现
我们使用冒泡排序来进行qsort函数的模拟实现,首先先介绍一下什么是冒泡排序
3.1冒泡排序
目前的排序方式有很多,快速排序,希尔排序,冒泡排序,我们现在使用冒泡排序进行类比排序
void BubbleSort(int* pa, int sz)
{for (int i = 0; i < sz - 1; i++){for (int j = 0; j < sz - 1 - i; j++){if (*(pa + j) > *(pa + j + 1)){int temp = *(pa + j);*(pa + j) = *(pa + 1 + j);*(pa + 1 + j) = temp;}}}
}void Print(int* arr, int sz)
{for (int i = 0; i < sz; i++)printf("%d ", *(arr + i));
}int main()
{int arr[] = { 2,3,4,5,1,6,7,9,10 };//冒泡排序int sz = sizeof(arr) / sizeof(arr[0]);BubbleSort(arr, sz);//进行打印Print(arr, sz);return 0;
}
3.2冒泡排序的改造
//冒泡函数的改造
void Change(char* pa, char* pb, int sz)
{for(int i = 0; i<sz; i++){char temp = *pa;*pa = *pb;*pb = temp;pa++;pb++;}
}void BubbleSort(void* pa, size_t sz, size_t width, int(* compare)(const void* pa, const void* pb))
{for (int i = 0; i < sz - 1; i++) //尽管是改造,但是这两个for循环是不用改变的{ //第一个for循环表示循环次数for (int j = 0; j < sz - 1 - i; j++) //第二个for循环是将两个数进行比较{//仍然是判断,如果compare函数返回值大于0,进行交换if (compare((char*)pa + j * width, (char*)pa + (j + 1) * width) > 0)Change((char*)pa + j * width, (char*)pa + (j + 1) * width, width); //进行交换,但是这个交换一次要交换数组类型个字节}}
}int main()
{//给定学生数据struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };//冒泡排序int sz = sizeof(arr) / sizeof(arr[0]);BubbleSort(arr, sz, sizeof(arr[0]), SortByName); //void qsort(void* base, //size_t num, //size_t width, //int(__cdecl * compare)(const void* elem1, const void* elem2));BubbleSort(arr, sz, sizeof(arr[0]), SortByAge);return 0;
}