thecodex.expert · The Codex Family of Knowledge
Snippets

C Snippets

12 essential C patterns — copy, paste, adapt. Compile with gcc -Wall -Wextra -std=c17.

C17 12 snippets Always use -fsanitize=address in dev
Cpointers_basics.c
Pointers: address-of, dereference, and pass-by-pointer
#include <stdio.h>

void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void increment(int *p, int amount) {
    *p += amount;   /* modify caller's variable */
}

int main(void) {
    int x = 10, y = 20;
    int *p = &x;   /* p stores the address of x */

    printf("x = %d\n", x);    /* 10 */
    printf("*p = %d\n", *p);  /* 10 — dereference */

    *p = 99;   /* modify x through the pointer */
    printf("x = %d\n", x);    /* 99 */

    swap(&x, &y);
    printf("x=%d y=%d\n", x, y);  /* x=20 y=99 */

    increment(&x, 5);
    printf("x = %d\n", x);   /* 25 */

    /* Pointer arithmetic: p+1 advances by sizeof(int) */
    int arr[] = {10, 20, 30, 40, 50};
    int *ap = arr;
    printf("%d %d %d\n", *ap, *(ap+1), *(ap+2));  /* 10 20 30 */

    /* arr[i] == *(arr + i) */
    printf("%d\n", *(arr + 3));  /* 40 */

    return 0;
}
Cdynamic_memory.c
Dynamic memory: malloc, realloc, free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    int n = 5;

    /* malloc: allocate uninitialised memory */
    int *arr = malloc(n * sizeof(int));
    if (arr == NULL) {   /* ALWAYS check — malloc can fail */
        fprintf(stderr, "malloc failed\n");
        return 1;
    }

    for (int i = 0; i < n; i++) arr[i] = i * i;
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);  /* 0 1 4 9 16 */
    printf("\n");

    /* calloc: allocate and zero-initialise */
    double *matrix = calloc(4 * 4, sizeof(double));  /* 4x4 zeros */

    /* realloc: resize — NEVER realloc into same pointer (leak on failure) */
    int *bigger = realloc(arr, 10 * sizeof(int));
    if (bigger == NULL) {
        free(arr);   /* free original if realloc fails */
        free(matrix);
        return 1;
    }
    arr = bigger;   /* arr may now point to a new location */

    /* Always free and null the pointer */
    free(arr);    arr    = NULL;
    free(matrix); matrix = NULL;

    return 0;
}
Cstructs.c
Structs: definition, heap allocation, arrow operator
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char name[64];
    int age;
    double score;
} Student;

/* Pass pointer to avoid copying the whole struct */
void print_student(const Student *s) {
    printf("%s (age %d): %.1f\n", s->name, s->age, s->score);
    /* s->field == (*s).field */
}

void set_score(Student *s, double score) {
    s->score = score;
}

Student *student_new(const char *name, int age) {
    Student *s = malloc(sizeof(Student));
    if (!s) return NULL;
    strncpy(s->name, name, sizeof(s->name) - 1);
    s->name[sizeof(s->name) - 1] = '\0';  /* ensure null termination */
    s->age = age;
    s->score = 0.0;
    return s;
}

int main(void) {
    /* Stack allocation */
    Student alice = {"Alice", 20, 95.5};
    print_student(&alice);

    /* Heap allocation */
    Student *bob = student_new("Bob", 22);
    if (!bob) return 1;
    set_score(bob, 87.0);
    print_student(bob);
    free(bob);

    return 0;
}
Cstrings.c
Safe string handling: snprintf, strncpy, strtol
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

int main(void) {
    /* snprintf: safe formatting — always null-terminates */
    char buf[64];
    int written = snprintf(buf, sizeof(buf), "Hello, %s! You are %d.", "Alice", 30);
    printf("%s (wrote %d chars)\n", buf, written);

    /* strncpy: limited copy — manually null-terminate */
    char dst[16];
    strncpy(dst, "Hello World!", sizeof(dst) - 1);
    dst[sizeof(dst) - 1] = '\0';
    printf("%s\n", dst);

    /* String length: O(n) — walks to \0 */
    size_t len = strlen(buf);

    /* String comparison */
    if (strcmp("abc", "abc") == 0) printf("equal\n");
    if (strncmp("abc", "abcdef", 3) == 0) printf("first 3 match\n");
    if (strcasecmp("Hello", "hello") == 0) printf("case-insensitive match\n");

    /* Safe integer parsing */
    char *numstr = "  42  ";
    char *endptr;
    long n = strtol(numstr, &endptr, 10);
    if (endptr == numstr) {
        fprintf(stderr, "no digits found\n");
    } else {
        printf("Parsed: %ld\n", n);
    }

    /* String search */
    char haystack[] = "Hello, World!";
    char *found = strstr(haystack, "World");
    if (found) printf("Found at index %td\n", found - haystack);

    /* Convert to uppercase in-place */
    for (char *p = haystack; *p; p++) *p = toupper((unsigned char)*p);
    printf("%s\n", haystack);

    return 0;
}
Cfile_io.c
File I/O: fopen, fgets, fprintf, fclose
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Write CSV file */
void write_csv(const char *path) {
    FILE *f = fopen(path, "w");
    if (!f) { perror("fopen"); return; }

    fprintf(f, "name,age,score\n");
    fprintf(f, "Alice,30,95.5\n");
    fprintf(f, "Bob,25,87.0\n");

    fclose(f);  /* always close — flushes buffer */
}

