Menu

For Loop in C: Syntax, Examples, and Common Mistakes

How to repeat code with the C for loop - the three-part header, counting up and down, walking arrays with the sizeof trick, nested loops, infinite loops, and the off-by-one and unsigned bugs that catch everyone.

This page includes runnable editors - edit, run, and see output instantly.

Why a for Loop

if and switch choose a branch and run it once. Real programs need to do things repeatedly: print every score, sum a list of numbers, draw ten rows of a grid, try each character in a string. The for loop is C's workhorse for repeating code a known number of times, with a counter you control.

Everything a for loop needs sits in one compact header, so "how many times, and how" is visible in a single line.

The Three-Part Header

A for header has three parts separated by semicolons: an initializer, a condition, and an update.

for (initializer; condition; update) {
    // body - runs while the condition is nonzero
}

They run in a specific order, and knowing it explains every for loop you will ever read:

  1. The initializer runs once, before anything else.
  2. The condition is tested. If it is zero, the loop ends immediately.
  3. The body runs.
  4. The update runs.
  5. Back to step 2.

Trace the loop above with that list: int i = 0 runs once. 0 < 5 holds, so the body prints i = 0, then i++ makes i equal 1. The condition is tested again, and so on. When i reaches 5 the test fails, the body is skipped, and done prints. The body ran exactly five times, with i taking the values 0 through 4.

Two consequences follow directly. The condition is checked before the first pass, so a loop whose condition starts false runs zero times - for (int i = 10; i < 5; i++) never enters the body at all. And the update runs after the body, so i still holds the old value throughout the body.

Declaring the counter inside the header (int i = 0) has been legal since C99 and is the right default: i then exists only inside the loop, so it cannot collide with anything after it, and each loop in a function can reuse the name freely.

Counting Up, Down, and by Steps

The update is not restricted to i++. Count down, step by any amount, or double each pass:

Match the condition to the update. Counting up pairs with < or <=; counting down pairs with > or >=. Getting that pairing wrong is how you write a loop that never ends.

Note the second loop uses <= 10 because 10 is a value we want to include, while the first example used < 5 because 5 is not. That choice is where off-by-one bugs are born, so make it consciously: i < n runs n times starting at 0; i <= n runs n + 1 times.

Looping Over an Array

The most common use of a counting loop is walking an array by index. The counter doubles as the position you read.

Two things to take from this one.

The sizeof trick. sizeof(scores) is the size of the whole array in bytes, and sizeof(scores[0]) is the size of one element, so their quotient is the element count. It adapts automatically when you add an element, which a hard-coded 5 does not. The catch - and it is a big one - is that it only works where the array itself is in scope. Pass the array to a function and it decays to a pointer, so sizeof there gives the size of a pointer instead. Inside a function, always take the length as a separate parameter.

The condition is i < n, never i <= n. A five-element array has valid indices 0 through 4. Reading scores[5] is undefined behavior: it might print garbage, crash, or appear to work while quietly corrupting something else. C does no bounds checking whatsoever, so this is entirely on you.

Walking an array backwards is the same idea in reverse:

Start at n - 1 (the last valid index), stop at 0 inclusive - hence >=, not >. Keep i a signed int here; the next section explains why.

Nested Loops

Put one for inside another to work with grids, tables, or every pair of items. The inner loop runs to completion for each single step of the outer loop.

The outer loop fixes a row; the inner loop sweeps every col for that row; the printf("\n") after the inner loop ends the line. Move that newline inside the inner loop and the whole table becomes one column - a useful thing to try, because it makes the nesting structure concrete.

Give the counters distinct names. row/col or i/j are fine; reusing i for both shadows the outer counter and produces baffling results. And watch the cost: an n-loop inside an n-loop runs the body n * n times, so a pair of 1,000-iteration loops is a million passes.

Here is a nested loop doing real work - a triangle of stars, where the inner loop's bound depends on the outer counter:

break and continue

Two keywords change the flow mid-loop. break leaves the loop immediately; continue skips the rest of the current pass and jumps to the update.

