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[])
{
int i,j,temp,max;
int a[]={}; for (i = ,temp =;i<strlen(x);i++)
{
temp=x[i]-;
a[temp]+=;
} for(i=,max = a[],j=;i<;i++)
{
if(max<a[i])
{
j=i;
max = a[i];
}
} return j+;
} int maxchar(char x[]);
int main()
{ char s[],c[];
int T,i;
scanf("%d",&T); for (i=;i<T;i++)
{
scanf("%s",s);
c[i]=maxchar(s);
} for (i=;i<T;i++)
{
printf("%c\n",c[i]);
} return ;
}
评析:
总体:
已经学会把函数类型声明写在函数定义外面了,但把其他函数定义写在main()之前,总体上还是有头重脚轻之感。
main():
char s[],c[];
int T,i;
s数组显然不应该定义在这里,因为这个数组只在第一个for语句内部用到。
c数组不应该定义为26个元素,因为题目中说的是“0<T<25”。
scanf("%d",&T);
这条语句无可指责,但输入后没考虑数据有效性。
for (i=;i<T;i++)
{
scanf("%s",s);
c[i]=maxchar(s);
} for (i=;i<T;i++)
{
printf("%c\n",c[i]);
}
原作者显然不了解这类ACM问题的套路(参见 C语言初学者代码中的常见错误与瑕疵(5) 11楼~13楼)。不过话说回来,ACM对这类问题的描述确实容易让外人误解,ACM是否应该自我检讨一下呢?
除了不了解ACM的套路,这里的一个有欠考虑的地方是没有注意检查输入数据的有效性(当然,ACM对此是不管不顾的)。如果考虑输入数据的有效性应该不理会无效数据:
scanf("%d",&T);
if ( <T && T < )
{
//求解问题
}
或者“死等”
while ( scanf("%d",&T) , !( <T && T < ) )
{
//提示重新输入
}
考虑的更周到些的话,可以
while ( scanf("%d",&T)!= || !( <T && T < ) )
{
while ( getchar()!='\n')
;
//提示重新输入
}
此外,这段代码中的
scanf("%s",s);
这句如果写成
scanf("%1009s",s);
就无可挑剔了。尽管ACM的测试数据不会出问题,但这是应该考虑到的一个问题。程序员最重要的品质应该是思虑周到。
maxchar()函数 :
int maxchar(char x[])
{
int i,j,temp,max;
int a[]={}; for (i = ,temp =;i<strlen(x);i++)
{
temp=x[i]-;
a[temp]+=;
} for(i=,max = a[],j=;i<;i++)
{
if(max<a[i])
{
j=i;
max = a[i];
}
} return j+;
} int maxchar(char x[]);
函数定义和函数类型声明都存在同一个问题,就是[]内的1010。这个是不应该写的,写了编译器也不“看”,写得毫无意义。
int a[]={};
这个写成
int a['z'-'a'+]={};
为好。注意这里应该是假定使用ASCII码制,如果不是ASCII码,代码不能这样写。
for (i = ,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语句的功能相对各自独立,各抽象为一个独立的函数为好。
for(i=,max = a[],j=;i<;i++)
{
if(max<a[i])
{
j=i;
max = a[i];
}
}
这个地方写得有点笨,主要是变量太多。作者用max记录最大值元素,用j记录其下标,其实只要一个j就够了
for(i=,j=;i<;i++)
{
if(a[j]<a[i])
{
j=i;
}
}
最后
return j+;
这个也是谭浩强之流不入流的写法,非常难看。应该写为
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 ( ! ( < T && T < ) )
return ; while ( T -- > )
{
char s[ MAX_LEN ]; scanf("%"N(S_LEN)"s" , s );
printf("%c\n" , find_major( s ) );
} return ;
} char find_major( char * s )
{
int num[ 'z' - 'a' + ] = { } ; count( num , s ) ; //统计字母个数
return 'a' + be_most( num , sizeof num / sizeof num[] );//返回出现最多字符
} 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)的更多相关文章
- C语言初学者代码中的常见错误与瑕疵(23)
见:C语言初学者代码中的常见错误与瑕疵(23)
- 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)
问题: 问题出处见 C语言初学者代码中的常见错误与瑕疵(5) . 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己 ...
- C语言初学者代码中的常见错误与瑕疵(5)
问题: 素数 在世博园某信息通信馆中,游客可利用手机等终端参与互动小游戏,与虚拟人物Kr. Kong 进行猜数比赛. 当屏幕出现一个整数X时,若你能比Kr. Kong更快的发出最接近它的素数答案,你将 ...
- C语言初学者代码中的常见错误与瑕疵(19)
见:C语言初学者代码中的常见错误与瑕疵(19)
- C语言初学者代码中的常见错误与瑕疵(14)
见:C语言初学者代码中的常见错误与瑕疵(14) 相关链接:http://www.anycodex.com/blog/?p=87
- 分数的加减法——C语言初学者代码中的常见错误与瑕疵(12)
前文链接:分数的加减法——C语言初学者代码中的常见错误与瑕疵(11) 重构 题目的修正 我抛弃了原题中“其中a, b, c, d是一个0-9的整数”这样的前提条件,因为这种限制毫无必要.只假设a, b ...
- 要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)
在 C语言初学者代码中的常见错误与瑕疵(7) 中,我给出的重构代码中存在BUG.这个BUG是在飞鸟_Asuka网友指出“是不是时间复杂度比较大”,并说他“第一眼看到我就想把它当成一个数学问题来做”之后 ...
- 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,计算可以从中找到 ...
- C语言初学者代码中的常见错误与瑕疵(1)
曾在豆瓣上看到过一个小朋友贴出他自己的代码(http://www.douban.com/group/topic/40293109/),当时随口指点了几句.难得这位小朋友虚心修正.从善如流,不断地改,又 ...
随机推荐
- magento去掉小数点后面的0
<?php echo $_product->getPrice()?> PHP number_format() 函数 <?php echo number_format($_p ...
- 9Types of Leader
Using the Enneagram Personality Types: The Perfectionist. The People Pleaser. The Achiever. The Indi ...
- css中的zoom的使用
css中的zoom的使用 zoom : normal | number normal : 默认值.使用对象的实际尺寸 number : 百分数 | 无符号浮点实数.浮点实数值为1.0或百分数为1 ...
- thinkphp文章列表及删除文章
出师不利,数据一次删完了... 教程:http://www.thinkphp.cn/topic/9757.html 首先要构造mysql数据库 模板代码 </head> <body& ...
- Centos php项目发布问题
LAMP环境,项目运行错误日志路径:/var/log/httpd 错误日志例如: [Sat Jul :: ] [error] [client , referer: http://192.168.100 ...
- Oracle数据库之PL/SQL基础
介绍PL/SQL之前,先介绍一个图像化工具:Oracle SQL Developer 在oracle的开发过程中, 我们难免会使用第三方开发的软件来辅助我们书写SQL, pl/sql是一个不错的sql ...
- SocketServer model_use
#!/usr/bin/env python #-*- coding:utf- -*- import SocketServer class MySocker(SocketServer.BaseReque ...
- 仿Smarty替换模板标签时遇到的问题
最近正在做一个微型的仿TP框架,当然以鄙人之技术只能略仿表层,于是遇到的问题层出不穷.今天做到View层替换模板部分,本以为一下子搞掂的事,果不其然又是败下阵来. 好了,来重点. 模板文件 test1 ...
- Android 开发环境搭建以及编译
两种搭建编译环境的方式,一种方法是用户安装虚拟机,然后安装基础的Ubuntu12.04.2 系统,利用提供的工具和详细的使用步骤,搭建编译环境:另外一种方法是用户安装虚拟机,然后直接加载 “搭建好的U ...
- MySQL Replication的相关文件
1.master.info文件 位于slave端的数据目录下,存储slave连接到master的相关信息,如,master主机地址.连接用户.密码.端口.已经获取的日志信息. 复制过程中修改.删除ma ...