tags:

views:

158

answers:

6

Can someone explain why I can do:

int x[4] = { 0, 1, 2, 3 };
int *p = x;

But cannot do:

int x[2][2] = { 0, 1, 2, 3 };
int **p = x;

Is there a way to be able to assign to **p the x[][]?

TIA

+2  A: 

No, there's no way to assign the array to an "int **", because a two-dimensional array is an array of arrays, not an array of pointers.

You could for instance do:

  int x1[2] = {0, 1};
  int x2[2] = {2, 3};
  int *x[2] = {x1, x2};
  int **p = x;

... and maybe that would be an acceptable equivalent to what you are trying to do (depending on what exactly that is of course!).

Update: If you must keep x as a two-dimensional array, you could also do: int (*p)[2] = x; which gives you a pointer-to-array-of-int.

davmac
Arrays and pointers are essentially the same thing. A two-dimensional array is not an array of arrays, it is still one contiguous array.
Alexander Rafferty
@Alexander: please *refrain* from saying that they are "essentially the same thing" - they are not... see my other answer here... http://stackoverflow.com/questions/2124935/c-strings-confusion/2125429#2125429
tommieb75
@Alexander, they are absolutely not the same thing. An array is an object holding a sequence of one or more elements. A pointer is a pointer. Your confusion might be arising because you can use the array subscript access notation on pointer values. Most importantly, a two dimensional array *is* an array of arrays.
davmac
yes, in practice, an array and a pointer can be USED in exactly the same way. E.g. a c-string can be defined as char* or char[]. A dynamically created array will always be defined as a pointer. And yes, a multidimensional array is still an array, not an array of an array. Please read it up.
Alexander Rafferty
tommieb75
@Alexander, if you can point me to where in the C++ standard it says that multi-dimensional array is not an array-of-arrays, I'll gladly "read it up". Try taking the sizeof() the first element of such an array - what does it tell you, and what does that suggest?
davmac
@Alexander, from the standard: static int x3d [3][5][7];declares a static three-dimensional array of integers, with rank 3 × 5 × 7. In complete detail, x3d is an array of three items; each item is an array of five arrays; each of the latter arrays is an array of seven integers.
davmac
well, if you insist that they are arrays-of-arrays, then fine. It doesn't really matter how they are laid out in memory, it wouldn't make a difference to the way they are used. The reason I believe that multi-dim arrays are the same as one-dim arrays is: http://www.cplusplus.com/doc/tutorial/arrays/
Alexander Rafferty
@Alexander, even the reference you give contains this text: Multidimensional arrays can be described as "arrays of arrays"
davmac
@Alex: It *does* matter. If you coerce `int**p` into pointing at a `int a[2][2]` and try to double dereference `p` it *won't* access the expected element of `a`. Try it and see. You can build a data structure (often called a ragged array; of which the thing `argv` points to is an example) off of a pointer-to-pointer that can be correctly dereferenced as `p[i][j]`, but it is *not* the same thing as `a`.
dmckee
+1  A: 

If you are really using c++ instead of c, you can get this effect by using std::vector (or some other collection type).

typedef std::vector<std::vector<int> > intmatrix;
intmatrix x;
intmatrix::iterator p = x.begin();

or some such.

TokenMacGuy
+2  A: 

Using the pointer notation you can do this

*(p + n) will return back a value in the subscript n which is equivalent of p[n], a "single dimension array"

*( * (p + i) + j) will return back a value in the subscripts i and j which is equivalent of p[i][j], a "double dimension array"

This will prove that using array subscripts [] decays into pointers as per the rule - see ANSI C Standard, 6.2.2.1 - "An array name in an expression is treated by the compiler as a pointer to the first element of the array", furthermore, ANSI C Standard 6.3.2.1 - "A subscript is always equivalent to an offset from a pointer", and also ANSI C Standard 6.7.1 - "An array name in the declaration of a function parameter is treated as a pointer to the first element in the array"

If you are not sure in understanding how pointers and arrays work, please see my other answer which will explain how it works...

Please ignore anyone who says arrays and pointers are the same - they are not...

tommieb75
+1  A: 

It's all about Standard Conversion rule ($4.2)

An lvalue or rvalue of type “array ofN T” or “array of unknown bound of T” can be converted to an rvalue of type “pointer to T.” The result is a pointer to the first element of the array.

The type of od and td respectively are

char [3]

char [1][3]

This means that od has type 'array of 3 chars' (N = 3, T = char).

So in accordance with the above quote, it can be converted to 'pointer to char'

Therefore char *p = od; is perfectly well-formed

Similarly the type of od is 'array of 1 array of 3 chars' (N = 1, T = array of 3 chars).

So in accordance with the above quote, it can be converted to 'pointer to array of 3 chars'

Therefore char (*p)[3] = td; is perfectly well-formed

Is there a way to be able to assign to **p the x[][]?

No. Because type of td[x][y] for valid x and y is char. So what you can really do is char *pc = &td[0][0].

Chubsdad
+8  A: 

A pointer to int int * can point at an integer within an array of integers, so that's why the first is OK;

int x[4] = { 0, 1, 2, 3 };
int *p = x;

This makes p point to x[0], the first int in x.

A pointer to a pointer-to-int int ** can point at a pointer-to-int within an array of pointers-to-int. However, your second array is not an array of pointers-to-int; it is an array of arrays. There are no pointers-to-int, so there is nothing sensible to point int **p at. You can solve this in two ways. The first is to change the type of p so that it is a pointer-to-array-of-2-ints:

int x[2][2] = { 0, 1, 2, 3 };
int (*p)[2] = x;

Now p points at x[0], the first int [2] in x.

The alternative is to create some pointers-to-int to point at:

int x[2][2] = { 0, 1, 2, 3 };
int *y[2] = { x[0], x[1] };
int **p = y;

Now p points at y[0], which is the first int * in y. y[0] in turn points at x[0][0], and y[1] points at x[1][0].

caf
+2  A: 

There is no way to meaningfully initialize you variable p with x. Why? Well, there's no way to answer your question until you explain how you even came to this idea. The type of p is int **. The type of x is int[2][2]. These are two different types. Where did you get the idea that you should be able to assign one to the other?

If you really need to access elements of your x through a pointer of type int **, you have to do it indirectly. You have to create an additional intermediate array that will hold pointers to first elements of consecutive rows of array x:

int *rows[2] = { x[0], x[1] };

and now you can point your p to the beginning of this intermediate array

int **p = rows;

Now when you assess p[i][j] you get x[i][j].

There's no way to do it directly, without an intermediate array.

AndreyT