Lessons
Variables, types, and operators
int, char, float, double, unsigned; printf and scanf; arithmetic and bitwise operators; type casting; sizeof.
What to look for:
- C is statically typed — every variable has a type declared at compile time
- printf format specifiers: %d (int), %f (float), %s (string), %p (pointer), %zu (size_t)
- Integer types: char (1 byte), short (≥2), int (≥2, usually 4), long (≥4), long long (≥8)
- sizeof(type): returns the byte size — use %zu format specifier
Control flow: if, for, while, switch
if/else if/else, for loop, while loop, do-while, switch/case (with break), break, continue, and goto (and why to avoid it).
Prerequisite: Lesson 1
What to look for:
- switch cases fall through by default — always add break unless intentional
- for (int i = 0; i < n; i++) — the most common C loop; i declared inside is C99+
- There is no bool type in C89 — use int (0 = false, non-zero = true); C99 adds <stdbool.h>
- goto exists but avoid it except for error-cleanup patterns in systems code
Functions, parameters, and scope
Function declaration and definition, return types, pass-by-value, function prototypes, local vs global scope, and static local variables.
Prerequisite: Lesson 2
What to look for:
- C is pass-by-value — the function gets a copy; to modify the caller's variable, pass a pointer
- Declaration vs definition: int add(int a, int b); declares; the body defines
- static local: int count = 0 inside a function persists across calls (initialised once)
- Declare before use — or use a forward declaration (prototype) at the top of the file
First pointers: &, *, and pass-by-pointer
Declaring pointers (int *p), address-of (&), dereference (*), passing pointers to functions, and NULL.
Prerequisite: Lesson 3
What to look for:
- int *p = &x — p holds the address of x; *p reads/writes the value at that address
- p->field is shorthand for (*p).field — used with structs
- Always check if a pointer parameter is NULL before dereferencing
- int* p, q — only p is a pointer; q is a plain int (star binds to variable name)
Arrays and the decay rule
Fixed-size arrays, array initialisation, sizeof for size, array decay to pointer, and why you must pass the length separately to functions.
Prerequisite: Lesson 4
What to look for:
- sizeof(arr)/sizeof(arr[0]) — correct way to get element count (only works in declaring scope)
- When passed to a function, an array decays to a pointer — sizeof gives 4 or 8, not the array size
- arr[i] == *(arr + i) — array indexing is pointer arithmetic
- No bounds checking: arr[100] on a 5-element array is undefined behaviour — silent corruption
How to use this track: Compile every example with gcc -Wall -Wextra -std=c17 file.c -o file. Practice at godbolt.org — you can see the assembly output and understand what C compiles to. K&R (The C Programming Language, 2nd ed.) is the canonical text.
Track quiz
4 questions to check your understanding.
In C, what does passing an int to a function do?
What does int *p = &x mean?
What does sizeof(arr)/sizeof(arr[0]) calculate?
What happens when an array name is passed to a function in C?