Skip to content

C & Systems Programming (Zero to the Kernel)

Learn C the way the systems world actually uses it — as the portable assembly that the Linux kernel, device drivers, embedded firmware, databases, and network stacks are written in.

Learn C the way the systems world actually uses it — as the portable assembly that the Linux kernel, device drivers, embedded firmware, databases, and network stacks are written in. You go from your first program to manual memory management with no safety net (and the tools to stay safe), to writing the allocator underneath malloc and a set of reusable data-structure libraries, to the POSIX system-call layer (processes, files, pipes, signals), to concurrency and networking (you build a real concurrent server), and finally down to bare metal: memory-mapped I/O, microcontrollers, interrupts, Linux kernel modules, and character device drivers. The capstone is a concurrent in-memory key-value store server. Data structures are built here, not imported, because C ships none - it has no list, no map, no set, no queue - so hand-rolling them is what production C actually does, and each one doubles as the exercise that teaches ownership, alignment, and API design. What this track deliberately does NOT teach is algorithms: balanced trees, graph algorithms, and dynamic programming are a different subject with a different bar, taught in the dsa-cpp track (Data Structures & Algorithms in C++). This is the foundation beneath the C++ track — the layer where the kernel, embedded/robotics firmware, and the lowest-latency systems live, and where C is non-negotiable. Where pure C is used most: kernel engineering, the lowest-latency trading systems (alongside C++), and embedded firmware in robotics, automotive and aerospace — a narrower area than C++, and the foundation for working at the very bottom of the stack.

6 phases · 48 projects · v1.1.0 · 48 video lessons · free first project

Target roles: Systems / Kernel Engineer, Embedded / Firmware Engineer, Low-Latency Engineer (foundation), OS / Database / Network Internals Engineer

Stack: C11/C17, gcc/clang, make, valgrind / AddressSanitizer, POSIX / Linux

Want to try the material before you ask? 14 free exercises (92 minutes) run in your browser, no account needed.

Watch the video series for this track

PHASE 1 · 8 projects

C Foundations & the Toolchain

Compile and run C from zero: the toolchain, types and integer/float representation, operators, control flow, functions, formatted I/O, strings, and arrays.

  1. 01 · featured

    Hello, C & the Toolchain

    Write your first C program, trace the four-stage gcc compilation pipeline (preprocess/compile/assemble/link), and understand why C produces tiny, fast native binaries.

    C11/C17 · gcc · binutils

  2. 02 · featured

    Types & How Numbers Are Stored

    Explore C's fundamental types, use sizeof and <limits.h> to inspect platform sizes and bounds, use <stdint.h> fixed-width types, and understand why signed overflow is undefined behavior while unsigned wraparound is not.

    C11/C17 · gcc · stdint.h · limits.h

  3. 03 · featured

    Operators & Expressions

    Master C's arithmetic, comparison, logical, and bitwise operators, understand operator precedence traps, and implement the set/test/clear/toggle bit-manipulation patterns used in every device driver and systems library.

    C11/C17 · gcc

  4. 04 · featured

    Control Flow

    Master C's if/else, switch with fallthrough, all three loop forms, break/continue, and the kernel-style goto cleanup ladder — the control flow patterns found in the Linux kernel, git, nginx, and SQLite.

    C11/C17 · gcc

  5. 05 · featured

    Functions, Scope & the Stack

    Write prototypes and definitions, observe pass-by-value, trace the call stack through recursion, use static local variables for persistent state, and control file-scope visibility with static/extern linkage.

    C11/C17 · gcc

  6. 06 · featured

    Formatted I/O & C Strings

    Master printf/scanf format strings, read input safely with fgets, understand C strings as null-terminated char arrays, and use <string.h> functions (strlen, strcpy, strcmp, strcat) while learning why gets() was a security disaster.

    C11/C17 · gcc · stdio.h · string.h

  7. 07 · featured

    Arrays & Multidimensional Arrays

    Declare, initialize, and iterate 1D and 2D arrays, understand array decay to pointer, verify row-major memory layout, and observe why C performs no bounds checking — and how AddressSanitizer catches the resulting bugs.

    C11/C17 · gcc · AddressSanitizer

  8. 08 · featured

    A Real CLI Tool

    Build a complete wc-style line/word/character counter using argc/argv, fopen/fgets/fclose, multi-function design, error handling with stderr, and a Makefile — synthesizing every concept from Phase 1 into a real Unix-quality command-line tool.

    C11/C17 · gcc · make

PHASE 2 · 8 projects

Pointers, Memory & Manual Management

