第十二讲:指针(4)
总结:该篇博客详细对以下两个内容进行讲解:
1.回调函数
2.qsort函数
1.回调函数
1.1什么是回调函数
回调函数就是一个通过函数指针调用的函数
如果我们将函数的地址作为参数传递给另一个函数,当通过这个指针被用来调用其指向的函数时,被调用的函数就是回调函数,回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外一方调用的,用于对该事件或条件进行响应
下面我们通过代码来理解什么是回调函数:
1.2深入理解并使用回调函数
我们写一个简易的计算器
1.2.1简单写法
c
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优化
c
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>库中
函数原型:
c
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函数排序整形数据
c
//使⽤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函数排序结构数据
c
//使⽤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冒泡排序
目前的排序方式有很多,快速排序,希尔排序,冒泡排序,我们现在使用冒泡排序进行类比排序
c
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冒泡排序的改造
c
//冒泡函数的改造
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;
}