Skip to content

A generic (type-agnostic) linked list implementation in C.

gvrio/generic-linked-list

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Generic Linked List in C

File: src/list.c
Header: include/list.h
Author: gvrio

A generic, singly-linked list implementation in C. Supports storing elements of any type using void* pointers and user-provided print and comparison functions.

This library was written as part of a learning journey in C and data structures.


Folder structure

.
├── demo/
│   └── demo.c      # demo of usage
├── include/
│   └── list.h      # header for imports
├── src/
│   └── list.c      # source code

Overview

This linked list implementation is generic, type-agnostic, and designed for beginners to explore pointers, memory, and data structures. Each node stores a copy of the data for primitives types, or a pointer for structs.

Users must provide:

  • A print function for displaying elements.
  • A cmp function for comparing elements.

Requirements

  • A C compiler (GCC, Clang, etc.)
  • Optional: Make to simplify building

Build & Run Example

# Clone the repo
git clone https://github.com/gvrio/generic-linked-list.git

# Navigate to the demo folder
cd generic-linked-list

# Compile the demo with library
gcc demo/demo.c src/list.c -I include/ -o demo_exec

# Run the demo executable
./demo_exec

Data Structures

Node Structure (node_t)

typedef struct Node {
    void *data;
    struct Node *next;
} node_t;
  • data: Pointer to stored element (copied).
  • next: Pointer to next node.

Linked List Structure (list_t)

typedef struct LinkedList {
    node_t *head;
    size_t dsize;
    void (*print)(void*);
    int (*cmp)(void*, void*);
} list_t;
  • head: Pointer to first node.
  • dsize: Size of each element (in bytes).
  • print: Print function pointer for elements.
  • cmp: Comparison function pointer for elements.

Data Ownership

Data Kind Ownership Allocation Freed By Description
Primitives (int, float, etc.) Node (library) Inside init_node() Library (delete*()) Node owns a copy of the primitive; safe to free() directly.
Strings Node (library) Deep-copied via malloc Library (delete*()) Node makes a separate heap copy, so deleting node frees the string safely.
Structs User User-managed User User owns the memory; user responsible for freeing if structs have nested pointers.
Lists (nested) User User-managed User (via destroy()) User must call library-provided destroy() recursively to free each nested list safely.

Initialization

list_t *init_list(size_t size, void (*printfn)(void*), int (*cmpfn)(void*, void*));
  • Creates an empty list.
  • Returns a pointer to list_t or NULL on failure.

Parameters:

  • sizesizeof(element_type)
  • printfn — Function to print an element
  • cmpfn — Function to compare two elements

Insertion Functions

All insertion functions return int:

  • 0 → success
  • 1 → failure
Function Description
allocateh(list_t* list, void* data) Insert at head
allocatet(list_t* list, void* data) Insert at tail
allocaten(list_t* list, void* data, void* key) Insert after first node->data matching key

Deletion Functions

All deletion functions return int:

  • 0 → success
  • 1 → failure
Function Description
deleteh(list_t* list) Delete head node
deletet(list_t* list) Delete tail node
deleten(list_t* list, void* key) Delete first node->data matching key

Traversal & Printing

traverse()

void traverse(list_t* list);
  • Prints each element using the list's print function.
  • Output format: elem1 -> elem2 -> ... -> NULL.
  • Does not print a newline to remain composable for nested lists (so printList() can embed traverse output).

Helper Print Functions

void printInt(void* num);
void printChar(void* c);
void printStr(void* string);
void printFloat(void* num);
void printList(void* list);
  • Provided helpers for common types.
  • printList recursively prints nested lists (it uses traverse() internally).

Destroying the List

void destroy(list_t* list);
  • Frees all nodes and their stored data.
  • Safe to call on an empty or already-empty list pointer (function checks for NULL internally).

Helper Functions — Comparison

int cmpInt(void* a, void* b);
int cmpChar(void* a, void* b);
int cmpStr(void* a, void* b);
int cmpFloat(void* a, void* b);
int cmpList(void* a, void* b);
  • Return 0 if elements match, non-zero otherwise.
  • These functions are convenient to pass into init_list() when storing these common types.

Return Codes

Value Meaning
0 Success
1 Failure (NULL pointer, allocation error, key not found)

Example Usage

#include "list.h"
#include <stdio.h>

int main() {
    list_t *list = init_list(sizeof(int), printInt, cmpInt);
    int a = 10, b = 20;

    allocateh(list, &a);
    allocatet(list, &b);

    printf("My list: ");
    traverse(list);  // Output: 10 -> 20 -> NULL
    printf("\n");

    destroy(list);
    return 0;
}

Complexity Summary

Operation Time Complexity
Insert head O(1)
Insert tail O(n)
Insert after key O(n)
Delete head O(1)
Delete tail O(n)
Delete by key O(n)
Traverse O(n)

About

A generic (type-agnostic) linked list implementation in C.

Resources

Stars

Watchers

Forks

Languages