Topic 38 of 100 Input and Output Functions Interactive Tutorial

Formatted Input and Output in C: Practical Techniques

13 mins read Last updated: 22 Aug 2026 22,300 views
C Compiler 0.00%

What is Formatted Input and Output in C? Core Concept & Direct Summary

Core Objective & Problem Statement

How do memory and stream formatted functions (`sprintf`, `snprintf`, `sscanf`, `fprintf`, `fscanf`) process strings and files?

Direct Answer Summary

Over the last several tutorials, we've met each of C's I/O functions one at a time — printf(), scanf(), getchar(), putchar(), gets(), and puts(). Now it's time to zoom out and look at the system that ties the two most powerful of them together: formatting.

Here's a secret about professional-looking C programs: the difference between amateur and polished output usually isn't logic — it's formatting. Aligned columns, consistent decimal places, padded invoice numbers, clean data entry. All of it comes from mastering the format string, that little piece of text inside printf() and scanf() that controls everything.

Most tutorials give you the specifiers table and stop there. This one goes further — flags, width, precision, length modifiers, and the practical patterns real programs actually use. Let's get into it.

(Suggested image: an "anatomy" diagram — %[flags][width][.precision][length]type with each segment labeled and color-coded. This is THE key graphic for this page.)


How Does Formatted Input and Output in C Work? In-Depth Mechanics & Architecture

The Anatomy of a Format Specifier

Every format specifier you've used — %d, %f, %s — is actually the simplest possible version of a much richer pattern:

main.c
Run Online
%[flags][width][.precision][length]type

Breaking that down:

ComponentWhat It ControlsExample
%Starts every specifier—
flagsAlignment, signs, padding-, +, 0, , #
widthMinimum field width10
.precisionDecimals / max characters.2
lengthData size modifierl, ll, h
typeThe data typed, f, s, c...

You already know the last part. The magic lives in the middle four. Let's take them one at a time — always with printf() first, since output is where these features shine most.


Technique 1: Field Width — The Secret to Aligned Columns

A number between % and the type sets a minimum field width. If the value is shorter, printf() pads it with spaces (right-aligned by default):

main.c
Run Online
printf("[%d]\n", 42);
printf("[%5d]\n", 42);
printf("[%10d]\n", 42);

Output:

The brackets aren't part of the formatting — they're just there so you can see the padding. And padding is everything when you're printing tables:

main.c
Run Online
printf("%-12s %8s %10s\n", "Product", "Qty", "Price");
printf("%-12s %8d %10.2f\n", "Apples", 25, 450.50);
printf("%-12s %8d %10.2f\n", "Oranges", 40, 720.00);
printf("%-12s %8d %10.2f\n", "Mangoes", 12, 1440.75);

Output:

main.c
Run Online
Product Qty PriceApples 25 450.50Oranges 40 720.00Mangoes 12 1440.75

