XOR linked list implementation I am trying to resolve below question in order to prepare for an interview xD

An XOR linked list is a more memory efficient doubly linked list.
Instead of each node holding next and prev fields, it holds a field
named both, which is an XOR of the next node and the previous node.
Implement an XOR linked list; it has an add(element) which adds the
element to the end, and a get(index) which returns the node at
index.

Please suggest how this implementation can be improved. Thank you in prior.
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

typedef struct {
    int value;
    long both;
    
} StNode; 
typedef StNode *pStNode;

pStNode add(pStNode lastNode, int value)
{
    pStNode newNode = (StNode *) malloc(sizeof(StNode));
    newNode-&gt;value = value;
    
    //[both]=value of previous node pointer if it is last node
    newNode-&gt;both = (long)lastNode; 
    
    //calculating previous node [both] value
    lastNode-&gt;both = (long)newNode ^ lastNode-&gt;both;
    
    return newNode;
}

pStNode get(pStNode headNode, int index)
{    
    pStNode prevNode;
    pStNode currNode;
    long tmp;
    
    //special handling
    //case: cur=1, prev=0
    //we have set previous node of head node value to be 0 manually
    currNode = (StNode *) ((headNode-&gt;both) ^ 0);
    prevNode = headNode;
    
    //skim through linked list
    for(int i=2; i&lt;=index; i++)
    {
        tmp = (long)prevNode;
        prevNode = currNode;
        currNode = (StNode *)(currNode-&gt;both ^ tmp);
    }
    
    return currNode;
}


int main() {  
    
    //I named first node as headNode, and last node as tailNode
    //create head node with both=0 since there is no previous node to it
    pStNode headNode = (StNode *) malloc(sizeof(StNode));
    headNode-&gt;both = 0; 
    headNode-&gt;value = 2;
    
    //assign pointers
    pStNode tailNode = headNode;
    
    //lets add 10 nodes after head, and assign values
    for(int i=3; i&lt;13; i++)
    {
        tailNode = add(tailNode, i);
    }
    
    //get node value where index=3
    pStNode iNode = get(headNode, 3);
    printf( &quot;result: %d\n&quot;,  iNode-&gt;value);
    
    return 0;
}
long both;


Using a long for storing a cast pointer can be both wasteful and too little. Just use the dedicated uintptr_t. Even if your implementation might not be fully up to C99 (MS greets), it probably has &lt;stdint.h&gt; and the typedef.

pStNode newNode = (StNode *) malloc(sizeof(StNode));

The above line demonstrates three bad ideas:

More pieces to keep track of means more complexity, which is bad. Thus hiding pointers behind typedefs is a bad idea, unless that pointer-type is never dereferenced, and is thus the one true type used.

Casting a void* is superfluous and error-prone.
See &quot;Do I cast the result of malloc?
&quot;.

Don't use sizeof(TYPE) unless unavoidable. Getting it right even if the types aren't obscured is error-prone. Just use sizeof *pointer.


pStNode get(pStNode headNode, int index)


There is a type uniquely suited as an index: size_t. Alternatively, if you want something signed, you might be interested in ptrdiff_t. Though yes, if your use-case guarantees few enough nodes, int might work.

You really should encapsulate your list somehow. Currently, you are creating a one-off in main().
Also, cleanup should be possible without terminating the program.

If you use at least C99, main() has an implicit return 0;.