为什么在2D数组中a和*指向同一地址?

时间:2018-01-12 11:56:27

标签: c arrays multidimensional-array

我只是想了解如何实现2D数组以及如何进行内存分配。所以我在给定的c程序中有一些疑问,为什么a和* a给出相同的地址。

#include<stdio.h>
main()
{
    int i,j;
    int a[3][3]={1,2,3,4,5,6,7,8,9};


    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            printf("%d\t",*(*(a+i)+j));
        }
        printf("\n");
    }


    printf("%d\n",a);
    printf("%d\n",a[0]+1);
    printf("%d\n",a[0][0]);
    printf("%d\n",a+1);
    printf("%d\n",*a);
}

这是输出 enter image description here

4 个答案:

答案 0 :(得分:3)

2D阵列与第一个1D阵列位于同一地址,而第一个1D阵列又与第一个元素位于同一地址。那就是它,没有更多的东西。

答案 1 :(得分:1)

实际上,数组是内存的范围。

在表达式中,数组指示符将转换为指向其第一个元素的指针。

类型为&a的表达式int (*)[3][3]给出了数组a存在的相同范围的地址。在这种情况下,数组a占用的内存可以通过以下方式解释

int b[1][3][3]= { { {1,2,3 } , { 4,5,6 }, { 7,8,9 } } };

并且表达式中使用的数组指示符b将转换为地址int ( * )[3][3]类型&a的第一个元素。

因此表达式

&a[0][0]
a[0]
a
&a

产生的值与数组占用范围的地址相同。

考虑到要输出指针,您应该使用转化说明符p而不是d

答案 2 :(得分:1)

首先,您不应使用%d来打印指针的地址,而应使用%p%d适用于可能适合或不适合表示地址的有符号整数,具体取决于实现。接下来,您将在C标记wiki的其他answer中找到有趣的参考资料。

现在直接回答。 int a[3][3];声明一个由3个整数组成的3个数组的数组。所以a[0](或*a)是三个元素的第一个数组。

printf("%p\n", *a);数组*a decays中指向其第一个元素的指针,即&a[0][0],换句话说,你得到数组开头的地址。 / p>

printf("%p\n", a);中,数组a也会衰减到指向其第一个元素&a[0]的指针。这里再次获得数组开头的地址,这就是打印值相同的原因。

但即使它们指向相同的地址,&a[0]&a[0][0]也是指向不同类型的指针:第一个指向3个整数的数组,而第二个指向整数。同样,&a仍将指向相同的地址,但仍然指向另一个类型和3个数组的数组到3个整数。

由于对象的地址是其第一个字节的地址,(char *) a(char *) *a(char *) &a都是相等的,并且是指向数组第一个字节的char指针。这是合法的,因为C语言指定可以将指向对象的指针转换为指向对象的第一个字节的char的指针。但是不允许将a传递给期望int *的函数,如果你这样做,正确的编译器应该发出不同间接级别的警告。

答案 3 :(得分:1)

理解2D阵列的直观方式就是这样......

a --> a[0] --> [1,2,3]
      a[1] --> [4,5,6]
      a[2] --> [7,8,9]

a [0],a [1],a [2]是逻辑表示而不是实际存储器。

so a[0] = a + 0*[bytes occupied by one row], 
   a[1] = a + 1*[bytes occupied by one row], 
   a[2] = a + 2*[bytes occupied by one row] 

因此*a => a[0] => a

请注意,即使地址相同,&#34;类型&#34;当我们调用a vs a[0]*a时,指针会发生变化。这可以通过(a + 1)和(a [0] +1)的打印输出轻松看出。