使用数组名称作为二维数组的地址

时间:2016-01-06 20:49:57

标签: c arrays

我知道对于C中的一维数组,您可以使用数组的名称作为地址:

int k;
double x[6], sum=0;
...
/*  Sum the values in the array x.  */
for (k=0; k<=5; k++)
    sum += *(x+k);

我的问题是,为什么这对二维数组不起作用?

int g[2][4]={{5,2,2,3},{1,2,3,4}};
int g_count=8, k, sum=0;

for (k=0; k<=g_count-1; k++)
    sum += *(g+k);

我注意到虽然&g[0][0]g保持相同的值,但&g[0][0]+1g+1却没有。有人可以解释一下原因吗?感谢。

6 个答案:

答案 0 :(得分:2)

声明为(*g)g[M][N]的大小是N乘以元素的大小。原因很简单,第一个索引的增量将“跳过”内存中的N个元素。因此*(g+k)相当于&g[k][0]。请注意,取消引用g(g+k)会返回子阵列的地址

答案 1 :(得分:2)

问题1

  

我的问题是,为什么这对二维数组不起作用?

<强>答案

for (k=0; k<=g_count-1; k++)
    sum += *(g+k);

有两个错误。

  1. *(g+k)未评估为int
  2. *(g+k)k > 1
  3. 时访问数组越界

    g被声明为:

    int g[2][4];
    

    g衰减为int (*)[4]类型的指针。它不会衰减为int*类型的指针。

    g+k评估的是哪种类型?它还会计算为int (*)[4]类型的指针。

    它指向哪里?用图表来看是很有帮助的。

    |<---     memory used by g   -->|
    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
    
    address of g
    |
    v
    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
    
    address of g[0] address of g[1]
    |               |
    v               v
    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
    

    在表达式中使用时,g会衰减到g[0]的地址。

    表达式g的计算结果为g[0]的地址  表达式g+1的计算结果为g[1]

    的地址
    g               g+1             g+2
    |               |               |
    v               v               v
    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
    

    如您所见,g+k指向k > 1之后超出有效限制的位置。在g+k时,Derefercencing k > 1将导致未定义的行为。

    您可以使用:

    int* ptr = &g[0][0];  // Pointer to the first int in the 2D array.
    for (k=0; k<=g_count-1; k++)
        sum += *(ptr+k);
             // ^^^ ptr, not g
    

    这将有效地使用数组和指针。

    问题2

      

    我注意到虽然&g[0][0]g保持相同的值,但&g[0][0]+1g+1却没有。有人可以解释一下原因吗?

    <强>答案

    鉴于阵列,我们有:

    g               g+1
    |               |
    v               v
    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
    
    &g[0][0]
    |   &g[0][0]+1
    |   |
    v   v
    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
    

    从图中,您可以看到为什么表达式g&g[0][0]计算到同一地址。但是,表达式的类型不一样。表达式g评估为int (*)[4],而&g[0][0]评估为int*

    由于表达式g的类型为int (*)[4],因此gg+1之间的偏移量与4 int的大小相同。

    由于表达式&g[0][0]的类型为int*,因此&g[0][0]&g[0][0]+1之间的偏移量与int的大小相同。< / p>

    这解释了为什么g+1评估的地址与&g[0][0]+1不同,即使g&g[0][0]评估到同一地址。

答案 2 :(得分:0)

为了理解这是如何工作的,你必须考虑你正在创造什么。在创建数组数组时,实际上是在创建一个指针数组。即

mainFcty

这里,抓取第一个数组中的第0个值与抓取[0] [0]相同。但是,抓取第一个数组中的第一个值与抓取[0] [1]不同,它与抓取[1] [0]相同。

<强>更新

我修改了图表,以显示第一个数组如何指向一组独立的数组以形成2D数组,以更好地说明我的观点。

第二次更新

经过一番讨论后,看来这实际上并不正确。第一个数组不是指向数组的指针数组,如前所述。第一个数组包含类型&#34;数组&#34;的元素。 (它与类型&#34;指针&#34;不同),因此不等同于指向数组的指针数组。更合适的图表如下:

       0 1 2 3 4
0[] -> [][][][][]
1[] -> [][][][][]
2[] -> [][][][][]
3[] -> [][][][][]
4[] -> [][][][][]

顶行显示第一个数组的索引,底行显示第二个数组的索引。现在,看看原始问题,它只是偏移到该阵列的问题。第一对(&amp; g [0] [0]和g)都偏移到数组0中。第二对(&amp; g [0] [0] +1和g + 1)具有不同的数组偏移量因此提供不同的价值观。有关详细说明,请参阅@R Sahu的答案。

答案 3 :(得分:0)

对于2D数组,数组的名称也是地址,但是 2D阵列中第一个1D数组的地址。

所以,

  • g[0]是第一个1D数组的地址。
  • g[1]是第二个1D数组的地址。
  • 等等。

要访问单个元素,例如第一个1D数组,您需要以下内容:

    {li> *( g[0] + 0 ) g[0][0] {li> *( g[0] + 1 ) g[0][1]

通常,您需要*( g[i] + k )才能访问元素g[i][k]

答案 4 :(得分:0)

首先需要了解指针与数组和指针算术之间的关系 在表达式中使用时,在大多数上下文中,数组将转换为指向其第一个元素的指针 对于1D阵列

double x[6];  

x将转换为指向其第一个元素x[0]的指针。对于2D阵列

int g[2][4];

g将转换为指向其第一个元素g[0]的指针。请注意,g[0]本身就是一个数组,因此g实际上转换为指向数组的指针。

请注意,如果p是指向T类型的指针,则添加1会将其增加到内存中的sizeof(T),即下一个连续元素的地址。

因此,表达式*(g+k)等同于*(&g[0] + k)。由于&g[0]是数组的地址,因此添加1将提供g[1]的地址,并向其添加k将提供g[k]的地址。

答案 5 :(得分:-1)

sum += *(x+k);有效,因为此处(因为xint的一维数组)x是指向int的指针所以当递增{时{1}}它指向位置k

的数组元素

x[k]不起作用,因为此处(因为sum += *(g+k);g的二维数组)int是指向{{1}的一维数组的指针所以当我们将g增加g时,它指向数组int。因此,当您通过k取消引用它时,您将获得数组g[k],这是第一个元素的地址。

因此,对于以下代码段:

*(g+k)

您将获得g[k]

第一列中所有元素的总和