A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
printf is not a language keyword. It is a function in the standard library, declared in stdio.h. That distinction matters because it means printf can be replaced, mocked, or redefined. It also means that if you forget the include, the compiler might still compile your code (with a warning) and then crash at runtime. I have seen that exact bug cost someone three hours on a take-home assignment.
Every %d, %f, %c, %s in your format string is a promise to the compiler and to the runtime: "the next argument on the stack will be this type." Break that promise and you get garbage output, crashes, or worse. printf does not type-check its variadic arguments at runtime. It trusts you completely.
#include <stdio.h>int main(void) {int count = 42;float price = 19.99f;char initial = 'J';char name[] = "Jordan";printf("Count: %d\n", count);printf("Price: $%.2f\n", price);printf("Initial: %c\n", initial);printf("Name: %s\n", name);printf("Mixed: %s bought %d items at $%.2f each\n", name, count, price);return 0;}
You can pad output to a minimum width and control decimal precision. The syntax is %width.precisionf for floats, and %widthd for integers. A negative width left-justifies. This is how you produce aligned columnar output without a formatting library.
#include <stdio.h>int main(void) {printf("|%10d|\n", 42);printf("|%-10d|\n", 42);printf("|%010d|\n", 42);printf("|%10.3f|\n", 3.14159);printf("|%.0f|\n", 3.7);return 0;}
That last line surprises people. %.0f with 3.7 prints 4, not 3. The precision for %f controls rounding, not truncation. If you need truncation, you cast to int first or use a different approach.
Pass a double where printf expects %d, or an int where it expects %s, and the function reads the wrong number of bytes off the stack. On 64-bit systems, pointers are 8 bytes and ints are 4, so a mismatch shifts every subsequent argument. The output looks like random garbage because it is reading adjacent stack memory as your data.
#include <stdio.h>int main(void) {int x = 100;printf("Wrong: %s\n", x);return 0;}
Always compile with -Wall. GCC's -Wformat flag (included in -Wall) catches most specifier mismatches at compile time. Without it, these bugs ship to production and manifest as intermittent crashes that are nearly impossible to reproduce.
printf is deceptively deep. We will revisit it when we cover fprintf for file output and sprintf for string formatting. For now, drill the specifier table into your muscle memory: %d for int, %f for double, %c for char, %s for char*, %zu for size_t, %p for pointers. Next up: reading input with scanf, which has its own set of traps.
Finish the lesson once you have worked through the material. This awards ★ 20 XP.