Master the heart of C: pointers, the array/string/pointer relationship, structs and unions, the stack vs heap, malloc/free, memory bugs and the tools that catch them, and function pointers - capped by writing the layer underneath malloc, an arena and pool allocator you benchmark against it.

  1. 01 · featured

    Pointers

    Declare pointer variables, use & and * to take addresses and dereference, handle NULL safely, and use pointer-to-pointer to pass pointers as output parameters.

    C17 · gcc · valgrind

  2. 02 · featured

    Pointers, Arrays & Strings

    Explore array-to-pointer decay, pointer arithmetic, and null-terminated strings by implementing my_strlen and my_strcpy from scratch using only pointer operations.

    C17 · gcc · valgrind

  3. 03 · featured

    Structs, Unions & Enums

    Define structs and access fields with . and ->, observe struct padding with offsetof/sizeof, use unions for type punning float bits, and pair enums with typedef for clean state machines.

    C17 · gcc · valgrind

  4. 04 · featured

    The Stack, the Heap & malloc/free

    Compare stack vs heap lifetime by printing their addresses, then use malloc/calloc/realloc/free to manage dynamic arrays and return heap memory from a function with documented ownership transfer.

    C17 · gcc · valgrind

  5. 05 · featured

    Dynamic Memory Patterns

    Build a growable heap array using the double-capacity realloc strategy, manage arrays of structs with owned string fields, implement deep vs shallow copy, and verify zero leaks with Valgrind.

    C17 · gcc · valgrind

  6. 06 · featured

    Memory Bugs & the Tools That Catch Them

    Deliberately reproduce a memory leak, use-after-free, double-free, and buffer overflow in C, then detect each with Valgrind --leak-check=full and GCC -fsanitize=address, and produce a clean fixed version.

    C17 · gcc · valgrind · AddressSanitizer

  7. 07 · featured

    Function Pointers & Callbacks

    Declare and call function pointers, pass a comparator to qsort, build a dispatch table, and implement a minimal struct file_operations-style vtable to understand how C achieves runtime polymorphism.

    C17 · gcc · valgrind

  8. 08 · featured

    An Arena & Pool Allocator from Scratch

    Write the layer underneath malloc: a bump/arena allocator over one heap block with correct alignment via _Alignof and max_align_t, a fixed-size pool allocator whose free list lives inside the free blocks themselves, and a bitset for occupancy tracking — then benchmark the arena against malloc and report the measured speedup with its conditions.

    C17 · gcc · make · valgrind · AddressSanitizer

PHASE 3 · 8 projects

Modular C & Data Structures

Build real C software: multi-file projects, make and the preprocessor, generic code with void*, and reusable dynamic-array, linked-list, hash-table and ring-buffer libraries with disciplined error handling, packaged as a tested static library. These are taught as exercises in memory ownership and API design - the containers systems code hand-rolls - not as an algorithms course; balanced trees, graphs and dynamic programming belong to the dsa-cpp track.

  1. 01 · featured

    The Build System: Headers, Translation Units, make & the Preprocessor

    Take a C program from source text to executable: split it into headers and translation units with include guards and extern, build it incrementally with a Makefile, then open the layer underneath — raw macro expansion with gcc -E, the precedence and multiple-evaluation traps, conditional compilation, assert, and the X-macro pattern.

    C17 · gcc · make

  2. 02 · featured

    Generic Programming with void*

    Build type-erased C functions using void* pointers, memcpy for element copying, and comparator/printer callbacks — the model behind qsort, bsearch, and every C container library.

    C17 · gcc

  3. 03 · featured

    A Reusable Dynamic Array (Vector)

    Build a growable array library in C using void* + element size, realloc with a doubling strategy for amortized O(1) push, and a clean opaque-struct API with create/destroy/push/pop/get/set.

    C17 · gcc · make · AddressSanitizer

  4. 04 · featured

    A Linked List Library

    Build singly and doubly linked list libraries in C, then implement the Linux kernel's intrusive list_head pattern with container_of — giving O(1) insert/remove at any known node.

    C17 · gcc · make · AddressSanitizer

  5. 05 · featured

    A Hash Table

    Build a string-keyed hash map with separate chaining, FNV-1a hashing, and automatic rehashing when the load factor exceeds 0.75 — achieving O(1) average lookup for any key.

    C17 · gcc · make · AddressSanitizer

  6. 06 · featured

    A Ring Buffer (FIFO)

    Build the fixed-capacity queue that kernels, UART drivers, audio stacks, and low-latency feeds are built on: a flat power-of-two buffer indexed by bitmask instead of modulo, free-running cursors that resolve the full-vs-empty ambiguity the way Linux kfifo does, and wrap-around handled by two memcpy calls with no data ever moved.

    C17 · gcc · make · AddressSanitizer · Valgrind

  7. 07 · featured

    Error Handling in C (Without Exceptions)

    Master C error-handling patterns: return-code conventions, errno + perror/strerror, the goto-cleanup pattern for multi-resource functions, and designing APIs that cannot silently leak on failure.

    C17 · gcc · AddressSanitizer · Valgrind

  8. 08 · featured

    A Tested C Library (Finale)

    Package the dynamic array, doubly linked list, and hash table into a single libds static library with a professional directory layout, a Makefile that builds libds.a, and a test runner that is Valgrind and ASan-clean.

    C17 · gcc · make · ar · AddressSanitizer · Valgrind

