1

Can anyone please explain visually as to how the 2D array is stored in memory as: a , &a, &a[0] , a[0] all have the same address... It seems like a pointer pointing to itself in a way...and that cant be right... This has been bugging me for nearly a year and searching on the web has lead me to no apt answer as well..... help is really appreciated....thanx

enter code here

#include<stdio.h>

int main()
{
    int a[2][3]={10,20,30,40,50,60};

    int row =0,col=0;

    printf("&a = %d ",&a);    
    printf("\na = %d ",a);
    printf("\n&a[0] = %d ",&a[0]);
    printf("\na[0] = %d ",a[0]);
    printf("\n&a[1] = %d ",&a[1]);
    printf("\na[1] = %d ",a[1]);
    printf("\n&a[0][0] = %d ",&a[0][0]);

    int *p;
    printf("\n\n sizeof(p) = %d ",sizeof(p) );

    printf("\n\n sizeof(a) = %d ",sizeof(a) );
    printf("\n\n sizeof(&a) = %d ",sizeof(&a) );
    printf("\n\n sizeof(&a[0]) = %d ",sizeof(&a[0]) );
    printf("\n\n sizeof(a[0]) = %d ",sizeof(a[0]) );
    printf("\n\n sizeof(&a[1]) = %d ",sizeof(&a[1]) );
    printf("\n\n sizeof(a[1]) = %d ",sizeof(a[1]) );
    printf("\n\n sizeof(&a[0][0]) = %d ",sizeof(&a[0][0]) );
}

OUTPUT

&a = 2293536
a = 2293536
&a[0] = 2293536
a[0] = 2293536
&a[1] = 2293548
a[1] = 2293548
&a[0][0] = 2293536

sizeof(p) = 4

sizeof(a) = 24

sizeof(&a) = 4

sizeof(&a[0]) = 4

sizeof(a[0]) = 12

sizeof(&a[1]) = 4

sizeof(a[1]) = 12

sizeof(&a[0][0]) = 4

Don't refer me to Memory map for a 2D array in C ... that didnt help ...

Community
  • 1
  • 1
  • Refer "http://stackoverflow.com/questions/12868003/pointers-with-two-dimensional-array/12869239#12869239" which describes similiar context โ€“ Vivek Maran Oct 18 '12 at 11:54

2 Answers2

5

So the array a is one object taking up a block of memory:

| a                                                         |

It's an array of length 2, so if we draw in the elements that make it up it looks like this:

| a[0]                        | a[1]                        |

a[0] in turn is an array of length 3, and looks like this:

| a[0][0] | a[0][1] | a[0][2] |

a[1] looks the same, so we can redraw the array a to look like this:

| a[0][0] | a[0][1] | a[0][2] | a[1][0] | a[1][1] | a[1][2] |

Notice that a, a[0] and a[0][0] are all located at the same point in memory: the start of the object a. However, they do have different sizes: a is the entire "2D array", a[0] is a regular array, and a[0][0] is a single `int.

This explains why &a, &a[0] and &a[0][0] are the same addresses (though they have different types) - they're the addresses of things located at the same point in memory.

Additionally, there's a rule that if an array is evaluated in an expression where it's not the subject of the unary & or sizeof operators, it evaluates to a pointer to its first element: that is, using a plain a is equivalent to &a[0]. Since a[0] is also an array, using a plain a[0] is equivalent to &a[0][0]. This explains why a and a[0] also evaluate to the same addresses as &a, &a[0] and &a[0][0].

The fact that the address of an array and the adddress of the first element in that array are the same isn't really surprising: the same thing happens with struct, too. Given:

struct { int a; int b; } x;

You'll find that &x and &x.a are the same address (albeit with different types).

caf
  • 233,326
  • 40
  • 323
  • 462
  • may i know the source of the rule? and when i use 'a' it means im using address of 'a' and when using '&a' it means im pointing to 'a' ....therego doesnt it mean a points to itself ???? โ€“ Vishnu Kumaar Oct 18 '12 at 14:50
  • 1
    @VishnuKumaar: The source of the rule is the C standard - it is defined in ยง6.3.2.1 in C99. The array doesn't point anywhere because it's not a pointer, it's an array. In most expressions `a` *evaluates to* a pointer to its first element, but that's not what it *is*. โ€“ caf Oct 18 '12 at 21:07
1

Except when it is the operand of the sizeof _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted to an expression of type "pointer to T" and the value of the expression will be the address of the first element in the array.

Assume the following memory map (assumes little-endian, 4-byte ints; addresses pulled out of thin air):

Item         Address          00   01   02   03    Sub array    Sub array element
----         -------          --   --   --   --    ---------    -----------------
   a         0xfffebc00       00   00   00   0a    a[0]         a[0][0]
             0xfffebc04       00   00   00   14                 a[0][1]
             0xfffebc08       00   00   00   1e                 a[0][2]
             0xfffebc0c       00   00   00   28    a[1]         a[1][0]
             0xfffebc10       00   00   00   32                 a[1][1]
             0xfffebc14       00   00   00   3c                 a[1][2]

Going by the rule mentioned above, the expression a will be converted from type "2-element array of 3-element array of int" to "pointer to 3-element array of int", and the value of the expression will be the address of the first element of the array. The first element of a is a[0], and the address of a[0] is 0xfffebc00.

Similarly, the expression a[0] will be converted from type "3-element array of int" to "pointer to int", and its value will be the address of the first element of the array. The first element of a[0] is a[0][0], and its address is ... 0xfffebc00.

The expression &a is one of the exceptions to the rule above. In this case, a is not converted to a pointer type before applying the & operator; the type of the expression is "pointer to 2-element array of 3-element array of int" (int (*)[2][3]), and its value is the address of a, which is ... 0xfffebc00.

Similarly, the expression &a[0] has type "pointer to 3-element array of int" and its value is the address of a[0], which is ... 0xfffebc00.

Hopefully the type and value of &a[0][0] should be obvious.

So yes, the expressions a, &a, *a, a[0], &a[0], and &a[0][0] all yield the same value, but their types are different: int (*)[3], int (*)[2][3], `int *, int *, int (*)[3], and int *, respectively.

John Bode
  • 119,563
  • 19
  • 122
  • 198