πŸ‡―πŸ‡΅ ζ—₯本θͺž | πŸ‡ΊπŸ‡Έ English

πŸ”¦ Lesson 11: Stuck? printf every variable

Turn the time you spend staring at code into time spent seeing variable values. The most practical debugging skill for beginners.

πŸ“– What to learn on this page
βœ… Must-know essentials
  • Not understanding = not seeing the values
  • When in doubt: printf("x=%d\n", x);
  • Drop them inside loops, at function entry/exit
⭐ Read if you have time
  • Tag debug lines with [DEBUG] for grepping later
  • Watch out for output buffering (always \n)
  • Graduate to gdb / lldb / IDE debuggers once fluent

Why printf debugging is the strongest tool β€” 90% of beginners get stuck here

Here's the pattern that trips up most beginners:
staring at the code and trying to execute it in their head, then freezing when they can't figure it out.
πŸ”΄ Wrong approach
The fatal flaw: no human brain can track five or six variables at once. Add a loop or branch and it all falls apart. Eyeballing the code = giving up.
βœ… Right approach
Let the computer show you the values. That's it.
// Drop printfs anywhere that looks suspicious.
printf("[DEBUG] i=%d, sum=%d\n", i, sum);
Ten printfs take three minutes. Those three minutes buy you the same information as an hour of staring at the screen. This is the single biggest gap between beginners and pros.
🎯 Pros do the same thing: senior engineers reach for IDE debuggers or gdb, but the core activity β€” "watching live variable values" β€” is identical. printf is just the friendliest way in.

Where to drop printfs β€” the three golden patterns

Pattern β‘ : inside loops β€” print every iteration
for (int i = 0; i < 5; i++) {
    sum = sum + arr[i];
    printf("[DEBUG] i=%d, arr[i]=%d, sum=%d\n", i, arr[i], sum);  // ← this
}
Loops are where things go sideways. Printing state on every iteration pinpoints exactly which pass broke.
Pattern β‘‘: function entry and exit
int calc(int a, int b) {
    printf("[DEBUG] calc entry: a=%d, b=%d\n", a, b);
    int result = a * 2 + b;
    printf("[DEBUG] calc exit: result=%d\n", result);
    return result;
}
See what came in and what goes out. That instantly tells you whether the bug lives inside the function or in the caller.
Pattern β‘’: around if branches
printf("[DEBUG] before check: score=%d\n", score);
if (score >= 60) {
    printf("[DEBUG] pass branch\n");
    printf("Pass\n");
} else {
    printf("[DEBUG] fail branch\n");
    printf("Fail\n");
}
99% of "why isn't my branch being taken?" bugs come down to the condition variable not being what you thought it was. Print it just before the check.
πŸ’‘ When in doubt: printf every variable that could be wrong. Overkill is fine β€” you'll delete them later.

Before / After β€” same bug, very different pain

A classic bug: "summing 1 through 10 should give 55, but I'm getting 45." Let's compare the two debugging approaches.
😩 Before: no printfs
int sum = 0;
for (int i = 1; i < 10; i++) {
    sum = sum + i;
}
printf("Sum = %d\n", sum);
// Output: Sum = 45
// "Wait, shouldn't that be 55?"
// ...stare at the code for 10 minutes...
// ...still lost...
Time wasted: 10–60 min
😌 After: add printfs
int sum = 0;
for (int i = 1; i < 10; i++) {
    sum = sum + i;
    printf("[D] i=%d sum=%d\n", i, sum);
}
printf("Sum = %d\n", sum);
// Output:
// [D] i=1 sum=1
// [D] i=2 sum=3
// ...
// [D] i=9 sum=45    ← i stops at 9, not 10!
// Sum = 45
Time spent: 30 sec β†’ change i<10 to i<=10
The difference: printfs give you the concrete fact "i maxed out at 9." Without them, the distinction between i < 10 and i <= 10 stays fuzzy in your head, and the bug never gets fixed.

Format specifier cheat sheet

Different types need different format specifiers. Copy-paste from here when in doubt.
πŸ“Œ At Lesson 11, you only need the top two (%d and %f).
char, strings, pointers, and hex are covered in their own later lessons (Strings, Pointers, Bitwise, and so on). For now, int β†’ %d, double β†’ %f is all you need.
TypeSpecifierExampleOutput
int β˜… use now%dprintf("%d", x)42
float / double β˜… use now%fprintf("%.2f", z)3.14
long%ldprintf("%ld", y)1234567890
char later%cprintf("%c", c)A
char[] / string later%sprintf("%s", s)Hello
pointer/address later%pprintf("%p", p)0x7ffee...
hex later%xprintf("%x", n)ff
πŸ’‘ Fastest template: paste printf("[D] var1=%d var2=%d\n", var1, var2); wherever you need it and swap in your variable names. Don't forget the \n (see the next section).

Pitfalls and cleanup

πŸ”΄ Pitfall β‘ : a missing \n delays your output
printf buffers its output for efficiency and only flushes on a newline \n (line buffering).
printf("[D] got here");   // ← no \n β†’ nothing shows up on screen yet!
// If the program crashes after this line, you'll conclude
// "we never reached this point" β€” even though we did.
Fix: always end debug printfs with \n, or call fflush(stdout); right after.
⚠️ Pitfall β‘‘: the wrong specifier prints garbage
double x = 3.14;
printf("%d\n", x);    // ❌ %d is for int β€” undefined behavior
Fix: check the table above, and compile with -Wall so the compiler warns you about mismatches.
🧹 Cleanup β€” delete before committing
Once the bug is fixed, delete every debug printf. Leaving them behind makes code hard to read and can flood production logs.
πŸ’‘ Make them easy to find: always tag debug prints with [DEBUG] or [D]. Then a single grep for [D] finds them all.
πŸš€ Next step: once you're comfortable with printf, move on to Debugging Techniques and the gdb practical guide. Being able to pause and inspect variables interactively doubles or triples your speed.

Related Lessons

Intro
printf & scanf
A refresher on the specifier basics.
Loops & arrays
Debugging Techniques
Deeper debugging strategies and common bug patterns.
Advanced topics
gdb practical guide
The natural next step β€” interactive variable inspection.
← Previous
Assignment & Increment
Next β†’
if Statement

Review Quiz

Check your understanding of this lesson!

Q1. Which format specifier prints an int variable in decimal?

%d
%f
%s

%d is for decimal integers, %f is for floating-point, and %s is for strings.

Q2. Which escape sequence represents a newline?

\n
/n
\r only

\n is a newline, \t is a tab, and \\ is a literal backslash.

Q3. Which format specifier is appropriate for printing a pointer address?

%p
%a
%d

%p formats a void * as hexadecimal safely. Using %d is implementation-defined and unsafe.