2015-10-25 98 views
-1

這是C代碼由丹尼斯里奇,章「陣列」:爲什麼我們需要「-'0'」來修改數組?

#include <stdio.h> 
/* count digits, white space, others */ 
main() 
{ 
    int c, i, nwhite, nother; 
    int ndigit[10]; 
    nwhite = nother = 0; 
    for (i = 0; i < 10; ++i) 
     ndigit[i] = 0; 
    while ((c = getchar()) != EOF) 
     if (c >= '0' && c <= '9') 
      ++ndigit[c-'0']; 
     else if (c == ' ' || c == '\n' || c == '\t') 
      ++nwhite; 
     else 
      ++nother; 
    printf("digits ="); 
    for (i = 0; i < 10; ++i) 
     printf(" %d", ndigit[i]); 
    printf(", white space = %d, other = %d\n", nwhite, nother); 
} 

爲什麼我們這一行需要-'0'

++ndigit[c-'0']; 

如果我將其更改爲++ndigit[c],程序不能正常工作。爲什麼我們不能只寫++ndigit[c]

我已閱讀本書的解釋,但我不明白。

只有'0','1',...,'9'具有連續遞增值時,這纔有效。幸運的是,對於所有字符集都是如此。根據定義,字符只是小整數,所以char變量和常量與算術表達式中的整數相同。這很自然,方便;例如,c-'0' 與對應於該字符0和9之間的值的整數表達式‘保存在c 0’到‘9’,並且因此對於陣列的有效下標ndigit

回答

3

理解爲什麼我們需要「-'0' 」你首先需要了解ASCII表 - http://www.asciitable.com/

現在你要明白,在C每個字符由0到127(255之間的數字來表示擴展)。

例如,如果你打印的字符 '0' 爲他的數值:

printf("%d", '0');

輸出:48

現在你已經聲明大小的數組10 - ndigit[ 10 ],其中n單元表示數字n作爲輸入的次數。

所以如果你收到'0'作爲輸入你想要做ndigit[ 0 ]++所以你需要從char轉換爲整數。你能做到這一點減去48(= '0')爲什麼我們使用的線++ndigit[c-'0'];

這就是如果c = '5',我們將得到

++ndigit['5' - '0']

++ndigit[ 53 - 48 ]

++ndigit[ 5 ]

完全一樣,我們希望它是

+0

「幸運的是,對於所有字符集都是如此」的想法是,這不會取決於特定的字符編碼,例如ASCII。它對所有字符集都是「真實的」,因爲它在C規範中。 '[c-'0']'也適用於編碼爲「0」的字符集,然後「ndigit ['0'] ++'將工作相同。 (除此之外,你的答案是正確的 - 只是想指出*它不依賴於ASCII *的主要觀點;) – usr2564301

+1

非常感謝!我使用ASCII更清晰,但你絕對正確 –

+1

你比MikeCat更好地解釋它! – FDuldul

3

c = getchar()將將讀取的字符代碼存儲到c,與字符代表的整數不同。

報價從N1256 5.2.1字符集

。在源和執行基本字符集中,上述十進制數字列表中0之後的每個字符的值 應該大於前一個值的 。

由於這顯示,對於十進制數字的字符代碼是連續的,所以你可以通過減去'0',這是0的字符編碼的十進制數字的字符代碼轉換爲整數的字符代表,從字符碼。

總之,c-'0'會得到c中字符所代表的整數。

+0

感謝親,現在我明白了 – FDuldul

+1

而'++ ndigit [c]'(更準確地說,只是位ndigit [c]')不起作用,因爲字符「0」的*值*可以超出'ndigit [10];(在使用ASCII的C的當前實現中,它的值將是'48')的允許索引。 – usr2564301

+0

@FDuldul:請閱讀[當某人回答我的問題時該怎麼辦?](http://stackoverflow.com/help/someone-answers)。您也可以閱讀本網站的簡短介紹。 – usr2564301