You can run it through a debugger or you can run it through that bit of wetware inside your skull - both will show you that it works fine. For example, let's start with the list:
head(47) -> [47]single_node -> [NULL]end-of-list.
Running that list through your statements:
ptr = head
sets ptr
to 47.
head
is non-zero so enter loop.
head = head->next
sets head
to NULL.
delete ptr
will delete the single_node
.
ptr = head
sets ptr
to NULL.
head
is now NULL (0) so exit loop.
There you go, you've deleted the only entry in the list and head
is now set to NULL. That's all you need to do.
You can do a similar thing with a longer list or an empty list, you'll find it's still okay (there's no real difference between a one-element list and a fifty-element list).
As an aside, I'm not a big fan of treating pointers as booleans - I'd rather write it as something like:
for (ptr = head; head != NULL; ptr = head)
It makes the code read better in my opinion and you don't really sacrifice any performance (unless you have a brain-dead compiler). But that's a matter of taste.
Re your comment:
The thing that concerns me is reaching the very last node. The condition "head;" should check that it is not null, but I'm not sure if it will work.
It will work. A value of zero will be treated as false so you'll find that you never dereference head->next when head is NULL simply because you will have exited the loop body before that point (or not even entered the body if the list is empty).
Any other pointer value will be treated as true and you will enter or continue the loop body.