Perfectly aligned columns — no libraries, no tricks, just width values. (The - flag makes the strings left-aligned; we'll cover flags next.)

(Suggested image: this exact table rendered as a clean terminal screenshot — it's a very satisfying visual)


Technique 2: The Five Flags

Flags are single characters placed right after % that tweak the output:

FlagEffectExampleResult
-Left-align%-6d with 4242
+Always show sign%+d with 42+42
0Pad with zeros%06d with 42000042
(space)Space before positives% d with 4242
#Alternate form%#x with 2550xff

Where each one earns its place:

main.c
Run Online
// Zero-padding: invoice numbers, IDs, datesprintf("Invoice #%05d\n", 234);        // Invoice #00234printf("Date: %02d/%02d/%d\n", 5, 8, 2026);  // Date: 05/08/2026
// Plus sign: temperature changes, scores, financial deltasprintf("Change: %+d points\n", -15);   // Change: -15 pointsprintf("Change: %+d points\n", 20);    // Change: +20 points
// Hash: showing number bases clearlyprintf("%#o  %#x  %#X\n", 64, 255, 255);  // 0100  0xff  0XFF

Left vs. right alignment matters more than people think — text reads better left-aligned, numbers read better right-aligned (so the digits line up by place value):

main.c
Run Online
printf("%-15s %10d\n", "Subscribers", 1250);
// text left, number right

That one habit alone will make every table you print look professionally done.


Technique 3: Precision — Controlling Decimals and Strings

Precision comes after a dot, and it means different things for different types:

For floats — decimal places:

main.c
Run Online
float pi = 3.14159265;
printf("%f\n", pi);
// 3.141593  (default: 6 decimals)printf("%.2f\n", pi);
// 3.14printf("%.10f\n", pi);
// 3.1415927410 (note: float precision limits show here)

For strings — maximum characters printed:

main.c
Run Online
printf("%.5s\n", "Programming");
// Progr

Handy for truncating long text to fit a column.

For integers — minimum digits (pads with leading zeros):

main.c
Run Online
printf("%.4d\n", 42);
// 0042

Combined with width — width sets the total field, precision sets the detail:

main.c
Run Online
printf("[%10.3f]\n", 3.14159);
// [     3.142]  — 10 wide, 3 decimals

Pro move — dynamic width and precision with *:

main.c
Run Online
int width = 10, decimals = 2;
float price = 99.456;
printf("%*.*f\n", width, decimals, price);
// "     99.46"

Each * pulls its value from the argument list, so your program can decide formatting at runtime. Very few beginners know this one exists.


Technique 4: Length Modifiers — Matching the Type Exactly

Length modifiers sit between the precision and the type, and they must match your variable's actual size:

ModifierPairs WithUse For
l%ld, %lu, %lflong, unsigned long, double (in scanf)
ll%lld, %llulong long
h%hdshort
z%zusize_t (sizes, sizeof results)
main.c
Run Online
long population = 1400000000L;
long long stars = 100000000000LL;
size_t bytes = sizeof(double);
printf("Population: %ld\n", population);
printf("Stars: %lld\n", stars);
printf("double takes %zu bytes\n", bytes);

Mismatched modifiers cause silent garbage — %d reading a long will cheerfully print nonsense on many systems. When output looks insane for no reason, check your specifier against the variable type first. It's the culprit more often than not.


Technique 5: Formatted Input — scanf() Patterns That Actually Work

Formatting isn't just for output. scanf()'s format string has its own set of practical tricks.

Literal character matching — require specific separators:

main.c
Run Online
int dd, mm, yyyy;
printf("Enter date (dd-mm-yyyy): ");
scanf("%d-%d-%d", &dd, &mm, &yyyy);
// Input must look like: 15-08-1947

If the user types 15/08/1947 instead, the match fails at the / — which is why checking scanf's return value matters so much:

main.c
Run Online
if (scanf("%d-%d-%d", &dd, &mm, &yyyy) != 3) {
    puts("Invalid date format!");
}

Width limits on strings — the safety trick from the scanf() tutorial:

main.c
Run Online
char name[50];
scanf("%49s", name);
// never overflows: 49 chars + '\0' = 50

Reading only specific characters — the scanset %[...]:

main.c
Run Online
char vowels[20];
printf("Type letters: ");
scanf("%[aeiou]", vowels);
// reads ONLY vowels, stops at anything else// Input: "aero" → captures "ae", stops at 'r'

The caret inverts it — %[^\n] means "read everything except newline":

main.c
Run Online
char line[100];
scanf(" %99[^\n]", line);
// reads a full line WITH spaces (fgets alternative)

This is the classic workaround for %s stopping at spaces — though honestly, fgets() remains the cleaner solution for line input, as we covered in the gets() tutorial.

Suppressing assignment with * — read something and throw it away:

main.c
Run Online
int day, year;
char month[20];
scanf("%d %s %d", &day, month, &year);
// vs.scanf("%d %*s %d", &day, &year);
// Input "15 August 1947": first version stores the month,// second version skips it entirely — %*s reads but discards

Technique 6: Printing Special Values Cleanly

Percentages (double %% prints a literal percent):

main.c
Run Online
float score = 87.5;
printf("Pass rate: %.1f%%\n", score);
// Pass rate: 87.5%

Hex and octal for debugging:

main.c
Run Online
int flags = 255;
printf("Decimal: %d  Hex: %#x  Octal: %#o\n", flags, flags, flags);
// Decimal: 255  Hex: 0xff  Octal: 0377

Scientific notation:

main.c
Run Online
double lightSpeed = 299792458.0;
printf("%.3e\n", lightSpeed);
// 2.998e+08

Pointer addresses (useful while learning pointers later):

main.c
Run Online
int x = 10;
printf("Address of x: %p\n",(void *)&x);
// e.g. 0x7ffc...

The Complete Reference Table

Bookmark-worthy — every commonly used specifier in one place:

SpecifierTypeExample Output
%d / %iint42
%uunsigned int42
%ld / %lldlong / long long1400000000
%ffloat / double (printf)3.141593
%.2ffloat, 2 decimals3.14
%e / %Escientific3.14e+00
%gauto: %f or %e, shorter wins3.14
%ccharA
%sstringHello
%x / %Xhex (lower/upper)ff / FF
%ooctal52
%ppointer0x7ffc...
%zusize_t8
%%literal %%

(Suggested image: this table as a downloadable-style cheat sheet graphic — this kind of asset earns backlinks and shares, which is gold for your SEO)


A Capstone Example: A Formatted Receipt Generator

Everything from this page in one program:

main.c
Run Online
#include <stdio.h>
int main() {
    char item[50];
    int qty;
    float price, total, grandTotal = 0;
    int count, i;
    printf("How many items? ");
    scanf("%d", &count);
    puts("\n======================================");
    puts("            SUPER MART              ");
    puts("======================================");
    printf("%-15s %5s %10s %10s\n", "Item", "Qty", "Price", "Total");
    puts("--------------------------------------");
    for (i = 0; i < count; i++) {
        printf("Item %d name: ", i + 1);
        scanf(" %49[^\n]", item);
        printf("Qty and price: ");
        scanf("%d %f", &qty, &price);
        total = qty * price;
        grandTotal += total;
        printf("%-15s %5d %10.2f %10.2f\n", item, qty, price, total);
    }
    puts("--------------------------------------");
    printf("%-15s %5s %10s %10.2f\n", "GRAND TOTAL", "", "", grandTotal);
    puts("======================================");
    printf("Items: %d  |  Avg: %.2f\n", count, grandTotal / count);
    puts("     Thank you, visit again!         ");
    return 0;
}

Sample Run:

main.c
Run Online
How many items? 2
Item 1 name: Basmati Rice
Qty and price: 2 350.50
Item 2 name: Olive Oil
Qty and price: 1 599.99
======================================
SUPER MART
======================================
Item Qty Price Total
--------------------------------------
Basmati Rice 2 350.50 701.00
Olive Oil 1 599.99 599.99
--------------------------------------
GRAND TOTAL 1300.99
======================================
Items: 2 | Avg: 650.50
Thank you, visit again!

Width, precision, alignment, puts() for fixed lines, printf() for data, safe string input with a scanset — the entire tutorial, working as one program. That receipt could pass for real software output.


Common Formatting Mistakes

  1. Specifier/type mismatch — %d with a long, %f with a double in scanf: silent garbage, no warnings (compile with -Wall to catch these)
  2. Forgetting - flips alignment — %-10s vs %10s produce mirror-image columns
  3. %0 padding on strings — zero-padding only works with numbers
  4. Width is a minimum, not a maximum — %5d won't truncate a 10-digit number; it just expands
  5. %s in scanf without a width limit — buffer overflow waiting to happen; always %49s style
  6. Precision with the wrong type — %.2d pads with zeros, %.2f rounds decimals; same dot, totally different behavior

(Suggested image: "6 Formatting Mistakes" checklist graphic, consistent with the series style)


Final Thoughts

Formatted I/O is one of those skills that quietly separates "code that works" from "code that looks like it was written by a professional." The entire system boils down to one pattern — %[flags][width][.precision][length]type — and once that pattern clicks, every format string you ever encounter becomes readable at a glance.

My suggestion: take the receipt program and bend it. Change column widths, break the alignment on purpose, feed it weird input. Ten minutes of playful sabotage teaches more than an hour of reading ever will.


Runnable C Code Example & Practical Implementation

main.c
Run Online
#include <stdio.h>
int main() {
    char logEntry[128];
    int errorCode = 404;
    char url[] = "/api/v1/users";
    // Format safely into string buffer
    snprintf(logEntry, sizeof(logEntry), "HTTP %d: Failed request for %s", errorCode, url);
    printf("Formatted String: %s\
", logEntry);
    // Parse tokens from a string
    char dateStr[] = "2026-09-20";
    int year, month, day;
    if (sscanf(dateStr, "%d-%d-%d", &year, &month, &day) == 3) {
        printf("Parsed Date -> Year: %d, Month: %02d, Day: %02d\
", year, month, day);
    }
    return 0;
}

Key Takeaways, Best Practices & Memory Safety Rules

Best Practice & Key Takeaways
Always use snprintf() instead of sprintf() to prevent buffer overflow vulnerabilities.

Frequently Asked Questions & Technical Interview Insights

Technical Interview & Viva Questions

Frequently asked C programming interview questions
Q

Q: Why should `snprintf()` always be preferred over `sprintf()`?

A: `sprintf()` does not take a buffer size parameter and will write past buffer bounds if the formatted output exceeds capacity. `snprintf()` truncates safely and guarantees null-termination.
Q

Q: What does `sscanf()` return?

A: The number of input items successfully matched and assigned, or `EOF` before any conversion occurred.

Related Tools, Tutorials & Authoritative References

Recommended Interactive Tools

Authoritative Standards & Citations