Pointers (and pointers to pointers) are relatively easy to understand when you have simple types such as int, char etc but I've always found it tricky to understand dynamic memory allocation and pointers (to pointers) when you have structs.
That's why I posted an earlier thread trying to understand dynamically allocating memory for a simple struct. I have recently started studying the use of pointers to pointers, and was trying to do a practical exercise shown in another thread: Why use double pointer? or Why use pointers to pointers? especially the part where it says
"Pointers to pointers also come in handy as "handles" to memory where you want to pass around a "handle" between functions to re-locatable memory."
Following the code template provided in the thread, I created the following functions (LIB_OBJECT is a simple struct as defined in the template in the thread):
void lib_free_memblock(LIB_OBJECT** memblock)
{
if (*memblock) {
free(*memblock);
*memblock = NULL;
}
}
LIB_OBJECT **lib_create_memblock(void)
{
LIB_OBJECT *memblock = (LIB_OBJECT*) malloc(10 *
sizeof(LIB_OBJECT));
LIB_OBJECT **ptr_to_memblock = (LIB_OBJECT **) malloc(sizeof(LIB_OBJECT*));
*ptr_to_memblock = memblock;
if (ptr_to_memblock == NULL)
{
printf("Memory block allocation (memblock) failed!\n");
exit(1);
}
printf("%d bytes of memory block successfully allocated starting at address %x\n", NUM_OBJECTS, *ptr_to_memblock);
return ptr_to_memblock;
}
void lib_resize_memblock (LIB_OBJECT **b, int new_size)
{
*b = (LIB_OBJECT*) realloc ((void *)*b, new_size);if (b == NULL)
{
printf("Resizing memory block failed!\n");
exit(1);
}
printf("Memory block at start address %x has been resized to %d bytes\n", *b, new_size);
}
The program works successfully:
LIB_OBJECT **my_memblock = lib_create_memblock();
lib_resize_memblock(my_memblock, 20);
lib_free_memblock(my_memblock);
10 bytes of memory block successfully allocated starting at address 233c010
Memory block at start address 233c010 has been resized to 20 bytes
However, when I change
*ptr_to_memblock = memblock;
to
ptr_to_memblock = &memblock;
I can succesfully allocate the 10 bytes using lib_create_memblock:
10 bytes of memory block successfully allocated starting at address 1c2b010
but the program crashes at lib_resize_memblock:
Breakpoint 2, lib_resize_memblock (b=0x7fffffffdf40, new_size=20)
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7aa3c01 in realloc_hook_ini () from /lib64/libc.so.6
Now isn't
*ptr_to_memblock = memblock;
and
ptr_to_memblock = &memblock;
same?
Can someone please clarify?
If I understand correctly, *b is the start address of the memory block allocated and **b is the pointer to the start address of the memory block allocated thus allowing the programmer to do modifications on the allocated memory block. Then, how does the compiler understand what *b mean in lib_resize_memblock where we send **b as argument to the function? From the following initialization?
*ptr_to_memblock = memblock;
I guess the compiler follows a chain connection, from the pointer to pointer into pointer and finally into the address that the pointer points to, all I have to do is to make the right connection, am I right? Thanks in advance..