zoukankan      html  css  js  c++  java
  • 垃圾代码评析——关于《C程序设计伴侣》6.2(二)

    前文链接:http://www.cnblogs.com/pmer/archive/2012/11/04/2754294.html

    【样本】

      用qsort()函数对二维数组进行排序

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <math.h>
    5. // 获得一维数组的平均值
    6. float getaver(const int* st)
    7. {
    8.    int count = 0;
    9.    int total = 0;
    10.    // 只要没有遇到表示数据结束的0值,
    11.    // 就一直累加所有数据的值
    12.    while(0!=*st)
    13.    {
    14.       ++count;               // 数据个数加1
    15.       total += *st;          // 累加数据
    16.       ++st;  // 指向下一个数据
    17.    }
    18.    
    19.    // 返回平均值
    20.    if( 0 == count )  // 对没有元素的情况作特殊处理
    21.    {
    22.       return 0.0f;
    23.    }
    24.    else
    25.    {
    26.       return (float)total/count;
    27.    }
    28. 
    29. }
    30. 
    31. // 通过数组的平均值大小进行比较
    32. int cmp(const void* a, const void* b)
    33. {
    34.    // 获得两个数组的平均值
    35.    float avera = getaver((int*)a);
    36.    float averb = getaver((int*)b);
    37.    
    38.    // 返回比较结果
    39.    if(fabs(avera - averb) < 0.0001)
    40.    {
    41.       return 0; 
    42.    }
    43.    else if( avera > averb )
    44.    {
    45.       return 1;  
    46.    }
    47.    else
    48.    {
    49.       return -1;
    50.    }
    51.     
    52. }
    53. int main() 
    54. {
    55.    //
    56.    
    57.    // 利用qsort()函数对二维数组进行排序
    58.    qsort(scores,  // 数组名,也就是数组首地址
    59.       classnum,   // 数组元素个数
    60.       stnum*sizeof(int),        // 每个数据元素占用的空间
    61.       cmp);        // 比较规则函数
    62.    
    63.    return 0;
    64. }

       因为我们需要根据数组的平均值进行排序,所以我们首先定义了一个getaver()函数用于获取一个数组(以这个数组的首地址作为参数)的平均值。在getaver()函数中,我们利用一个while循环统计各个数据的总和以及数据个数,直到遇到表示数组数据结束的0为止(while(0!=*st))。最后getaver()返回的就是这个数组的平均值((float)total/count)。在比较规则函数cmp()函数中,我们正是利用getaver()函数来方便地夺得了两个待比较的数组的平均值,最后cmp()函数返回的是两个平均值相减的结果,也就是两个数组的比较结果。这里我们需要注意的是,cmp()函数的两个参数,在这里不再是指向两个单独的数据元素的指针,而成为了指向二维数组中的两个一维数组的指针,是这两个一维数组的首地址,所以可以经过类型转换后传递给getaver()函数直接获得两个数组的平均值。最后,qsort()函数会调用这个比较规则函数cmp()以此来实现二维数组的快速排序,而排序的结果也会重新写回这个数组。换句话说,经过qsort()函数调用后的数组,已经是排序完成的数组。
        ——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p105~107

    【评析】

      这种头重脚轻的代码结构(把main()写在后面)非常难于阅读,使人不得不用“拿大鼎”的姿势来看代码。先来看main()。
      这个函数中只写了一个函数调用,这个调用基本没有问题。只是其中的“stnum*sizeof(int)”是非常啰嗦的写法,是“sizeof scores”的画蛇添足版。
      下面再来看cmp():

    31. // 通过数组的平均值大小进行比较
    32. int cmp(const void* a, const void* b)
    33. {
    34.    // 获得两个数组的平均值
    35.    float avera = getaver((int*)a);
    36.    float averb = getaver((int*)b);

      这里的a、b两个形参名我就不吐槽了。业余到什么程度大家心里有数。
      要说的是35、36行,这里两次调用了getaver()函数,求两个一维数组所有元素的平均值,注意这里都只有一个实参,这个实参是指向一维数组起始元素的指针。通常这是不行的,因为getaver()函数并不清楚数组中元素的个数。
      既然getaver()函数并不清楚数组中元素的个数,那它又如何求平均值呢?再来看一下getaver()函数。在这个函数中有这样一段代码

    12.    while(0!=*st)
    13.    {
    14.       ++count;               // 数据个数加1

      原来它试图通过找到0确定数组中有多少个数据是有效的。然而,前文分析表明,整个二维数组中可能一个0值元素都没有。在这种情况下,程序运行的结果必然是一场灾难。
      仅此,就足矣判定这个程序死刑,MVP的代码是垃圾代码。除了做code review的反面教材,这种代码没有任何价值。
    为了了解代码中的其他问题,不妨捂着鼻子把代码看完。
      现在回到cmp(),其中

    38.    // 返回比较结果
    39.    if(fabs(avera - averb) < 0.0001)
    40.    {
    41.       return 0; 
    42.    }
    43.    else if( avera > averb )
    44.    {
    45.       return 1;  
    46.    }
    47.    else
    48.    {
    49.       return -1;
    50.    }

      其中的fabs(avera - averb) < 0.0001无疑是在判断avera、averb是否相等,但在这里其实有些煞有介事。写成

       // 返回比较结果
       if( avera < averb )
          return -1;  
    
       if( avera > averb )
          return 1;  
    
       return 0;
    

    其实就很好。不但简洁,而且也不会产生其他什么问题。

     

  • 相关阅读:
    从aop中获取被拦截方法中的参数
    使用多线程 执行有返回值的方法
    MyBatis中#{}和${}的区别
    Java 调用api,json化结果
    Spring入门
    实用: 将程序的内容写出到excel中
    实用:Java基础流计算
    2020年7月12号笔记
    2020年7月11号笔记
    2020年7月6号笔记
  • 原文地址:https://www.cnblogs.com/pmer/p/2754784.html
Copyright © 2011-2022 走看看