Here is my beginner code for dealing with a linked list. I appreciate any comments on structure, logic, formatting, and anything small or large. I have run the code using gcc and tested the small main function using Valgrind with no errors.
ll.h
#ifndef LL_H
#define LL_H
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct ll_LinkedList ll_LinkedList;
typedef struct ll_LinkedListNode ll_LinkedListNode;
struct ll_LinkedList {
ll_LinkedListNode* head;
};
struct ll_LinkedListNode {
void* data;
ll_LinkedListNode* next;
};
ll_LinkedList* ll_create ();
void ll_destroy (ll_LinkedList* ll);
void ll_append (ll_LinkedList* ll, void* data);
void* ll_at (ll_LinkedList* ll, size_t pos);
void ll_clear (ll_LinkedList* ll);
void ll_insert (ll_LinkedList* ll, size_t pos, void* data);
void* ll_remove (ll_LinkedList* ll, size_t pos);
bool ll_is_empty (ll_LinkedList* ll);
size_t ll_length (ll_LinkedList* ll);
void ll_prepend (ll_LinkedList* ll, void* data);
#endif
ll.c
#include "ll.h"
void ll_append(ll_LinkedList* ll, void* data) {
ll_insert(ll, ll_length(ll), data);
}
void* ll_at(ll_LinkedList* ll, size_t pos) {
ll_LinkedListNode* node = ll->head;
while (pos > 0) {
node = node->next;
pos--;
}
return node->data;
}
void ll_clear(ll_LinkedList* ll) {
ll_LinkedListNode* node = ll->head;
while (node != NULL) {
ll_LinkedListNode* next = node->next;
free(node);
node = next;
}
ll->head = NULL;
}
ll_LinkedList* ll_create() {
ll_LinkedList* ll = malloc(sizeof(*ll));
ll->head = NULL;
return ll;
}
void ll_destroy(ll_LinkedList* ll) {
ll_LinkedListNode* node = ll->head;
while (node != NULL) {
ll_LinkedListNode* next = node->next;
free(node);
node = next;
}
free(ll);
}
void ll_insert(ll_LinkedList* ll, size_t pos, void* data) {
assert(pos <= ll_length(ll));
ll_LinkedListNode* new_node = malloc(sizeof(*new_node));
new_node->data = data;
if (ll->head == NULL) {
new_node->next = NULL;
ll->head = new_node;
}
else if (pos == 0) {
new_node->next = ll->head;
ll->head = new_node;
}
else {
ll_LinkedListNode* node = ll->head;
while (pos > 1) {
node = node->next;
pos--;
}
new_node->next = node->next;
node->next = new_node;
}
}
bool ll_is_empty(ll_LinkedList* ll) {
return ll_length(ll) == 0;
}
size_t ll_length(ll_LinkedList* ll) {
size_t length = 0;
ll_LinkedListNode* node = ll->head;
while (node != NULL) {
node = node->next;
length++;
}
return length;
}
void ll_prepend(ll_LinkedList* ll, void* data) {
ll_insert(ll, 0, data);
}
void* ll_remove(ll_LinkedList* ll, size_t pos) {
assert(pos <= ll_length(ll));
if (pos == 0) {
ll_LinkedListNode* rm = ll->head;
ll->head = rm->next;
void* data = rm->data;
free(rm);
return data;
}
else {
ll_LinkedListNode* h = ll->head;
ll_LinkedListNode* t = h->next;
while (pos > 1) {
h = h->next;
t = t->next;
pos--;
}
h->next = t->next;
void* data = t->data;
free(t);
return data;
}
}
int main() {
int a = 1;
int b = 2;
int c = 3;
int d = 4;
ll_LinkedList* ll = ll_create();
ll_insert(ll, 0, &c);
ll_insert(ll, 0, &b);
ll_insert(ll, 0, &a);
ll_insert(ll, 2, &d);
ll_insert(ll, 4, &d);
ll_clear(ll);
ll_insert(ll, 0, &c);
ll_insert(ll, 0, &b);
ll_insert(ll, 0, &a);
printf("Removed: %d\n", *((int*) ll_remove(ll, 0)));
printf("Removed: %d\n", *((int*) ll_remove(ll, 0)));
printf("Removed: %d\n", *((int*) ll_remove(ll, 0)));
ll_insert(ll, 0, &c);
ll_insert(ll, 0, &b);
ll_insert(ll, 0, &a);
printf("Removed: %d\n", *((int*) ll_remove(ll, 1)));
if (!ll_is_empty(ll)) {
printf("It is not empty.\n");
}
ll_clear(ll);
if (ll_is_empty(ll)) {
printf("It is empty.\n");
}
ll_append(ll, &a);
ll_append(ll, &b);
ll_append(ll, &c);
ll_prepend(ll, &c);
ll_prepend(ll, &c);
printf("Length: %ld\n", ll_length(ll));
for (size_t i = 0; i < ll_length(ll); ++i) {
printf("%d, ", *((int*) ll_at(ll, i)));
}
printf("null\n");
ll_destroy(ll);
return 0;
}
```