FirstHack Learn
Log in Sign up free

Loops: for, while and do-while

10 min read · 30 views

Loops: for, while and do-while

A loop repeats a block of code. The syntax is short, but nearly every loop bug traces back to the same two questions: exactly when is the condition checked, and exactly when does the counter change. Keep those straight and loops stop being mysterious.

C has three loop forms. They are equally powerful, and any one can be rewritten as another. Choosing between them is about stating your intent clearly.

The for loop

Use for when you know before entering how many times you want to repeat.

C
#include <stdio.h>

int main(void)
{
    for (int i = 1; i <= 5; i++) {
        printf("Iteration %d\n", i);
    }

    int sum = 0;
    for (int i = 1; i <= 100; i++) {
        sum += i;
    }
    printf("Sum of 1 to 100 = %d\n", sum);

    printf("Countdown: ");
    for (int i = 5; i >= 1; i--) {
        printf("%d ", i);
    }
    printf("\n");

    return 0;
}

The header holds three parts separated by semicolons, and each runs at a different moment.

  1. Initialisation (int i = 1) runs once, before the first iteration.
  2. Condition (i <= 5) is tested before every iteration, including the first. If it is false at the start, the body never runs at all.
  3. Update (i++) runs after each iteration, and then the condition is tested again.

Declaring the counter inside the header keeps it local to the loop, which is good practice: the variable cannot leak into code that should not see it.

The while loop

Use while when the number of repetitions depends on something you discover as you go.

C
#include <stdio.h>

int main(void)
{
    int number = 9042;
    int digits = 0;
    int sum    = 0;
    int temp   = number;

    while (temp > 0) {
        sum += temp % 10;
        temp /= 10;
        digits++;
    }

    printf("Number     : %d\n", number);
    printf("Digits     : %d\n", digits);
    printf("Digit sum  : %d\n", sum);

    int n = 1;
    while (n <= 64) {
        printf("%d ", n);
        n *= 2;
    }
    printf("\n");

    return 0;
}

Nothing here knows in advance that 9042 has four digits. The loop simply keeps stripping digits until nothing is left. That is the situation while is built for.

Notice what you must do manually with while: initialise before the loop, and update inside it. Forget the update and the condition never becomes false.

The do-while loop

do-while tests the condition after running the body, so the body always executes at least once.

C
#include <stdio.h>

int main(void)
{
    int i = 10;

    do {
        printf("This runs once even though 10 > 5 is the exit test.\n");
        i++;
    } while (i < 5);

    int countdown = 3;
    do {
        printf("%d...\n", countdown);
        countdown--;
    } while (countdown > 0);

    printf("Done. i ended at %d\n", i);

    return 0;
}

The first loop runs exactly once. An ordinary while (i < 5) with i starting at 10 would run zero times. That is the entire difference, and it is the reason do-while is the natural choice for menus and for input validation: you must show the menu once before you can know whether the user wants to quit.

Note the semicolon after the closing while (...). It is required, and leaving it out is a compile error.

Form Condition checked Minimum runs Typical use
for Before each pass 0 Known count, arrays
while Before each pass 0 Unknown count
do-while After each pass 1 Menus, validation

break and continue

break leaves the loop immediately. continue skips the rest of the current pass and jumps to the next one.

C
#include <stdio.h>

int main(void)
{
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) {
            continue;
        }
        printf("%d ", i);
    }
    printf("\n");

    int target = 7;
    for (int i = 1; i <= 100; i++) {
        if (i == target) {
            printf("Found %d, stopping early.\n", i);
            break;
        }
    }

    int n = 91;
    int isPrime = 1;
    for (int d = 2; d * d <= n; d++) {
        if (n % d == 0) {
            isPrime = 0;
            break;
        }
    }
    printf("%d is %s\n", n, isPrime ? "prime" : "not prime");

    return 0;
}

break matters for efficiency and for correctness. In the prime check, once a divisor is found there is nothing left to learn, so continuing would waste time and could overwrite the result.

⚠️continue behaves differently in a while loop

In a for loop, continue still runs the update part, so the counter advances. In a while loop, continue jumps straight back to the condition and skips any update you wrote at the bottom of the body. If the counter lives there, you have just created an infinite loop. Increment before the continue, or use for.

Nested loops and patterns

A loop inside a loop is how you handle anything two-dimensional: tables, matrices, and the star patterns that fill first-year question papers. The inner loop completes fully for every single pass of the outer loop.

C
#include <stdio.h>

int main(void)
{
    int rows = 5;

    for (int i = 1; i <= rows; i++) {
        for (int j = 1; j <= i; j++) {
            printf("* ");
        }
        printf("\n");
    }

    printf("\n");

    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 4; j++) {
            printf("%4d", i * j);
        }
        printf("\n");
    }

    return 0;
}

The recipe for every pattern question is the same, and it is worth memorising as a method rather than as individual answers.

  1. The outer loop controls rows. It runs once per line of output.
  2. The inner loop controls what appears on that line.
  3. Work out the relationship between the row number and the count. Here the row number i is exactly how many stars that row needs, so the inner loop runs j <= i times.
  4. Print the newline in the outer loop, after the inner loop finishes. Putting it inside the inner loop is the classic error that gives you one character per line.

For an inverted triangle, run the inner loop j <= rows - i + 1 times. For a pyramid, use two inner loops: one printing spaces, one printing stars.

Infinite loops

A loop whose condition never becomes false runs forever. Sometimes that is deliberate, as in while (1) with a break inside. Usually it is a bug, and it comes from one of three causes: the counter is never updated, it is updated in the wrong direction, or the condition can never be reached because of the step size.

If your program hangs in the terminal, press Ctrl and C together to stop it, then look at the update expression first.

Common mistakes

  • Semicolon after the loop header. for (int i = 0; i < 5; i++); ends the loop with an empty body. The block below then runs once. This compiles without error.
  • Off-by-one bounds. i <= n versus i < n differ by one full pass. For arrays of size n the correct form is almost always i < n.
  • Forgetting to update in a while. The condition stays true forever. Update inside the body, every path.
  • Missing semicolon after do-while. } while (x < 5) without the final semicolon is a compile error.
  • Printing the newline inside the inner loop. Nested pattern output collapses to one item per line. The newline belongs to the outer loop.
  • Reusing the same variable for both loops. Using i for outer and inner destroys the outer count. Use i and j.
  • Changing the counter inside the body of a for. It works, but it makes the loop very hard to reason about. Let the header own the counter.

Loops are where programs start doing real work. Write the multiplication table, the star triangle and a digit-sum program yourself before moving on. Then take on the graded versions on the Practice page.

Create a free account to track what you have finished.