0

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 enter image description here

Roman Byshko
  • 8,591
  • 7
  • 35
  • 57
Coderandhacker
  • 135
  • 1
  • 11
  • 4
    Please use `printf("%p\n", (void*)expr)` to correctly and safely print pointer values. – aschepler Jan 12 '18 at 12:28
  • 4
    Please search before posting. This has been covered countless times. e.g. [How come an array's address is equal to its value in C?](https://stackoverflow.com/questions/2528318/how-come-an-arrays-address-is-equal-to-its-value-in-c) / https://stackoverflow.com/questions/1641957/is-an-array-name-a-pointer / https://stackoverflow.com/questions/4607128/in-c-are-arrays-pointers-or-used-as-pointers / etc. – underscore_d Jan 12 '18 at 12:33
  • 2
    @underscore_d To do justice to the OP: None of the questions you list is asking the same thing. The OP *dereferences* an array (quite the opposite of taking its address!) and is surprised to find that the result is identical to the array after "adjusting" its value to a pointer (by passing it to `printf`). He also does not wonder whether an array is a pointer, which would be a completely different question. – Peter - Reinstate Monica Jan 12 '18 at 15:20
  • 2
    [**Do not post images of code or errors!**](https://meta.stackoverflow.com/q/303812/995714) – Rob Jan 12 '18 at 15:35

4 Answers4

3

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    “Starts at” would be better phrasing than “resides on”. The array resides on many addresses, many of which are not the same as its first subarray or first element of that subarray. – Eric Postpischil Jan 12 '18 at 13:09
  • @Eric While that is true, it is also true for an `int`, which still can be said to "be" or "reside" at a given address. All objects but chars and probably bools are larger than a single addressable entity. – Peter - Reinstate Monica Jan 12 '18 at 15:21
1

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.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • After reading it a couple of times I understand what you want to say, but in C two variables cannot refer to the same object (e.g. an array `a` cannot be in the same position as an array `b`). You could be clearer by saying that the 3-dimensional array `b` can be seen as a 1-dimensional array of 2-dimensional arrays which each have the same *type* as `a`. – Peter - Reinstate Monica Jan 12 '18 at 15:38
  • @PeterA.Schneider My English is not good so sometimes it is difficult to understand what I wanted to say.:) – Vlad from Moscow Jan 12 '18 at 22:45
1

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.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Re “In `printf("%p\n", *a);` the array `*a` decays to a pointer to its first element,…”: In `*a`, there are two automatic conversions of an array to the address of its first element, not just one. Quite likely you are so familiar with C that you automatically think of `*a` as representing the first subarray of `a`. You do not need to consciously work through it. But, if we are answering for somebody who is new to this and who has to reason through these conversions explicitly, jumping over a step can seem cryptic. – Eric Postpischil Jan 12 '18 at 13:15
  • @EricPostpischil: are you thinking of *`*a` is `a[0]`*? – Serge Ballesta Jan 12 '18 at 13:19
  • 1
    In `printf("%p\n", *a)`, `a` is an lvalue that is an array. It is converted to a pointer to its first element. Then `*` dereferences the pointer, and the result is an lvalue that is an array. It is converted to a pointer to its first element. – Eric Postpischil Jan 12 '18 at 13:24
  • @EricPostpischil I got your point! But honestly I think it is simpler for a beginner to think that `a[i]` is the i-th element of array `a` than it is the lvalue obtained by converting `a` to a pointer to its first element, then doing pointer arithmetics to obtain a pointer to the i-th element and finaly dereferencing it... – Serge Ballesta Jan 12 '18 at 13:32
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).

Ketan Mukadam
  • 789
  • 3
  • 7