C Format Specifiers
What Are Format Specifiers?
In C, `printf` and `scanf` use format specifiers to determine how data is displayed or read.
They act as placeholders inside strings and must match the type (and, for integers/floats, the correct length) of the value being printed or read.
Specifier | Typical Use | Example (printf) | Notes |
---|---|---|---|
%d / %i | signed int (decimal) | int x=5; printf("%d", x); | For `scanf`, use "%d" to read int. |
%u | unsigned int (decimal) | unsigned u=42; printf("%u", u); | |
%x / %X | unsigned int (hex) | unsigned val=3735928559u; printf("%x", val); | Lower/upper hex. |
%o | unsigned int (octal) | unsigned v=511; printf("%o", v); | |
%ld / %lld | long / long long (decimal) | long long n=123; printf("%lld", n); | Match length with the type. |
%f | double (fixed-point) | double pi=3.14; printf("%f", pi); | In `printf`, floats are promoted to double. |
%e / %E | double (scientific) | printf("%e", 3.14); | |
%g / %G | double (compact) | printf("%g", 3.1400); | Chooses %f or %e form. |
%.2f | double with precision | printf("%.2f", 3.14159); | Precision controls decimals (print only). |
%c | char (character) | char grade='A'; printf("%c", grade); | For `scanf`, consider a leading space: " %c" to skip whitespace. |
%s | char* (C string) | char name[]="John"; printf("%s", name); | For `scanf`, limit width: e.g., "%99s". |
%p | pointer address | int *p=&x; printf("%p", (void*)p); | Cast to `(void*)` for portability. |
%zu | size_t (unsigned) | printf("%zu", sizeof(int)); | Use `%td` for ptrdiff_t (signed). |
%% | literal % | printf("100%%"); | Prints a percent sign. |
Controlling Output Format
• Precision can be set for floating-point values using `%.nf`. Example: `%.3f` prints 3 decimals.
• Width can be specified for alignment. Example: `%5d` reserves 5 spaces for an integer.
• Flags: `-` (left-justify), `+` (always show sign), `0` (zero pad), space (leading space for positive), `#` (alternate form for `%o/%x/%e/%f/%g`).
#include <stdio.h>
int main(void) {
double pi = 3.14159;
printf("Default: %f\n", pi);
printf("2 decimals: %.2f\n", pi);
printf("Width 10: %10.2f\n", pi);
printf("Zero-pad: %010.2f\n", pi);
printf("Sign: %+10.2f\n", pi);
return 0;
}
Default: 3.141590 2 decimals: 3.14 Width 10: 3.14 Zero-pad: 0000003.14 Sign: +3.14
scanf vs printf (Important Differences)
• In `scanf`, `%f` reads into a `float*`, **`%lf` reads into a `double*`**. In `printf`, `%f` always prints a `double`.
• Always pass the address of the variable to `scanf` (e.g., `&x`).
• For `%c`, leading whitespace in the input may be consumed by a prior read; use a leading space in the format string (e.g., " %c") to skip whitespace.
• Limit `%s` to avoid buffer overflows, e.g., `char name[100]; scanf("%99s", name);`
#include <stdio.h>
int main(void) {
int a; double d; char c; char name[100];
/* Sample input: 7 3.5 Y Alice */
if (scanf("%d %lf %c %99s", &a, &d, &c, name) != 4) return 1;
printf("a=%d, d=%.3f, c=%c, name=%s\n", a, d, c, name);
return 0;
}
a=7, d=3.500, c=Y, name=Alice
Length Modifiers (Cheat Sheet)
Modifier | Use With | Means | Example |
---|---|---|---|
h | %d/%u/%x | short / unsigned short | short s; scanf("%hd", &s); |
l | %d/%u/%x/%o | long / unsigned long | long L; printf("%ld", L); |
ll | %d/%u/%x/%o | long long / unsigned long long | long long q; printf("%lld", q); |
z | %u | size_t | size_t n; printf("%zu", n); |
t | %d | ptrdiff_t (signed) | ptrdiff_t d; printf("%td", d); |
L | %f/%e/%g | long double (printf/scanf) | long double x; printf("%Lf", x); |
Quick Examples
#include <stdio.h>
int main(void) {
int n = 42; unsigned u = 42; double x = 1234.567; char ch = 'A';
printf("int: %d, unsigned: %u\n", n, u);
printf("hex: 0x%X, octal: %o\n", u, u);
printf("fixed: %.2f, scientific: %.2E, compact: %g\n", x, x, x);
printf("char: %c, string: %s\n", ch, "Hello");
printf("size: %zu bytes\n", sizeof n);
return 0;
}
int: 42, unsigned: 42 hex: 0x2A, octal: 52 fixed: 1234.57, scientific: 1.234567E+03, compact: 1234.57 char: A, string: Hello size: 4 bytes
Best Practices
1. Match specifiers exactly to the type and length (use length modifiers).
2. For `scanf`, always pass addresses (and limit `%s` input width).
3. Use `(void*)` with `%p` in `printf` for portability.
4. Prefer `%.nf` to control floating-point output precision; avoid comparing floats directly for equality elsewhere.
5. Validate `scanf` return values to ensure inputs were read successfully.