2009-12-08 70 views
0

我被分配來對其他人編寫的C程序進行一些更改......我想首先理解它以正確工作......我遇到了一個函數,該函數生成ASCII值的直方圖來自給定的一串長長的數據。這是這樣的。直方圖生成函數

//load the symbols the old data 
    for(int k = 0;k < 256;++k) 
    { 
    sym[k].Symbol = k; 
    sym[k].Count = 0; 
    } 

    //Creating the probability distribution for each of the source symbols. 
    for(int k = size;k;--k) 
    { 
    sym[*in ++].Count ++; 
    } 

這裏「中」是一個包含字符的字符陣列(字符串)要被計數。 sym是一個結構變量。我不太明白這是如何工作的。任何人都可以告訴我第二個循環如何生成字符串中符號1到255(ASCII)的計數?

+0

當然'sym'是一個結構數組(具有'Symbol'和'Count'字段),而不是你聲稱的結構本身? – 2009-12-08 18:58:11

回答

4
for(int k = 0; k < size; k++) 
    { 
    sym[in[k]].Count++; 
    } 

這基本上就是第二回路正在做的事情。

它們只是取消引用,然後在一個步驟中移動到下一個ascii值,併爲該ascii值增加計數器。

0

如果'in'是輸入字符串,那麼* in ++將取出字符串中的每個字符,並在ascii列表sym []中查找與該字符值相對應的條目。

因此,如果該字符串開頭「A」然後(*在)是65和它引用符號[65]

編輯:符號[k]的.symbol有點冗餘可以僅僅指剛有一個數組由於sym [n]必須爲符號編號'n',所以用256個整數表示ascii圖表。

1

總之,很差。基本思想非常簡單,但代碼無需複雜。特別是,他的Symbol成員完全沒用。

你通常想要做的是這樣的:

int counts[UCHAR_MAX] = {0}; 

size_t len = strlen(input_string); 
for (int i=0; i<len; i++) 
    ++counts[unsigned char(input_string[i])]; 

所以,這裏的基本想法是很簡單:通過串走,並在字符串中的每個項目,增加計數爲那個角色。

他在做同樣的事情,但保留Count作爲一個結構的成員,以及Symbol。由於Symbol總是等於該項目的下標,因此存儲它毫無意義且浪費。

除此之外,他在他的循環中倒數 - 可能是一個微優化,因爲(至少在某些機器上)零標誌將根據計數器的值在遞減時設置,以零來避免循環中的比較。考慮到他在結構上浪費的金額和不必要的存儲值,這根本就沒有意義。

如果你真的關心代碼是接近最優,你可以寫更多的東西是這樣的:

int counts[UCHAR_MAX] = {0}: 

while (*in) 
    ++counts[(unsigned char)*in++]; 

對於任何人想知道中投,這是不必要的如果你確定你的輸入會始終是真正的ASCII碼,永遠不會有高位設置。因爲你很少能夠保證輸入,所以通常轉換爲unsigned char更安全。否則,設置其最高位的字符通常會被解釋爲負數,並且索引超出數組範圍。當然,這是可能默認情況下字符是未簽名的,但它是非常罕見的。在典型的(二補)機器上,演員陣容不需要任何額外的操作;它只管理現有位模式將如何解釋。

+0

有趣的是,如何將原始代碼歸咎於不必要的複雜,但是在主循環之前保留了(不必要的)對長度的單獨計算。我認爲你的演員語法也是錯誤的。 – 2009-12-08 19:06:02

+0

而代碼不是通過字符串向後走。它正在遞減'k',但是從字符串的開始到結尾遞增指針'in'。 – 2009-12-08 19:16:52

+1

是的,你可以避免計算循環外的長度,但是(至少從我看到的)大多數人發現這種方式更容易理解。如果(且僅當)嚴格地爲C而不是C++,則強制轉換語法是錯誤的。然而,這些都沒有改變原始代碼毫無意義的複雜的事實。 – 2009-12-08 19:38:00

0

in++增量in,指向正在讀取的字符的指針。

*in++,解析爲*(in++),是當前讀取的字符。它也是一個數字,算法利用它將其用作數組中的索引。適當的計數(剛剛讀取的字符的計數)sym[*in ++].Count遞增。

0

第二個循環使用指針指向的字符的值來索引count數組。

調查此代碼的一個很好的方法是在它周圍放置一些printf語句。打印*的值,增加後打印計數。你很快會以這種方式得到這張照片。

另一種選擇是運行通過調試器不瞭解的代碼。

0

something++表示「將1加到something,並在加入之前返回其值」。

in是指向輸入的第一個字符的指針。

因此,*in++的意思是「將輸入指針向前移動一個項目,並返回它指向的項目」。

因此可以看到的是

sym[*in ++].Count ++;

指「移動輸入指針一個項目起,並遞增對應於在當前輸入指針的字符數組sym在元件的Count場定位它指向的項目「;

和封閉循環執行此size次,從而處理輸入。