Why in a 2D array a and *a point to same address?

2020-05-06 12:01发布

问题:

I am just trying to learn how 2D arrays implemented and how memory allocation takes place. so I get some doubt in the given c program that why a and *a giving same address.

#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);
}

and here's the output

回答1:

A visual way to understand the 2D array is like this...

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

a[0], a[1], a[2] are logical representation and not actual memory.

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] 

Hence *a => a[0] => a

Note that even though the address is same the "type" of pointer changes when we invoke a vs a[0] or *a. This can be easily seen by your print output of (a+1) and (a[0]+1).



回答2:

The 2D array resides on the same address as the first 1D array, which in turn resides on the same address as the first element. That's it, there's nothing more to it.



回答3:

In fact arrays are extents of memory.

In expressions array designators are converted to pointers to their first elements.

The expression &a that has type int (*)[3][3] gives the address of the same extent where the array a exists. In this case the memory occupied by the array a can be interpreted the following way

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

and the array designator b used in expressions is converted to address to its first element of the type int ( * )[3][3] that is to &a.

Thus the expressions

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

yield the same value that is the address of the extent occupied by the array.

Take into account that to output pointers you should use the conversion specifier p instead of d.



回答4:

First, you should not use %d to print the address of a pointer, but %p. %d is meant for signed integers that may be or not appropriate to represent an address depending on the implementation. Next you will find interesting references in that other answer from the C tag wiki.

Now for a direct answer. int a[3][3]; declares an array of 3 arrays of three integers. So a[0] (or *a) is the first array of three elements.

In printf("%p\n", *a); the array *a decays to a pointer to its first element, namely &a[0][0], said differently you get the address of the beginning of the array.

In printf("%p\n", a); the array a also decays to a pointer to its first element &a[0]. Here again you get the address of the beginning of the array, that is why the printed values are the same.

But even if they point to same address, &a[0] and &a[0][0] are pointers to different types: first points to an array of 3 integers, while second points to an integer. And the same, &a will still point to the same address, but to still another type and array of 3 arrays to 3 integers.

As the address of an object is the address of its first byte, (char *) a, (char *) *a and (char *) &a are all equal and are a char pointer to the first byte of the array. This is legal because the C language specifies that a pointer to an object can be casted to a pointer to char pointing to the first byte of an object. But it is not allowed to pass a to a function expecting an int * and a correct compiler should emit a warning for different indirection levels if you did.