7

I want to assign a statically allocated, multi-dimensional array to a temporary variable. Consider the following example:

void foo(int b[3][2])
{
    b[1][1] = 1; // no segmentation fault
}

int main()
{
    int a[3][2] = {{1, 2}, {11, 12}, {21, 22}};

    foo(a);

    int** c;
    c = (int**)&a;
    c[1][1] = 1; // segmentation fault on execution

    int* d[3];
    d[0] = (int*)&(a[0]);
    d[1] = (int*)&(a[1]);
    d[2] = (int*)&(a[2]);
    d[1][1] = 1; // no segmentation fault

    return 0;
}

Basically I want to do what the compiler does with the parameter b of foo(). But the only working solution I could come up with is d. Is there no less complicated way?

1
  • It's strange how many people think a 2D array somehow casts directly to a pointer to pointers. Commented Nov 21, 2011 at 14:36

6 Answers 6

12

cdecl (man page) is your friend:

cdecl> explain int b[3][2]
declare b as array 3 of array 2 of int
cdecl> declare b as pointer to array 2 of int
int (*b)[2]

So, try this:

void foo(int b[3][2])
{
    b[1][1] = 1; // no segmentation fault
}

int main()
{
    int a[3][2] = {{1, 2}, {11, 12}, {21, 22}};

    foo(a);

    int (*b)[2] = a;

    b[1][1] = 1;

    return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

huh - that's new. where/what is cdecl?
OMG cdecl :D:D:D I have never seen this :D There's online version: @sehe - cdecl.org
9

int[3][2] and int** are incompatible types. You cannot cast one to another.

Try this:

int (*c)[2];
c = a; //no need to cast 
c[1][1] = 1; //ok

Or you could do this (declaration as well as initialization):

int (*c)[2] = a; //no need to cast 
c[1][1] = 1; //ok

Thumb of rule:

  • Don't use c-style cast in C++. Use C++-style cast. Had you used C++-style cast, the compiler would have told you the problem much before (ideone) (no need to run the code to see the problem):

    prog.cpp:5: error: invalid static_cast from type ‘int (*)[3][2]’ to type ‘int**’
    

    But C-style cast compiles it fine (ideone), as you already know.

  • And whenever you use cast, even C++-style cast, your first doubt should be the cast itself if the program doesn't work as expected.

Comments

6

As you are probably aware now, from the other answers, the type of a is not actually equivalent to int** - it jsut decays to that (when returned/passed by value).

int (*b)[2] = a; // would solve that

There is a more C++ way:

typedef std::array<std::array<int, 2>, 3> M23;

void foo(M23& b)
{
    b[1][1] = 1; 
}

int main()
{
    M23 a = {{1, 2}, {11, 12}, {21, 22}};

    foo(a);

    M23 d = a;
    d[1][1] = 1;
}

1 Comment

@sehe: This is good, but you should also answer the question, and explain the problem with OP's code. Once you explained that, you can suggest better alternative solution.
3

If you are using a pretty modern compiler that supports enough parts of the C++11 standard, you can use auto:

int a[3][2] = ...;
auto &b = a;
b[1][1] = 1;  // a[1][1] will be set

Of course, both a and b has to be defined in the same scope for it to work. You can't have an auto parameter in a function for example (that's what templates are for.)

Comments

2

Don't cast explicitly, so try writing

 c = &a;

Then the GCC compiler (using gcc -Wall -g bidim.c -o bidim to compile) gives you the correct warning:

bidim.c:13:7: warning: assignment from incompatible pointer type [enabled by default]

And then you should realize that a 2D matrix is not implemented as an array of pointers to 1D arrays.

Comments

0

The first thing that comes into my mind is using a typedef and reference like

typedef int thing_t[3][2];
thing_t& e = a;
e[1][1] = 1;

With pointers

int (*f)[2] = a;
f[1][1] = 1;

Another possibility is to encapsulate it in struct.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.