简体   繁体   中英

Convert int* to int(*)[n] in C / C++

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM