Try "playing computer" and think it through.
What do you think the line *curr = entry->next does?
It's playing the same role as prev->next = next in the single-pointer version.
Code:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
struct Node *next;
int value;
} Node;
void *xmalloc(size_t sz) {
void *p = malloc(sz);
if (!p) { perror("xmalloc"); exit(EXIT_FAILURE); }
return p;
}
void remove_if(Node **head, int(*rm)(Node*)) {
for (Node **curr = head; *curr; ) {
Node *entry = *curr;
if (rm(entry)) {
*curr = entry->next;
free(entry);
}
else
curr = &entry->next;
}
}
Node *new_node(int value, Node *next) {
Node *nd = xmalloc(sizeof *nd);
nd->next = next;
nd->value = value;
return nd;
}
Node *list_prepend(Node *head, int value) {
return new_node(value, head);
}
void list_print(Node *head) {
for (Node *p = head; p; p = p->next)
printf("%d ", p->value);
putchar('\n');
}
int rm(Node *nd) {
return nd->value % 2 == 0;
}
int main() {
int a[] = {2, 5, 3, 4 ,6, 9, 2, 1, 6, 4};
Node *head = NULL;
// prepend array elements in reverse order
for (size_t i = sizeof a/sizeof *a; i-- > 0; )
head = list_prepend(head, a[i]);
list_print(head);
remove_if(&head, rm);
list_print(head);
return 0;
}