06 Formatted IO Engineering Practices
1. Introduction to Formatted I/O
The printf and scanf functions are the primary interface between a C program's internal binary memory and the external text-based world. They act as translators governed by a precise "protocol": the Format Specifier String.
2. Anatomy of the Format Specifier
The specifier defines the rules for this translation.
% [flags] [width] [.precision] [length] type
A. The Core: type Specifier
Defines the interpretation of the binary data.
* d, i: Signed Decimal Integer.
* u: Unsigned Decimal Integer.
* x, X: Hexadecimal Integer.
* f, e, g: Floating Point.
* c, s: Character, String.
* p: Pointer Address.
* %: A literal '%' character.
B. length Modifier (The Memory Ruler)
This is critical for matching the size of the data type in memory. A mismatch leads to incorrect data representation or memory corruption.
* hh: For signed/unsigned char.
* h: For signed/unsigned short.
* l: For long or double (in scanf).
* ll: For long long.
* L: For long double.
C. Formatting Options (Primarily printf)
flags: Controls alignment and appearance.-: Left-justify.+: Force sign display (+or-).0: Pad with leading zeros instead of spaces.
width: Minimum field width..precision:- For floats: Number of decimal places.
- For strings: Maximum characters to print.
D. Special Modifiers
*(Asterisk): Dynamic Width/Precision. The value for width/precision is taken from an extraintargument.n: Writeback Counter. Stores the number of characters processed so far into anint*argument.[](Scanset):scanfonly. Matches a set of characters.%[abc]: Matchesa,b, orc.%[^abc]: Matches any character excepta,b, orc.
3. printf: The Output Composer
A. Core Function
Converts binary data from memory into a human-readable string representation for display. * Safety: It is a read-only operation on variables, so it is generally safe.
B. Usage of * (Dynamic Formatting)
Used for creating aligned tables where column widths are determined at runtime.
printf("%*d", 10, 123); // Prints " 123" (width 10)
printf("%.*f", 2, 3.14159); // Prints "3.14" (precision 2)
C. Usage of %n (Writeback)
Used to capture the number of characters printed to assist in further formatting.
int count;
printf("Hello%n", &count); // After this call, count == 5
D. Return Value
- Success: Returns the total number of characters successfully printed.
- Failure: Returns a negative value if an output error occurs (e.g., broken pipe, disk full).
- Engineering Use: In system-level programming, checking for a negative return value is crucial for verifying I/O device health.
4. scanf: The Input Parser
A. Core Function
Converts a sequence of text characters into their binary representation and stores them at specified memory addresses. * Safety: It is a write operation, making it inherently dangerous. Incorrect usage can lead to memory corruption and security vulnerabilities.
B. Mandatory Address Operator (&)
scanf requires the memory address of variables to store results. Passing a value instead of an address (&) is a common and critical bug.
C. Strict Length Modifier Matching (The Critical Trap)
scanf does not perform argument promotion. The length modifier must precisely match the variable's type.
* double d; scanf("%lf", &d); // Correct
* double d; scanf("%f", &d); // INCORRECT. Writes 4 bytes into an 8-byte space, corrupting memory.
D. The * Modifier (Assignment Suppression)
Used to read and discard data from the input stream.
// Input: "ID: 1001"
int id;
scanf("%*s %d", &id); // Reads and discards "ID:", then reads 1001.
E. The Scanset (%[^,]) for CSV Parsing
Used to read a string until a specific delimiter is found.
char data[100];
scanf("%[^,]", data); // Reads all characters up to the first comma.
- Risk: Like
%s, this can cause a buffer overflow if the input is longer than the buffer. Use a width specifier (e.g.,%99[^,]) for safety.
F. Return Value
- Success: Returns the number of items successfully matched and assigned. This is the only reliable way to check if the input was valid.
- Failure:
- Returns
0if the first item fails to match (e.g., user enters "abc" for%d). - Returns
EOF(End Of File) if the input stream ends before any match.
- Returns
- Engineering Use: Always check the return value of
scanfto validate user input. Assuming success is a primary source of bugs.c if (scanf("%d %d", &a, &b) != 2) { // Handle input error }