PHASE 4 · 8 projects

Systems Programming I — Processes, Files & IPC

Program the OS directly: system calls, file I/O with descriptors, processes (fork/exec/wait), pipes and redirection, signals, the process environment, and memory-mapped files — capped by building a shell.

  1. 01 · featured

    System Calls & the Unix Philosophy

    Learn what system calls are, how the user/kernel mode boundary works, and how to use write(2), errno, perror, and strace to understand and debug programs at the OS level.

    C17 · gcc · strace · Linux/POSIX

  2. 02 · featured

    File I/O with File Descriptors

    Master the POSIX open/read/write/close/lseek syscall family, understand O_* flags, and build working cat and cp clones using raw file descriptors.

    C17 · gcc · Linux/POSIX · strace

  3. 03 · featured

    Processes: fork, exec & wait

    Learn to create and manage processes using fork, exec, and waitpid — the foundation of every Unix shell, build system, and process supervisor.

    C17 · gcc · Linux/POSIX

  4. 04 · featured

    Pipes & Redirection

    Implement shell-style pipes and redirection in C using pipe(), dup2(), fork(), and exec() — connecting processes so one's output feeds another's input.

    C17 · gcc · Linux/POSIX

  5. 05 · featured

    Signals

    Master POSIX signal handling with sigaction, implement graceful shutdown, use SIGCHLD to reap children asynchronously, and understand async-signal-safety.

    C17 · gcc · Linux/POSIX

  6. 06 · featured

    The Process Environment

    Build well-behaved CLI programs in C: parse options with getopt, read and modify environment variables, register atexit cleanup handlers, and measure wall and CPU time.

    C17 · gcc · Linux/POSIX

  7. 07 · featured

    Memory-Mapped Files & Shared Memory

    Use mmap() to access files as memory arrays, create anonymous mappings, and build a POSIX shared-memory IPC channel between two processes using shm_open.

    C17 · gcc · Linux/POSIX

  8. 08 · featured

    Build a Unix Shell

    Capstone project: build a working interactive Unix shell in C that handles external commands, single pipes, input/output redirection, built-ins (cd, exit, help), and Ctrl-C gracefully.

    C17 · gcc · Linux/POSIX

PHASE 5 · 8 projects

Systems Programming II — Concurrency & Networking

Make C concurrent and networked: pthreads and synchronization, C11 atomics and lock-free basics, TCP sockets, robust I/O, epoll event loops, and a thread-pool server.

  1. 01 · featured

    Threads with pthreads

    Create and join POSIX threads, pass arguments via void*, retrieve results, compare threads vs processes, and observe a data race with ThreadSanitizer.

    C17 · pthreads · gcc · ThreadSanitizer

  2. 02 · featured

    Synchronization: Mutexes & Condition Variables

    Fix a data race with pthread_mutex, implement a bounded producer-consumer queue with condition variables, and demonstrate and prevent deadlock.

    C17 · pthreads · gcc · ThreadSanitizer

  3. 03 · featured

    Atomics & Lock-Free Basics (C11)

    Use <stdatomic.h> to build a lock-free counter and a single-producer/single-consumer ring buffer, and benchmark atomics against mutexes on a multi-core machine.

    C17 · stdatomic.h · pthreads · gcc · ThreadSanitizer

  4. 04 · featured

    TCP Sockets

    Build a TCP echo server and client from raw POSIX syscalls, handle partial send/recv, set SO_REUSEADDR and TCP_NODELAY, and measure loopback round-trip latency.

    C17 · POSIX sockets · gcc · ss

  5. 05 · featured

    Robust I/O & Framing

    Implement read_n/write_n helpers that handle partial reads, EINTR, and EOF, then build a length-prefix framing layer and use it to exchange variable-length messages between a framed echo server and client.

    C17 · POSIX sockets · gcc

  6. 06 · featured

    Event-Driven I/O with epoll

    Build a single-threaded TCP echo server using the epoll API (epoll_create1/epoll_ctl/epoll_wait) with non-blocking sockets, handle 100 simultaneous clients, and understand the reactor pattern.

    C17 · epoll · POSIX sockets · gcc

  7. 07 · featured

    A Thread-Pool Server

    Build a fixed-size thread pool backed by a synchronized task queue, dispatch accepted TCP connections to worker threads, pre-allocate connection structs to avoid per-request malloc, and benchmark throughput against the single-threaded event loop.

    C17 · pthreads · POSIX sockets · gcc · Valgrind

  8. 08 · featured

    A Concurrent Networked Server

    Build a production-quality key-value server combining an epoll accept loop, a thread pool, a mutex-protected hash table, and a binary request/response protocol, with a clean shutdown that passes Valgrind with zero leaks.

    C17 · epoll · pthreads · POSIX sockets · gcc · Valgrind · ThreadSanitizer

