C in 100 Seconds: Format Specifiers | Episode 3
Video: C in 100 Seconds: Same Data Different Output — Format Specifiers | Episode 3 by Taught by Celeste AI - AI Coding Coach
C Format Specifiers: Same Data, Different Output
%ddecimal,%xhex,%ffloat,%.2fprecision,%sstring,%ppointer,%10dright-padded,%-10dleft-padded. The printf format mini-language.
printf's power is its format string. The same value can be printed as decimal, hex, padded, scientific notation, or address — depending on which format specifier you use.
The full example
#include <stdio.h>
int main() {
int n = 42;
float pi = 3.14159;
char name[] = "Alice";
printf("%d\n", n); // 42
printf("%x\n", n); // 2a
printf("%f\n", pi); // 3.141590
printf("%.2f\n", pi); // 3.14
printf("%s\n", name); // Alice
printf("%p\n", &n); // 0x7ffe... (address)
printf("[%10d]\n", n); // [ 42]
printf("[%-10d]\n", n); // [42 ]
return 0;
}
Eight different format specifiers, each rendering the same data differently.
Integer formats
printf("%d\n", 42); // decimal: 42
printf("%i\n", 42); // also decimal: 42 (synonym for %d)
printf("%x\n", 42); // lowercase hex: 2a
printf("%X\n", 42); // uppercase hex: 2A
printf("%o\n", 42); // octal: 52
printf("%u\n", 42u); // unsigned: 42
printf("%b\n", 42); // binary (C23+): 101010
For longer integers, prefix the specifier:
printf("%ld\n", 9999999999L); // long
printf("%lld\n", 9999999999LL); // long long
printf("%zu\n", sizeof(int)); // size_t (return of sizeof)
Float formats
printf("%f\n", 3.14159); // 3.141590 (default 6 decimals)
printf("%.2f\n", 3.14159); // 3.14 (2 decimals)
printf("%.0f\n", 3.14159); // 3 (rounded)
printf("%e\n", 314159.0); // 3.141590e+05 (scientific)
printf("%.3e\n", 314159.0); // 3.142e+05
printf("%g\n", 3.14); // 3.14 (shortest of %f or %e)
%f is the most common. %.Nf for N decimal places. %e for scientific notation. %g picks whichever is shorter.
Strings and characters
char name[] = "Alice";
printf("%s\n", name); // Alice
printf("%c\n", name[0]); // A
printf("%d\n", name[0]); // 65 (ASCII for 'A')
%s for null-terminated strings. %c for a single char. %d on a char prints its ASCII value.
Pointers
int n = 42;
printf("%p\n", (void*)&n); // 0x7ffe... (memory address)
%p prints a pointer's address as hex. Cast to void* for portability — printf expects void*, and although most compilers accept int* directly, the standard says cast.
Width and padding
printf("[%10d]\n", 42); // [ 42] — right-aligned, width 10
printf("[%-10d]\n", 42); // [42 ] — left-aligned, width 10
printf("[%010d]\n", 42); // [0000000042] — zero-padded to width 10
printf("[%5.2f]\n", 3.14); // [ 3.14] — width 5, 2 decimals
Widths control the minimum output width. If the value is wider, it overflows (no truncation).
- flag: left-align. 0 flag: zero-pad (only useful for numbers, right-align). + flag: always show sign.
printf("%+d\n", 42); // +42
printf("%+d\n", -42); // -42
Precision
For %f, precision = decimals. For %s, it's max string length:
printf("[%.3s]\n", "Hello"); // [Hel] (truncated to 3 chars)
printf("[%5.3s]\n", "Hello"); // [ Hel] (width 5, max 3 chars)
For %d, precision = minimum digits (zero-padded):
printf("[%.5d]\n", 42); // [00042]
Variable width and precision
* lets you pass width or precision as an argument:
int width = 10;
int n = 42;
printf("[%*d]\n", width, n); // [ 42]
int prec = 4;
double pi = 3.14159;
printf("%.*f\n", prec, pi); // 3.1416
Useful when the formatting depends on runtime data — column widths in a table, etc.
Common mistakes
Wrong specifier for the type. printf("%d", 3.14); prints garbage — the compiler reinterprets the double's bytes as an int. Match types.
Forgetting the type promotion. printf("%f", 3.14f); works because float promotes to double when passed. So %f covers both.
Using %s on a non-string. printf("%s", 42); segfaults — %s expects a char*, gets the int 42 as a "pointer," tries to dereference. Crash.
Forgetting \n. Output buffers until newline (or flush, or program exit). Without \n, you might not see output before a crash.
Using %lf for double. Some old C texts say %lf. In modern C (C99+), %f works for both float and double in printf. (scanf is different — there %lf is required for double.)
%X vs %x. Different! Uppercase prints 2A; lowercase 2a.
Why this matters
printf is the workhorse of C debugging. Knowing the format specifiers is half of "is my program doing what I think." For tables, padding makes columns align. For low-level debugging, %x and %p reveal what's actually in memory.
What's next
Episode 4: arithmetic operators. + - * / % and the surprising integer-division truncation: 7 / 2 is 3, not 3.5.
Recap
Integer: %d decimal, %x/%X hex, %o octal, %u unsigned. Float: %f (6 decimals default), %.Nf N decimals, %e scientific. String: %s. Char: %c (or %d for ASCII value). Pointer: %p (cast to void*). Width: %10d (right-align), %-10d (left-align), %010d (zero-pad). Precision: %.2f (decimals for floats; max length for strings). Variable: %*d and %.*f. Mismatch types and you get garbage or a crash.
Next episode: arithmetic and integer division.