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

浏览:
字体:
发布时间:2013-12-20 16:18:38
来源:
字母的个数
 
现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,如果出现次数最多字母有多个那么输出最小的那个。 
输入:第一行输入一个正整数T(0<T<25) 
随后T行输入一个字符串s,s长度小于1010。 
输出:每组数据输出占一行,输出出现次数最多的字符; 
样例:
 
输入 
abcd 
bbaa 
jsdhfjkshdfjksahdfjkhsajkf
 
输出: 
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("%c/n",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("%c/n",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("%1009s",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]!='/0'就可以了。由此可见源文件开头的
 
#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。 
输出:每组数据输出占一行,输出出现次数最多的字符; 
样例:输入 
abcd 
bbaa 
jsdhfjkshdfjksahdfjkhsajkf 
输出: 
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("%c/n" , 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 != '/0' )
      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 ;//最大值元素下标
}
>更多相关文章
24小时热门资讯
24小时回复排行
资讯 | QQ | 安全 | 编程 | 数据库 | 系统 | 网络 | 考试 | 站长 | 关于东联 | 安全雇佣 | 搞笑视频大全 | 微信学院 | 视频课程 |
关于我们 | 联系我们 | 广告服务 | 免责申明 | 作品发布 | 网站地图 | 官方微博 | 技术培训
Copyright © 2007 - 2024 Vm888.Com. All Rights Reserved
粤公网安备 44060402001498号 粤ICP备19097316号 请遵循相关法律法规
');})();