当前位置:首页 » 《随便一记》 » 正文

【C语言】深入理解指针(四)qsort函数的实现

24 人参与  2024年09月07日 14:06  分类 : 《随便一记》  评论

点击全文阅读


指针4

1.回调函数是什么2.qsort使用举例3.qsort函数的模拟实现

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("*********************\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;}

我们发现调用的函数都是int (int,int)类型的,我们可以把调⽤的函数的地址以参数的形式传递过去,使⽤这样类型的函数指针接收,函数指针指向什么函数就调⽤什么函数,这⾥其实使⽤的就是回调函数的功能。

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(*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;    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;}

因为上方代码,只有调⽤函数的逻辑是有差异的,我们可以把调⽤的函数的地址以参数的形式
传递过去,使⽤函数指针接收,函数指针指向什么函数就调⽤什么函数,这⾥其实使⽤的就是回调函
数的功能
注意区分这和我们在【C语言篇】深入理解指针3(附转移表源码)中实现的转移表,这里使用的是回调函数,但在转移表中我们使用的是函数指针数组

2.qsort使用举例

默认升序
在这里插入图片描述
quick sort快速排序的思想,冒牌排序是拍整形数据,这个是对任意类型的排序,
在这里插入图片描述

1.指向待排序数组第一个元素的指针
2.数组元素个数
3.数组中一个元素的大小,单位是字节
4.函数指针 指向函数的地址,指向比较2个元素的函数的指针,它指向的是一个需要两个无类型指针作为参数的函数
在这里插入图片描述

qsort函数排序整型数据

#include <stdio.h>#include <stdlib.h>    //qosrt函数的使⽤者得实现⼀个⽐较函数    int int_cmp(const void * p1, const void * p2){    return (*( int *)p1 - *(int *) p2);//p1 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);    //sizeof(int)=sizeof(arr[0])    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)    {        printf( "%d ", arr[i]);    }    printf("\n");    return 0;}

使用qsort排序结构数据

struct Stu //学⽣{    char name[20];//名字    int age;//年龄};//假设按照年龄来⽐较 e1e2一交换就是降序int cmp_stu_by_age(const void* e1, const void* e2){//强转为结构体指针,找成员,整数比较做差    return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;}//strcmp - 是库函数,是专⻔⽤来⽐较两个字符串的⼤⼩的,比较对应位置上字符的ASCII的大小//假设按照名字来⽐较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;}

3.qsort函数的模拟实现

qsost底层采用的是快速排序的方法,在这里我们使用更简单的冒泡排序的排序算法来模拟实现qsort函数,这里使用void*的指针,以实现泛型编程,换句话说,使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)。

#include <stdio.h>int int_cmp(const void * p1, const void * p2){ return (*( int *)p1 - *(int *) p2);}void _swap(void *p1, void * p2, int size){ int i = 0; for (i = 0; i< size; i++) {   //一个一个字节交换 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++)//趟数内部比较{ //都是base,所以强转,size是宽度单位字节,arr首元素的地址传给base //if后面的(是到最后size的 if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0){ _swap(( char *)base + j*size, (char *)base + (j + 1)*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;}

在这里插入图片描述
qsort的实现思路推荐博客


点击全文阅读


本文链接:http://zhangshiyu.com/post/156679.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1