2015-04-05 76 views
1

下面發生了什麼?float arrayName [] []和float(* arrayNamePointer)之間的區別是什麼[]

以下是由C的Primer Plus的摘錄:

const float rain[YEARS][MONTHS] = 
    { 
     { 4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6 }, 
     { 8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3 }, 
     { 9.1, 8.5, 6.7, 4.3, 2.1, 0.8, 0.2, 0.2, 1.1, 2.3, 6.1, 8.4 }, 
     { 7.2, 9.9, 8.4, 3.3, 1.2, 0.8, 0.4, 0.0, 0.6, 1.7, 4.3, 6.2 }, 
     { 7.6, 5.6, 3.8, 2.8, 3.8, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 5.2 } 
    }; 

    int year, month; 
    float subtot, total; 

    printf(" YEAR RAINFALL (inches)\n"); 

    for (year = 0, total = 0; year < YEARS; year++) 
    { 
     // for each year, sum rainfall for each month 
     for (month = 0, subtot = 0; month < MONTHS; month++) 
     { 
      subtot += rain[year][month]; 
     } 

     printf("%5d %15.1f\n", 2010 + year, subtot); 
     total += subtot; // total for all years 
    } 

我不得不改變這種使用指針,而不是數組下標。

所以我決定用:

[....] 

float (* rainPointer)[2]; 
rainPointer = rain; 

[....] 

subtot += *(*(rainPointer + year) + month); 

這適用於0年的年遞增正確與正確每月重置。但是,第一年並沒有指向我預期的目標。我經歷了這一百萬次,我將它們並排運行,rainPointer總是(在我眼中)看起來是正確的,年份和月份總是正確的。

我發現通過谷歌的答案,我應該使用:

subtot += *(*(rain + year) + month); 

什麼是雨水和rainPointer之間有什麼不同?爲什麼它們不一樣,如果它們都指向兩個整數的開始?

發生了某些事情,我顯然沒有意識到或完全缺失。

+3

它是'rainPointer'聲明的最內層數組維數是[[2]'而不是'[12]'還是'[MONTHS]')? – Wintermute 2015-04-05 16:17:06

+0

不是我所知道的嗎?我可能會誤解,但就書中所述(並且該片段是逐字的),您必須聲明一個指向數組的指針,該數組必須指向具有兩個整數的數組的起始位置?我沒有解釋得那麼好。 – 2015-04-05 16:32:55

+0

'int's似乎沒有涉及; 'rain'和'rainPointer'都涉及「浮動」數組。事情是:'rain'是每個12個'float'數組的數組,'rainPointer'是每個2個'float'數組的指針。它們並不完全兼容,只有在想要訪問數據時纔會這樣做,就好像它是在2D數組中放置的一樣(並且不關注嚴格的別名規則)。如果你想這樣做,那麼它聽起來好像你有預期的行爲。 – Wintermute 2015-04-05 16:37:17

回答

1

雨是一個二維陣列聲明如下

const float rain[YEARS][MONTHS]; 

在表達式中的陣列的名稱轉換爲指針數組的第一個元素。例如,如果你有一個數組

T rain[YEARS]; 

然後在表達rain轉換爲類型T *

事實上的指針的二維陣列是一維數組的元素,其反過來一維陣列。

因此聲明

const float rain[YEARS][MONTHS]; 

可以寫成像

typedef float T[MONTHS]; 
const T rain[YEARS]; 

其中T具有類型float [MONTHS}

那麼作爲rain被轉換爲指針,是指向其第一元件其第一行然後由於指針算術表達式rain + year是指向一維數組(行)t帽子對應今年。

表達式*(rain + year)產生這個數組就是這一行。

所以*(雨+年)是一排是一維數組。數組再次轉換爲指向其第一個元素的指針。元素的類型是const float因此,表達式*(rain + year) + month是指向此一維數組(行)中與給定月份對應的元素的指針。

最後表達式*(*(rain + year) + month)產生該行的該元素。

因此,使用表達式rain + year遍歷行。使用表達式*(rain + year) + month可遍歷給定行的元素 。

如果你想重寫只使用指針環路那麼他們可以像

const float (*rain_ptr)[MONTHS]; 
const float *month_ptr; 
float total = 0.0f; 

for (rain_ptr = rain; rain_ptr != rain + YEARS; ++rain_ptr) 
{ 
    // for each year, sum rainfall for each month 
    float subtot = 0.0f; 
    for (month_ptr = *rain_ptr; month_ptr != *rain_ptr + MONTHS; ++month_ptr) 
    { 
     subtot += *month_ptr; 
    } 

    printf("%5d %15.1f\n", 2010 + rain_ptr - rain, subtot); 
    total += subtot; // total for all years 
} 

當然,如果編譯器允許那麼就沒有任何必要的循環之前聲明的指針。最好在循環語句中聲明它們。

+0

謝謝。我認爲我大部分都理解了這一點,我確實掌握了數組名稱如何衰變爲指針,我明白爲什麼我的嘗試方法不需要(爲什麼指向使用rainPointer的數組的起始時間,我可以使用雨本身),我無法理解爲什麼使用rainPointer並做相同的算術給出了不同的結果。 – 2015-04-06 08:01:26

+0

@Scotty Smiles你能舉出一個能給出不同結果的例子嗎?順便說一下,您可能會在我的個人論壇中向我提問英文問題(第一部分),網址爲www.cpp.forum24.ru – 2015-04-06 08:15:08

+0

@Scotty Smiles請親自向我查看我對您問題的回答。:) – 2015-04-06 13:35:10

相關問題