/* Read CSV line by line */
void read_csv(const char *path) {
    FILE *f = fopen(path, "r");
    if (!f) { perror("fopen"); return; }

    char line[256];
    int lineno = 0;
    while (fgets(line, sizeof(line), f)) {
        /* fgets includes '\n' — strip it */
        size_t len = strlen(line);
        if (len > 0 && line[len-1] == '\n') line[len-1] = '\0';

        if (lineno++ == 0) { continue; }  /* skip header */
        printf("Line: %s\n", line);
    }

    if (ferror(f)) perror("read error");
    fclose(f);
}

/* Binary I/O */
void write_binary(const char *path, const int *data, size_t count) {
    FILE *f = fopen(path, "wb");
    if (!f) return;
    fwrite(data, sizeof(int), count, f);
    fclose(f);
}

int main(void) {
    write_csv("/tmp/test.csv");
    read_csv("/tmp/test.csv");
    return 0;
}
Clinked_list.c
Singly linked list: push, pop, print, free
#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int value;
    struct Node *next;   /* must use struct Node here — typedef not yet complete */
} Node;

Node *node_new(int value) {
    Node *n = malloc(sizeof(Node));
    if (!n) return NULL;
    n->value = value;
    n->next = NULL;
    return n;
}

/* Prepend: O(1) */
Node *list_prepend(Node *head, int value) {
    Node *n = node_new(value);
    if (!n) return head;
    n->next = head;
    return n;  /* new head */
}

void list_print(const Node *head) {
    for (const Node *n = head; n; n = n->next)
        printf("%d -> ", n->value);
    printf("NULL\n");
}

int list_length(const Node *head) {
    int count = 0;
    for (const Node *n = head; n; n = n->next) count++;
    return count;
}

/* Free entire list */
void list_free(Node *head) {
    while (head) {
        Node *next = head->next;  /* save next BEFORE freeing */
        free(head);
        head = next;
    }
}

int main(void) {
    Node *head = NULL;
    head = list_prepend(head, 3);
    head = list_prepend(head, 2);
    head = list_prepend(head, 1);
    list_print(head);   /* 1 -> 2 -> 3 -> NULL */
    printf("Length: %d\n", list_length(head));
    list_free(head);
    return 0;
}
Cfunction_pointers.c
Function pointers: callbacks and dispatch tables
#include <stdio.h>
#include <stdlib.h>

/* Function pointer typedef: cleaner than inline syntax */
typedef int (*Comparator)(const void *, const void *);
typedef void (*Processor)(int);

int compare_asc(const void *a, const void *b) {
    return *(int*)a - *(int*)b;
}
int compare_desc(const void *a, const void *b) {
    return *(int*)b - *(int*)a;
}

void print_item(int x)  { printf("%d ", x); }
void double_item(int x) { printf("%d ", x * 2); }

void apply_to_array(const int *arr, int n, Processor fn) {
    for (int i = 0; i < n; i++) fn(arr[i]);
    printf("\n");
}

/* Dispatch table: array of function pointers */
typedef struct {
    const char *name;
    void (*handler)(const char *);
} Command;

void cmd_hello(const char *arg) { printf("Hello, %s!\n", arg); }
void cmd_quit (const char *arg) { (void)arg; printf("Goodbye.\n"); }

