垃圾“程序是怎樣練成的”——關於《C程序設計伴侶》第A章(五)


前文鏈接: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毫無關聯的錯誤同前,不再贅述。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM