The C Path — learn C, visually

🌱 C Basics

for loops: init, test, step — all in one line

⏱ 13 min · free interactive lesson · quizzes, visualizations & a real compiler

▶ Open the interactive lesson — free, no signup
Why you're learning this

Print 100 scores, check every character of a password, draw each row of a game board — "do this N times" is the single most common instruction in programming. The for loop packs the whole job into one line, and this lesson also arms you against the off-by-one mistake that has haunted every programmer who ever lived.

Last lesson's healthy-loop checklist — initialize, test, update — is so universal that C gives it a shorthand of its own. The for loop puts all three on one line, where you can't forget any of them:

sum100.c
#include <stdio.h>

int main(void) {
    int sum = 0;

    for (int i = 1; i <= 100; i++) {
        sum += i;
    }
    printf("1 + 2 + ... + 100 = %d\n", sum);
    return 0;
}
terminal
$ gcc sum100.c -o sum100 && ./sum100
1 + 2 + ... + 100 = 5050
# young Gauss computed this in his head; your CPU does it in nanoseconds

for (init; condition; step) runs like this — note it's exactly a while loop in a tailored suit:

This spot has an interactive flow widget — open the interactive lesson to play with it.

Watch all three phases fire in order:

This spot has an interactive trace widget — open the interactive lesson to play with it.

🧠 Checkpoint: In for (int i = 0; i < 5; i++), when does i++ run?

  • Before the body, each time
  • After the body, before the next condition check
  • Once, at the very end of the loop
  • Whenever i is used
Show answer

After the body, before the next condition check — Order per iteration: test → body → step → test again. The step always runs after a completed body — that’s why the trace showed i changing right before each new test.

The loop variable's tiny life

Declare i in the init clause and it exists only inside the loop — after the closing brace, i is gone, and mentioning it is a compile error. This is a feature: each loop gets a fresh, private counter, and no stale counters leak around your function.

⚠️

Off-by-one, the eternal enemy: for (int i = 0; i < n; i++) runs exactly n times — the idiomatic C loop (and it will match array indexing perfectly in Part 2). Writing <= runs n+1 times. When a loop misbehaves, check the boundary first: does it start at 0 or 1? Is the test < or <=?

🧠 Checkpoint: How many times does for (int i = 0; i <= 10; i += 2) run its body?

  • 5
  • 10
  • 6
  • 11
Show answer

6 — i takes 0, 2, 4, 6, 8, 10 — six values (the <= keeps 10 in). With < it would be five. Counting fence posts carefully is half of C programming.

Nested loops: the times table

A loop body can contain another loop. The inner loop runs to completion for every single iteration of the outer one — 10 × 10 = 100 inner bodies here:

timestable.c
#include <stdio.h>

int main(void) {
    for (int row = 1; row <= 10; row++) {
        for (int col = 1; col <= 10; col++) {
            printf("%4d", row * col);
        }
        printf("\n");        /* end the row */
    }
    return 0;
}
terminal
$ gcc timestable.c -o tt && ./tt
   1   2   3   4   5   6   7   8   9  10
   2   4   6   8  10  12  14  16  18  20
   3   6   9  12  15  18  21  24  27  30
   4   8  12  16  20  24  28  32  36  40
   5  10  15  20  25  30  35  40  45  50
   6  12  18  24  30  36  42  48  54  60
   7  14  21  28  35  42  49  56  63  70
   8  16  24  32  40  48  56  64  72  80
   9  18  27  36  45  54  63  72  81  90
  10  20  30  40  50  60  70  80  90 100
# %4d right-aligns each number in 4 columns — instant neat table

Two counters at once: the comma operator

The init and step clauses each accept only one expression — but the comma operator chains several into one, evaluating left to right. It's the idiomatic way to walk two indices together (you'll meet it again reversing arrays in Part 2):

comma.c
#include <stdio.h>

int main(void) {
    /* two counters marching toward each other */
    for (int lo = 0, hi = 9; lo < hi; lo++, hi--) {
        printf("lo=%d hi=%d\n", lo, hi);
    }
    return 0;
}
terminal
$ gcc comma.c -o comma && ./comma
lo=0 hi=9
lo=1 hi=8
lo=2 hi=7
lo=3 hi=6
lo=4 hi=5
🤔

All three clauses are optional. for (;;) — affectionately "forever" — is a perfectly legal infinite loop, equivalent to while (1). The semicolons stay, though: for () won't compile.

This spot has an interactive editor widget — open the interactive lesson to play with it.

🧠 Checkpoint: After for (int i = 0; i < 3; i++) { }, what does printf("%d", i); do?

  • Prints 3
  • Prints 2
  • Compile error — i no longer exists
  • Prints garbage
Show answer

Compile error — i no longer exists — A variable declared in the init clause is scoped to the loop. After the closing brace it’s not garbage — it’s GONE, and the compiler rejects the name outright. Declare i before the for if you need its final value.

You can now start loops — next you'll learn to escape them early: break, continue, and the infamous goto.

▶ Practice this lesson interactively (with live gcc)