int main(void) {
    int arr[] = {5, 2, 8, 1, 9};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(int), compare_asc);
    apply_to_array(arr, n, print_item);   /* 1 2 5 8 9 */

    qsort(arr, n, sizeof(int), compare_desc);
    apply_to_array(arr, n, double_item);  /* 18 16 10 4 2 */

    /* Dispatch table */
    Command commands[] = {
        {"hello", cmd_hello},
        {"quit",  cmd_quit},
    };
    /* Look up and call */
    commands[0].handler("World");  /* Hello, World! */

    return 0;
}
Carrays_2d.c
Arrays: 2D, dynamic, and sizeof idiom
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ROWS 3
#define COLS 4

int main(void) {
    /* Static 2D array: row-major storage */
    int matrix[ROWS][COLS] = {
        {1,  2,  3,  4},
        {5,  6,  7,  8},
        {9, 10, 11, 12}
    };

    for (int r = 0; r < ROWS; r++) {
        for (int c = 0; c < COLS; c++) printf("%3d", matrix[r][c]);
        printf("\n");
    }

    /* sizeof idiom: count elements (only in declaring scope) */
    int arr[] = {10, 20, 30, 40, 50};
    int n = (int)(sizeof(arr) / sizeof(arr[0]));  /* 5 */
    printf("count: %d\n", n);

    /* Dynamic 2D array: array of pointers */
    int rows = 4, cols = 5;
    int **dyn = malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        dyn[i] = calloc(cols, sizeof(int));
    }
    dyn[2][3] = 42;
    printf("dyn[2][3] = %d\n", dyn[2][3]);

    /* Free: inner arrays first, then outer */
    for (int i = 0; i < rows; i++) free(dyn[i]);
    free(dyn);

    /* Flat dynamic 2D (more cache-friendly) */
    int *flat = malloc(rows * cols * sizeof(int));
    flat[2 * cols + 3] = 99;  /* row 2, col 3 */
    printf("flat[2][3] = %d\n", flat[2 * cols + 3]);
    free(flat);

    return 0;
}
Cbit_manipulation.c
Bit manipulation: set, clear, toggle, check
#include <stdio.h>
#include <stdint.h>

/* Bit flags using an enum */
typedef enum {
    FLAG_READ    = 1 << 0,  /* 0001 = 1 */
    FLAG_WRITE   = 1 << 1,  /* 0010 = 2 */
    FLAG_EXECUTE = 1 << 2,  /* 0100 = 4 */
    FLAG_HIDDEN  = 1 << 3,  /* 1000 = 8 */
} FileFlags;

void print_flags(uint8_t flags) {
    printf("r:%d w:%d x:%d h:%d\n",
        (flags & FLAG_READ)    ? 1 : 0,
        (flags & FLAG_WRITE)   ? 1 : 0,
        (flags & FLAG_EXECUTE) ? 1 : 0,
        (flags & FLAG_HIDDEN)  ? 1 : 0);
}

int main(void) {
    uint8_t flags = 0;

    /* Set bits */
    flags |= FLAG_READ;
    flags |= FLAG_WRITE;
    print_flags(flags);  /* r:1 w:1 x:0 h:0 */

    /* Clear a bit */
    flags &= ~FLAG_WRITE;
    print_flags(flags);  /* r:1 w:0 x:0 h:0 */

    /* Toggle a bit */
    flags ^= FLAG_EXECUTE;
    print_flags(flags);  /* r:1 w:0 x:1 h:0 */

    /* Check if bit is set */
    if (flags & FLAG_READ) printf("readable\n");

    /* Common tricks */
    int n = 42;
    printf("is even:        %s\n", (n & 1) ? "no" : "yes");
    printf("multiply by 2:  %d\n", n << 1);   /* left shift */
    printf("divide by 2:    %d\n", n >> 1);   /* right shift (arithmetic for signed) */
    printf("clear lowest:   %d\n", n & (n-1)); /* clears lowest set bit */
    printf("isolate lowest: %d\n", n & (-n));  /* isolates lowest set bit */

    return 0;
}
Cerror_handling.c
Error handling: errno, perror, return codes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/* C error handling: return codes + errno */
int read_config(const char *path, char *buf, size_t bufsize) {
    FILE *f = fopen(path, "r");
    if (!f) {
        /* errno set by fopen */
        fprintf(stderr, "fopen(%s): %s\n", path, strerror(errno));
        return -1;
    }

    size_t bytes = fread(buf, 1, bufsize - 1, f);
    if (ferror(f)) {
        perror("fread");   /* perror: prints errno message to stderr */
        fclose(f);
        return -2;
    }

    buf[bytes] = '\0';
    fclose(f);
    return 0;  /* success */
}

