Reputation: 39
I have been a sysadmin most of my life, but recently decided to practice some my dev knowledge and attempt a devops position. I have as such been practicing some C and Python skills and wrote some code for inserting a number into a linked list.
void list_insert(struct list *h, int d)
{
struct list *elem = malloc(sizeof(struct list));
elem->data = d;
elem->next = NULL;
if (!h) {
h = elem;
} else {
elem->next = h;
h = elem;
}
}
I noticed that this function doesn't seem to alter the outside view of the variable h (i.e whatever is passed to list_insert) and I noticed that printing at the end of the insert function seems to work. So having tried to look for answers online, I couldn't find anything, obvious but I found most list implementations would have double-pointers. I changed my function to use double-pointers and then it suddenly started working. Could someone help me understand what's happening here as I know pointer management is an important concept and I think I understand what a pointer is and how it relates to memory, but I don't think I get why a single pointer does not get changed, whereas a double-pointer does.
Thanks!
Upvotes: 1
Views: 2104
Reputation:
In C, arguments to function are passed by values. Even pointers are passed by values.
For example:
#include<malloc.h>
#include<stdio.h>
int allocatingMemory(int* ptr)
{
ptr = malloc(sizeof(int));
if(ptr==NULL)
return -1;
else
return 0;
}// We are not returning the pointer to allocated memory
int main(void)
{
int* ptr;
int allocated = allocatingMemory(ptr);
if(allocated == 0)
{
*ptr = 999;// Boom!!!
free(ptr);
}
return 0;
}
To overcome this issue, we use
int allocatingMemory(int** ptr)
{
*ptr = malloc(sizeof(int));
if(*ptr == NULL)
return -1;
else
return 0;
}
int main(void)
{
int* ptr;
int isAllocated = allocatingMemory(&ptr);
if(isAllocated == 0)
{
*ptr = 999;
free(ptr);
}
return 0;
}
If you are working with linked list
s and say for example, you want to modify the head. You will pass a pointer to pointer
(Note that, it is not called as double pointer) to head node
.
Upvotes: 6
Reputation: 399949
To change memory in the caller's context, a function needs to have a pointer to that memory.
If the caller of your function has an empty list in a variable, and does an insert on that list like so:
struct list *numbers = NULL;
list_insert(numbers, 4711);
then of course inside list_insert()
all we have is the NULL pointer, so we can't change the value of the variable numbers
in the caller's context.
If, on the other hand, we're given a pointer to the variable, we can change the variable.
That said, it's much cleaner (in my opinion) to return the new head of the list, i.e. make the function's signature be struct list * list_insert(struct list *head, int x);
.
Upvotes: 4
Reputation: 974
h is actually a copy of the original pointer, so your original pointer doesnot get modified. That is why you should use a double pointer.
There are numerous questions related to that on SO. for example Using single versus double pointers in Linked lists implemented in C
Upvotes: 1