tags:

views:

645

answers:

3

Hi, i have some bidimensional arrays like:

int shape1[3][5] =  {1,0,0,
       1,0,0,
       1,0,0,
       1,0,0,
       1,0,0};
int shape2[3][5] =  {0,0,0,
       0,0,0,
       0,1,1,
       1,1,0,
       0,1,0};

and so on.

How can i make an array of pointers to those?

I tried the following, but they don't work (warning: initialization from incompatible pointer type):

int *shapes[]=  {&shape1,&shape2};

int *shapes[]=  {shape1,shape2};

int **shapes[]= {&shape1,shape2};

Any help?

+3  A: 

Updated Fixed type. Thanks j_radom_hacker for bringing this to my attention!

[EDIT: Actually the type here was not correct -- see Robert S. Barnes' answer for the correct type to use.]

Figure out the type of shape1 and shape2 first:

typedef int (*shape_array_t)[5];

Now use this:

shape_array_t sat[] = { shape1, shape2 };
dirkgently
Thanks, but it still yelds the same error!
pistacchio
Hey I made a typo -- sorry about that :P
dirkgently
@j_random_hacker: I think I fixed it sometime before your comment ;-)
dirkgently
Ah you did too :)
j_random_hacker
that worked, thank you very much :)
pistacchio
ACTUALLY, I've read Robert Barnes' answer closely and he's right -- we shouldn't be including the outer subscript ("[3]") in the type of sat. As it stands, to access an individual int with your (or my original) code, you would need to write e.g. "sat[1][0][2][4]" -- the *second* subscript, "[0]", is needed to select the first 3x5 array!
j_random_hacker
@dirkgently: I have meanly edited your answer so I could -1 it... Please don't take it personally but it is now clear that this answer (which is currently marked as Accepted) is wrong. (So is/was my own answer, which you should probably downvote.)
j_random_hacker
I have just fixed the answer. I am not going to bother myself with downvoting but I will give Robert a +1.
dirkgently
That was quick! +2 for you.
j_random_hacker
+3  A: 

First of all, the first array bound refers to the outermost array dimension, so you should probably declare shape1 as:

int shape1[5][3] =  {1,0,0,
                     1,0,0,
                     1,0,0,
                     1,0,0,
                     1,0,0};

and similarly for shape2.

[EDIT: I've changed the type of shapes below to correspond to Robert Barnes' answer -- we don't want the outermost subscript to be included in this type!]

The slightly strange-looking typename you need is:

int (*shapes[])[3] = { shape1, shape2 };

This allows the element at row 4, column 1 of shape2 to be addressed using

shapes[1][3][0]

Breakdown of subexpressions and their C types:

shapes            // has type "int (*x[2])[3]" (decays to "(**x)[3]")
shapes[1]         // has type "int (*x)[3]"
shapes[1][3]      // has type "int x[3]" (decays to "int *x")
shapes[1][3][0]   // has type "int x"

(Note that a dummy x has been included in the types above to make them clearer -- in fact this identifier is not part of the type.)

A rule of thumb for decoding C/C++ types is "starting from the variable name, read right when you can and left when you hit a closing parenthesis." So the decoded typename for shapes is:

An array of pointers to an array of 3 integers.

In general it's much nicer to use typedefs for these complicated types, as dirkgently suggests.

j_random_hacker
+3  A: 

I believe I just verified what I wrote was correct. The following works as expected:

#include <stdio.h>

int main(int argc, char **argv) {

int shape1[5][3] =  {1,0,0,
                 1,0,0,
                 1,0,0,
                 1,0,0,
                 1,0,0};

int shape2[5][3] =  {0,0,0,
                 0,0,0,
                 0,1,1,
                 1,1,0,
                 0,1,0};

typedef int (*shapes_p)[3];
shapes_p shapes[2] = { shape1, shape2 };

shapes[0][1][0] = 5;
shapes[1][1][0] = 5;

printf("shape1[1][0] == %d\n", shape1[1][0]);
printf("shape2[1][0] == %d\n", shape2[1][0]);

}

The thing to remember is that the type of shape1 and shape2 is actually:

int *shape1[5];

What you have in memory is 3 adjacent arrays of 5 ints each. But the actual type is pointer to array of 5 ints. When you write:

shape1[1][2] = 1;

you're telling the compiler to index to the second array of int[5] and then access the 3rd element of that array. What the compiler actually does is pointer arithmetic on the underlying type pointed to, in this case int[5]. You could do the same with the following code:

int *p = shapes1[0];
p+7 = 1;  // same as shape1[1][2] = 1;

So if you want an array of pointers to int *[5] then you would do:

typedef int (*shapes_p)[5];
shapes_p shapes[2];
Robert S. Barnes
-1 sorry -- the type of shape1 is in fact "int shape1[3][5]", it's just that **using the name shape1 in an expression** produces a value of type "int *[5]" (i.e. a pointer to the first element of the array).
j_random_hacker
Maybe I'm missing something, but I checked my solution and it works as expected. I added a full compilable example at the beginning of my post.
Robert S. Barnes
My apologies Robert, you're totally right. You would use a "T *ptr" to access a 1D array of T, so you should use a "T (*ptr)[3]" to access a 2D array of T with rows of width 3. +1.
j_random_hacker