Lesson 4 · ~14 min · ← Lesson 3

Loops: for, while, do-while, foreach

Four loops, one mental model: repeat a body while a condition holds. The differences are about where the counting lives and what you're iterating over.

for: when you know how many times

Three clauses in the header — start, keep-going test, step:

for (int i = 1; i <= 5; i++)   // start i at 1; repeat while i <= 5; i++ after each pass
{
    Console.Write(i * 2 + " ");
}
Console.WriteLine();

The loop variable i is born and dies inside the for — trying to use it after the loop is error CS0103.

The accumulator pattern

The single most useful loop shape: a variable declared before the loop, updated every pass:

int sum = 0;                    // accumulator starts at 0 — always
int count = 0;
for (int i = 1; i <= 5; i++)
{
    sum += i;                   // fold each value in
    count++;
}
Console.WriteLine($"sum: {sum}, count: {count}");

while: when you DON'T know how many times

// double a number until it passes 10 — how many passes? we don't know yet
int n = 1;
while (n <= 10)
{
    Console.WriteLine(n);
    n = n * 2;          // without this line: infinite loop (see below)
}

Rule: something inside the body must move the condition toward false. The engine here has a step-watchdog that stops runaway loops instead of freezing your tab — in Visual Studio, an infinite loop just… runs.

do-while: check AFTER, run at least once

Classic for input validation — ask first, then decide whether to ask again:

string[] attempts = { "abc", "-5", "42" };
int pos = 0;
int value;

do
{
    int.TryParse(attempts[pos], out value);   // try to parse the next attempt
    pos++;
} while (value <= 0);                        // loop again if we didn't get a positive number

Console.WriteLine("accepted: " + value);

A plain while checks before the first pass — if the condition is false immediately, the body never runs. do-while guarantees one pass. That difference is exactly why Count the Digits solves its n = 0 edge case with a do-while.

foreach: over a collection, no counting at all

int[] scores = { 72, 95, 88 };

foreach (int s in scores)        // "for each element, call it s"
{
    Console.WriteLine("score: " + s);
}

Console.Write("letters in Ada: ");
foreach (char c in "Ada")        // strings are sequences of chars
{
    Console.Write(c + " ");
}
Console.WriteLine();

break and continue: steering from inside

int[] scores = { 72, 95, 88 };

// break: leave the loop entirely (first match)
for (int i = 0; i < scores.Length; i++)
{
    if (scores[i] > 90)
    {
        Console.WriteLine($"found {scores[i]} at index {i}");
        break;
    }
}

// continue: skip the rest of THIS pass only
for (int i = 1; i <= 5; i++)
{
    if (i % 2 == 0) continue;   // skip evens
    Console.Write(i + " ");
}

Nested loops: the multiplication table corner

for (int row = 1; row <= 3; row++)
{
    for (int col = 1; col <= 3; col++)
    {
        Console.Write(row * col + " ");
    }
    Console.WriteLine();       // newline after each row — note WHERE it sits
}

The inner loop runs completely for every single step of the outer one: 3 × 3 = 9 prints. The classic beginner bug is putting the WriteLine() inside the inner loop (every number on its own line) or outside both (everything on one line) — run it and move it around until the shape makes sense.

Which loop when?

LoopReach for it when…Signature move
forYou know how many passes (or the range)Counting: for (int i = 0; i < n; i++)
whileRepeat until a condition changes; maybe zero timesSentinel: "until input is valid"
do-whileSame, but at least onceMenu / retry prompts
foreachYou want the elements, not the indexesSumming, printing a collection

Practice this now