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.