First: some issues in your code:
newnode* head = (newnode*) malloc(sizeof(newnode));
This allocates a node, but leaves its members uninitialised. This is not good, as iterating such a list will lead to undefined behavior when the head->next
is used for potentially finding a next node. It must be set to NULL
. And as we are at it, there is no good reason to leave the node's value uninitialised either.
Secondly, this malloc
duplicates code. You already have a function that performs such allocation and which initialises its members and makes a head pointer point to it. That's really all you want to happen here!
So change the above code to:
newnode* head = NULL;
addnode(*head, 0);
You write in a code comment:
I assumed since push (i.e. addnode
) takes a newnode**
argument, that head
should have an additional asterisk prefixed to it.
Yes, that is correct. This is needed because addnode
will want to assign a new pointer value to "your" head
, and so it needs to get the address of where to put it. It is a bit misleading to use the name head
for this address in addnode
, as it really is not the same thing as head
in the main function. I suggest to rename it to headPtr
. Also in C it is consider better practice to not cast the pointer returned by malloc
void push(newnode ** headPtr, int val)
{
newnode * new_node = malloc(sizeof(newnode));
new_node->value = val;
new_node->next = *headPtr;
*headPtr = new_node;
}
I will now assume that version of the code with this corrected code for main
:
newnode* head = NULL;
addnode(*head, 0);
addnode(*head, 4);
...and make a visualisation of what happens when this gets executed. We start with head
set to NULL
:
┌─head─┐
│ NULL │
└──────┘
The addnode
function is called with the address of head
and the value 0. addnode
has its own variable headPtr
which now is a pointer to head
:
┌─headPtr─┐
│ ┬ │
└────│────┘
▼
┌─head─┐
│ NULL │
└──────┘
With malloc
a new node is allocated and initialised with value 0:
┌─headPtr─┐ ┌─new_node─┐
│ ┬ │ │ ┬ │
└────│────┘ └─────│────┘
▼ ▼
┌─head─┐ ┌──value──┐
│ NULL │ │ 0 │
└──────┘ ├───next──┤
│ ??? │
└─────────┘
Then the assignment new_node->next = *headPtr;
is made, which copies the value from *headPtr
, i.e. from head
, i.e. NULL
... to that next
element:
┌─headPtr─┐ ┌─new_node─┐
│ ┬ │ │ ┬ │
└────│────┘ └─────│────┘
▼ ▼
┌─head─┐ ┌──value──┐
│ NULL │ │ 0 │
└──────┘ ├───next──┤
│ NULL │
└─────────┘
Still, this new node is not yet "in the list": the final assignment of addnode
will do this: *headPtr = new_node
. This will copy the address of the node to *headPtr
, i.e. to head
:
┌─headPtr─┐ ┌─new_node─┐
│ ┬ │ │ ┬ │
└────│────┘ └─────│────┘
▼ ▼
┌─head─┐ ┌──value──┐
│ ├────────►│ 0 │
└──────┘ ├───next──┤
│ NULL │
└─────────┘
Note how that will influence what the main
function will see when that first call to addnode
has returned. head
is now no longer NULL
. Because we passed a pointer to head
, addnode
was able to modify head
's (pointer) value. This is what we see in main
:
┌─head─┐ ┌──value──┐
│ ├────────►│ 0 │
└──────┘ ├───next──┤
│ NULL │
└─────────┘
Let's do the second call of addnode
in the same way. headPtr
will again point to head
, and this time the value is 4. A new node is allocated with malloc
, and the value
member is assigned 4 (I have to make a bit of room in the diagram for it):
┌─headPtr─┐ ┌─new_node─┐
│ ┬ │ │ ┬ │
└────│────┘ └─────│────┘
│ ▼
│ ┌──value──┐
│ │ 4 │
│ ├───next──┤
│ │ ??? │
▼ └─────────┘
┌─head─┐ ┌──value──┐
│ ├─────────────────────────►│ 0 │
└──────┘ ├───next──┤
│ NULL │
└─────────┘
Now we get to the "magic" two assignments. First new_node->next = *headPtr;
. This will establish the link between the new node, and the already existing one (from the previous call to add_node
):
┌─headPtr─┐ ┌─new_node─┐
│ ┬ │ │ ┬ │
└────│────┘ └─────│────┘
│ ▼
│ ┌──value──┐
│ │ 4 │
│ ├───next──┤
│ │ ├──────┐
▼ └─────────┘ │
┌─head─┐ │ ┌──value──┐
│ ├────────────────────┴────►│ 0 │
└──────┘ ├───next──┤
│ NULL │
└─────────┘
And finally, *headPtr = new_node;
will make the new node the first node of the list:
┌─headPtr─┐ ┌─new_node─┐
│ ┬ │ │ ┬ │
└────│────┘ └─────│────┘
│ ▼
│ ┌──value──┐
│ │ 4 │
│ ├───next──┤
│ ┌──►│ ├──────┐
▼ │ └─────────┘ │
┌─head─┐ │ │ ┌──value──┐
│ ├────┘ └────►│ 0 │
└──────┘ ├───next──┤
│ NULL │
└─────────┘
When back in main
, this is what remains:
┌─head─┐ ┌──value──┐ ┌──value──┐
│ ├───────►│ 4 │ │ 0 │
└──────┘ ├───next──┤ ├───next──┤
│ ├───────────►│ NULL │
└─────────┘ └─────────┘
Hope this clarifies it.