PROGRAMMING COURSE
One complete C course built around the thing C is actually about: memory. Pointers, arrays, dynamic allocation, undefined behaviour, and multi-file builds.
<stdio.h>
int main(void) {
printf("Hello from C\n");
return 0;
}COURSE CURRICULUM
Work through a section at a time, or jump straight to the concept you need.
Explain what kind of language C is, read the machine-level meaning of a small C program, and name the places C is still the default choice today.
Install and verify a working C toolchain on Linux, macOS, or Windows, then write and build a first program that prints a line of text.
Trace a .c file through preprocessing, compiling, assembling and linking, and tell from an error's wording which stage failed.
Comment, format and name C code deliberately: why /* */ cannot nest, why indentation never changes behaviour, and which identifiers are reserved.
Build a C source file into a named executable with gcc, run it from the shell, and know why the default is a.out and why you must type ./
Return meaningful exit codes from main, read them back with echo $?, and predict the status the shell reports for values like -1 or 300.
Read gcc diagnostics precisely, tell warnings from errors, and use -Wall -Wextra to expose bugs the compiler would otherwise translate in silence.
Work out the exact range of int on any target, explain why it differs between platforms, and write range checks that never overflow themselves.
Predict what unsigned arithmetic does when a result leaves its range, and use modulo 2^N reasoning to avoid wrapped counters and bad subtractions.
Pick between short, int, long and long long by the range your values need, print each with the right length modifier, and know why long differs by platform.
Pick fixed-width types like int32_t and uint64_t deliberately, use their limit macros, and print them portably with the PRI macros from inttypes.h.
Use sizeof correctly on types, expressions, arrays and structs, print it with %zu, and know why an array parameter loses its size.
Inspect the individual bytes of an integer in memory, decide whether your machine is little- or big-endian, and pack integers in a fixed byte order.
Work out the exact type and value of any C arithmetic expression by applying the integer promotions and then the usual arithmetic conversions.
Predict and fix comparisons that mix signed and unsigned operands, from size_t lengths to countdown loops and bounds checks that let -1 through.
Convert values between C types with explicit casts, predict exactly what a narrowing conversion discards, and check whether a value survives the trip.
Read your platform's integer ranges from limits.h and use them in #if and static_assert to pick types and reject unsuitable targets.
Treat char as an 8-bit integer, tell the three char types apart, and stop bytes above 0x7F or EOF from silently going negative.
Work out the exact type of any C constant from its base and suffix, and use U, L, LL and f deliberately to control how an expression is computed.
Pick the correct conversion letter and length modifier for any C value, and know why a mismatch is undefined behavior, not just wrong text.
Align printf output with field width, choose the padding side and character, and set precision correctly for floats, integers and strings.
Choose puts, fputs, putchar or printf deliberately: which appends a newline, which parses % directives, and which is safe for arbitrary text.