41

Learning pointers can be tricky. Accessing them like arrays is pretty straight forward and easy to understand. Creating them can be tricky to understand because of the multiple ways & can be used. Casting them to anything seems to be really easy to do, and a way to break all sorts of things if not done carefully.

Two things I wasn't taught about was casting pointers to arrays and assignment of arrays. Pointers cast to basically any type, so presumably it should be an easy task to cast to an array type. As for assigning to arrays, this presumably will be possible since everything else is assignable unless const.

So something like the following would be so elegant for casting a pointer to an array type and assigning to an array.

int x = 1
int arr[2] = { 2, 3 };
int* ptr   = new int[10];
// plus some initialization code for ptr
arr = &ptr[1]; // assign address of ptr[1] to arr

This didn't work, so before wasting anyone's time I wanted to make sure I understood the data I was working with. Values, and addresses primarily. So, I made a simple program to output some of the addresses and values. The output is just below:

Address of {type: int}    &x      =       0031FEF4; x    = 1
Address of {type: int[2]} &arr    =       0031FEE4; arr    = 0031FEE4
Address of {type: int[2]} &arr[0] =       0031FEE4; arr[0] = 2
Address of {type: int[2]} &arr[1] =       0031FEE8; arr[1] = 3
Address of {type: int*}   &ptr    =       0031FED8; ptr    = 008428C8
Address of {type: int*}   &ptr[0] =       008428C8; ptr[0] = 2
Address of {type: int*}   &ptr[2] =       008428D0; ptr[2] = 1

After making it clear to myself that I "knew" what values were where such as the address stored at arr I came here to figure out why arr = &ptr[1]; did not work.

Shouldn't arr be assignable? Can I not cast a pointer to an array in such a way?

8
  • 7
    First, why would you need that ? Hint: int* and int [2] have different purposes (though the second one can decay into the first). Commented Nov 18, 2013 at 11:17
  • I am trying to simplify a file reading function. This is the concept I am grappling with in order to do said simplification. Commented Nov 18, 2013 at 11:34
  • 2
    Things never get simpler with pointers-to-arrays. Just use plain pointers and sizes. Commented Nov 18, 2013 at 11:36
  • 1
    I often wish I could do this in the debugger, not so much in production code where it's generally not a good practice. For example, if I have an array of float that happens to be represented in the code as a float pointer, it would be nice to expand the array. Commented Mar 10, 2021 at 3:27
  • 1
    @JBL "First, why would you need that ? Hint: int* and int [2] have different purposes". Exactly! So what if array decaying is not your purpose? It's forced on you inside a function and many times you'd want to treat it as an array like f.i. std::begin(arr) Commented Mar 29, 2021 at 22:31

2 Answers 2

48

First of all b is an array, not a pointer, so it is not assignable.

Also, you cannot cast anything to an array type. You can, however, cast to pointer-to-array. Note that in C and C++ pointer-to-arrays are rather uncommon. It is almost always better to use plain pointers, or pointer-to-pointers and avoid pointer-to-arrays.

Anyway, what you ask can be done, more or less:

int (*c)[2] = (int(*)[2])new int[2];

But a typedef will make it easier:

typedef int ai[2];
ai *c = (ai*)new int[2];

And to be safe, the delete should be done using the original type:

delete [](int*)c;

Which is nice if you do it just for fun. For real life, it is usually better to use std::vector.

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

12 Comments

So this is the only way to take a memory address and make it the start of an array? By changing the way I define said array; turning it into a pointer to an array and then casting to that?
Actually the C way is to use the pointer as-is: remember that you can subscript a pointer just fine. The cast to pointer-to-array is mostly useless, except maybe in multi-dimension arrays. I mean, you can think of a int* as pointing to a single integer, or as pointing to the first of an array of integers.
This undefined behavior in C++. int* and int(*)[2] are two different pointer types. You are essentially doing an illegal reinterpret_case from one type to another and violating the strict aliasing rule.
@ThomasMcLeod No time to look it up in the standard, but I believe that an aggregate type and the type of its first element are not unrelated and that pointers to each can be cast between.
@ThomasMcLeod Actually casting the int * to an int(*)[] is indeed an aliasing violation (and your original remark is correct) because there never was an array object -- funny as that seems since we usually allocate array "substitutes" --, but the reverse cast would be OK, provided the address is indeed the location of an array. I had that latter cast in mind.
|
3

Though you can't reassign an array identifier.. sometimes the spirit of what you're doing allows you to simply create a reference and masquerade yourself as an array. Note: this is just a slight extension of rodrigo's answer... and it is still worth mentioning that there is probably a better way to accomplish whatever the task is.

#include <iostream>

int main() {
    int x[1000] = {0};
    for(int i = 0; i < 10; ++i) {
        int (&sub_x)[100] = *(int(*)[100])(&x[i*100]);
        //going right to left basically:
        // 1. x[i*100] -- we take an element of x
        // 2. &x[N] -- we take the address of the element
        // 3. (int(*)[100]) -- we cast it to a pointer to int[100]
        // 4. *(...) -- lastly we dereference the pointer to get an lvalue
        // 5. int (&sub_x)[100] -- we create the reference `sub_x` of type int[100]
        for(int j = 0; j < 100; ++j) {
            sub_x[j] = (i*100)+j;
        }
    }
    for(int i = 0; i < 1000; ++i) {
        if(i != 0) {
            std::cout << ", ";
        }
        std::cout << x[i];
    }
    std::cout << std::endl;
}

As you'd expect the output just ends up printing 0-999 with no gaps

output:

0, 1, 2, ..., 999

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.