wukaihua119
wukaihua119

Reputation: 5

extract elements from a pointer to pointer to array of structures

I have a problem with a point to a pointer to an array of structures.

I declare and initialize three points to structure which has a member val. I create a pointer arr to an array of pointer to structure. Then I create a pointer pa to pointer arr and a pointer pa1 to pa.

I encounter the problem when I try to extract the second element of the arr using pa1.

Main.cpp

#include<iostream> 
#include<cstdio> 

struct a{ 
    int val; 
}; 

int main(){ 

    // create structures 
    a *a1 = new a; 
    a1->val = 5; 
    a *a2 = new a; 
    a2->val = 3; 
    a *a3 = new a; 
    a3->val = 4; 

    a *arr[3] = { a1, a2, a3 }; 
    a **pa = arr; 

    std::cout << "Using pa:\n"; 
    std::printf( "1st val: %d\n", (*(pa+0))->val ); 
    std::printf( "1st pos: %p\n", (*(pa+0)) ); 
    std::printf( "2nd val: %d\n", (*(pa+1))->val ); 
    std::printf( "2nd pos: %p\n", (*(pa)+1) ); // modified 

    std::cout << std::endl << std::endl; 

    // a pointer to pa's value
    a *pa1 = *pa;  

    std::cout << "Using pa1:\n"; 
    std::printf( "1st val: %d\n", pa1->val ); 
    std::printf( "1st pos: %p\n", pa1 ); 
    std::printf( "2nd val: %d\n", (pa1+1)->val ); 
    std::printf( "2nd pos: %p\n", pa1+1 ); 


    delete a1, a2, a3;  

    return 0; 
}

Then I get the result as below,

Using pa:
1st val: 5
1st pos: 0000000000e761e0
2nd val: 3
2nd pos: 0000000000e761e4

Using pa1:
1st val: 5
1st pos: 0000000000e761e0
2nd val: 0
2nd pos: 0000000000e761e4

The question is why the 2nd val of pa1 is not 3 but 0?

Both pa and pa1 seem to point to the same address 0000000000e761e4.



UPDATE

The line // modified should be std::printf( "2nd pos: %p\n", *(pa+1) );.

And the result becomes as below

Using pa:
1st val: 5
1st pos: 0000000000ee61d0
2nd val: 3
2nd pos: 0000000000ee61f0


Using pa1:
1st val: 5
1st pos: 0000000000ee61d0
2nd val: 0
2nd pos: 0000000000ee61d4

The 2nd pos of pa and pa1 is actually not the same.

Now the question is How can I get the second element from arr using pa1?

Upvotes: 0

Views: 919

Answers (2)

KIIV
KIIV

Reputation: 3739

You have to make a diagram, what is stored where and how:

For example:

// Allocated values (they are completely unrelated and may point into different locations):
a1 = 0x11111100;
a2 = 0x22222200;
a3 = 0x33333300;
// Where each of those addresses points to the place in memory with one constructed element of a 

// next is creating arr of three pointers to a:
a * arr[3] = { a1, a2, a3 };
// which is effectively:
a * arr[3] = { 0x11111100, 0x22222200, 0x33333300};

// the arr is stored somewhere too, and it contains location, where those three addresses are stored
arr = 0xFFFFF340; // for example

// so when you do:
a ** pa = arr;
// then
pa == 0xFFFFF340;
// and pa + 1 == 0xFFFFF344  (increment depends on architecture) 
// ==> dereferenced value is location where pointer to a2 is stored

However, if you do:

a * pa1 = *pa; 
// then it means you did:
a * pa1 = arr[0];
// therefore:
pa1 == 0x11111100;
// and pa1+1 is memory location after a1 object eg.:
pa1+1 == 0x11111104;
// but as you've created only one element in that place, dereferencing it causes buffer overflow and using uninitialized memory

BTW: you could use debugger and variable watches to track what is happening and what is pointing where and its values

EDIT: Added bigger structs, so differences are much more obvious:

#include <stdio.h>

struct Data {
    int x[100] = {0};
};


int main()
{
    Data * a = new Data[10];
    Data * b = new Data[5];
    Data * c = new Data[1];

    printf("a value: %p\n", a);
    printf("b value: %p\n", b);
    printf("c value: %p\n", c);

    Data * arr[] = { a, b, c};

    for (auto const& ptr : arr)
    {
        printf("Arr: element addr: %p  position: %ld  ptr to: %p\n", &ptr, &ptr-arr, ptr);
    }

    Data ** pa = arr;
    printf("pa   value: %p  dereferenced value: %p\n", pa, *pa);
    printf("pa+1 value: %p  dereferenced value: %p\n", pa+1, *(pa+1));
    printf("pa+2 value: %p  dereferenced value: %p\n", pa+2, *(pa+2));

    Data * pa0 = *pa;
    printf("pa0   value: %p\n", pa0);
    printf("pa0+1 value: %p\n", pa0+1);
    printf("pa0+2 value: %p\n", pa0+2);

    // cleanup - eventually :D  But using std::unique_ptr would be much better.
}

And the output:

a value: 0x55bd5d988eb0
b value: 0x55bd5d989e60
c value: 0x55bd5d98a640
Arr: element addr: 0x7ffc528dcf00  position: 0  ptr to: 0x55bd5d988eb0
Arr: element addr: 0x7ffc528dcf08  position: 1  ptr to: 0x55bd5d989e60
Arr: element addr: 0x7ffc528dcf10  position: 2  ptr to: 0x55bd5d98a640
pa   value: 0x7ffc528dcf00  dereferenced value: 0x55bd5d988eb0
pa+1 value: 0x7ffc528dcf08  dereferenced value: 0x55bd5d989e60
pa+2 value: 0x7ffc528dcf10  dereferenced value: 0x55bd5d98a640
pa0   value: 0x55bd5d988eb0
pa0+1 value: 0x55bd5d989040
pa0+2 value: 0x55bd5d9891d0

Upvotes: 1

user9400869
user9400869

Reputation:

Both pa and pa1 seem to point to the same address 0000000000e761e4.

But they are of different type. Therefor the +1 gives a different address.

pa1 is of type a*, therefor the pa1+1 is reinterpret_cast<a*>(reinterpret_cast<unsigned char*>(pa1)+sizeof(a)). Note we stripped one layer of indirection for calculating the offset.

pa is of type a**, therefor the pa1+1 is reinterpret_cast<a**>(reinterpret_cast<unsigned char*>(pa)+sizeof(a*)).

Since reinterpret_cast<unsigned char*>(pa)==reinterpret_cast<unsigned char*>(pa1), but sizeof(a)!=sizeof(a*) we have different results.

The thing is that pa1 is not the first address in an array of a! Therefor this calculation is wrong.

Upvotes: 0

Related Questions