1

Lets assume there's variable of type int** which is the pointer to a 5x5 2D array:

int** ptr_array_5by5; 

and a function with the following prototype:

void print2DArray_with5Columns(int (*ptr_row)[5]); 

Is there a way to cast ptr_array_5by5 into some type which would match the type of the first argument of the function?

print2DArray_with5Columns( (<some casting type>) ptr_array_5by5) 
5
  • 4
    Yes, you can cast any pointer type to any other pointer type. Doing so is nearly always wrong. If you have to ask, it is always wrong. int** and int (*)[5] are different not because creators of C and C++ hate you personally, they are different because they really, truly, genuinely different. Commented Jun 11, 2014 at 14:41
  • @n.m. Ok. I was just wondering whether it's possible to cast. :) I didn't know how to write down the type of parameter. Commented Jun 11, 2014 at 14:49
  • if you redefine ptr_array_5by5 as int ptr_array_5by5[5][5];, it will "just work" - is that an option ? If not, why not ? Commented Jun 11, 2014 at 14:49
  • Five answers so far and a lot of discussion. Nice question! Commented Jun 11, 2014 at 15:36
  • related FAQ, see part 4, last section Commented Jun 11, 2014 at 15:55

5 Answers 5

3

The important thing to realize here is that int** is not a pointer to a 2D array of anything. It is a pointer to a 1D array of pointers. int (*)[5] is a pointer to a 2D array of int (or more correctly, it is a pointer to the first element of such an array). You can pretty much convert any pointer type to any other pointer type using reinterpret_cast, but it is also pretty much guaranteed not to work at runtime. (There are special exceptions, but they are all very platform specific, and very close to the hardware.)

If you really have an int** which points to 5 int*, each of which points to 5 int, and you need an int (*)[5], the only way you're going to be able to successfully convert is by doing a conversion on the actual underlying data (which will involve a copy), and not a conversion on the pointer. Something like:

int tmp[5][5]; for ( int i = 0; i != 5; ++ i ) { int* row = ptr_array_5by5[i]; for ( int j = 0; j != 5; ++ j ) { tmp[i][j] = row[j]; } } 

You can then pass tmp to your function without any casts: the implicit conversion of array to pointer will convert int [5][5] to int (*)[5].

Sign up to request clarification or add additional context in comments.

2 Comments

The one answer that actually points out the danger within the question. I can add, that casting the int** to int (*)[5] is guaranteed not to work as expected, because it will interprete the pointers of the index array as integers. If the 2D region is guaranteed to be allocated in one slap, casting *ptr_array_5by5 to int (*)[5] might work, but that's assuming a lot about the data layout.
@cmaster If the region was allocated as an int[25], and you then cast the int* to int (*)[5], and access it through that, you formally have undefined behavior. Practically, it will work on almost all implementations; the only one I've ever heard of where it might not is ObjectCenter, which does (or did---I don't know if the compiler is still available) bounds checking.
3

Of course.

int** ptr_array_5by5; void print2DArray_with5Columns(int (*ptr_row)[5]); print2DArray_with5Columns( (int (*)[5]) ptr_array_5by5); print2DArray_with5Columns( reinterpret_cast<int (*)[5]>(ptr_array_5by5)); 

The C language declaration syntax, for all its faults, lets you create casts by simply rewriting the declaration omitting any identifiers. It compiles, and it might even work.


There is a lot of confusion here because the descriptive wording does not match the C declarations. Here is some code that implements this (peculiar) cast and shows that it can work, just as I said.

void print2DArray_with5Columns(int (*ptr_row)[5]) { for (int i = 0; i < 5; i++) cout << (*ptr_row)[i] << " "; cout << std::endl; } int main() { int* a; int** ptr_array_5by5; a = new int[25]; for (int i = 0; i < 25; i++) a[i] = i; ptr_array_5by5 = (int**)a; print2DArray_with5Columns((int (*)[5])(ptr_array_5by5)); return 0; } 

Please note that this declaration is not a 5x5 matrix. The cast is simply a pointer to an array of 5 ints, which decays to a simple array. This code generates a 5x5 flat matrix and prints the first row.

I suspect the real problem is that the cast is wrong and therefore the whole question is wrong.


The question has been asked whether this is the dreaded Undefined Behaviour. With suitable care it is not. The standard in effect allows any kind of a pointer-to-object to be cast to some other pointer-to-object or to a void pointer or to a large enough integer, and back again. [Pointer-to-function and pointer-to-member are treated a bit differently.] The round-tripped pointer is guaranteed to retain the same value. Therefore this cast is not UB provided the rules are followed, which is not that hard to do.

14 Comments

+1 for actually answering the question that was asked.
Let's try this: ideone.com/lVzNrN I admit, it is possible. But I don't think I will implement this ever.
It will not work. The reason for the awkward syntax in C++ is precisely because such things almost never work. (There are, of course, special cases when you're writing near to hardware code.) It was felt that the C syntax made it too easy to screw up, and too difficult to find the screwups.
@JamesKanze unfortunately the example code, which was added later, may not be correct (though I'll bet it works on most architecture-compiler combinations anyway). However, in terms of answering the question of how to cast an int ** to an int (*)[5], the answer is bang on.
(furthermore, there are cases where performing such a cast and then dereferencing the resulting pointer would not result in undefined behaviour!).
|
1
  1. int** and int(*)[5] are different types (as n.m. pointed out)
  2. You may treat an array as a pointer, e.g. int a[5]; *(a+1) = 6;
  3. You may treat a pointer as an array, e.g. int *a = new int[5]; a[1] = 6;.

But treating object A as if it were an object B does not mean that it actually is object B.

What you can do though is declaring an int (*)[5], write the values of ptr_array_5by5 into it (after allocating memory, of course), and pass it to print2DArray_with5Columns.

On the other hand, yes there are casts that make your code compile. But I doubt that using one of them is getting you closer to your goal (see http://ideone.com/lVzNrN).

3 Comments

I think this is wrong. There is no need to allocate more storage and copy data into it, and a perfectly valid cast does exist. See my answer.
@david.pfx though I agree a valid cast does exist, I think this answer is dealing with the problem that an int ** points to an array of int pointers rather than an array of arrays. If the original pointer actually points at the data type it describes then the conversion (via allocation / data copying) is necessary. I.e. you can use a simple cast but the resulting pointer is not necessarily valid.
I don't agree with the wording "You may treat". You can't really treat one as the other; an array converts to a pointer, but the reverse isn't true, and both *(a + 1) and a[1] are pointer operations (and when used with arrays, count on the implicit conversion).
0

I think you are confused by assuming that pointers are arrays. Pointers are not arrays and vice-versa. If ptr_array_5by5 would be a 2D array then the parameter in prototype is fine for passing ptr_array_5by5 as argument. But you declared it as int **ptr_array_5by5, it is better to change the parameter to int ** type.

6 Comments

Aeeays decay to pointers and pointers can be indexed as if they were arrays, so the distinction is often moot.
@david.pfx; No. Distinction is very clear.
I think if you read the first answer to that link, you will find it exactly agrees with what I said. What is your point exactly?
@david.pfx; My point is: Arrays are not pointers and pointers are not arrays. Both are different data types.
But that's blindingly obvious and quite uninteresting. My point is that you can often use a pointer where an array is expected and vice versa. That makes it much more interesting.
|
0

Why would you like to cast int **?

You use pointers to point to addresses.

So instead of type casting pointers, you have to point this pointer to some variable.

There is no meaning of type casting pointers because they themselves don't store values.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.