I never really had much of a problem with the syntax, but the point at which the behavior of pointers really clicked for me (after a night of many segfaults of course) was when I realized that when you pass a pointer to a function, you're sending a copy of that pointer, just like with any other primitive type. E.g:
void foo(int *p)
{
/* assignment won't be persistent after foo() returns; need to send **p */
p = (int *)malloc(1024 * sizeof(int));
}
Not sure why my brain had decided to make an exception for pointers for the rule that all variables are passed as copies when I first learned C, but after that I never had any problems.
I experienced the same frustration. The exercise that gave me the "ah-ha!" moment I needed was prepending to a linked list via the head instead of the tail: You need to pass the address of `head` into the function so that the new head is reflected in the calling environment when you say `head = np`.