滥用变量综合症
1.假如我国国民生产总值的年增长率为10%,计算10年后我国国民经济生产总值与现在相比增长多少百分比。计算公式为:
p=(1+r)^n
r为年增长率,n为年数,p为与现在相比的倍数。
解:从附录D(库函数)可以查到: 可以用pow函数求x^y的值,调用pow函数的具体形式是pow(x,y)。在使用pow函数时需要在程序的开头用#include指令将 <math.h>头文件包含到本程序模块中。可以用下面的程序求出10年后国民生产总值是现在的多少倍。
#include <stdio.h>
#include <math.h>
int main()
{float p,r,n;
r=0.1;
n=10;
p=pow(1+r,n);
printf("p=%f\n",p);
return 0;
}
运行结果:
p=2.593742
即10年后国民生产总值是现在的2.593742倍。
——谭浩强 ,《C程序设计(第四版)学习辅导》,清华大学出版社,2010年7月,p14
这个解答至少存在如下几方面的问题:
1.驴唇不对马嘴
从小学开始,老师就会教导我们不要答非所问。这个程序犯的第一个错误就是答非所问。
题目中要求“计算10年后我国国民经济生产总值与现在相比增长多少百分比”,然而程序给出的结果却是“10年后国民生产总值是现在的2.593742倍”。程序错没错,小学生都知道。
写程序最基本的一个常识是,要满足功能要求。不能装疯卖傻,指东打西。
把功能要求撇在一边,自说自话、自娱自乐且像盲人骑瞎马一样地写代码,是头脑不清的表现。这样的代码把小学老师多年的辛勤教诲毁之于一旦,是教小朋友学坏。
2.古怪的常数
10%、10这两个数是问题给出的条件,这种数据通常应该写成符号常量的形式:
#define GROWTH_RATE ((double)10/(double)100)
#define YEARS 10
这是良好的编程习惯。这样的好处至少有以下三点:
1).在某种程度上实现了数据与代码的分离,“把上帝的还给上帝,把魔鬼的交给魔鬼”。这是现代程序设计的一个基本思想。那种把数据和代码不分青红皂白地搅和在一起“乱炖”的写法,是缺乏基本编程素养的表现。
2).代码更具有可读性。显然“r=GROWTH_RATE;”的写法要比“r=0.1;”要好的多。
3).便于测试。只要将
#define YEARS 10
稍做修改就可以测试其他年(比如1年)后的情况。注意,这个修改是在预处理命令部分进行的,因此对main()中的代码没有任何影响。这从另一个角度表明了把数据与代码分离开的优越性。
3.滥用变量
很容易看出,代码中的那个变量p是压根不必要的。这个p变量唯一起到的作用是记录“pow(1+r,n)” 的值完成输出,然而“pow(1+r,n)” 本身既然有值,为什么不直接输出呢?printf("p=%f\n",pow(1+r,n));不是很漂亮的一条语句吗?何必画蛇添足地定义一个p呢?
同理,r与n这两个变量也是毫无必要的,因为代码根本就不需要这两个值改变,pow(1+0.1,(double)10)的作用和pow(1+r,n)完全一样。所以定义r与n这两个变量纯属于脱裤子放屁,多此一举,是糊里糊涂、莫名其妙的写法。
或问,pow(1+r,n)写起来不是比 pow( 1 + 0.1 ,(double)10)更简洁么?不然。常量就是常量,变量就是变量,把常量的值赋值给变量,利用变量的值进行运算事实上增加了代码出错的风险,因为变量的值可能无意中被错误地被改变,而且毫无意义地浪费内存资源。用增加错误风险和浪费资源的代价来换取代码的简洁不是正路子。
4.数据类型的问题
代码中的p、n、r被定义成了float类型,然而 0.1、pow(1+r,n)都是double类型,在
r=0.1
p=pow(1+r,n)
这两个赋值表达式中基本上必然会产生精度损失。这种精度牺牲非常无谓,没有任何回报。
5.题解中说“将<math.h>头文件包含到本程序模块中”,抱歉,谭大爷,“<”和“>”怎么竟然成了文件名的一部分?这两个符号可以出现在文件名中吗?那是预处理命令的成分,根本不是文件名的组成成分。
6.不规范
C标准中提到main()的写法有两种
int main(void){/**/}
和
int main(int argc,char *agrv[]){/**/}
把“()”内的形参内容省略,不符合规范。
最后,给出一个参考代码:
#include <stdio.h>
#include <math.h>
#define GROWTH_RATE ( (double)10 / (double)100 )
#define YEARS 10
int main( void )
{
printf ( "%d年后我国国民经济生产总值比现在增长 %f%%\n" ,
YEARS ,
( pow ( 1. + GROWTH_RATE , ( double ) YEARS ) - 1. ) / 1. * 100.
) ;
return 0;
}