I am reading the book "C Programming: A Modern Approach" by KN King, where in chapter 17.5 on page 432 they define a function for deleting a node from a singly linked list:
The following function,
delete_from_list, uses the strategy that we've just outlined. When given a list and an integern, the function deletes the first node containingn. If no node containsn,delete_from_listdoes nothing. In either case, the function returns a pointer to the list.struct node *delete_from_list(struct node *list, int n) { struct node *cur, *prev; for (cur = list, prev = NULL; cur != NULL && cur->value != n; prev = cur, cur = cur->next) ; if (cur == NULL) return list; /* n was not found */ if (prev == NULL) list = list->next; /* n is in the first node */ else prev->next = cur->next; /* n is in some other node */ free(cur); return list; }
The book refers to this function in an exercise on page 454:
Exercises
- Modify the
delete_from_listfunction so that is uses only one pointer variable instead of two (curandprev).
My question is about the following solution I found on Github:
struct node *delete_from_list(struct node **list, int n) {
struct node *item = *list;
while (item) {
if (item->value == n) {
*list = item->next;
free(item);
break;
}
list = &item->next;
item = item->next;
}
return *list;
}
I understand what a pointer to a pointer is. But I don't understand what happens after the line struct node **list. I would very much appreciate it if anybody could explain this solution line by line with visualization.
Let's take an example linked list with values 1, 2, and 3, where
headpoints to its first node, and we have a valuenthat equals 2. We can picture the state of the list in the main program as follows:With this solution code, the caller must pass a pointer to a pointer to a node, and so if the
headvariable in the main program is a pointer to the first node, we need to pass its address, like so:Let's now picture how the function sees its own
listvariable:The first statement is:
So we get:
Execution enters the loop, but the
ifcondition is false, so the next executed statement is:Now the local
listvariable will point to the address of thenextmember of the node thatitempoints to:The last statement in the loop's body is:
So we get:
In the next iteration the
ifcondition is true, so then we execute this:Which mutates the list as follows:
Now the found node can be freed with
free(item):Finally the function returns
*list, but that is of little use: the caller should not use that return value for assignment to its ownheadvariable, or things would go bad. The caller should just rely on the function to adapt itsheadif necessary (not the case in this example).This is what the caller ends up with:
Remarks
In my opinion this is not really a "fair" solution, as it changes the signature of the function:
The original function would have to be called like this:
...while this function should be called like this:
For the above reasons, I am not sure this was the intended solution for the exercise. For other ideas to solve this, see this Q&A.