How does the memory layout look like when a double pointer is assigned to a single pointer?

128 Views Asked by At

I am currently working on a legacy code (still proprietary, so we'll have to make do with an MRE instead; and by legacy I mean code written in 1991). This is what I've come across:

#include <iostream>

void foo(void*& ptr2) {
    
    // whatever
    
}

int main() {
    int** ptr = new int*[5];
    void* ptr2;
    int i = 1;
    for(int j = 0; j < 5; j++) {
        ptr[j] = new int;
        ptr[j][0] = i++;
    }
    ptr2 = ptr;
    foo(ptr2);

    // further operations here... and a comment which suggests the above was done to prevent accidental double dereferencing when ptr2 was passed by reference to another function
    return 0;
}

How does the logical layout of ptr2 look like in this case? I am assuming that ptr[0][0] becomes ptr2[0], ptr[1][0] becomes ptr2[1] and so on, but the print statements (not required in the MRE, just standard cout statements on various indices) prove my assumption wrong. What am I missing here?

1

There are 1 best solutions below

0
M.M On

The question is pretty unclear but I will try to answer anyway:

  • casting pointers does not alter any memory layout
  • the layout of a pointer is some contiguous bytes (usually 4 or 8) that hold a memory address. This should not be confused with the layout of memory that a pointer may be pointing to.
  • the layout of the objects allocated by new int *[5] is 5 contiguous pointers each of type int *. Mucking around with other pointers that point to this memory block does not change the layout of this memory block.

Inside foo, the memory that was allocated by new int *[5] can be accessed by recovering its address with the correct type:

void foo(void*& ptr2)
{
     int **ptr = static_cast<int **>(ptr2);

     for(int j = 0; j < 5; j++)
         std::cout << ptr[j] << '\n';
}

Any other ways of attempting to access the memory block in question cause undefined behaviour. (Well, except for aliasing it as unsigned char).