Basic queue implementation in C I'm practicing data structures in C and I implemented a queue based on its description:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

struct QueueNode {
    int data;
    struct QueueNode* nextNode;
};

struct Queue{
    struct QueueNode* priorNode;
    struct QueueNode* lastNode;
};

struct Queue* initQueue(){
    struct Queue* queue = malloc(sizeof(struct Queue)); //only one is needed
    if(!queue){
        fprintf(stderr,"memory error");
        exit(1);
    }
    queue-&gt;priorNode = NULL;
    queue-&gt;lastNode = NULL;
    return queue;
}

void enqueue(struct Queue* queue, int num){
    struct QueueNode* queuenode = malloc(sizeof(struct QueueNode));
    if(!queuenode){
        fprintf(stderr,"memory error");
        exit(1);
    }
    queuenode-&gt;data = num;
    queuenode-&gt;nextNode = NULL;

    if(!queue-&gt;priorNode){
        queue-&gt;priorNode = queuenode;
    }

    if(queue-&gt;lastNode){
        struct QueueNode* temp = queue-&gt;lastNode;
        queue-&gt;lastNode = queuenode;
        temp-&gt;nextNode = queue-&gt;lastNode;
    } else {
        queue-&gt;lastNode = queuenode;
    }
}

struct QueueNode dequeue(struct Queue* queue){
    if(!queue-&gt;priorNode){
        fprintf(stderr,"Queue is empty.\n");
        struct QueueNode nullnode = {0, NULL};
        return nullnode;
    }
    struct QueueNode prior = *queue-&gt;priorNode;
    free(queue-&gt;priorNode);
    if(prior.nextNode){
        queue-&gt;priorNode = prior.nextNode;
    } else {
        queue-&gt;priorNode = NULL;
    }
    return prior;
}

void peekQueue(struct Queue* queue){
    printf("\"%d\" is the current prior element in the queue\n", queue-&gt;priorNode-&gt;data);
}

void listQueue(struct Queue* queue){
    struct QueueNode* qn = queue-&gt;priorNode;

    printf("elements in the queue from left(the most prior) to right(the least prior) are:\n");
    while(qn){
        if(!qn-&gt;nextNode){
            printf("%d",qn-&gt;data);
            break;
        }
        else{
            printf("%d - ",qn-&gt;data);
            qn = qn-&gt;nextNode;
        }
    }
    printf("\n");
}

void closeQueue(struct Queue* queue){

    struct QueueNode* next = NULL;
    while(queue-&gt;priorNode){
        next = queue-&gt;priorNode-&gt;nextNode;
        free(queue-&gt;priorNode);
        if(!next) break;
        queue-&gt;priorNode = next;
    }

    free(queue);
}

int main(){
    struct Queue* queue = initQueue();

    enqueue(queue,15);
    enqueue(queue,4);
    enqueue(queue,8);
    enqueue(queue,13);
    enqueue(queue,7);

    listQueue(queue);

    peekQueue(queue);

    struct QueueNode node;

    node = dequeue(queue);
    printf("\"%d\" came out of the queue\n",node.data);
    node = dequeue(queue);
    printf("\"%d\" came out of the queue\n",node.data);
    node = dequeue(queue);
    printf("\"%d\" came out of the queue\n",node.data);
    node = dequeue(queue);
    printf("\"%d\" came out of the queue\n",node.data);
    node = dequeue(queue);
    printf("\"%d\" came out of the queue\n",node.data);
    node = dequeue(queue);
    printf("\"%d\" came out of the queue\n",node.data);

    closeQueue(queue);
return 0;
}


I especially didn't know what to do in my dequeue function when the queue was empty. I don't want the 0 to be returned as well because that would of course be confusing to the user.
I'm not able to review the functionality of the code currently, but to address your concerns:

In dequeue(), rather than returning the node, add a parameter (pointer to QueueNode) to store that node in. This is similar to functions like memcpy(3), strtoul(3) (end pointer), and so on. It allows you to return an error value however you wish.

int dequeue(struct Queue *queue, struct QueueNode *out);


If the queue is empty, don't bother modifying out, and just return an error code.

I would also avoid printing &amp; exiting from within the queue's functions upon error. Instead return some kind of error value and leave it for the user to check.

For example, consider if malloc fails. The user may want to check errno, or use a fallback data structure.

int enqueue(struct Queue *queue, int num) {
    struct QueueNode *queuenode = malloc(sizeof(struct QueueNode));

    if(queuenode == NULL){
        return -1;
    }

    queuenode-&gt;data = num;
    queuenode-&gt;nextNode = NULL;

    if(!queue-&gt;priorNode){
        queue-&gt;priorNode = queuenode;
    }

    if(queue-&gt;lastNode){
        struct QueueNode* temp = queue-&gt;lastNode;
        queue-&gt;lastNode = queuenode;
        temp-&gt;nextNode = queue-&gt;lastNode;
    } else {
        queue-&gt;lastNode = queuenode;
    }

    return 0;
}