前言
掌握函数指针数组的使用,qsort函数的实现。
1.函数指针数组的⽤途
作用:可以让代码更简洁,逻辑更清晰
计算机的实现:
简单的加减法运算
代码1
#include <stdio.h> int add(int a, int b)//加法 { return a + b; } int sub(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(" 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; default: printf("选择错误\n"); break; } } while (input); return 0; }
这个时候就可以用函数指针数组了,
改造:
代码2
#include <stdio.h> int add(int a, int b) { return a + b; } int sub(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 x, y; int input = 1; int ret = 0; int(*p[3])(int x, int y) = { 0, add, sub }; //转移表 do { printf("*************************\n"); printf(" 1:add 2:sub \n"); printf(" 0:exit \n"); printf("*************************\n"); printf("请选择:"); scanf("%d", &input); if ((input <= 4 && input >= 1)){ printf( "输⼊操作数:" ); scanf( "%d %d", &x, &y); ret = (*p[input])(x, y); printf( "ret = %d\n", ret); } else if(input == 0) { printf("退出计算器\n"); } else { printf( "输⼊有误\n" ); } return 0; }
看这样子是不是很简洁,那么是怎么调用的呢?
int(*p[3])(int x, int y) = { 0, add, sub };
如图:
2. 回调函数
回调函数就是⼀个通过函数指针调⽤的函数
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。
回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。上面代码1中我们写的计算机的实现的代码中,红⾊框中的代码是重复出现的,其中虽然执⾏计算的逻辑是区别的,但是输⼊输出操作是冗余的,有没有办法,简化⼀些呢?
因为红⾊框中的代码,只有调⽤函数的逻辑是有差异的,我们可以把调⽤的函数的地址以参数的形式传递过去,使⽤函数指针接收,函数指针指向什么函数就调⽤什么数,这⾥其实使⽤的就是回调函数的功能。
3 . qsort函数
qsort函数可以排序所有数据类型
传参必要参数:
那她是怎么实现的呢?
代码3:
#include <stdio.h> //qosrt函数的使⽤者得实现⼀个⽐较函数 int int_cmp(const void * p1, const void * p2) { return (*( int *)p1 - *(int *) p2); } int main() { int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; int i = 0; qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp); for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++) { printf( "%d ", arr[i]); } printf("\n"); return 0; }
解释如图:
比较函数是用函数指针接收,内部实现后面我还会讲
3. 1使⽤qsort排序结构体数据
可以按名字,也可以按年龄
代码4:
struct Stu //学⽣ { char name[20];//名字 int age;//年龄 }; //假设按照年龄来⽐较 int cmp_stu_by_age(const void* e1, const void* e2) { return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age; } //strcmp - 是库函数,是专⻔⽤来⽐较两个字符串的⼤⼩的 //假设按照名字来⽐较 int cmp_stu_by_name(const void* e1, const void* e2) { return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name); } //按照年龄来排序 void test2() { struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} }; int sz = sizeof(s) / sizeof(s[0]); qsort(s, sz, sizeof(s[0]), cmp_stu_by_age); } //按照名字来排序 void test3() { struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} }; int sz = sizeof(s) / sizeof(s[0]); qsort(s, sz, sizeof(s[0]), cmp_stu_by_name); } int main() { test2(); test3(); return 0; }
其中代码解释,如图:
5 …qsort函数的模拟实现
使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)。
补充:qsort可以排所有的数据类型,下面写的代码是qsort内部实现
注意:这⾥第⼀次使⽤ void* 的指针,讲解 void* 的作⽤。
#include<stdio.h> int int_cmp(const void * p1, const void * p2)//比较函数跟qsort函数的比较函数一样 { return (*( int *)p1 - *(int *) p2); } void _swap(void *p1, void * p2, int size) { int i = 0; for (i = 0; i< size; i++)//因为不知道数据类型(void)所以两个元素选择一个一个字节交换 { char tmp = *((char *)p1 + i); *(( char *)p1 + i) = *((char *) p2 + i); *(( char *)p2 + i) = tmp; } } void bubble(void *base, int count , int size, int(*cmp )(void *, void *)) { int i = 0; int j = 0; for (i = 0; i< count - 1; i++) { for (j = 0; j<count-i-1; j++){//和冒泡相似 if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0)//cmp函数返回值是int,判断>0,如果成立,执行语句 { _swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);//size是宽度,不知道 } } } } int main() { int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; int i = 0; bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp); for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)//打印 { printf( "%d ", arr[i]); } printf("\n"); return 0; }
解析:在上面代码注释里,还有if语句代码的解释,如图: