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?
The question is pretty unclear but I will try to answer anyway:
new int *[5]is 5 contiguous pointers each of typeint *. 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 bynew int *[5]can be accessed by recovering its address with the correct type:Any other ways of attempting to access the memory block in question cause undefined behaviour. (Well, except for aliasing it as
unsigned char).