2
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[101][101];
    a[2][0]=10;
    cout<<a+2<<endl;
    cout<<*(a+2)<<endl;
    cout<<*(*(a+2));
    return 0;
}

Why are the values of a+2 and *(a+2) same? Thanks in advance!

Mad Physicist
  • 76,709
  • 19
  • 122
  • 186
Shubham
  • 51
  • 1
  • 3
  • 3
    Could just be coincidence, if you believe in that sort of thing... – Mad Physicist Jul 05 '16 at 13:28
  • Even if pointer value printed are the same, type are not. – Jarod42 Jul 05 '16 at 13:28
  • 4
    You're in luck! Today, and only today, on stackoverflow.com we have a special going: answer your own question! Create a small array, say `int a[2][2]`. Put four values into it, say 1, 2, 3, and 4. Get a pointer to the first element, `int *p=&a[0][0];`. Then look, with a debugger, what `p` is pointing to, and answer your own question. What a bargain!! – Sam Varshavchik Jul 05 '16 at 13:30
  • 2
    [Pieces](http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-in-c-considered-bad-practice) of [advice](http://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h). – Quentin Jul 05 '16 at 13:31
  • Take a look at [this old answer of mine](http://stackoverflow.com/questions/18440205/casting-void-to-2d-array-of-int-c/18440456#18440456), it shows how an array of arrays is laid out in memory. – Some programmer dude Jul 05 '16 at 13:34
  • @MadPhysicist: it is not by coincidence, but surprisingly it is required by standard... I had to read the code twice to make sure that no UB was involved, but it is perfectly correct code. – Serge Ballesta Jul 05 '16 at 13:45
  • @SergeBallesta. I wasn't sure until you posted. Def upvoting that. – Mad Physicist Jul 05 '16 at 13:48
  • c.f. effective duplicate from today: http://stackoverflow.com/questions/38202077/what-does-getting-address-of-array-variable-mean/38203803 and the one _it_'s a duplicate of: http://stackoverflow.com/questions/11552960/about-the-expression-anarray-in-c – underscore_d Jul 05 '16 at 13:50

5 Answers5

8

a is a 2D array, that means an array of arrays. But it decays to a pointer to an array when used in appropriate context. So:

  • in a+2, a decays to a pointer to int arrays of size 101. When you pass is to an ostream, you get the address of the first element of this array, that is &(a[2][0])
  • in *(a+2) is by definition a[2]: it is an array of size 101 that starts at a[2][0]. It decays to a pointer to int, and when you pass it to an ostream you get the address of its first element, that is still &(a[2][0])
  • **(a+2) is by definition a[2][0]. When you pass it to an ostream you get its int value, here 10.

But beware: a + 2 and a[2] are both pointers to the same address (static_cast<void *>(a+2) is the same as static_cast<void *>(a[2])), but they are pointers to different types: first points to int array of size 101, latter to int.

Serge Ballesta
  • 121,548
  • 10
  • 94
  • 199
2

I'll try to explain you how the memory is mapped by the compiler:

Let's consider a more pratical example multi-dimentional array:

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

You can execute the command

x/10w a

In GDB and look at the memory:

0x7fffffffe750: 1   2   3   4
0x7fffffffe760: 5   6   7   8
0x7fffffffe770: 9   0

Each element is stored in a int type (32 bit / 4 bytes). So the first element of the matrix has been stored in:

1) a[0][0] -> 0x7fffffffe750
2) a[0][1] -> 0x7fffffffe754
3) a[0][2] -> 0x7fffffffe758
4) a[1][0] -> 0x7fffffffe75c
5) a[1][1] -> 0x7fffffffe760
6) a[1][2] -> 0x7fffffffe764
7) a[2][0] -> 0x7fffffffe768
        ...

The command:

std::cout << a + 2 << '\n'

It will print the address 0x7fffffffe768 because of the pointer aritmetic: Type of a is int** so it's a pointer to pointers. a+2 is the a[0] (the first row) + 2. The result is a pointer to the third row.

*(a+2) deferences the third row, that's {7,8,9}

The third row is an array of int, that's a pointer to int.

Then the operator<< will print the value of that pointer.

BiagioF
  • 8,545
  • 2
  • 21
  • 45
1

A 2-dimensional array is an array of arrays, so it's stored like this in memory:

char v[2][3] = {{1,3,5},{5,10,2}};

Content: | 1 | 3 | 5 | 5 | 10 | 2
Address:   v  v+1 v+2 v+3 v+4 v+5

To access v[x][y], the compiler rewrites it as: *(v + y * M + x) (where M is the second dimension specified)

For example, to access v[1][1], the compiler rewrites it as *(v + 1*3 + 1) => *(v + 4)

Be aware that this is not the same as a pointer to a pointer (char**). A pointer to a pointer is not an array: it contains and address to a memory cell, which contains another address.

To access a member of a 2-dimensional array using a pointer to a pointer, this is what is done:

char **p;
/* Initialize it */
char c = p[3][5];
  1. Go to the address specified by the content of p;
  2. Add the offset to that address (3 in our case);
  3. Go to that address and get its content (our new address).
  4. Add the second offset to that new address (5 in our case).
  5. Get the content of that address.

While to access the member via a traditional 2-dimensional array, these are the steps:

char p[10][10];
char c = p[3][5];
  1. Get the address of pand sum the first offset (3), multiplied by the dimension of a row (10).
  2. Add the the second offset (5) to the result.
  3. Get the content of that address.
Mattia F.
  • 1,590
  • 8
  • 17
1

If you have an array like this

T a[N];

then the name of the array is implicitly converted to pointer to its first element with rare exceptions (as for example using an array name in the sizeof operator).

So for example in expression ( a + 2 ) a is converted type T * with value &a[0].

Relative to your example wuth array

int a[101][101];

in expression

a + 2

a is converted to rvalue of type int ( * )[101] and points to the first "row" of the array. a + 2 points to the third "row" of the array. The type of the row is int[101]

Expression *(a+2) gives this third row that has type int[101] that is an array. And this array as it is used in an expression in turn is converted to pointer to its first element of type int *.

It is the same starting address of the memory area occupied by the third row.

Only expression ( a + 2 ) has type int ( * )[101] while expression *( a + 2 ) has type int *. But the both yield the same value - starting address of the memory area occupied by the third row of the array a.

Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268
0

The first element of an array is at the same location as the array itself - there is no "empty space" in an array.

In cout << a + 2, a is implicitly converted into a pointer to its first element, &a[0], and a + 2 is the location of a's third element, &a[2].

In cout << *(a + 2), the array *(a + 2) - that is, a[2] - is converted into a pointer to its first element, &a[2][0].

Since the location of the third element of a and the location of the first element of the third element of a are the same, the output is the same.

molbdnilo
  • 55,783
  • 3
  • 31
  • 71