zoukankan      html  css  js  c++  java
  • 使用函数指针实现任意数据类型大小比较

    使用函数指针实现任意数据类型大小比较

    学习如鹏网C语言也能干大事,第三章透彻讲指针 中的第 13 节 函数指针案例:获得任意类型数组的最大值

    讲述了使用函数指针如何求任意数据类型的最大值,大家知道典型的max函数如下所示,通过将数组第一个元素复制给一个中间变量max,然后max与所有的数组数据进行比较,如果max小于数组某个元素,将该元素的值赋给max,这样遍历完所有元素之后,max取得数组的最大值。

     1 //函数功能:求int数组的最大值
     2 //假设输入数组为{8,7,2,9},length=4,下述函数返回值max为9
     3 int IntMax(int *array,int length)
     4 {
     5     int max,i;
     6     max = array[0];
     7     for(i=1;i<length;i++)
     8     {
     9         if(max<array[i])
    10         {
    11             max = array[i];
    12         }
    13     }
    14     return max;
    15 }


    如果使用函数指针,那么如何求得任何类型的数据最大值,关键是使用函数指针

    1. 1 //如果data1>data2,返回值为正数
      2 //比如输入int类型数据8和9,返回值为-1,如果输入int类型数据10和7返回值为3
      3 typedefint(*compareFun)(void*data1,void*data2);
      4 //具体的int比较函数如下所示
      5 int*intCompare(void*data1,void*data2)
      6 {
      7     return *(int*)data1-*(int*)data2;//(int *)为指针类型转换为int
      8 }

      关键在于使用函数指针调用对应的类型比较函数(浮点型,整型,char型比较等),将准确的数据类型首地址传达给data1和data2,这样在调用的函数当中才能确定以什么类型的指针解引用数据进行比较。

    进行比较时,不同类型的数据指针地址,递加的最小单位是不一样的。比如int类型数据递加最小单位为4
    int *a的地址假设为0x30000,那么a++后a的值为0x30004,因为一个int变量是4个字节
    如果是char *a的地址假设为0x30000,那么a++后a的值为0x30001,一个char变量是1个字节
    1.  1 //任意数据类型求最大值
       2 //nums:比较数据首地址,unitSize:数据单元大小,size:数据大小
       3 //size:数据大小,int数组{1,2,3,4}size大小为4
       4 //compareFun func指针,数组大小data1>data2,返回正数
       5 void *Max(void *data,int unitSize,int size,compareFun func)
       6 {
       7     int i;
       8     char *max = (char *) data;
       9     char *item;
      10     for(i=0;i<size;i++)
      11     {
      12         item = (char *)data + i*unitSize;
      13         if(func(item,max)>0)
      14         {
      15             max = item;
      16         }
      17     }
      18     return max;
      19 }

       测试程序如下所示:

    1. 1 int main(int argc, char *argv[])
      2 {
      3     int a[]={9,3,2,6,8,6,4,1,12};
      4     int *max;
      5     max =(int *)Max(a,sizeof(int),sizeof(a)/sizeof(int),intCompare);
      6     printf("max=%d
      ",*max);
      7     return 0;
      8 }

      打印输出值为“max=12”

    接下来我们换一种数据类型,例如比较两个结构体变量的大小,假设有下列结构体

    1 typedef struct _Dog
    2 {
    3     char *name;
    4     int age;
    5 }Dog;

    注意:注意结构体变量指针,假设我定义Dog *dog1变量,要访问age需要的语句是dog1->age,而不是*dog1->age或者dog1.age(指针需要使用->符号访问)这两个都是错误的,如果是Dog dog2,使用dog2.age。

    上述结构的大小比较函数如下所示:

    1 int dogCompare(void *data1,void *data2)
    2 {
    3     return ((Dog *)data1)->age -((Dog *)data2)->age;
    4 }

    测试主程序如下所示

     1 int main(int argc, char *argv[])
     2 {
     3 
     4     Dog dogs[]={{"John",1},{"Marks",3},{"Swift",6},{"Lucy",7}};
     5     Dog dog1,dog2;
     6     dog1.name = "Tom";
     7     dog1.age = 1;
     8     printf("dog1's name is %s,%d years old
    ",dog1.name,dog1.age );//测试普通结构体变量的使用
     9     Dog *OlderDog = (Dog *)Max(dogs,sizeof(Dog),sizeof(dogs)/sizeof(Dog),dogCompare);
    10     printf("Oldest dog is %s,%d years old
    ",OlderDog->name,OlderDog->age);
    11     return 0;
    12 }

     补充说明:sizeof(Dog)求得是结构体占用字节大小,char *name占用的是32位地址,其值为4个字节,int age为整型变量,占用4个字节,其值为4+4=8;sizeof(dogs)/sizeof(Dog)求得是数组包含结构体元素个数,sizeof(dogs)=4个元素*8字节=32字节

    输出结果为:

    ---------- 运行 ----------
    dog1's name is Tom,1 years old
    Oldest dog is Lucy,7 years old

    输出完成 (耗时 0 秒) - 正常终止

    补充:

    使用qsort函数进行排序

    功 能: 使用快速排序例程进行排序
    头文件:stdlib.h
    用 法: void qsort(void *base,int nelem,int width,int (*fcmp)(const void *,const void *));
    参数: 1 待排序数组首地址
    2 数组中待排序元素数量
    3 各元素的占用空间大小
    4 指向函数的指针,用于确定排序的顺序

    如执行 qsort(dogs,sizeof(dogs)/sizeof(Dog),sizeof(Dog),dogCompare);之后,dogs数组内部的数据就会依据比较函数dogCompare的返回值进行了排序

    核心思想:把算法中固定的部分固化;变化的地方使用函数指针调用,灵活定制

    总结:很明显,这个例子使用函数指针的方法提供了一种非常方便的方法让我们求各种不同数据类型的数组最大值,代码可以重复使用,只需要编写对应的数据类型比较函数,然后把函数指针指向该比较函数,就可以非常方便的求出数组最大值,上述主程序假设你需要加入其它的dog数据,只需要直接在结构体数组定义中加入相关内容就可以,代码其它地方不需要修改,这里就体现了一种非常睿智和科学的编程方法论,这也是高级程序员和普通程序员在编程时的差异。普通程序员的代码可能加入一个新的dog数据,其它的地方代码也需要修改,假设是一个很大的工程,普通程序员未必能够遍历所有需要修改的地方,这样程序代码一旦达到一定的规模,普通程序员可能就忙于修复各种自己留下的bug。作为一个程序员,加班的时间多并不一定是因为你的工作多,而是因为你的编程习惯,导致你有很多时间需要去救火。说到这里,应该明白要成为一个优秀的程序员就需要多多思考和学习科学的编程方法。同时也不断的撰写技术博客,分享自己技术心得,让知识传播的更远。我们改革开放才40多年,相对于欧美动辄上百年的工业文化积累,我们这个社会的工程师底蕴和文化还没有成为气候,一个庞大的工程师中产阶层也随着中国大学扩招慢慢的在形成,看欧美电视的时候会很惊讶于欧美随便一个普通的老百姓可以使用那么多专业的词汇以及流利的吐槽,评论当前的社会制度和发展。我们大中国很多地方还处于市井文化尚未褪去,各种城乡结合部的洗剪吹风行大街小巷的阶段。所以需要我们工程师们沉静下来,慢慢积累,相信不久的将来,工程师为赢得越来越多的尊重。

  • 相关阅读:
    带你剖析WebGis的世界奥秘----点和线的世界
    XML解析
    Java-工厂设计模式
    分享:软件包和文档
    启航,新开始
    docker容器网络通信原理分析(转)
    【好书分享】容器网络到kubernetes网络
    go语言接受者的选取
    go语言的unsafe包(转)
    protocol buffers生成go代码原理
  • 原文地址:https://www.cnblogs.com/codecamel/p/4590193.html
Copyright © 2011-2022 走看看