I'm a C Beginner and I am looking for feedback on my implementation of a singly linked list. The code is split between list.c
and list.h
.
list.h:
#ifndef LIST
#define LIST
#include <stddef.h>
typedef struct List {
int val;
struct List* next;
} List;
int list_len(List* head);
void list_insert(List* head, int val, int index);
void list_insert_end(List* head, int val);
void list_insert_all(List* head, int* vals, size_t size);
List* array_to_list(int* vals, size_t size);
int list_get(List* head, int index);
void list_set(List* head, int val, int index);
void list_remove(List* head, int index);
int list_indexof(List* head, int val);
int list_rindexof(List* head, int val);
void free_list(List* head);
void print_list(List* head);
#endif
list.c:
#include "list.h"
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int list_len(List* head) {
assert(head != NULL && "Empty List");
List* curr = head;
int i = 1;
while (curr->next) {
curr = curr->next;
i++;
}
return i;
}
void list_insert_end(List* head, int val) {
assert(head != NULL && "Empty List");
List* item = malloc(sizeof(List));
item->val = val;
item->next = NULL;
List* curr = head;
while (curr->next) {
curr = curr->next;
}
curr->next = item;
}
void list_insert(List* head, int val, int index) {
assert(head != NULL && "Empty List");
List* item = malloc(sizeof(List));
item->val = val;
if (index == 0) {
item->next = head;
head = item;
return;
}
List* prev;
List* curr = head;
for (int i = 0; i < index; i++) {
prev = head;
assert(!curr->next && "Index Out of Bounds");
curr = curr->next;
}
prev->next = item;
item->next = curr;
return;
}
void list_insert_all(List* head, int* vals, size_t size) {
assert(head != NULL && "Empty List");
for (size_t i = 0; i < size; i++) {
list_insert_end(head, vals[i]);
}
}
List* array_to_list(int* vals, size_t size) {
List* list = malloc(sizeof(List));
list->val = vals[0];
list->next = NULL;
list_insert_all(list, vals + 1, size - 1);
return list;
}
int list_get(List* head, int index) {
assert(head != NULL && "Empty List");
List* curr = head;
for (int i = 0; i < index; i++) {
assert((curr->next) != 0 && "Index Out of Bounds");
curr = curr->next;
}
printf("%i", curr->val);
return curr->val;
}
void list_set(List* head, int val, int index) {
assert(head != NULL && "Empty List");
List* curr = head;
for (int i = 0; i < index; i++) {
assert((curr->next) != 0 && "Index Out of Bounds");
curr = curr->next;
}
curr->val = val;
}
void list_remove(List* head, int index) {
assert(head != NULL && "Empty List");
List* curr = head;
if (index == 0) {
head = head->next;
free(curr);
return;
}
for (int i = 0; i < index - 1; i++) {
assert((curr->next) != 0 && "Index Out of Bounds");
curr = curr->next;
}
List* next = curr->next->next;
free(curr->next);
curr->next = next;
}
int list_indexof(List* head, int val) {
assert(head != NULL && "Empty List");
List* curr = head;
int i = 0;
while (curr->next) {
if (curr->val == val) {
return i;
}
i++;
curr = curr->next;
}
return -1;
}
int list_rindexof(List* head, int val) {
assert(head != NULL && "Empty List");
List* curr = head;
int i = 0, j = -1;
while (curr->next) {
if (curr->val == val) {
j = i;
}
i++;
curr = curr->next;
}
return j;
}
void free_list(List* head) {
assert(head != NULL && "Empty List");
List* curr = head;
List* next;
while (curr->next) {
next = curr->next;
free(curr);
curr = next;
}
head = NULL;
}
void print_list(List* head) {
assert(head != NULL && "Empty List");
List* curr = head;
fputs("[", stdout);
printf("%i", curr->val);
while (curr->next) {
curr = curr->next;
printf(", %i", curr->val);
}
fputs("]", stdout);
}
int main() {
List list = *array_to_list((int[]){1, 2, 3, 4}, 4);
list_insert_all(&list, (int[]){1, 2, 3, 4}, 4);
list_set(&list, 10, 2);
print_list(&list);
list_remove(&list, 7);
print_list(&list);
printf("%i ", list_get(&list, 3));
printf("%i", list_len(&list));
printf(" %i", list_rindexof(&list, 1));
}