Reputation: 27852
I have seen this question:
Which uses the following code to add an element o a list: C linked list inserting node at the end
int addNodeBottom(int val, node *head){
//create new node
node *newNode = (node*)malloc(sizeof(node));
if(newNode == NULL){
fprintf(stderr, "Unable to allocate memory for new node\n");
exit(-1);
}
newNode->value = val;
newNode->next = NULL; // Change 1
//check for first insertion
if(head->next == NULL){
head->next = newNode;
printf("added at beginning\n");
}
else
{
//else loop through the list and find the last
//node, insert next to it
node *current = head;
while (true) { // Change 2
if(current->next == NULL)
{
current->next = newNode;
printf("added later\n");
break; // Change 3
}
current = current->next;
};
}
return 0;
}
Why head is passed as node *head
instead of node **head
if we are going to change it inside and we want the changes to be propagated outside the function? What am I missing here?
Upvotes: 2
Views: 243
Reputation:
You could probably make that code a little bit more elegant using a pointer to a pointer, like so:
int addNodeBottom(int val, node **link){
node *newNode = ...;
...
if(*link == NULL){
printf("added at beginning\n");
}
else
{
while (*link)
link = &(*link)->next;
printf("added later\n");
}
*link = newNode;
return 0;
}
...
addNodeBottom(some_val, &head->next);
... something to this effect. Not the biggest difference though but maybe a little bit nicer. It'd be simpler if the list didn't use a dummy node for the head and didn't need to print out when it adds to the beginning of the list vs. the end. In that case we could simply do:
void addNodeBottom(int val, node **link){
node *newNode = ...;
...
while (*link)
link = &(*link)->next;
*link = newNode;
}
...
addNodeBottom(some_val, &head);
... which is starting to look considerably nicer with no special cases to handle. If there's an absolute need to use this kind of dummy head and print out whether the insertion was to the front of the list or not, maybe it'd help to return a pointer to the new node (null on failure, e.g.), like so:
node* addNodeBottom(int val, node **link){
node *newNode = ...;
...
while (*link)
link = &(*link)->next;
*link = newNode;
return newNode;
}
...
if (addNodeToBottom(some_val, &head->next) == head->next)
printf("added at beginning\n");
else
printf("added later\n");
Why head is passed as node *head instead of node **head if we are going to change it inside and we want the changes to be propagated outside the function?
As others pointed out, this is kind of an unusual linked list where the head
is some kind of dummy node or something. It never gets modified in that function, only head->next
, so changes to head
will propagate and cause external side effects.
I never understood the point of those types of linked list implementations storing dummy nodes in languages like C and C++ since they don't cut down on special cases. They just waste memory for no good reason. They might make sense for a language that doesn't allow more than one level of indirection, but make no sense at all in languages that have pointers. Maybe the person who implemented that linked list originally came more from a background of languages without pointers, like Java or Python or something. Probably linked lists of this sort with dummy nodes aren't so unusual in those languages as a workaround to get around the fact that the language doesn't allow pointers to pointers (or references to references) to avoid some if
statements here and there.
Upvotes: 0
Reputation: 12023
Fundamentally, no reason why it couldn't. In fact, this is one of the things that Linus Torvalds points out as demonstrating mastery over pointers. Related question: Using pointers to remove item from singly-linked list
Upvotes: 0
Reputation: 23699
head
is never modified directly in this function. Only head->next
is assigned to another value. Therefore you don't need to use a pointer to pointer.
Upvotes: 3