zoukankan      html  css  js  c++  java
  • flag标志什么?哦,它标志代码馊了——(三)

      有时候flag会以别的名字出现,但同样会把代码弄得馊不可闻。例如下面的代码

    样本代码5

    View Code
    #include <stdio.h>
    #include <string.h>
    #define N 10
    int main( void )
    {
    /**/
    int num[N],number;
    char name[N][8];
    / * */
    printf("\ninput number to look for:");
    scanf("%d",&number);
    search(number,num,name);
    /**/
    return 0;
    }

    void search(int n,int num[],char name[N][8])
    {int top,bott,mid,loca,sign;
    top=0;
    bott=N-1;
    loca=0;
    sign=1;
    if((n<num[0])||(n>num[N-1]))
    loca=-1;
    while((sign==1)&&(top<=bott))
    {mid=(bott+top)/2;
    if(n==num[mid])
    {loca=mid;
    printf("No.%d,his name is %s.\n",n,name[loca]);
    sign=-1;
    }
    else if(n<num[mid])
    bott=mid-1;
    else
    top=mid+1;
    }
    if(sign==1||loca==-1)
    printf("%d not been found.\n",n);
    }

        ——谭浩强 ,《C程序设计(第四版)学习辅导》,清华大学出版社,2010年7月,p92

      这段代码中的search()函数的主要功能是用二分法在已排好序的num数组中搜索n,求出n在num数组中的位置loca后输出对应在name数组中相同下标的元素name[loca]。

      这个search()函数的第一个毛病是缺少数组尺寸参数,char name[N][8]这个参数中的N毫无意义,函数内的N则来得无缘无故。这是一个很大的毛病,这使得函数丧失通用性,而没有通用性的函数基本上就是是废品函数。但这些由于和flag无关,所以这里暂且放置不谈。

      在这个函数内,loca和sign都属于那种flag变量,尽管没有取名为flag。

      loca这个变量用来记录n在num数组中的位置,如果数组中不存在则将loca的值置为-1。将loca的初值取为0极不合理,因为这表示一开始就假设n在数组中存在且为第一个元素,这是毫无道理的假设。loca合理的初值应该为-1。这样,只有在找到的情况下这个值才会改变,代码可以大为简化:

    View Code
    void search(int n,int num[],char name[N][8])
    {
    int top = 0 ,bott = N-1,mid,loca=-1,sign = 1 ;
    while((sign==1)&&(top<=bott))
    {
    mid=(bott+top)/2;
    if(n==num[mid])
    {
    loca=mid;
    printf("No.%d,his name is %s.\n",n,name[loca]);
    sign=-1;
    }
    else if(n<num[mid])
    bott=mid-1;
    else
    top=mid+1;
    }
    if(loca==-1)
    printf("%d not been found.\n",n);
    }

      现在不难看出,代码中的sign不过是break或return语句的一个拙劣的替代品而已,完全没有必要。代码可以进一步简化

    void search( int n , int num[] , char name[][8] )
    {
       int top=0,bott=N-1,mid;
    
       while( top<=bott )
       {
          mid=(bott+top)/2;
          if( n == num[mid] )
          {
              printf("No.%d,his name is %s.\n",n,name[mid]);
              return  ;
          }
          else if( n < num[mid] )
             bott = mid - 1 ;
          else
             top  = mid + 1 ;
      }
    
      printf("%d not been found.\n",n);
    
    }

      结论就是,原来代码中的loca和sign没有任何存在的意义,因为它们除了把代码弄得更晦涩更复杂之外没有起到任何好作用。

      标志变量的毛病改完了,但这个search()其实还有另外的毛病,这个毛病就是根本不应该把查找与输出这两个功能搅和在一起。完成单一任务是函数设计的一个基本原则。因此从整个程序设计的角度来说更干净的写法应该是:  

    #include <stdio.h>
    
    #define N 10
    #define NOT_FOUND (-1) 
    
    int search( int  , int [] , size_t );
    
    int main( void )
    {
       /*  */
       int num[N] , number ;
       char name[N][8] ;
       / *  */
       printf("\ninput number to look for:");
       scanf("%d",&number);
       {
          int site = search( number , num , N );
    
          if( site != NOT_FOUND )
             printf("No.%d,his name is %s.\n" , number , name[site] );   
          else
             printf("%d not been found.\n",n);
       
       }
       /* */
       return 0;
    }
    
    int search( int  n, int num[] , size_t size )
    {
       int top  = 0         ,
           bott = size - 1  , 
           mid  ;
    
       while( top <= bott )
       {
          mid = ( bott + top ) / 2 ;
          if( n == num[mid] )
              return  mid ;
              
          if( n < num[mid] )
              bott = mid - 1 ;
          else
              top  = mid + 1 ;
       }
    
       return  NOT_FOUND ; 
    }
    

      通过前面的几个例子,不难看出,在代码中轻率地使用flag之类的标志变量确实能够败坏代码的味道,使得代码变馊。

      那么,是否在代码中绝对不应该使用标志变量呢?却也不是。使用flag标志变量的前提首先是解决问题的算法要求使用这样的变量,离开了这个前提使用flag标志变量就难免成为东施效颦;其次,不应该生硬死板地为标志变量命名为flag,无论什么问题总是一味地flag或sign,不是头脑僵化就是思维扭曲。

      最后看一个例子,欣赏一下大师是如何使用标志变量的。下面的代码出自K&R,程序功能是统计输入的行数、单词数和字符数:

    #include <stdio.h>
    
    #define IN  1     /*在单词内*/
    #define OUT 0     /*在单词外*/
    /* 统计输入的行数、单词数和字符数 */
    main()
    {
      int c,nl,nw,nc,state;
      
      state = OUT ;
      nl = nw = nc = 0 ;
      while((c = getchar())!= EOF){
          ++nc;
          if( c == '\n')
             ++nl;
          if( c ==' ' || c =='\n' || c =='\t')
             state = OUT ;
          else if(state == OUT){
             state = IN ;
             ++nw;
          }      
      }
      printf("%d %d %d\n", nl , nw , nc );
    }
    

       这里,标志变量并没有使用丑陋的flag作为名称,而是恰当地使用了state这个与问题相贴切的名字。再加上两个漂亮的符号常量IN和OUT,使得代码的含义不言自明,连注释都用不着。三十多年过去了,这段代码不但没有腐朽,相反,依然还是那么清新典雅,垂范后人,令人高山仰止。(完)

  • 相关阅读:
    Flink实战(七十三):FLINK-SQL使用基础(一)简介(一)入门
    Flink实战(七十二):监控(四)自定义metrics相关指标(二)
    k8s启动
    k8s containerd
    安装containerd
    k8s镜像
    crictl
    Kubernetes: Using containerd 1.1 without Docker
    docker images --digests
    ctr images pull docker.io/library/redis:latest
  • 原文地址:https://www.cnblogs.com/pmer/p/2255646.html
Copyright © 2011-2022 走看看