remove kth last element from singly-linked list - Follow up
In the function del_element_from_last, when removing the first element of the list, you update llist-&gt;head. However, when removing the last element of the list, you do not update llist-&gt;tail.
If keeping track of the tail of the list is only intended for building the list, and is not intended to be updated by the function del_element_from_last, then you should not pass the entire struct xllist to the function del_element_from_last. Rather, you should change the function signature to the following, so that the function only has access to the head:
bool del_element_from_last( xlnode **pp_head, int k )

According to the task description, k is guaranteed to be smaller than the list. This means that the list is guaranteed to be not empty. In that case, the line
if(llist-&gt;head)
in the function del_element_from_last is redundant, because the condition will always be true.
On the other hand, defensive programming is good programming style. Therefore, it may still be appropriate to keep it.
However, if you decide to keep it, your program should handle both cases properly. If the condition is false, your program will cause undefined behavior, because you read the uninitialized value of last. Therefore, you should probably instead immediately return false when the condition is false.
An alternative to the if statement would be to use the assert macro, like this:
assert( llist-&gt;head );
That way, you don't have to provide code to handle both cases. Instead, a diagnostic error message will appear if the variable does not have the expected value (only on debug builds though, not on release builds).