营销型网站试运营调忧,网站建设和成本,电子商务从事什么工作,中关村科技租赁大家好啊#xff0c;我是小象٩(๑ω๑)۶ 我的博客#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家#xff0c;希望能够和大家一起交流学习#xff0c;共同进步。 今天我们一起来学习转移表#xff0c;回调函数#xff0c;qsort… 目录 一、转移表1.1 定义与原理1.3… 大家好啊我是小象٩(๑òωó๑)۶ 我的博客Xiao Xiangζั͡ޓއއ 很高兴见到大家希望能够和大家一起交流学习共同进步。 今天我们一起来学习转移表回调函数qsort… 目录 一、转移表1.1 定义与原理1.3 优点 二、回调函数是什么1.1 原理1.2 使用方法1.3 优点 三、qsort 使用举例3.1 使用qsort函数排序整型数据3.2 使用qsort排序结构数据 四、结尾 一、转移表
在 C 语言中转移表Jump Table是一种用于实现多路分支选择的技术也被称为跳转表或分支表。
1.1 定义与原理
转移表本质上是一个函数指针数组数组中的每个元素都是一个指向函数的指针。它的原理是通过计算索引值来选择调用数组中的某个函数指针从而实现根据不同条件跳转到不同代码段的功能类似于根据索引查找表中的内容并执行相应操作。
1.3 优点
代码清晰简洁 相比于使用大量的if-else语句或switch语句嵌套转移表能使代码结构更加清晰逻辑更加直观。尤其是在处理多个分支情况时代码的可读性更高。 高效性 在执行多路分支选择时转移表的查找和跳转操作通常比复杂的if-else或switch判断更快。因为它主要通过数组索引直接定位到目标函数而不需要逐个进行条件判断。 可扩展性 当需要添加新的分支或功能时只需在转移表中添加相应的函数指针并实现对应的函数逻辑即可对原有代码的改动较小易于维护和扩展。
举例计算器的⼀般实现
#include stdio.h
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;
}使⽤函数指针数组的实现
#include stdio.h
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;int(*p[5])(int x, int y) { 0, add, sub, mul, div }; //转移表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);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);}} while (input);return 0;
}二、回调函数是什么
回调函数是一个作为参数传递给另一个函数的函数而接收回调函数作为参数的函数会在合适的时候调用这个传递进来的函数。简单来说就是 A 函数将 B 函数作为参数传递给 C 函数C 函数在某个时刻调用 B 函数此时 B 函数就是回调函数。
1.1 原理
回调函数的核心原理基于函数指针。在 C 语言中函数名本质上代表该函数的入口地址而函数指针则可以存储这个地址。通过将函数指针作为参数传递给另一个函数接收该参数的函数就可以在需要的时候通过这个指针调用对应的函数。
1.2 使用方法
以下是使用回调函数的基本步骤 定义回调函数首先要定义一个符合特定参数和返回值要求的函数这个函数将作为回调函数使用。 定义接收回调函数作为参数的函数该函数需要有一个函数指针类型的参数用于接收回调函数的地址。 调用接收回调函数的函数在调用时将回调函数的名称作为参数传递给接收回调函数的函数。
1.3 优点
灵活性通过回调函数可以在不修改接收回调函数的函数的源代码的情况下改变其行为。只需要传递不同的回调函数就可以实现不同的功能。 代码复用可以将一些通用的逻辑封装在接收回调函数的函数中而将具体的处理逻辑放在回调函数中。这样不同的回调函数可以复用接收回调函数的函数的代码。 异步编程在异步编程中回调函数非常有用。当某个操作完成时可以通过回调函数通知调用者进行后续处理。
//使⽤回调函数改造前
#include stdio.h
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(*************************\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;三、qsort 使用举例
qsort 是 C 标准库中用于对数组进行快速排序的函数它基于快速排序算法实现能对任意类型的数组进行排序。
3.1 使用qsort函数排序整型数据
#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.2 使用qsort排序结构数据 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;
}注意事项 比较函数的实现比较函数的实现要正确确保能准确反映元素之间的大小关系。不同的比较函数实现可以实现升序、降序或其他自定义的排序规则。 类型转换在比较函数中由于 qsort 函数的通用性传入的参数是 const void * 类型需要将其转换为实际的数据类型才能进行比较操作。 稳定性qsort 是不稳定的排序算法即相等元素的相对顺序在排序后可能会改变。如果需要稳定的排序算法可以考虑使用其他排序函数或自行实现稳定排序。 性能qsort 平均时间复杂度为 (O(n log n))但在最坏情况下时间复杂度为 (O(n^2))。不过在大多数实际应用场景中它的性能表现良好。 四、结尾
这一课的内容就到这里了下节课继续学习指针的其他一些知识 如果内容有什么问题的话欢迎指正有什么问题也可以问我