Yes, the function recursively calls itself with the "next" follower, before free()'ing anything.
If we start out with this layout:
Code:
k -> follower
|
v
next -> follower
|
v
next -> follower
|
v
NULL
Then the first check obviously is false (k is something). Then, this is passed to the function:
Code:
next -> follower
|
v
next -> follower
|
v
NULL
On this, second call to the function, the internal representation of state looks like this:
Code:
k -> follower
|
v
next -> follower
|
v
NULL
Again, the first check is false (again, k is something). So the function is called again, with "k->next" as argument.:
Code:
next -> follower
|
v
NULL
Internally, this is seen as
Code:
k -> follower
|
v
NULL
Again, k is something. So we call this function with k->next as the argument:
Now, on the fourth call, k is NULL. This means the recursion stops, and the function returns immediately.
So, we're back in the third call, where k still is something, and we're done with k->next. Now we null out the follower and free the struct.
The implicit return at the end of the function brings us to the second call.
Here we are right after the free_followers(k->next) call and have this data structure:
Code:
k -> follower
|
v
free()'d memory
So we clean up by free()'ing the k object, and traversing up the call stack to the first call. This has exactly the same data structure:
Code:
k -> follower
|
v
free()'d memory
(Albeit with a different memory address for the k and free'd memory). Again, we free k, and we're done with the last (and first) call to the function.