Simple lightweight queue implementation using data size registration and singly linked lists as the underlying type
/* Author: Jared Thomas Date: Tuesday, August 2, 2022 Type-generic queue using singly linked lists */ #include <stdlib.h> #include <stdio.h> typedef struct Node { void * data; struct Node * next; } Node; typedef struct Queue { Node * head; size_t data_size; } Queue; typedef struct Person { char const * name; unsigned short int age; char const * occupation; } Person; Queue *create_queue(); void register_new_size(Queue *, size_t data_size); void enqueue(Queue *, void *data); void *front(Queue *); int length(Queue *); int is_empty(Queue *); void dequeue(Queue *); Queue *copy_queue(Queue *); void print(Queue *); void destroy_queue(Queue *); int is_empty(Queue *b) { if(b->head == NULL) { return 1; } return 0; } Queue *create_queue() { Queue *new_queue = (Queue *)malloc(sizeof(Queue)); new_queue->head = NULL; return new_queue; } void destroy_queue(Queue *b) { while(!is_empty(b)) { dequeue(b); } free(b); } void enqueue(Queue *b, void *data) { Node *new_node = (Node *)malloc(sizeof(Node)); new_node->data = malloc(b->data_size); memcpy(new_node->data, data, b->data_size); new_node->next = NULL; if(is_empty(b)) { b->head = new_node; return; } Node *n = b->head; while(n->next != NULL) { n = n->next; } n->next = new_node; } void *front(Queue *b) { return (b->head)->data; } int length(Queue *b) { Queue *copy = create_queue(); register_new_size(copy, b->data_size); int count = 0; while(!is_empty(b)) { enqueue(copy, front(b)); dequeue(b); count++; } while(!is_empty(copy)) { enqueue(b, front(copy)); dequeue(copy); } destroy_queue(copy); return count; } void dequeue(Queue *b) { Node *upcoming = b->head->next; free(b->head); b->head = NULL; if(upcoming != NULL) { b->head = upcoming; } } Queue *copy_queue(Queue *b) { Queue *copy = create_queue(); register_new_size(copy, b->data_size); int count = length(b); while(count > 0) { void *d = front(b); enqueue(copy, d); dequeue(b); enqueue(b, d); count--; } return copy; } void print(Queue *b) { if(is_empty(b)) { printf("[empty]\n"); return; } Queue *copy = copy_queue(b); printf("["); while(!is_empty(copy)) { struct Person *d = (struct Person *)front(copy); printf("%s, ", d->name); dequeue(copy); } printf("]"); printf("\n"); destroy_queue(copy); } void register_new_size(Queue *b, size_t data_size) { b->data_size = data_size; } int main(void) { Queue *queue = create_queue(); Person chase = { "Chase", 49, "Banker" }; Person evan = { "Evan", 34, "Doctor" }; Person susie = { "Susie", 43, "Teacher" }; register_new_size(queue, sizeof(Person)); enqueue(queue, &chase); enqueue(queue, &evan); enqueue(queue, &susie); print(queue); dequeue(queue); print(queue); dequeue(queue); print(queue); dequeue(queue); print(queue); destroy_queue(queue); return 0; } ```
malloc()
returningNULL
\$\endgroup\$dequeue
returns the dequeued data. It allows for use cases likewhile( data = queue->dequeue() ) { /* do something with data */ )
.\$\endgroup\$