1

What exactly happens when I cast a [pointer to a variable sized array] to a [pointer to pointer] ?

int ar[r][c];
int **ptr = (int**)ar;  // implicit casting not allowed
ptr[0][0] = 100;

The above code gives a runtime error.

Casting a variable sized array to a pointer works as expected:

int ar[c];
int *ptr = ar;
ptr[0] = 100;

Here ar decays into a pointer to the first element.

But what happens internally when casting an int(*)[c] to int**? Why does it result in a runtime error when reading/writing to the int** variable?

7
  • Can you describe your "runtime error" in your post ? Commented Jun 2, 2014 at 15:11
  • The application just hangs. I guess it gets a SIGSEGV Commented Jun 2, 2014 at 15:12
  • 1
    int ar[r][c]; is mostly equivalent to int ar[r * c]; with modified accessor. Commented Jun 2, 2014 at 15:23
  • 1
    "What exactly happens" — undefined behaviour. Commented Jun 2, 2014 at 15:35
  • 2
    Nothing special happens internally during the cast. You tell the compiler "trust me, this thing that you think is the address of an array is actually the address of a pointer" and it believes you. Then you crash. Because you lied. Commented Jun 2, 2014 at 15:43

3 Answers 3

2

An array is not a pointer.

An array is a block of contiguous memory of data all of the same type, all packed together. As it happens, if you have a pointer to the first element, and you know the type of the data, you can do many of the same things with your pointer that you could do with your array.

foo[5] on an array gets the 5th element, and on a pointer to the first element also gets the 5th element.

In fact, you can convert an array to a type foo to a pointer to the first element implicitly.

Now, what you are doing is something completely different. The pointer to the first element is a pointer to int[5] -- an entire array.

Suppose you had an array of pointers to int* of length 5. Each one of them could point to a different int[5], and you could use the int*[6] as a two-dimensional array. But you'll note here we have an array of pointers to int*, not an array of int[5]. And as arrays are not pointers, these are different things.

Now, we can fix this.

template<unsigned...>struct indexes{typedef indexes type;};
template<unsigned Max, unsigned...Is> struct make_indexes:make_indexes<Max-1, Max-1, Is...>{};
template<unsigned...Is> struct make_indexes<0, Is...>:indexes<Is...>{};
template<unsigned Max> using make_indexes_t = typename make_indexes<Max>::type;

template<typename T, unsigned N, unsigned M, unsigned... Is>
std::array<T*, M> as_array_of_pointers( indexes<Is...>, T(&arr)[M][N] ) {
  return { arr[Is]... };
};
template<typename T, unsigned N, unsigned M>
std::array<T*, M> as_array_of_pointers( T(&arr)[M][N] ) {
  return as_array_of_pointers( make_indexes_t<M>{}, arr );
}

The above is a fancy C++11 way to write:

std::array<int*, 5> arr = { ar[0], ar[1], ar[2] };

Now you can take your ar and turn it into an array-of-pointers. If you have a function taking int** you can call as_array_of_pointers and take an explicit pointer to the first element, and rely on temporary lifetime to do the work:

void foo( int** x ) {}

int main() {
  int a[5][3] = {0};
  foo( &(as_array_of_pointers(a)[0]) );
}

this requires C++11. You can instead do it manually in C++03.

The crash you are seeing (via undefined behavior) is probably the result of reinterpreting the first element of your array as a pointer-to-int, instead of one or more int (depending on the relative size of pointers and int on your system).

live example

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

3 Comments

BTW, I don't think that lifetime of the final (tmp) array is long enough.
@Jarod42 It will last as long as the line of code it was in, which is long enough for foo to run. (The rule of thumb is that temporaries last "until the ;", or to the end of the block if bound directly to a reference)
I see that you were able to convert array of arrays to array of pointers. Although I couldn't understand how (that code is too complicated for me) :-)
1

The problem is that ptr[0] or *ptr is supposed to be a pointer, but it is not. That is, ptr[0] or *ptr does not contain a valid pointer. At this address there is the first element of array ar. So you will get a run-time error when will use expression ptr[0][0] That is in general case the program behaviour is undefined.

Comments

0

When you declare int **ptr , it refers to an array of int pointers. But you declared an array of arrays of int.

This is why the language does not provide any implicit cast for this, since the two types really don't relate.

Manipulating the result of the cast as you did has undefined behavior.

2 Comments

int **ptr has type (int**). An array of int pointers will have type int *ptr[c]. They're a bit different
No, they are not different, int* ptr[] decays to int**, thats really the same thing.

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.