垃圾代码评析——关于《C程序设计伴侣》6.2(三)
2012-11-06 00:10
260 查看
前文链接:/article/4777467.html
【样本】
输出二维数组结果排序完成之后,我们对于数据的处理就已经完成了,最后的任务就是将处理后的数据输出,告诉用户数据的处理结果。自然地,要将二维数组中的数据输出,我们还是利用for语句来循环遍历实现:
1. // … 2. 3. int main() 4. { 5. // … 6. 7. // 输出结果数据 8. for(int i = 0; i < classnum;++i) 9. { 10. printf("average score is %.2f :\n", 11. getaver(scores[i])); 12. 13. for(int j = 0; j < stnum; ++j) 14. { 15. if(0 == scores[i][j]) 16. break; 17. printf("%4d",scores[i][j]); 18. } 19. printf("\n"); 20. } 21. return 0; 22. }
因为此时的二维数组已经是排序完成的,我们只需要利用for语句循环遍历所有数据将其全部输出就可以了。在输出的时候,我们还顺带输出了各个班级的平均成绩,这时我们使用“scores[i]”调用getaver()函数,这也说明它其实就是各个一维数组的首地址。
——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p105~107
【评析】
大体上这段代码还过得去,如果是初学者的习作应该能得70分。但在书里这样写有些说不过去了。首先,把这么长的代码挤在main()中不妥,很业余。抽象为一个函数完成这个功能为好。
其次,代码的
10. printf("average score is %.2f :\n", 11. getaver(scores[i]));
居然再一次计算了各个班的平均成绩。作为专业程序员,如果没有特别过硬的理由,这绝对是一种奇耻大辱。这一方面反应了作者在思考代码时没有很好地进行数据结构的设计(整天把“算法才是王道”挂在嘴边的都爱犯这种毛病),另一方面反应了作者在算法方面也缺乏全盘考虑就开始写代码了,写到最后也顾不了那么多了,只好在这里随手打了一块难看的补丁。
代码中还有几处很业余的地方,例如
15. if(0 == scores[i][j]) 16. break;
这种写法显然是因为作者不懂得&&运算符的运算规则的缘故。(在该书77页,作者是这样讲解&&运算的:“例如:(a>0)&&(b>0) 在计算这个逻辑表达式的值的时候,会根据小括号确定的运算次序(或者表达式的默认运算顺序),首先计算a>0和b>0这两个关系表达式的值,然后逻辑运算符“&&”会根据这两个关系表达式的值最终得出整个逻辑表达式的值。”)不懂得细节就写不出漂亮的代码,神在细节当中。
其实那个内层循环语句应该这样写:
for(int j = 0; ( j < stnum ) && ( 0 != scores[i][j] ); ++j) { printf("%3d ",scores[i][j]); }
这里的另一处改动是把printf()中的实参"%4d"改成了"%3d ",这样即使scores[i][j]达到四位输出也不至于乱套。
最后一处
19. printf("\n");
还是写
putchar ('\n');
为好。当然,这只是一个小细节。
【重构】
绝对不要上来就写 “6个班,每个班的人数不等,但最多不超过100个” 这种傻乎乎的代码,理由很简单,根本无法测试!因此这里将这个条件改为“4个班,每个班的人数不等,但最多不超过3个”。这样便于测试,将来修改这两个常数也很容易。其次,既然原来的代码使用了qsort()标准函数,这里也将同样使用。
第三,设定分数不可能为负值,输入负值表示该班级分数输入完毕。
下面边分析边写代码。
首先,用枚举常量描述问题的规模:
enum { STNUM = 3 , CLNUM = 4 };
使用如下的数据结构描述班级:
typedef struct { int scores[STNUM] ; double average ; } CLASS ;
这样,所有的班级就构成了一个数组。
CLASS classes[CLASS_NUM];
总体思路非常简单:
int main( void )
{
CLASS classes[CLASS_NUM];//输入成绩
//计算平均分
//调用qsort()函数排序
//输出排序后各班成绩
return 0;
}
下面是完成之后的代码:
#include <stdio.h>
#include <stdlib.h>
enum {
STUDENT_NUM = 3 ,
CLASS_NUM = 4
};
typedef
struct {
int scores[STUDENT_NUM] ;
double average ;
}
CLASS ;
#define SIZE(A) ( sizeof(A) / sizeof((A)[0]))
void input_gr( CLASS [] , size_t );
void input_cl( int [] , size_t );
void cal_gr ( CLASS [] , size_t );
double cal_cl ( int [] , size_t ) ;
int cmp( const void * , const void * );
void output_gr( CLASS [] , size_t );
void output_cl( int [] , size_t );
int main( void )
{
CLASS classes[CLASS_NUM];
input_gr( classes , SIZE(classes) );//输入成绩
cal_gr ( classes , SIZE(classes) );//计算平均分
qsort( classes , SIZE(classes) , sizeof(CLASS) , cmp );//调用qsort()函数排序
output_gr( classes , SIZE(classes) );//输出排序后各班成绩
return 0;
}
void output_cl( int scr [] , size_t n)
{
size_t i ;
for( i = 0 ; (i < n)&&( scr[i] >= 0 ) ; i ++ )
printf( "%3d " , scr[i] );
putchar('\n') ;
}
void output_gr( CLASS cl[] , size_t n)
{
size_t i ;
for( i = 0 ; i < n ; i ++ )
{
output_cl( cl[i].scores , SIZE(cl[i].scores) );
printf( "平均分为:%f。\n" , cl[i].average ) ;
}
}
int cmp( const void *elem1 , const void *elem2 )
{
if(((CLASS *)elem1)->average > ((CLASS *)elem2)->average )
return 1;
if(((CLASS *)elem1)->average < ((CLASS *)elem2)->average )
return -1;
return 0;
}
double cal_cl ( int scr[] , size_t n )
{
size_t i ;
int total ;
if( n == 0 )
return 0.;
for(
i = 0 , total = 0 ;
( i < n ) && ( scr[i] >= 0 ) ;
i ++
)
{
total += scr[i] ;
}
return (double)total/(double)i;
}
void cal_gr ( CLASS cl[] , size_t n )
{
size_t i ;
for( i = 0 ; i < n ; i ++ )
cl[i].average = cal_cl ( cl[i].scores , SIZE(cl[i].scores) ) ;
}
void input_cl( int scr [] , size_t n)
{
size_t i ;
for( i = 0 ; i < n ; i ++ )
{
scanf( "%d" , scr + i );
if( scr[i] < 0 )
return ;
}
}
void input_gr( CLASS cl[] , size_t n)
{
size_t i ;
for( i = 0 ; i < n ; i ++ )
{
printf( "输入%d班成绩,输入负数表示结束:\n" , i + 1 ) ;
input_cl( cl[i].scores , SIZE(cl[i].scores) );
}
}
相关文章推荐
- 垃圾代码评析——关于《C程序设计伴侣》6.2(二)
- 垃圾代码评析——关于《C程序设计伴侣》6.2(一)
- 垃圾代码评析——关于《C程序设计伴侣》9.4——链表(四)
- 垃圾代码评析——关于《C程序设计伴侣》9.4——链表(三)
- 垃圾代码评析——关于《C程序设计伴侣》6.3.7
- 垃圾代码评析——关于《C程序设计伴侣》9.4——链表(一)
- 垃圾代码评析——关于《C程序设计伴侣》9.4——链表(二)
- 垃圾代码评析——关于《C程序设计伴侣》9.4——链表(三)
- 垃圾“程序是怎样练成的”——关于《C程序设计伴侣》第A章(五)
- 垃圾“程序是怎样炼成的”——关于《C程序设计伴侣》第A章(一)
- 垃圾“程序是怎样练成的”——关于《C程序设计伴侣》第A章(三)
- 垃圾“程序是怎样练成的”——关于《C程序设计伴侣》第A章(六)
- 垃圾“程序是怎样练成的”——关于《C程序设计伴侣》第A章(四)
- 垃圾“程序是怎样炼成的”——关于《C程序设计伴侣》第A章(二)
- 一段关于自增1输出的垃圾代码
- 垃圾“程序是怎样练成的”——关于《C程序设计伴侣》第A章(三)
- ASP.net关于C#代码与javaScript函数的相互调用
- 关于Java两种同步方法的理解(代码块级同步对象设置)
- 关于iStorageServer.CHS为XenServer 6.2创建高可用存储问题
- 转载的一篇关于如何优化JAVA代码及提高效率的文章