2015-04-05 90 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

相关问题