2

I wrote the following code:

#include <iostream>
using namespace std;

int main()
{
    int a[10][10];
    for (int i = 0; i < 10; i++)
        for (int j = 0; j < 10; j++)
            a[i][j] = i * j;
    cout << *(*(a + 3) + 4) << endl;
    return 0;
}

I was expecting it to print some garbage data, or a segmentation fault. What I got was 12. I tested it both in c and c++ (using gcc and g++ respectively), and I herd this works the same on VS although I haven't tested this. Why does this work, and is there a official documentation of this behavior?

elyashiv
  • 3,623
  • 2
  • 29
  • 52
  • Why shouldn't it work? – Kiril Kirov Dec 11 '13 at 16:14
  • 9
    Hint: `a[b] == *(a+b)` – devnull Dec 11 '13 at 16:15
  • 2
    @KirilKirov I think one reason one may think it shouldn't work this way is that one may think that adding, say, 3 to a pointer shifts the address it points to by 3 bytes. To answer OP's question, adding 3 to a pointer shifts the address it points to by `3 * sizeof(T)` bytes, where `T` is the type of object the pointer refers to. This is why it is important to keep pointer types correct, and why there is not just a universal type called `pointer`, or why we don't just use `void*` for everything. – Andrey Mishchenko Dec 11 '13 at 18:16
  • @Andrey - yep, that was my first thought, but then I saw "pointer arithmetic" in the title and it's the exact term for this, so then I decided the OP is familiarized with this. Anyway :) – Kiril Kirov Dec 12 '13 at 07:34

6 Answers6

8

*(a + b)=a[b] you take the address of a, move it by b and take the value at the corresponding address

So *(*(a + 3) + 4)means *(a[3]+4) which mean a[3][4]=12

slecorne
  • 1,720
  • 1
  • 11
  • 14
4

The declaration

int a[m][n];

means an array of m arrays, where each such inner array is of size n.

I remember that by remembering that the last index varies fastest.

In the expression (a + 3) the a reference to the outer array decays to pointer to item of that outer array. I.e. pointer to size n array. The + 3 then adds 3 times the byte size of the inner array, to the address of the a-as-pointer.

Dereferencing this gets you a pointer to int.

Adding 4 to that gets you 4 positions into the inner array.

The beauty of this scheme is that it also works with "jagged arrays", arrays of pointers, because there the types are different.

The very sad thing about it is that it doesn't work well with C++ derived classes, because an array of Derived decays to pointer to Derived which then can be implicitly converted to pointer to Base, which when indexed yields formal Undefined Behavior (the size of Derived can be greater than the size of Base).

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 1
    Isn't a 2D array just a long continuous piece of memory? Like remyabel explained? – elyashiv Dec 11 '13 at 16:28
  • 3
    @elyashiv: Yes it is. It's not entirely obvious that the standard places that requirement, though. The contiguousness requirement comes indirectly via size requirements, namely, in C++11 §5.3.3/2 you find "When [sizeof is] applied to an array, the result is the total number of bytes in the array. This implies that the size of an array of n elements is n times the size of an element." which in turn requires that a multidimensional array is stored contiguously, with no internal padding. – Cheers and hth. - Alf Dec 11 '13 at 17:08
2

See this question for a detailed explanation.

Two dimensional arrays ([][], not **) are contiguous in memory, as a result you can access elements using the following formula:

*((int *)array + X * NUMBER_OF_COLUMNS + Y);

i.e.

std::cout << *((int *)a + 3 * 10 + 4);
Community
  • 1
  • 1
  • I know this. the problem is - I didn't multiply by ten. – elyashiv Dec 11 '13 at 16:24
  • @elyashiv 10 is the amount of columns, that's why you need to multiply by 10 in the example I provided. It's not necessary for `*(*(a + 3) + 4)` because you're performing pointer arithmetic on `a`. –  Dec 11 '13 at 16:29
  • I think you meant `*(array + Y * NUMBER_OF_COLUMNS + X)`, because it takes `NUMBER_OF_COLUMNS` columns ("X's") to make one row ("Y") – Braden Best Aug 19 '16 at 03:56
1

You can index an array using *(arr + index) or arr[index]. They are semantically different, but functionally the same.

See this Stack Overflow discussion for more.

Difference Between *(Pointer + Index) and Pointer[]

Community
  • 1
  • 1
isick
  • 1,467
  • 1
  • 12
  • 23
1

When you want a simple answer build the complex type with typedefs

it means:

int a[10][10];

will be:

typedef int a10[10]; //a10 is array of 10 ints 
a10 a[10]; //a is array of 10 a10s

now to understand the sizes and position:

sizeof(a) = 10 * 10 * sizeof int
sizeof(a[0]) = is  10 * sizeof int
a+1 is equal to &a[1]

When you increment a pointer by 3 it is mean increment by sizeof of the type.

address of a[1] == address of a[0] + sizeof(a[0])

Therefore:

*(*(a + 3) + 4) == a[3][4] 
SHR
  • 7,940
  • 9
  • 38
  • 57
-2

The output you got is 12 and it is absolutely correct. You did a[i][j] = i*j ; for each element of the array. Now you print *( *(a + 3) + 4) which is the same as a[3][4]. As you did a[i][j] = i*j, you now have a[3][4] = 3*4 = 12. So it will print 12.

Pradhan
  • 16,391
  • 3
  • 44
  • 59
Ravi
  • 1
  • 1
    I think you're trying to say the right thing. However, your answer is poorly formatted so that it's hard to read and understand. Also, with already 5 good answers around, is it really worth while? :-) – Marcus Rickert Oct 14 '14 at 21:45