The first loop stops the moment it finds 7 and never checks the remaining 93 values. The second uses continue to skip the print for even numbers; the header's i++ still runs, so the loop keeps advancing. There is much more on both in break and continue, including how to escape a nested loop, which a single break cannot do.

Infinite Loops and Empty Parts

All three parts of the header are optional. Leave the condition out and it is treated as permanently true:

for (;;) {
    /* runs forever - exit with break or return */
}

for (;;) is the idiomatic C infinite loop, and the semicolons are still required. It is not a mistake as long as something inside can break, return, or exit - event loops and "keep asking until the input is valid" loops are written exactly this way.

Other parts can be dropped too. If the counter already exists, skip the initializer; if the body advances it, skip the update:

int i = 0;
for (; i < n; ) {
    /* ... */
    i += step;
}

That is legal but reads worse than the while loop it really is. Prefer a for when the counter, its limit, and its step belong together in the header, and a while loop when they do not.

The Comma Operator in a Header

The initializer and the update can each hold several expressions separated by commas, which is how you run two counters at once:

int i = 0, j = len - 1 declares both counters, and i++, j-- advances both. This is the comma operator, which evaluates its operands before and after in order. Use it for genuinely parallel counters; cramming unrelated work into a header just hides it.

Common Gotchas

A handful of traps account for most for-loop bugs in C.

Off-by-one. i <= n on a zero-based array reads one element past the end. Use i < n for "n times starting at 0".

A semicolon after the header. This compiles and is almost never what you meant:

/* BUG: the loop body is the empty statement; the printf runs once */
for (int i = 0; i < 5; i++);
{
    printf("%d\n", i);
}

The ; becomes the body, so the loop spins five times doing nothing and the braces below run once as a plain block. gcc -Wall warns about it.

Unsigned counters counting down. This is an infinite loop:

/* BUG: an unsigned value is never < 0 */
for (size_t i = n - 1; i >= 0; i--) {
    process(a[i]);
}

i >= 0 is always true for an unsigned type. When i reaches 0, i-- wraps around to a huge positive number and the loop carries on into memory it does not own. Use a signed int for downward counts, or write the condition as for (size_t i = n; i-- > 0; ), which decrements and tests in one step and stops correctly at zero.

Modifying the counter in both places. Changing i inside the body as well as in the header makes the iteration count unpredictable. Pick one place.

Floating-point counters. for (double x = 0.0; x != 1.0; x += 0.1) may never terminate, because 0.1 has no exact binary representation and the sum steps past 1.0 without hitting it. Loop with an integer count and compute the value inside:

for (int i = 0; i <= 10; i++) {
    double x = i / 10.0;
    /* ... */
}

Changing an array's length while looping over it. The condition i < n re-reads n every pass, so if the body shrinks the collection, adjust the index deliberately rather than letting the two drift apart.

Frequently Asked Questions

How do you write a for loop in C?

Put three parts in the header separated by semicolons - an initializer, a condition, and an update: for (int i = 0; i < 5; i++) { printf("%d\n", i); }. That runs the body five times with i taking the values 0 through 4, and stops as soon as the condition is false.

How do I loop through an array in C?

Count an index from 0 up to (but not including) the length: for (int i = 0; i < n; i++) { sum += a[i]; }. For an array declared in the same function you can compute the length with sizeof(a) / sizeof(a[0]); once the array has been passed to a function that trick no longer works, so pass the length as a parameter.

Why does my C for loop run one too many times?

That is the off-by-one bug. With a zero-based array of size n, valid indices are 0 through n - 1, so i <= n runs one extra iteration and reads past the end - undefined behavior. The safe default is i < n.

Can you declare the loop variable inside a C for loop?

Yes, since C99: for (int i = 0; i < n; i++). The variable then exists only inside the loop, which is what you want. Compile with gcc -std=c99 or later (modern GCC and clang default to C17, so it just works); the old C89 style declared i before the loop.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED