题目

字母的个数

现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,如果出现次数最多字母有多个那么输出最小的那个。
输入:第一行输入一个正整数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("%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。
输出:每组数据输出占一行,输出出现次数最多的字符;
样例:输入
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) #xchar 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 ;//最大值元素下标
}

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

  1. c语言一个数中是否含有8,要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)...

    在 飞鸟_Asuka网友指出"是不是时间复杂度比较大",并说他"第一眼看到我就想把它当成一个数学问题来做"之后,我又重新对问题进行了数学式的思考后发现的. 这个 ...

  2. 为什么c语言加法错误,分数的加减法——C语言初学者代码中的常见错误与瑕疵(12)...

    重构 题目的修正 我抛弃了原题中"其中a, b, c, d是一个0-9的整数"这样的前提条件,因为这种限制毫无必要.只假设a, b, c, d是十进制整数形式的字符序列. 我也不清 ...

  3. c语言间接级别不同_一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)...

    问题: 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己代码的改进和优化.标题只是为了保持系列的连续性. 改进 程 ...

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

    问题: 另一种阶乘 大家都知道阶乘这个概念,举个简单的例子:5!=1*2*3*4*5. 现在我们引入一种新的阶乘概念,将原来的每个数相乘变为i不大于n的所有奇数相乘 例如:5!!=1*3*5.现在明白 ...

  5. c语言编程过程中的常见错误,C语言编程常见错误与解决办法

    warning: excess elements in array initializer 警告:数组初始值设定项中有多余元素 (定义的数组长度比赋值的个数小) 数组定义出错 "confli ...

  6. WCF项目中出现常见错误的解决方法:基础连接已经关闭: 连接被意外关闭

    原文:WCF项目中出现常见错误的解决方法:基础连接已经关闭: 连接被意外关闭 在我们开发WCF项目的时候,常常会碰到一些莫名其妙的错误,有时候如果根据它的错误提示信息,一般很难定位到具体的问题所在,而 ...

  7. Android稳定性系列-01-使用 Address Sanitizer检测原生代码中的内存错误

    前言 想必大家曾经被各种Native Crash折磨过,本地测试没啥问题,一到线上或者自动化测试就出现各种SIGSEGV.SIGABRT.SIGILL.SIGBUS.SIGFPE异常,而且堆栈还是崩溃 ...

  8. 中虚数怎么表示_英文论文写作中的常见错误

    之前写过一篇如何写中文论文,这次就写个英文论文写作中的常见错误吧.都是平时自己整理总结的,也是一路摸爬滚打的见证吧.如有错误,欢迎批评指正.未完待续...... 1.逗号粘连: 两个独立的句子间要用句 ...

  9. SQL Server连接中的常见错误

    SQL Server连接中的常见错误: 一."SQL Server 不存在或访问被拒绝" 这个是最复杂的,错误发生的原因比较多,需要检查的方面也比较多. 一般说来,有以下几种可能性 ...

最新文章

  1. 自动唤醒解锁电脑 bat_吉行贴士 | 一键解锁智能语音新姿势
  2. 自学python需要多长时间-自学Python要学多久可以学会?
  3. 生活娱乐 在上海怎么租房
  4. numpy数组提取一定规律的数据
  5. 老码农:如何写出让自己满意的代码
  6. 计算机三级嵌入式系统考试之矩阵键盘
  7. 树莓派教程 - 1.0 树莓派GPIO库wiringPi 点亮LED
  8. Hadoop-RPC底层实现与解析
  9. arcgis java api,Java中调用ArcGIS Server REST API
  10. ai人工智能操控什么意思_为什么要建立AI分散式自治组织(AI DAO)
  11. JDBC实现增删改查功能
  12. 2021 常用的 7 款 MySQL 客户端工具
  13. [导入]WAP开发教程
  14. Java学习到什么程度可以找第一份工作?
  15. P2504 [HAOI2006]聪明的猴子-题目详解
  16. 广州特耐苏-广州风淋通道构造及特点
  17. 对话祁隆《借我星光》作词人温暖:已获知和合国际收购信息
  18. 真c++ 从二叉树到红黑树(3)之二叉搜索树BST
  19. 麦克内马尔检验(McNemar‘s Test)
  20. 【解决密码栏不显示】“可能是其他人在试图访问您的google账号....”

热门文章

  1. C语言 · 约数个数
  2. Tomcat发布Maven项目遇到异常:java.lang.OutOfMemoryError: PermGen space
  3. 片滚动插件myScroll
  4. linux整理笔记之六:samba软件包使用
  5. 自动化测试前序(https://blog.csdn.net/ling_mochen/article/details/79314118)
  6. python各进制、字节串间的转换
  7. linux下安装MySQL出错file /usr/share/mysql/charsets/latin2.xml from install of MySQL-......
  8. 使用MVVM绑定AppBar事件
  9. Virtools学习(七)—2D Picking
  10. Jscript 内部对象