PHASE 6 · 8 projects

Bare Metal, Embedded & the Kernel

Go below the OS: C down to the ABI, memory-mapped I/O and registers, bare-metal microcontrollers, interrupts and a tiny scheduler, Linux kernel modules, a character device driver, and real-time/embedded constraints.

  1. 01 · featured

    C Down to the Metal

    Compile C to assembly with gcc -S, trace the System V AMD64 calling convention and stack frame, apply volatile to hardware register simulation, write inline asm with RDTSC, and build a freestanding object with no OS runtime.

    C11 · gcc · x86-64 assembly · inline asm

  2. 02 · featured

    Memory-Mapped I/O & Registers

    Declare and manipulate simulated hardware registers using volatile pointers, implement the read-modify-write pattern for GPIO configuration and BSRR atomic set/clear, and simulate a polling UART transmit loop.

    C11 · gcc · stdint.h · Makefile

  3. 03 · featured

    Bare-Metal Microcontroller Programming

    Write a complete bare-metal blink program for ARM Cortex-M3 from scratch: linker script, startup.c reset handler with .data/.bss init, GPIO register writes, and a cross-compiled Makefile build runnable in QEMU.

    C11 · arm-none-eabi-gcc · GNU ld · QEMU · Makefile · ARM Cortex-M3

  4. 04 · featured

    Interrupts & a Tiny Scheduler

    Configure SysTick interrupts on a bare-metal Cortex-M3, write a naked context-switch ISR in inline ARM assembly, build fake initial task frames, and implement a two-task round-robin preemptive scheduler.

    C11 · ARM Cortex-M3 · arm-none-eabi-gcc · inline assembly · QEMU · Makefile

  5. 05 · featured

    Linux Kernel Modules

    Write, build, and load a Linux loadable kernel module using the Kbuild Makefile system; use printk, module_param, and module_init/exit; explain the kernel-space constraints that make C the kernel's language.

    C11 · Linux kernel · Kbuild · insmod/rmmod · dmesg · GNU Make

  6. 06 · featured

    A Character Device Driver

    Implement a complete Linux character device driver with a circular buffer: file_operations (open/release/read/write), alloc_chrdev_region, cdev_add, class_create/device_create for /dev, and copy_to_user/copy_from_user with proper mutex locking.

    C11 · Linux kernel · Kbuild · character devices · file_operations · copy_to_user

  7. 07 · featured

    Embedded & Real-Time Constraints

    Implement a static memory pool (no malloc), Q16.16 fixed-point PID controller, watchdog/WCET simulation, MISRA-C violation/fix examples, and a CAN frame builder — the full set of constraints governing safety-critical automotive/aerospace/robot firmware.

    C11 · gcc · fixed-point arithmetic · MISRA-C · CAN bus · Makefile

  8. 08 · featured

    Build Your Own memcached — a Concurrent In-Memory Key-Value Store in C

    Build a real networked key-value store server: an epoll event loop, a hand-written chaining hash table with resize, a line-oriented GET/SET protocol with partial-read handling, a test client, and a Makefile build proven memory-safe under Valgrind and AddressSanitizer.

    C11 · gcc · epoll · TCP sockets · hash table · Valgrind · AddressSanitizer · Makefile

Next step

Request C & Systems Programming (Zero to the Kernel)

An advisor reviews the fit and confirms terms in writing. A request is not an acceptance and nothing is charged until you agree.