The partial code, in C, is here:
typedef struct List {
double v;
struct List *next;
} List;
void deleteList (List **p) {
*p = (*p)->next;
}
I am confused about how the deleteList function is working. So the arguement is a pointer to a pointer to a List structure. So we have:
p : pointer_2 --> pointer_1 --> List
So I have some questions:
Say we have:
... la --> lb --> lc --> ld ....
And say we want to delete lb. I get the idea, theoretically. You alter the la->next to point to lc. But I am confused about the pointer business. What is the argument to deleteList()? Is it, deleteList(la->next)? Or something else? And then the really confusing part. *p = ... is supposed to be la->next because this is the pointer we want to alter. But then ...(*p)->next, wouldn't this just be the lb? But we want lc? So it seems like *p have different meaning in the same line?!
Let;s at first write the function correctly.
void deleteList( List **head )
{
while ( *head != NULL )
{
List *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
}
A pointer to the head node is passed to the function by reference.
If you will define the function like
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
that is if the pointer will not be passed by reference then the function will deal with a copy of the pointer. Changing a copy does not influence on the original pointer.
Consider the following demonstrative program.
#include <stdio.h>
#include <stdlib.h>
void f( int *p )
{
p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
Its output might look like
Before the function call px = 0x7ffe26689a2c
Adter the function call px = 0x7ffe26689a2c
That is the original pointer px
was not changed because the function dealt with a copy of the pointer.
To change the pointer you need to pass it to the function by reference
#include <stdio.h>
#include <stdlib.h>
void f( int **p )
{
*p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( &px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
Now the program output might look like
Before the function call px = 0x7ffed60815fc
Adter the function call px = (nil)
Within the function you need to dereference the parameter to get the access to the passed by reference pointer.
*p = NULL;
^^^^
The same occurs in the function deleteNode
. To check whether the passed pointer is equal to NULL there is used the following statement
while ( *head != NULL )
^^^
To access the data member next
of the node pointed to by the origibal pointer you again have to dereference the parameter to get access to the original pointer
*head
So this expression yields the original pointer. So to access the data member next you have to write
( *head )->next
You are using the parentheses because the postfix operator -> has a higher priority but you need at first to get the original pointer.
That is if you had no a referenced pointer you would write
head->next
But when you have a referenced pointer that is when you have a pointer to an original pointer then to get the original pointer you have to derefernce the referenceing pointer like
( *head )->next
You could write the function without accepting the pointer to the head node by reference. But in this case you should to add in the caller one more statement that will set the pointer head to NULL.
For example
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
and in the caller you need to write
List *head - NULL;
// the code thatf fills the list
deleteList( head );
head = NULL;
Or the function could return a null pointer like
List * deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
return head;
}
and in the caller you could write
List *head - NULL;
// the code thatf fills the list
head = deleteList( head );
The advantage of defining the function that accepts the pointer to the head node by reference is that the user of the function does not need to remember to set the pointer to NULL by himself.