2

How can I convert a pointer to a "pointer to array"? As an example, supose I have a pointer int *data to some memory block of 15 integers. I would like to do something like:

int (*mat)[5] = data;

so that I can now make:

for(int i = 0; i < 3; i++){
  for(int j = 0; j < 5; j++){
    mat[i][j] = // Something.
  }
}

However, I get a warning with gcc:

warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int (*mat)[5] = data;

and an error with g++:

error: cannot convert ‘int*’ to ‘int (*)[5]’ in initialization
     int (*mat)[5] = data;

If I add an explicit cast int (*mat)[5] = (int (*)[5])data; it compiles without warnings, but i don't know if this yields undefined behavior.

What is the correct way to accomplish this? Can it be made without an explicit cast?

Edit:

I know I can use the int * pointer like this:

data[5*i + j] = \\ Something.

but in my real situation I need to iterate the array through 3 dimensions, and the code inside the [] gets very long, thats why I want to use the mat[i][j] notation.

Sergio
  • 88
  • 1
  • 6
  • 2
    Related: [C++ Multidimensional array in existing memory](https://stackoverflow.com/questions/55593936/c-multidimensional-array-in-existing-memory) – Michael Chourdakis Aug 07 '19 at 09:34
  • Maybe pass the array through as `void*`? see https://ideone.com/zOeKcE – pmg Aug 07 '19 at 10:14
  • Can't you use directly an `int **` instead of `int *` ? This way you will be able to use the `[][]` semantics. A simple `int *` cannot do it. If you really want to convert it, you will need to create an `int **` and copy the `int *` contents according to the matrix dimensions you need. – Fareanor Aug 07 '19 at 11:44
  • There is no such language as C/C++. You need to pick one. For a question anyway. – Antti Haapala Aug 07 '19 at 12:18

2 Answers2

1

I think that casting a pointer to an array pointer and subsequently using it ought not to be UB and that it technically isn't, as long as there's enough space where the pointer point.

Pointer casts aren't UB provided you satisfy target alignment requirements. Pointer dereferences may be UB if they violate the strict aliasing rule. The caveat with array pointers, however, is that the strict aliasing rule only speaks about accesses through an lvalue of a given type and you can't ever use an lvalue of an array type for an access--you always end up accessing, presumably correctly typed, individual elements.

In spite of that, I think explicit pointer arithmetic might be preferable in this case. It's most apparently UB-free, and it avoids pointer casts, which are very often dangerous and arguably should look jarring to most C/C++ programmers.

PSkocik
  • 52,186
  • 6
  • 79
  • 122
  • The strict aliasing rule says "An object shall have its stored value accessed only by an lvalue expression that has one of the following types: ... - an aggregate or union type that includes one of the aforementioned types among its members" So the array case is covered, an array being an aggregate type. – Lundin Aug 07 '19 at 11:57
  • And can I asume that a `int[m][n]` is guaranteed to have the same memory representation than an `int[m*n]`? – Sergio Aug 08 '19 at 12:51
  • 1
    @Sergio Yes. Arrays are unpadded. Check out https://stackoverflow.com/questions/1066681/can-c-arrays-contain-padding-in-between-elements – PSkocik Aug 08 '19 at 13:00
0

int (*mat)[5] = (int (*)[5])data; is fine given that what's actually stored there is an int[5] array and nothing else. C is only concerned with the effective type of the object in memory.

To do it without an explicit cast, you'd have to do some union hacking, which is only valid in C and not in C++:

typedef union
{
  int* ptr;
  int(*arr)[5];
}arr_t;

int (*mat)[5] = (arr_t){ .ptr = data }.arr;

But that doesn't exactly improve readability so I wouldn't recommend it. Use a cast instead.

Lundin
  • 155,020
  • 33
  • 213
  • 341