/* Cleanup goto: common C pattern for resource management */
int process_data(const char *in_path, const char *out_path) {
    int ret = 0;
    FILE *in = NULL, *out = NULL;

    in = fopen(in_path, "r");
    if (!in) { perror("open input"); ret = -1; goto cleanup; }

    out = fopen(out_path, "w");
    if (!out) { perror("open output"); ret = -2; goto cleanup; }

    /* ... process files ... */

cleanup:
    if (in)  fclose(in);   /* safe — fclose(NULL) is OK but avoid it */
    if (out) fclose(out);
    return ret;
}

int main(void) {
    char buf[1024];
    int result = read_config("/etc/hostname", buf, sizeof(buf));
    if (result == 0) {
        printf("hostname: %s\n", buf);
    } else {
        fprintf(stderr, "Failed with code %d\n", result);
    }
    return 0;
}
Cgeneric_sort.c
qsort with comparators and bsearch
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Comparator for qsort: return neg/0/pos */
int cmp_int_asc(const void *a, const void *b) {
    int x = *(int*)a, y = *(int*)b;
    return (x > y) - (x < y);  /* safe — avoids overflow from subtraction */
}

int cmp_str(const void *a, const void *b) {
    return strcmp(*(const char**)a, *(const char**)b);
}

typedef struct { char name[32]; int age; } Person;

int cmp_person_age(const void *a, const void *b) {
    return ((Person*)a)->age - ((Person*)b)->age;
}

int main(void) {
    /* Sort integers */
    int nums[] = {5, 2, 8, 1, 9, 3};
    int n = sizeof(nums) / sizeof(nums[0]);
    qsort(nums, n, sizeof(int), cmp_int_asc);
    for (int i = 0; i < n; i++) printf("%d ", nums[i]);  /* 1 2 3 5 8 9 */
    printf("\n");

    /* Binary search (requires sorted array) */
    int key = 5;
    int *found = bsearch(&key, nums, n, sizeof(int), cmp_int_asc);
    if (found) printf("Found %d at index %td\n", *found, found - nums);

    /* Sort strings */
    const char *words[] = {"banana", "apple", "cherry", "date"};
    int wn = sizeof(words) / sizeof(words[0]);
    qsort(words, wn, sizeof(char*), cmp_str);
    for (int i = 0; i < wn; i++) printf("%s ", words[i]);  /* apple banana cherry date */
    printf("\n");

    /* Sort structs */
    Person people[] = {{"Alice",30},{"Bob",25},{"Carol",35}};
    qsort(people, 3, sizeof(Person), cmp_person_age);
    for (int i = 0; i < 3; i++) printf("%s(%d) ", people[i].name, people[i].age);
    printf("\n");  /* Bob(25) Alice(30) Carol(35) */

    return 0;
}
Cpreprocessor.c
Preprocessor: safe macros, X-macros, static_assert
#include <stdio.h>
#include <assert.h>
#include <stdint.h>

/* Safe macros: parenthesise everything */
#define MAX(a, b)   ((a) > (b) ? (a) : (b))
#define MIN(a, b)   ((a) < (b) ? (a) : (b))
#define ABS(x)      ((x) < 0 ? -(x) : (x))
#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))  /* only safe in declaring scope */
#define UNUSED(x)    (void)(x)   /* suppress unused variable warning */

/* Stringify and token paste */
#define STRINGIFY(x)  #x
#define TOSTRING(x)   STRINGIFY(x)
#define LINE_STR      TOSTRING(__LINE__)

/* X-macro: define data once, use in multiple contexts */
#define COLORS(X) \
    X(RED,   0xFF0000) \
    X(GREEN, 0x00FF00) \
    X(BLUE,  0x0000FF)

typedef enum {
    #define X(name, value) name,
    COLORS(X)
    #undef X
    COLOR_COUNT
} Color;

const char *color_names[] = {
    #define X(name, value) STRINGIFY(name),
    COLORS(X)
    #undef X
};

/* static_assert: compile-time check */
static_assert(sizeof(int) == 4, "Expected 32-bit int");
static_assert(ARRAY_LEN(color_names) == COLOR_COUNT, "Color table mismatch");

int main(void) {
    printf("MAX(3,7) = %d\n", MAX(3, 7));       /* 7 */
    printf("ABS(-5)  = %d\n", ABS(-5));         /* 5 */
    printf("Colors: %d\n", COLOR_COUNT);        /* 3 */
    printf("Color 0: %s\n", color_names[RED]);  /* RED */
    return 0;
}
C referenceC overview · Learn C
← SQL All Snippets →
Everything C in one place — learning paths, reference, playground, and more. C Hub →