前文鏈接:http://www.cnblogs.com/pmer/archive/2012/12/15/2819274.html
【樣本】
// 表示文件的結構體 typedef struct _txtfile { char name[128]; // 文件名 char text[1024*128]; // 文件的文本內容 word* list; // 保存單詞的鏈表 int total; // 單詞總數 float correlation; // 關鍵詞在文件中的詞頻 } txtfile;
——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p283
【評析】
“將詞頻添加到txtfile結構體中”是個愚蠢的想法,因為后面要根據詞頻進行排序,而txtfile中text成員是個極其龐大、笨重的char [1024*128]類型的數據對象。這就跟讓一群人抱着水缸但卻讓他們按的個頭高低排好隊一樣。
【樣本】
——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p283
【評析】
數據結構反反復復一點譜都沒有,居然不以為恥反以為榮。
看到“對於txtfile結構體的不斷擴展,也反映了C語言面向結構程序設計中的‘逐步求精’的過程”這句話,任何懂得編程的人恐怕都會產生一種扔臭雞蛋的沖動。但是這本書的閱讀對象是並不懂得編程小朋友。悲夫?!
【樣本】
// 計算詞頻模塊的實現 // 參數files和count是保存txtfile結構體的數組指針和元素個數, // keyword是要計算詞頻的關鍵詞 void countkeyword(txtfile* files,int count,char* keyword) { // 利用for循環,計算關鍵詞在每一個文件中的詞頻 for(int i = 0; i < count;++i) { // 在當前文件中查找關鍵詞結點 word* keynode = findnode(files[i].list,keyword); // 如果找到結點,則計算詞頻 if(NULL != keynode) { // 利用單詞的個數除以文件的單詞總數計算詞頻 files[i].correlation = keynode->count/(float)files[i].total; } else // 如果沒有找到,詞頻為0 { files[i].correlation = 0.0f; } } }
——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p284
【評析】
本想這回可以不用說什么了。可一不小心看到了第二行注釋中的“參數files和count是保存txtfile結構體的數組指針和元素個數”。“數組指針”不知所雲。
【樣本】
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> //... int main() { // 文件讀取以及數據預處理… // 無限循環,提供用戶查詢交互 while(true) { puts("please input the keyword:"); char keyword[30] = ""; // 獲取用戶輸入的關鍵詞 scanf("%s",keyword); // 如果用戶輸入的是“#”,則表示查詢結束退出循環 if(0 == strcmp(keyword,"#")) break; // 計算用戶輸入的關鍵詞在各個文件中的詞頻 countkeyword(files,filecount,keyword); } return 0; }
——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p284~285
【評析】
“我們還需要在主函數中構造一個無限循環,讓用戶輸入關鍵詞”是奇葩。因為最初問題的要求是“現在要求輸入一個關鍵詞”。
自底向上地寫代碼最終往往得到的就是這么個效果:本來說是要畫美人的,結果畫成了張飛。
代碼中
char keyword[30]="";
中的初始化多余,30是MagicNumber。
scanf("%s",keyword);
中存在危險的漏洞。這句話應該寫為
scanf("30%s",keyword);
文雅一點的寫法是
#define MAX_LEN 30 #define S_(X) #X #define S(X) S_(X) scanf(S(MAX_LEN )"%s",keyword);
if(0 == strcmp(keyword,"#")) break;
也是隨心所欲的胡寫,因為在最初的要求中根本就沒這一條。
countkeyword(files,filecount,keyword);
這里的filecount和files沒有關系,非常滑稽。
這條語句應該寫為
countkeyword(files,sizeof files/sizeof *files,keyword);
【樣本】
#include <math.h> // … // 比較規則函數 int cmp(const void* a,const void* b) { // 將void*類型的參數轉換為實際的txtfile*類型 const txtfile* file1 = (txtfile*)a; const txtfile* file2 = (txtfile*)b; // 比較txtfile結構體的詞頻 if(fabs(file1->correlation - file2->correlation) < 0.001) { return 0; } else if(file1->correlation > file2->correlation) { return 1; } else { return -1; } } // 文件排序模塊的實現 void sortfiles(txtfile* files,int count) { // 調用qsort()函數對數組進行排序 qsort(files,count,sizeof(txtfile),cmp); } // 數據輸出模塊的實現 // 參數files和count是保存txtfile結構體數據的數組, // keyword是本次查詢的關鍵詞 void printfiles(txtfile* files,int count,char* keyword) { // 輸出本次查詢的關鍵詞 printf("the keyword is \"%s\"\n",keyword); // 輸出這個關鍵詞在各個文件的詞頻 puts("the correlations are "); for(int i = 0; i < count;++i) { printf("%s %.4f\n",files[i].name,files[i].correlation); } }
——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p284
【評析】
“根據問題的要求,我們需要根據各個文件的詞頻大小,對保存在數組中的txtfile文件結構體進行排序”這個想法很愚蠢,因為問題的要求並非如此,而且只需要根據詞頻對文件名排序就可以了,然而txtfile(不知道啥叫“txtfile文件結構體”)其他部分一同參與排序簡直是吃飽了撐的。
代碼部分:
cmp()函數形參名稱很垃圾。
if(fabs(file1->correlation - file2->correlation) < 0.001)
這樣的寫法是食古不化,不僅毫無必要,而且弄出了一個MagicNumber 0.001。這里其實可以直接寫
if( file1->correlation == file2->correlation )
另外這里的結構也可以寫得更簡單些
if( file1->correlation == file2->correlation ) { return 0; } if(file1->correlation > file2->correlation) { return 1; } return -1;
sortfiles()函數像沒用的裹腳布一樣包在了qsort()上,使得qsort()的cmp實參變得不明不白。應該直接調用qsort()函數。
【樣本】
while(true) { // 輸入關鍵詞… // 計算關鍵詞在各個文件中的詞頻 countkeyword(files,filecount,keyword); // 按照關鍵詞在各個文件中的詞頻,對文件進行排序 sortfiles(files,filecount); }
——陳良喬 ,《C程序設計伴侶》,人民郵電出版社,2012年10月,p286
【評析】
非但笨拙,而且脫離了問題的要求。filecount和files毫無關聯的錯誤同前,不再贅述。