It should be something like this:
node * remove_key(char key, node * head)
{
// remove initial matching elements
while (head && head->data == key)
{
node * tmp = head;
head = head->next;
free(tmp);
}
// remove non-initial matching elements
// loop invariant: "current != NULL && current->data != key"
for (node * current = head; current != NULL; current = current->next)
{
while (current->next != nullptr && current->next->data == key)
{
node * tmp = current->next;
current->next = tmp->next;
free(tmp);
}
}
return head;
}
As an interesting mental exercise, imagine you had an "exchange" function (like C++ does):
node * exchange(node ** obj, node * newval)
{ node * tmp = *obj; *obj = newval; return tmp; }
Then you could write this code very simply:
node * remove_key(char key, node * head)
{
while (head && head->data == key)
free(exchange(&head, head->next));
for (node * current = head; current != NULL; current = current->next)
while (current->next != nullptr && current->next->data == key)
free(exchange(¤t->next, current->next->next));
return head;
}
You could even specialize to some kind of "exchange_with_next":
node * exchange_with_next(node ** n) { return exchange(n, (*n)->next); }