来自 计算机教程 2019-08-03 01:59 的文章
当前位置: 美洲杯冠军竞猜 > 计算机教程 > 正文

C语言初学者代码中的常见错误与瑕疵(9)美洲杯冠

题目

字母的个数

现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,如果出现次数最多字母有多个那么输出最小的那个。
输入:第一行输入一个正整数T(0<T<25)
随后T行输入一个字符串s,s长度小于1010。
输出:每组数据输出占一行,输出出现次数最多的字符;
样例:

输入
3
abcd
bbaa
jsdhfjkshdfjksahdfjkhsajkf

输出:
a
a
j

原代码

#include <stdio.h>  #include <string.h>  int maxchar(char x[1010])  {   int i,j,temp,max;   int a[26]={0};      for (i = 0,temp =0;i<strlen(x);i  )   {    temp=x[i]-97;    a[temp] =1;   }     for(i=1,max = a[0],j=0;i<26;i  )   {    if(max<a[i])    {     j=i;     max = a[i];    }   }     return j 97;  }    int maxchar(char x[1010]);  int main()  {     char s[1010],c[26];   int T,i;   scanf("%d",&T);     for (i=0;i<T;i  )   {    scanf("%s",s);    c[i]=maxchar(s);   }     for (i=0;i<T;i  )   {    printf("%cn",c[i]);   }     return 0;  }

评析:

总体:


  已经学会把函数类型声明写在函数定义外面了,但把其他函数定义写在main()之前,总体上还是有头重脚轻之感。

main():


 char s[1010],c[26];   int T,i;

  s数组显然不应该定义在这里,因为这个数组只在第一个for语句内部用到。
  c数组不应该定义为26个元素,因为题目中说的是“0<T<25”。

 scanf("%d",&T);

  这条语句无可指责,但输入后没考虑数据有效性。 

 for (i=0;i<T;i  )   {    scanf("%s",s);    c[i]=maxchar(s);   }     for (i=0;i<T;i  )   {    printf("%cn",c[i]);   }

  原作者显然不了解这类ACM问题的套路(参见 C语言初学者代码中的常见错误与瑕疵(5)   11楼~13楼)。不过话说回来,ACM对这类问题的描述确实容易让外人误解,ACM是否应该自我检讨一下呢?
  除了不了解ACM的套路,这里的一个有欠考虑的地方是没有注意检查输入数据的有效性(当然,ACM对此是不管不顾的)。如果考虑输入数据的有效性应该不理会无效数据:

scanf("%d",&T);  if ( 0 <T && T <25 )  {     //求解问题  }

或者“死等”

while ( scanf("%d",&T) , !( 0 <T && T <25 ) )  {      //提示重新输入  }

  考虑的更周到些的话,可以

while ( scanf("%d",&T)!= 1 || !( 0 <T && T <25 ) )  {      while ( getchar()!='n')          ;      //提示重新输入  }

  此外,这段代码中的

scanf("%s",s);

这句如果写成

scanf("09s",s);

就无可挑剔了。尽管ACM的测试数据不会出问题,但这是应该考虑到的一个问题。程序员最重要的品质应该是思虑周到。

maxchar()函数 :


int maxchar(char x[1010])  {   int i,j,temp,max;   int a[26]={0};      for (i = 0,temp =0;i<strlen(x);i  )   {    temp=x[i]-97;    a[temp] =1;   }     for(i=1,max = a[0],j=0;i<26;i  )   {    if(max<a[i])    {     j=i;     max = a[i];    }   }     return j 97;  }    int maxchar(char x[1010]);

   函数定义和函数类型声明都存在同一个问题,就是[]内的1010。这个是不应该写的,写了编译器也不“看”,写得毫无意义。

int a[26]={0};

   这个写成

 int a['z'-'a' 1]={0};

 为好。注意这里应该是假定使用ASCII码制,如果不是ASCII码,代码不能这样写。

 for (i = 0,temp =0;i<strlen(x);i  )   {    temp=x[i]-97;    a[temp] =1;   }

  这个槽点较多。首先temp明显多余,其次那个97太难看了,典型的谭浩强风格。应该写为'a'。

a[temp] =1;

  可以直接写为 

a[ x[i] - 'a'] =1;

  再有,i<strlen(x)写得很糟糕,因为在这里调用strlen(x),意味着在循环过程中每次循环都要调用这个函数,然而对于这个循环来说,strlen(x)其实是一个常量,并不需要每次都调用。这也是初学者常见的一个毛病,总忍不住有调用库函数的冲动,而不考虑有没有更好的写法。strlen(x)是被滥用最多的库函数之一。其实这里简单地写x[i]!=''就可以了。由此可见源文件开头的

#include <string.h>

也完全是多余的。
  另外这条语句的功能与下一条for语句的功能相对各自独立,各抽象为一个独立的函数为好。

 for(i=1,max = a[0],j=0;i<26;i  )   {    if(max<a[i])    {     j=i;     max = a[i];    }   }

美洲杯冠军竞猜,  这个地方写得有点笨,主要是变量太多。作者用max记录最大值元素,用j记录其下标,其实只要一个j就够了

 for(i=1,j=0;i<26;i  )   {    if(a[j]<a[i])    {     j=i;       }   }

   最后

return j 97;

这个也是谭浩强之流不入流的写法,非常难看。应该写为

return j 'a';

 重构

/*  字母的个数   现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,  如果出现次数最多字母有多个那么输出最小的那个。   输入:第一行输入一个正整数T(0<T<25)   随后T行输入一个字符串s,s长度小于1010。   输出:每组数据输出占一行,输出出现次数最多的字符;   样例:输入   3   abcd   bbaa   jsdhfjkshdfjksahdfjkhsajkf   输出:   a   a   j    作者:薛非  出处:http://www.cnblogs.com/pmer/   “C语言初学者代码中的常见错误与瑕疵”系列博文     */    #include <stdio.h>    #define S_LEN 1009  #define MAX_LEN (S_LEN   1)   #define N(x) N_(x)  #define N_(x) #x    char find_major( char * );  void count( int [] , char * ) ;  unsigned be_most( int [], unsigned );    int main( void )  {     int T ;       puts("行数?");     scanf("%d" , &T);          if ( ! ( 0 < T && T < 25 ) )        return 1;          while ( T -- > 0 )     {        char s[ MAX_LEN ];                scanf("%"N(S_LEN)"s" , s );        printf("%cn" , find_major( s ) );     }          return 0;  }    char find_major( char * s )  {     int num[ 'z' - 'a'   1 ] = { 0 } ;          count( num , s ) ;                 //统计字母个数      return 'a'   be_most( num , sizeof num / sizeof num[0] );//返回出现最多字符   }    void count( int num[] , char * s )   {     while ( *s != '' )        num[ * s    - 'a' ]    ;   }    unsigned be_most( int a[] , unsigned n )  {     unsigned max = 0u ;     unsigned i ;          for ( i = 1u ; i < n ; i    )        if ( a[max] < a[i] )           max = i ;       return max ;//最大值元素下标  }

 


本文由美洲杯冠军竞猜发布于计算机教程,转载请注明出处:C语言初学者代码中的常见错误与瑕疵(9)美洲杯冠

关键词: