remove kth last element from singly-linked list I have implemented a code to solve following problem. I would like to improve the code efficiency.

Pardon if I just printed out the result.
Code has O(N) time and constant space complexity.


Given a singly linked list and an integer k, remove the kth last
element from the list.

k is guaranteed to be smaller than the length of the list.
The list is very long, so making more than one pass is prohibitively expensive.
Do this in constant space and in one pass.


I used a window with the length of k and 2 pointers to track kth last element in the list. 2 pointers are: (1): previous to the first element, (2): the last element of window:
llnode *prev = llist-&gt;head;
llnode *last = llist-&gt;head;

CODE:
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdbool.h&gt;

typedef struct llnode
{
    int value;
    struct llnode *next;
} llnode;

typedef struct xllist
{
    llnode * head;
    llnode * tail;
    size_t length;
} xllist;

bool create_node(xllist *list, int value)
{
    llnode *node = malloc(sizeof *node);
    if(!node)
    {
        return false;
    }
    list-&gt;length++;

    node-&gt;value = value;
    node-&gt;next = NULL;
    if(!list-&gt;head)
    {
        list-&gt;head = node;
        list-&gt;tail = node;
    }
    list-&gt;tail-&gt;next = node;
    list-&gt;tail = node;
    return true;
}

bool del_element_from_last(xllist *llist, int k)
{
    printf(&quot;len:%d \n&quot;, llist-&gt;length);
    //window with 2 pointers, length of k
    //prev is the prev node to the window
    llnode *prev = llist-&gt;head;
    llnode *last = llist-&gt;head;

    if(k &gt; (size_t)llist-&gt;length)
    {
        return false;
    }
    else if (k == (size_t)llist-&gt;length)
    {
        llist-&gt;head = llist-&gt;head-&gt;next;
        return true;
    }

    for(int i=0; i&lt;k; i++)
    {
        last = last-&gt;next;
    }

    //move window until last reaches end
    while(last)
    {
        prev = prev-&gt;next;
        last = last-&gt;next;
    }

    //remove first node of the window
    printf(&quot;deleted element:%d \n&quot;, prev-&gt;next-&gt;value);
    prev-&gt;next = prev-&gt;next-&gt;next;

}

int main(void)
{
    /*Given a singly linked list and an integer k, remove the kth last element from the list.
    k is guaranteed to be smaller than the length of the list.
    The list is very long, so making more than one pass is prohibitively expensive.
    Do this in constant space and in one pass.*/
    xllist llist = {NULL, NULL, 0};

    for(int i=0; i&lt;100; i++)
    {
        if(!create_node(&amp;llist, 100+i))
            printf(&quot;create fail\n&quot;);
    }

    del_element_from_last(&amp;llist, 15);

}
I don't know what OS and compiler you use but running gcc -O2 main.c -o main -Wall -Wextra produces several warnings:
main.c: In function ‘del_element_from_last’:
main.c:41:18: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘size_t’ {aka ‘long unsigned int’} [-Wformat=]
   41 |     printf(&quot;len:%d \n&quot;, llist-&gt;length);
      |                 ~^      ~~~~~~~~~~~~~
      |                  |           |
      |                  int         size_t {aka long unsigned int}
      |                 %ld
main.c:47:10: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare]
   47 |     if(k &gt; (size_t)llist-&gt;length)
      |          ^
main.c:51:16: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare]
   51 |     else if (k == (size_t)llist-&gt;length)
      |                ^~
main.c:73:1: warning: control reaches end of non-void function [-Wreturn-type]
   73 | }
      | ^

valgrind reports memory leak:
$ valgrind ./main
==10611== Memcheck, a memory error detector
==10611== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10611== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==10611== Command: ./main
==10611==
len:100
deleted element:186
==10611==
==10611== HEAP SUMMARY:
==10611==     in use at exit: 1,600 bytes in 100 blocks
==10611==   total heap usage: 101 allocs, 1 frees, 2,624 bytes allocated
==10611==
==10611== LEAK SUMMARY:
==10611==    definitely lost: 32 bytes in 2 blocks
==10611==    indirectly lost: 1,568 bytes in 98 blocks
==10611==      possibly lost: 0 bytes in 0 blocks
==10611==    still reachable: 0 bytes in 0 blocks
==10611==         suppressed: 0 bytes in 0 blocks
==10611== Rerun with --leak-check=full to see details of leaked memory
==10611==
==10611== For lists of detected and suppressed errors, rerun with: -s
==10611== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)`

Why does this function
bool del_element_from_last(xllist *llist, int k)

and others return non-zero on success? Usually, functions in C return
0 on success and non-zero on failure. The current behavior in your
code is counter-intuitive.
You should add a function that prints the entire list.
If you do this:
del_element_from_last(&amp;llist, 1);

your code crashes:
$ ./main
len:100
Segmentation fault