views:

136

answers:

4

I have some problems using two dimensional array in the code and need some help.

static const int PATTERNS[20][4];

static void init_PATTERN()
{
   // problem #1
   int (&patterns)[20][4] = const_cast<int[20][4]>(PATTERNS);  
   ...
}

extern void UsePattern(int a, const int** patterns, int patterns_size);

// problem #2
UsePattern(10, PATTERNS, sizeof(PATTERNS)/sizeof(PATTERNS[0]));

in the first statement, I need to cast the const off the two dimensional array PATTERNS. The reason for this is that the init function is called only once, and in the remaining code, PATTERNS is strictly read-only.

In the second statement, I need to pass PATTERNS array to the int** argument. Direct passing resulted a compile error.

Thanks!

======================

I have solved the problem, just about the same time that Andrey posted the answer. Yes int[][] can't be casted to int**.

It can be casted to int* through &(PATTERNS[0][0]), and the function prototype must be modified with row size (the number of elements in a row). The array can be const_cast away with reference syntax.

A: 

When you declare PATTERNS as const, the compiler may set it up in read-only memory. You can't safely cast away const unless the item was originally declared without const.

I'm guessing that your compiler error was cannot convert 'int (*)[4]' to 'int**' for argument '2' to 'void UsePattern(int, int**, int)'?

Bill
+6  A: 

Firstly, there's no such thing as cast to array type (or to function type) in C++. Yet this is what you are trying to do. If you want to cast away constness from something, you have to cast to either pointer or reference type. In your case you have a reference on the receiving end of the cast, so the cast itself has to be to reference type as well

int (&patterns)[20][4] = const_cast<int (&)[20][4]>(PATTERNS); 

Of course, as Bill already noted, casting away constness from a constant object (and then attempting to modify the object) leads to undefined behavior.

Secondly, a two-dimensional array cannot be passed anywhere as an int ** pointer. If you want to pass your PATTERNS somewhere, you can pass it as const int (&)[20][4], const int (*)[20][4], const int [][4], const int (*)[4] or something similar to that, but not as int **. Do a search on SO and/or read some FAQ on arrays to understand why. This has been explained too many times to repeat it again.

AndreyT
A: 

AndreyT's answer is perfect. I'd only like to add that I believe you would be better using a class that does the init_PATTERN() work in the constructor and overrides the operator[] to give readonly access to the array elements.

This, of course, assuming you can change the UsePattern function to get a reference to such class instead of a pointer to int array.

goedson
A: 

C++ Arrays are complicated. You can't just throw them around and expect them to work like in some languages. The only way to initialize an array from another array is to navigate a for loop and copy each item individually. This goes doubly for two-dimensional arrays (meaning you'll need two for loops).

It seems like you're trying to make this more complicated than it needs to be. For instance, if the set of values you will be assigning to PATTERNS will be the same every time you run the program, you can initialize a two dimensional variable like this:

static const int foo[2][3] = {{11,12,13},{21,22,23}};

If the set of values assigned to PATTERNS varies from one execution to the next, then you should probably try to find a different way to approach the problem. I would probably wrap the data in a class, especially if your intention is to use similarly-sized two-dimensional arrays elsewhere in the code.

DoctorT