鸡窝里飞出伪凤凰
不少初學(xué)者在寫代碼時(shí)喜歡一main()到底——把所有的代碼都寫在main()函數(shù)中。代碼在作繭自縛的main()函數(shù)“迷宮”中像沒頭蒼蠅一樣左沖右突,寫到哪兒算哪兒。忙活了半天之后,終于成功“突圍”——可以運(yùn)行程序了,然后就一臉輕松。但是卻把main()函數(shù)弄得凌亂不堪,一地雞毛,形同雞窩。
這種代碼是一種“爬行”式思維的產(chǎn)物,是人類思維的一種返祖現(xiàn)象。人類在學(xué)會(huì)直立行走之前就是按照這種方式思考的。俗話說,站得高才能看得遠(yuǎn)。而匍匐在地上爬行,只能得到臟、亂、差的代碼。
這種代碼有一種變形,就是在一地雞毛的main()中可能會(huì)冷不丁地突然竄出一個(gè)令人眼前一亮的自定義函數(shù)調(diào)用,猶如一地雞毛的雞窩里仿佛要飛出一只金鳳凰似的。這樣的代碼多半出自那種半生不熟的新手,他們并不是自覺自愿地而往往是被強(qiáng)迫地使用一下自定義函數(shù)。這就使得代碼產(chǎn)生了一種滑稽的喜感,猶如一只小狗被要求站立起來作揖一樣,站立一秒鐘之后,很快就會(huì)重新伏到地上繼續(xù)爬行。下面的代碼就是一例:
#include <stdio.h>
int main( void )
{void inv(int x[],int n);
int i, a[10]={3,7,9,11,0,6,7,5,4,2};
printf("The original array:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
inv(a,10);
printf("The array has been vnverted:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
void inv(int *x,int n)
{int *p,temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}
————譚浩強(qiáng) ,《C程序設(shè)計(jì)》(第四版),清華大學(xué)出版社, 2010年6月,p241
首先來看main():
一進(jìn)門就可以看到main()函數(shù)的頭上頂著一條條幅——不是“北京歡迎您”,而是函數(shù)類型聲明“void inv(int x[],int n);”。這樣做的效果是使得main()顯得更加凌亂,并且有讓main()函數(shù)獨(dú)霸inv()函數(shù)使用權(quán)之嫌。因?yàn)槠渌a中的其他函數(shù)若需要調(diào)用inv()函數(shù)還得重新進(jìn)行函數(shù)類型聲明。這種不加思索地把函數(shù)類型說明隨便塞在某個(gè)地方的做法,絕不可能是出于事先周密思考權(quán)衡的結(jié)果,其原因估計(jì)多半只是為了對(duì)付編譯器的類型檢查而已。和下面的寫法對(duì)比一下,就不難發(fā)現(xiàn)函數(shù)類型聲明塞在函數(shù)內(nèi)部的荒謬性:
void inv(int x[],int n);
int main( void )
{
/*……*/
}
顯然,后者不但能完全實(shí)現(xiàn)樣本代碼的功能,而且main()更清爽,此外代碼的其他部分若需要調(diào)用inv()也不需要無謂地再次寫函數(shù)類型聲明了。
再繼續(xù)往下看
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
一地雞毛!在main()這樣重要的地方忙活雞毛蒜皮是庸人最擅長的事情。其原因在于:思想一直是在代碼層面上爬行,而又缺乏代碼重構(gòu)的意識(shí)。這是違背結(jié)構(gòu)化程序設(shè)計(jì)原則的一個(gè)報(bào)應(yīng)。結(jié)構(gòu)化程序設(shè)計(jì)要求“自頂向下”地思考,要達(dá)到這個(gè)境界,前提是要“站直了,別趴下”。一直趴著絕對(duì)寫不出優(yōu)雅,簡(jiǎn)潔的代碼。優(yōu)秀的代碼首先要站得高,其次很忌諱把事做“絕”。再往下看
View Code inv(a,10);前后都是一地雞毛,唯獨(dú)這個(gè)充分且簡(jiǎn)潔的函數(shù)調(diào)用猶如金鳳一樣擺出了一副展翅欲飛的優(yōu)美姿態(tài)。贊一個(gè)!再繼續(xù)看
View Code printf("The array has been vnverted:\n");for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
天哪!竟然寫出了和前面一模一樣的代碼!對(duì)于任何合格的程序員來說,這絕對(duì)是一種恥辱。這和車轱轆話來回說沒什么區(qū)別。這使得main()即使蒼蠅沒來下蛆就已經(jīng)臟亂得腐敗不堪了。當(dāng)然,有些人對(duì)此是不介意的。“不干不凈,吃了沒病”,你沒辦法對(duì)那些在垃圾桶里尋找食物的人說清楚什么叫做衛(wèi)生。“不干不凈,吃了沒病”這種想法在程序設(shè)計(jì)界的翻版“只要程序能運(yùn)行”,你同樣也無法和有些人說清楚代碼為什么應(yīng)該簡(jiǎn)潔優(yōu)美,這是沒有辦法的事情。但是,如果把這種丑陋的惡習(xí)寫在教科書里,那就成了一種教唆,我個(gè)人認(rèn)為應(yīng)該判刑。因?yàn)檫@就和《衛(wèi)生》課本里示范如何食用地溝油異曲同工。
再往后,就是那只從main()中飛出來的inv()函數(shù)的定義了。
{int *p,temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}
首先,把“int *p,temp,*i,*j,m=(n-1)/2;”這幾個(gè)變量定義緊密地寫在“{”之后是一種令人作嘔的風(fēng)格。此外,令人吃驚的是,實(shí)現(xiàn)如此簡(jiǎn)單的功能,居然一口氣使用了5個(gè)“蒙頭蓋臉”的變量——你從名字上絕對(duì)不可能看出這些變量是做什么用的。這也是趴在地上思考的成果。由于事先缺乏充分且有高度的思考,就免不了“東一榔頭西一棒子”地濫用變量(反正變量不要錢)。同樣是由于缺乏縝密的思考,所以使用這些變量只是由于一時(shí)興起,事后代碼作者自己恐怕也弄不清楚究竟這些變量的真正含義。實(shí)際上根本不需要這么多的變量。
首先來看p,它的作用僅僅是用來表示x+m這個(gè)值,顯然毫無必要,代碼完全可以寫成
{
int temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;
for(;i<=x+m;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}
再看m,它只是記錄了(n-1)/2這個(gè)在代碼中從沒有改變過的值而已,因而也沒有必要。
View Code void inv(int *x,int n){
int temp,*i,*j;
i=x;j=x+n-1;
for(;i<=x+(n-1)/2;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}
現(xiàn)在對(duì)代碼走查一下,假設(shè)n的值為3,那么i,j的變化情況為:
i??????????? ?j??????????
x????????? x+2????????
x+1?????x+1
不難發(fā)現(xiàn),當(dāng)i變化成x+1時(shí),程序進(jìn)行了一次毫無意義的交換。這說明“i<=x+(n-1)/2”這個(gè)表達(dá)式不但在寫法上過于啰嗦,在邏輯上也很非常蹩腳。實(shí)際上只要簡(jiǎn)單地?????????
{
int temp,*i,*j;
for(i=x,j=x+n-1 ; i < j ;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}
就可以了。
最后,
不但風(fēng)格上奇丑無比,而且同樣犯了把事做“絕”的毛病——絕則錯(cuò)。
所以,盡管從main()這個(gè)雞窩里飛了出來,但inv()只是一只“偽”鳳凰而已。
最后,對(duì)這段代碼重構(gòu)如下:
?
?
總結(jié)
- 上一篇: C#在线获取歌词(转)
- 下一篇: SmartQuery WebPart 2