13

As I see it int *x[n][m] declares x to be a 2-d array of pointers to integers, so allocating memory should be as easy as x[i][j] = new int and as expected it works fine. Now if I change the declaration to:

int (*x)[n][m]

x[i][j] = new int no longer works and results in a compilation error.

x = (int(*)[n][m]) malloc (sizeof(int[n][m])) however compiles. From the few tests I ran, after the memory allocation, the different declaration/allocation combination doesn't seem to effect the values stored in the variable. Am I missing something? So my question is, **Is there a difference between int *x[n][m] and int (x)[m][n]. How is int (x)[n][m] stored in memory?

Rakib Ansary
  • 4,078
  • 2
  • 18
  • 29
  • 1
    `int (*x)[n][m]` is a pointer to a 2D array of integers. The difference between this and a pointer to the first row of that array is subtle and potentially confusing; I don't have the mental capacity to go into it right now, as I've stayed up far too late. – user2357112 Apr 08 '14 at 11:05
  • 1
    You should know that in C and C++ parentheses often make much more difference than in human languages. – Wolf Apr 08 '14 at 11:14
  • 1
    ["Declare x as pointer to array of array of int."](http://cdecl.ridiculousfish.com/?q=int+%28*x%29%5B%5D%5B%5D) : ) – Radiodef Apr 08 '14 at 11:15
  • 1
    always works <3 : http://c-faq.com/decl/spiral.anderson.html so 1st means "x is an array n of array m of pointers to int" and 2nd one "x is a pointer to array n of array m of ints" – Hayri Uğur Koltuk Apr 08 '14 at 15:08

3 Answers3

21

int *a[n][m] is a two dimensional array of pointers to int.

int (*p)[n][m] is a pointer to a two dimensional array of ints (it is the type you get by taking the address of int[n][m]).

In both cases, n and m need to be compile time constants, otherwise the declarations are not legal in C++ (but are in C). Your compiler might have an extension to allow it, though.

First one can be used to simulate a three dimensional array. I say simulate, because it would not be a proper array with contiguous storage and the types are different in the first place. In each of the elements of a you can store the address to the first element of an array of integers. Each could have a different size and be allocated dynamically. You can store a pointer to a single (possibly stack allocated) integer, too.

int i = 0;
int a1[2] = {};

int* a2[2][2];
a2[0][0] = a1;  // array to pointer decay here
a2[0][1] = new int[42];
a2[1][0] = new int[84];
a2[1][1] = &i;

p can point to a single 2d array or an array thereof:

int arr[2][3];
int (*p1)[2][3] = &arr;  // arr decays to int(*)[3], so we need to take the address
int (*p2)[2][3] = new int[42][2][3]; // allocate 42 arrays dynamically
jrok
  • 54,456
  • 9
  • 109
  • 141
  • 2
    "(it is the type that int[n][m] decays to)" As your comment in the code correctly points out, `int[n][m]` does not decay to `int(*)[n][m]` - it decays to `int(*)[m]`. `int[o][n][m]` would decay to `int(*)[n][m]` (an array decays to a pointer to its first element - not to the array itself). – sepp2k Apr 08 '14 at 12:04
  • @sepp2k Oops, thanks for pointing it out. Don't know what I was thinking there. – jrok Apr 08 '14 at 13:39
4

As you can easily discover:

  • int *x[n][m] is a two dimensional array of pointers to int.
  • int (*x)[n][m] is a pointer to a two dimensional array of ints.

The answer to your question is that the first is an array so the memory is 'inline' - it might be static, automatic (on the stack) or on the heap, depending on where you define it.

The second is a pointer to an array and the pointer must be initialised before what it points to is used. Most likely the memory will be allocated on the heap, but it's also possible that it might be a static or auto array defined elsewhere. If you access members of the array before initialising the pointer, you get Undefined Behaviour.

david.pfx
  • 10,520
  • 3
  • 30
  • 63
  • There's no requirement for "heap allocation" in either case, e.g. `int a[5][3]; int (*x)[5][3] = &a;`, or even `int a[10][5][3]; int (*x)[5][3] = a;` – M.M Apr 08 '14 at 13:45
  • First case, of course not. Second case, oops. See edit. – david.pfx Apr 08 '14 at 14:21
1

Good site to decode C-declaration names. Taking your examples (and substituting n=1 and m=2) we see:

int *x[1][2]

Translates to:

declare x as array 1 of array 2 of pointer to int

Whereas

int (*x)[1][2]

Translates to:

declare x as pointer to array 1 of array 2 of int

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
αλεχολυτ
  • 4,792
  • 1
  • 35
  • 71
  • The downvotes were because [your original answer](http://stackoverflow.com/revisions/22940226/1) was a link-only answer, which we don't really like on this site. My edits show what a better answer would look like. – Duncan Jones Apr 10 '14 at 08:52
  • @Duncan thanks for explanation. Is it somewere described in SOF's terms of usage? – αλεχολυτ Apr 10 '14 at 09:39
  • 1
    See http://stackoverflow.com/help/how-to-answer, specifically **Provide context for links**. See also http://meta.stackexchange.com/q/8259. – Duncan Jones Apr 10 '14 at 10:00