1

In the following piece of code, I am getting the first two values of addresses same(call it x). I have run it on gcc compiler of ubuntu v18.04.4 LTS.

  int a[2][2] = {0};
  printf("%p %p %d\n", a, *a, **a);

This mean that:

  1. a contains the address x.
  2. a is pointing to the location x(as it is a pointer which is storing x).
  3. this means *a is stored in location x and it also contains the value x(as in the output of above code).
  4. now, on dereferncing *a i.e, **a, I am getting output as 0 which means that *a (whose value is x) is pointing to some location in which 0 is stored.

Now, from 1. , address of *a is x (as a points to *a and is storing x) and address of the number 0 is also x (as *a points to a[0][0] which is 0 and *a is storing x). So my question is what exactly is stored at the location x? Or have I mistaken something in making the conclusions?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
sksingh
  • 27
  • 1
  • 8
  • 1
    Arrays are not pointers. Pointers are not arrays. A sign pointing to the gas station is not a gas station. The gas station is not a sign pointing at the gas station. A sign does not contain gas. A gas station, when referred to by people trying to reach it, will be found at a street address. The gas station is not a street address, it's a building containing gas. A street address is not a gas station. And so on... – Lundin Jun 25 '20 at 12:06
  • Aren't array names used as pointers? Yes, a gas station can't point to another gas station. But as far as I know pointers do point to pointers! – sksingh Jun 25 '20 at 12:30
  • [Is an array name a pointer?](https://stackoverflow.com/questions/1641957/is-an-array-name-a-pointer). – Lundin Jun 25 '20 at 12:38
  • Thank you very much for that :). I now understand that array and pointer are two different things (there sizeof() return value is the only difference I figured out) but still isn't the array name decaying to a pointer and being used as a pointer? – sksingh Jun 25 '20 at 13:28

2 Answers2

2

I have not understood what is the magic 'x'.;)

You declared a two-dimensional array

int a[2][2] = {0};

Array designators used in expressions (with rare exceptions as for example using them in the sizeof operator) are implicitly converted to pointers to their first elements.

So the expression a used in this call

printf("%p %p %d\n", a, *a, **a);

is converted to the pointer of the type int ( * )[2] to the first element of the array. That is it is the address of the memory extent occupied by the array.

Using the indirection operator * the expression *a yields the first element of the type int[2] of the original array a.

Again this array designator *a in the call of printf is implicitly converted to pointer of the type int * to its first element that has the type int. This pointer will contain the same address of the memory extent occupied by the original array.

In this expression **a there are applied two indirection operators. The first indirection operator yields the first element of the two-dimensional array that is it yields an array of the type int[2]. This array used as an operand of the second indirection operator at once is implicitly converted to pointer to its first element that has the type int *. The second indirection operator yields the object pointed to by the pointer that is the object of the original array a[0][0] that is outputted by the printf call shown above. As this element was explicitly initialized by 0 then 0 is outputted as the value of the element.

To make it more clear the first indirection operator *a is equivalent to using the subscript operator a[0]. And the second indirection operator applied to this expression *a[0] is equivalent to the expression a[0][0].

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • After I ran the code I was getting the first two values i.e a and *a as same and this address location, I have called x as mentioned in the first line. I guess you have not completely understood my question, I wanted to ask that what exactly is stored at the memory address x? – sksingh Jun 25 '20 at 12:25
  • @SaketSingh At this address there is stored the array more precisely the first element (row) of the array a[0] and the first element a[0][0] of the first row. – Vlad from Moscow Jun 25 '20 at 12:34
  • I get that a[0][0] is stored here but how come a[0] is also stored here? – sksingh Jun 25 '20 at 13:24
  • @SaketSingh It is the starting address of the first row of the array. So this memory is occupied by the first row starting from its sub-object a[0][0]. That is this address is the address of the whole array, its firs element of the type int[2] and in turn of its element of the type int. – Vlad from Moscow Jun 25 '20 at 13:28
  • The bit configuration of this location can be only one thing as far as I understand. The value a[0][0] and a[0] are different, so how can both be stored in this location? – sksingh Jun 25 '20 at 13:33
  • @SaketSingh There is no variable which stores the address of `a`. Imagine that whenever you write `a` by itself, the compiler changes it to `&a[0]`. `&a[0]` is not a variable so it doesn't have an address. (`a[0]` is a variable, and its address is `&a[0]`). And the compiler changes \*a to &a[0][0] (actually it would be &(\*&a[0])[0] but the extra \*& cancels out) – user253751 Jun 25 '20 at 13:36
  • @SaketSingh To make it clear consider a definition of an object of a structure type. For example struct S { int x; } s = { 0 }; You may say that the memory at the address &s is occupied by the object s because this memory belongs to the object s. On the other hand at this address there is the data member x of the object s. – Vlad from Moscow Jun 25 '20 at 13:42
  • @SaketSingh The same is valid for arrays. An array occupies an extent of memory. So the array is placed in the extent starting from its address. On the other hand of course all elements of the array are not placed at this position. In this position there will be the first element of the array. But the memory belongs as to the array in whole and to its first element. – Vlad from Moscow Jun 25 '20 at 13:42
  • Thank you very much for that :). The last three comments really clear my doubt. – sksingh Jun 25 '20 at 13:43
