用驴子拖宝马——怎样滥用结构体
買了一輛寶馬,但不知道如何正確使用,找頭驢子拖著寶馬滿世界兜風(fēng)。這情景多半會(huì)讓人感到很滑稽。不正確地使用結(jié)構(gòu)體,代碼同樣會(huì)產(chǎn)生一種滑稽的喜感。
只有按照合適的方式使用一件物品才能得到恰如其分的效果,而濫用一件物品只能起到適得其反的作用。
題目:
輸入兩個(gè)學(xué)生的學(xué)號(hào)、姓名和成績(jī),輸出成績(jī)較高的學(xué)生的學(xué)號(hào)、姓名和成績(jī)。
*/
#include <stdio.h>
int main()
{struct Student
{ int num;
char name[20];
float score;
}student1,student2;
scanf("%d%s%f",&student1.num,student1.name,&student1.score);
scanf("%d%s%f",&student2.num,student2.name,&student2.score);
printf("The higher score is:\n");
if(student1.score>student2.score)
printf("%d %s %6.2f\n",student1.num,student1.name,student1.score);
else if(student1.score<student2.score)
printf("%d %s %6.2f\n",student2.num,student2.name,student2.score);
else
{printf("%d %s %6.2f\n",student1.num,student1.name,student1.score);
printf("%d %s %6.2f\n",student2.num,student2.name,student2.score);
}
return 0;
}
————譚浩強(qiáng) ,《C程序設(shè)計(jì)》(第四版),清華大學(xué)出版社,2010年6月,p299
首先,這段代碼把結(jié)構(gòu)體的類型聲明寫在了main()之內(nèi),這是讓人感到驚異的。因?yàn)?#xff0c;根據(jù)標(biāo)識(shí)符的作用域原則,這意味著struct Student是一種“局部”的類型,也就是說只能在main()只能使用這種結(jié)構(gòu)體。
這樣使用結(jié)構(gòu)體其實(shí)反倒不如不使用結(jié)構(gòu)體,因?yàn)榛旧线@樣的寫法只收獲了使用結(jié)構(gòu)體的麻煩:定義結(jié)構(gòu)體類型,臃長(zhǎng)復(fù)雜的成員引用,……,但是,沒有得到任何好處。對(duì)比一下不用結(jié)構(gòu)體的代碼就清楚了:
不難看出,后者與前者功能一致,但是更加清爽,代碼也更簡(jiǎn)潔。既然如此,又有什么必要舍近求遠(yuǎn)地使用結(jié)構(gòu)體呢?可見樣本代碼使用結(jié)構(gòu)體完全是一種吃力不討好的行為。之所以吃力不討好,是因?yàn)闃颖敬a并非是正確使用結(jié)構(gòu)體的方式,而是一種錯(cuò)誤方式——只使用了結(jié)構(gòu)體的短處,而沒有發(fā)揮結(jié)構(gòu)體的任何優(yōu)勢(shì)。
當(dāng)然,后來的這段代碼也并非沒有缺點(diǎn):幾句形式上完全一致但卻有些臃長(zhǎng)的printf()函數(shù)調(diào)用缺乏視覺美感(兩個(gè)scanf()函數(shù)調(diào)用也有同樣的感覺)。可以把這些臃腫的內(nèi)容各自用一個(gè)函數(shù)來實(shí)現(xiàn):
這段代碼首先在視覺上比前一個(gè)要更富于美感,這種美感并不是一種裝飾,而是有著更為實(shí)惠的利益,那就是整潔優(yōu)美的代碼更不容易出錯(cuò),即使出錯(cuò)也比看起來爛糟糟的代碼更容易查找和得到改正。
這段代碼的另一個(gè)優(yōu)勢(shì)在于,如果現(xiàn)在需要修改輸出的格式,比如把%6.2f改為%6.0f,現(xiàn)在只需要修改一處而對(duì)main()函數(shù)部分的代碼毫無影響,而前兩個(gè)代碼則需要修改4處,且修改之處一起糾結(jié)于main()函數(shù)之內(nèi)。俗話說,常在河邊走難免不濕鞋。修改的地方多,工作量大不說,出錯(cuò)的可能性也大。
現(xiàn)在,你可能會(huì)覺得傳遞的參數(shù)也忒多了些。這個(gè)代碼中傳遞的參數(shù)是3個(gè),如果是7、8個(gè)呢?你可能會(huì)感到非常煩躁。并且,我在前一個(gè)代碼中悄悄的特意留下了一個(gè)小BUG(某個(gè)name2被寫成了name1),你可能根本就沒有察覺。查找這類錯(cuò)誤往往非常困難,比那種“比眼力找差別”的智力游戲還要困難。
那么,應(yīng)該如何回避這些問題呢?答案顯然是避免分散地傳遞這些參數(shù)。既然這些數(shù)據(jù)在邏輯上從屬于一個(gè)主體,最好把它們都捏合在一起。就像電工布線時(shí)是把兩個(gè)電線擰在一起一樣。你沒見過把火線和地線分別鋪設(shè)的電工吧?
在代碼中怎樣才能把幾個(gè)在邏輯上從屬于一個(gè)主體的數(shù)據(jù)捏在一起呢?顯然就是結(jié)構(gòu)體。結(jié)構(gòu)體的作用之一就是簡(jiǎn)化函數(shù)之間的參數(shù)傳遞。既然如此,就意味著不只一個(gè)函數(shù)會(huì)使用這種結(jié)構(gòu)體類型,所以絕對(duì)不應(yīng)該把結(jié)構(gòu)體的類型聲明放在某個(gè)函數(shù)內(nèi)部。現(xiàn)在你總應(yīng)該懂得為什么把結(jié)構(gòu)體類型聲明放main()里是一種愚蠢的、似是而非的寫法了吧?
在使用結(jié)構(gòu)體的前提下對(duì)前一個(gè)代碼繼續(xù)改進(jìn):
現(xiàn)在,只需要傳遞一個(gè)參數(shù),傳遞多個(gè)參數(shù)時(shí)個(gè)別實(shí)參寫錯(cuò)的可能性大大降低,代碼也更加簡(jiǎn)潔了。并且,由于結(jié)構(gòu)體各個(gè)參數(shù)在邏輯上從屬于一個(gè)整體,代碼更具有概括力,函數(shù)的意義也更為清晰。
總之,結(jié)構(gòu)體的意義在于其“整體性”,如果建立了結(jié)構(gòu)體,而只是對(duì)其進(jìn)行了成員運(yùn)算,那么結(jié)構(gòu)體的意義如果不能說是全部喪失,恐怕也可以說是幾乎全部喪失。
此外要補(bǔ)充一點(diǎn)的是,在結(jié)構(gòu)體尺寸較大的情況下,結(jié)構(gòu)體的賦值可能比較費(fèi)時(shí),這時(shí)可以用傳遞指向結(jié)構(gòu)體指針的辦法來解決。如前面的output()函數(shù),可以寫為
?
View Code?
? 形參中的第一個(gè)const表示p_std指針?biāo)赶虻慕Y(jié)構(gòu)體對(duì)象不應(yīng)該被函數(shù)改變,第二個(gè)const表示p_std這個(gè)指針本身也不應(yīng)該在函數(shù)中被改變。這種寫法在必須提供給函數(shù)一個(gè)結(jié)構(gòu)體對(duì)象的備份時(shí)并不適用。
??
轉(zhuǎn)載于:https://www.cnblogs.com/swjm119/archive/2012/01/21/2328557.html
總結(jié)
以上是生活随笔為你收集整理的用驴子拖宝马——怎样滥用结构体的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用XShell上传、下载文件(使用sz
- 下一篇: springboot的缓存技术