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.
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.
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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
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.