2

Your assertion that a contains an address seems to indicate that you think a is a pointer. It is not a pointer but an array. They are related, but they are not the same thing.

An array, in most contexts, decays to a pointer to its first member. In this case, this means that in an expression a is the same as &a[0] and *a is the same as a[0] which is the same as &a[0][0]. This also means that the address of an array is the same as the address of its first member, which is what you're seeing when you print a and *a.

This would probably be better illustrated with a diagram:

      -----   -------   ----  ---
0x100 | 0 |   a[0][0]   a[0]  a
      -----   -------   
0x104 | 0 |   a[0][1]
      -----   -------   ----
0x108 | 0 |   a[1][0]   a[1]
      -----   -------
0x10c | 0 |   a[1][1]
      -----   -------   ----  ---

From here, you can see that a starts at address 0x100 (x in your example) and contains a total of 4 int values. Also note that the subarray a[0] has the same address as a, as does the initial int element a[0][0].

Generalizing this, the address of an array and the address of its first element, even though the types are different, are the same. So:

  • a is an array whose address is 0x100. It contains element of type int[2].
  • a[0] is an array whose address is 0x100. It contains element of type int.
  • a[0][0] is an int whose address is 0x100.
dbush
  • 205,898
  • 23
  • 218
  • 273
  • Thank you for making me realise that array name and pointers are not the same :). However, after reading your explanation I have a doubt that aren't a[0], a, a[0][0] of different types, how can they be stored in the same location. Moreover how can multiple values be stored in the same location? Could you please help me out! – sksingh Jun 25 '20 at 12:35
  • @SaketSingh An array is a sequence of array elements, so the address of an array will always be the same as the address of it's first element, even though the types are different. Specifically, `&a` has type `int(*)[2][2]`, `&a[0]` has type `int (*)[2]`, and `&a[0][0]` has type `int *`, and each has the same value. – dbush Jun 25 '20 at 12:48
  • a[0] uis not stored anywhere. It is only the value – 0___________ Jun 25 '20 at 13:03
  • I didn't get that how can the computer detect something unless it is stored somewhere?Like why is it that a[0] isn't stored anywhere? If a[0] has a value, it should be stored somewhere right?? – sksingh Jun 25 '20 at 13:24
  • @SaketSingh what to detect. Compiler knows where the array is located. Then it just calculates the addresses nothing else. \ – 0___________ Jun 25 '20 at 13:33
  • If I am asking the computer to print the value of a[0], then it must be stored somewhere. I was talking about detecting the value of a[0]. Sorry for not giving enough detail – sksingh Jun 25 '20 at 13:35
  • @SaketSingh `a[0]` is an array, so it doesn't have a "value". If you use it in an expression, it will decay to a pointer to its first element, i.e. `&a[0][0]`. – dbush Jun 25 '20 at 13:36
  • same as printf("%d", 5); where the 5 is stored. Nowhere. – 0___________ Jun 25 '20 at 13:36
  • Thank you very much for that, I have now got my doubt cleared. The last two comments really clarify it. Thank you very much :) – sksingh Jun 25 '20 at 13:40