题目

字母的个数

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

输入
3
abcd
bbaa
jsdhfjkshdfjksahdfjkhsajkf

输出:
a
a
j

原代码

#include <stdio.h>
#include <string.h>
])
{
 int i,j,temp,max;
 ]={};

 ,temp =;i<strlen(x);i++)
 {
  temp=x[i]-;
  a[temp]+=;
 }

 ,max = a[],j=;i<;i++)
 {
  if(max<a[i])
  {
   j=i;
   max = a[i];
  }
 }

 ;
}

]);
int main()
{

 ],c[];
 int T,i;
 scanf("%d",&T);

 ;i<T;i++)
 {
  scanf("%s",s);
  c[i]=maxchar(s);
 }

 ;i<T;i++)
 {
  printf("%c\n",c[i]);
 }

 ;
}

评析:

总体:


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

main():


 ],c[];
 int T,i;

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

 scanf("%d",&T);

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

 ;i<T;i++)
 {
  scanf("%s",s);
  c[i]=maxchar(s);
 }

 ;i<T;i++)
 {
  printf("%c\n",c[i]);
 }

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

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

或者“死等”

 <T && T < ) )
{
    //提示重新输入
}

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

 || !(  <T && T < ) )
{
    while ( getchar()!='\n')
        ;
    //提示重新输入
}

  此外,这段代码中的

scanf("%s",s);

这句如果写成

scanf("%1009s",s);

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

maxchar()函数 :


])
{
 int i,j,temp,max;
 ]={};

 ,temp =;i<strlen(x);i++)
 {
  temp=x[i]-;
  a[temp]+=;
 }

 ,max = a[],j=;i<;i++)
 {
  if(max<a[i])
  {
   j=i;
   max = a[i];
  }
 }

 ;
}

]);

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

]={};

  这个写成

 ]={};

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

 ,temp =;i<strlen(x);i++)
 {
  temp=x[i]-;
  a[temp]+=;
 }

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

a[temp]+=;

  可以直接写为

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

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

#include <string.h>

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

 ,max = a[],j=;i<;i++)
 {
  if(max<a[i])
  {
   j=i;
   max = a[i];
  }
 }

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

 ,j=;i<;i++)
 {
  if(a[j]<a[i])
  {
   j=i;
  }
 }

  最后

;

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

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);

    < T && T <  ) )
      ;

    )
   {
      char s[ MAX_LEN ];

      scanf("%"N(S_LEN)"s" , s );
      printf("%c\n" , find_major( s ) );
   }

   ;
}

char find_major( char * s )
{
    ] = {  } ;

   count( num , s ) ;                 //统计字母个数
   ] );//返回出现最多字符
}

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 ;//最大值元素下标
}

C语言初学者代码中的常见错误与瑕疵(9)的更多相关文章

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

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

  2. 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)

    问题: 问题出处见 C语言初学者代码中的常见错误与瑕疵(5) . 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己 ...

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

    问题: 素数 在世博园某信息通信馆中,游客可利用手机等终端参与互动小游戏,与虚拟人物Kr. Kong 进行猜数比赛. 当屏幕出现一个整数X时,若你能比Kr. Kong更快的发出最接近它的素数答案,你将 ...

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

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

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

    见:C语言初学者代码中的常见错误与瑕疵(14) 相关链接:http://www.anycodex.com/blog/?p=87

  6. 分数的加减法——C语言初学者代码中的常见错误与瑕疵(12)

    前文链接:分数的加减法——C语言初学者代码中的常见错误与瑕疵(11) 重构 题目的修正 我抛弃了原题中“其中a, b, c, d是一个0-9的整数”这样的前提条件,因为这种限制毫无必要.只假设a, b ...

  7. 要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)

    在 C语言初学者代码中的常见错误与瑕疵(7) 中,我给出的重构代码中存在BUG.这个BUG是在飞鸟_Asuka网友指出“是不是时间复杂度比较大”,并说他“第一眼看到我就想把它当成一个数学问题来做”之后 ...

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

    问题: 矩形的个数 在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,2个2*2的矩形,2个3*1的矩形和1个3*2的矩形,总共18个矩形.给出A,B,计算可以从中找到 ...

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

    曾在豆瓣上看到过一个小朋友贴出他自己的代码(http://www.douban.com/group/topic/40293109/),当时随口指点了几句.难得这位小朋友虚心修正.从善如流,不断地改,又 ...

随机推荐

  1. 解决 node-gyp command not found 的问题

    node-gyp明明已经安装了,但是不能执行,显示命令找不到,然后重装之,发现npm有一个提示信息: npm WARN prefer global node-gyp@3.4.0 should be i ...

  2. 学习 ---- JavaScript 高级设计程序 第三章(数据类型)

                                    3.4 数据类型 基本数据类型:Undefined.Null.Boolean.Number.String 复杂数据类型:Object 3 ...

  3. oracle round 函数,replace()函数

    (1)如何使用 Oracle Round 函数 (四舍五入)描述 : 传回一个数值,该数值是按照指定的小数位元数进行四舍五入运算的结果.SELECT ROUND( number, [ decimal_ ...

  4. 【bzoj1500】 noi2005—维护数列

    http://www.lydsy.com/JudgeOnline/problem.php?id=1500 (题目链接) 题意 要求维护数列,操作有区间删除,区间插入,区间反转,区间修改,区间求和,求最 ...

  5. AngularJS学习之模块

    1.模块定义了一个应用程序:模块是应用程序中不同部分的容器:模块是应用控制器的容器:控制器通常属于一个模块 2.创建模块:你可以通过AngularJS的angular.module函数来创建模块: & ...

  6. Linux 上的常用文件传输方式介绍与比较

    ftp ftp 命令使用文件传输协议(File Transfer Protocol, FTP)在本地主机和远程主机之间或者在两个远程主机之间进行文件传输. FTP 协议允许数据在不同文件系统的主机之间 ...

  7. 欧拉工程第60题:Prime pair sets

    题目链接 五个数,任意两个数的任意链接后的数还是质数 满足这个条件的最小五个数的和是多少? 结果:26033 纯暴力破解: package projecteuler51to60; import jav ...

  8. 【原】Spring与MongoDB集成:仓库

    上一篇文章用介绍了如何配置spring-data-mongo连接到MongoDB上,如何创建MongoTemplate.MongoTemplate就相当于一个通用的仓库,可以持久化业务对象. 在spr ...

  9. 算法笔记_066:Kruskal算法详解(Java)

    目录 1 问题描述 2 解决方案 2.1 构造最小生成树示例 2.2 伪码及时间效率分析 2.3 具体编码(最佳时间效率)   1 问题描述 何为Kruskal算法? 该算法功能:求取加权连通图的最小 ...

  10. WCF学习——构建第二个WCF应用程序(六)

    一.创建客户端应用程序 若要创建客户端应用程序,你将另外添加一个项目,添加对该项目的服务引用,配置数据源,并创建一个用户界面以显示服务中的数据.若要创建客户端应用程序,你将另外添加一个项目,添加对该项 ...