Loops Grade 10

Loops repeat a block of code multiple times. Delphi has three loop types — choose based on whether you know how many times to repeat.

T3Term 3 · Loops & Repetition Structures

What is a Loop?

A loop is a programming structure that repeats a block of code over and over until a certain point is reached. Instead of writing the same instruction many times, you write it once and tell the computer how often, or until when, to repeat it.

Everyday analogy: Think of doing push-ups. The coach does not shout "do a push-up" fifty separate times. He says "do fifty push-ups." That single instruction, repeated until you reach fifty, is a loop. The action (one push-up) is the loop body, and "fifty" is the condition that tells you when to stop.

Why Do We Use Loops?

Loops save us from repeating ourselves and let programs handle any amount of work with the same short piece of code.

The Three Loop Types in Plain Words

Choosing the right loop comes down to one question: do you know in advance how many times to repeat?

Types of Loops

LoopTypeUse when…
for … doUnconditional (fixed)You know exactly how many times
while … doConditional (pre-test)Repeat WHILE a condition is true — check first
repeat … untilConditional (post-test)Repeat UNTIL a condition is true — always runs at least once

FOR Loop (Fixed / Unconditional)

Runs a set number of times. The counter increments or decrements automatically.

We call it fixed or unconditional because the number of repeats is decided before the loop even starts and cannot change while it runs. You give it a start value and an end value, and Delphi handles the counting for you — you never have to add 1 to the counter yourself.

WHEN TO USE

Reach for a FOR loop whenever you can finish the sentence "do this exactly ___ times" with a number — printing 1 to 10, working through all 30 learners in a class, or drawing 12 rows of a table.

THE FOR LOOP Keyword — starts the loop Keyword — leads into the repeated code for i := 1 to 5 do Counter — created and incremented automatically Start value End value — loop stops once this is reached
Syntax — counting UP
for counter := lowest to highest do
begin
  // code repeated each iteration
end;
Delphi — print 1 to 5
for i := 1 to 5 do
begin
  memOut.Lines.Add(IntToStr(i));
end;

FOR … DOWNTO (counting down)

Delphi — countdown 5 to 1
for i := 5 downto 1 do
begin
  memOut.Lines.Add(IntToStr(i));
end;

FOR Loop — Running Total

Delphi — sum 1 to 10
var
  i, iTotal: Integer;
begin
  iTotal := 0;  // initialise!
  for i := 1 to 10 do
    iTotal := iTotal + i;
  lblTotal.Caption := 'Sum = ' + IntToStr(iTotal);
end;

FOR Loop — the Counter Can Be Any Ordinal Type

A FOR loop's counter does not have to be an Integer — it can be declared as any ordinal type, provided the start value, end value and the counter variable itself all agree on that type. A Char counter, for instance, steps through the alphabet one letter at a time instead of counting through numbers.

Delphi — listing the letters 'B' to 'F'
var
  cLetter: char;
begin
  for cLetter := 'B' to 'F' do
    memOut.Lines.Add(cLetter);
end;
Keep the case consistent

A start value in uppercase paired with an end value in lowercase (or the reverse) will not behave the way you expect — uppercase and lowercase letters occupy separate blocks in the ASCII table, so mixing them changes how far apart the two values actually are, and therefore how many times the loop runs. Pick one case and stick to it for both bounds.

WHILE … DO Loop (Pre-Conditional)

Checks the condition before each iteration. If the condition is false from the start, the loop body never runs.

We call it pre-conditional ("pre" = before) because it tests the condition first, and only then decides whether to run the body. This makes it the safe choice when there is a chance the loop should not run at all.

WHEN TO USE

Use WHILE when you do not know how many repeats you need and it might be zero — for example, "keep reading numbers while the user hasn't typed 0". If they type 0 immediately, you correctly do nothing.

Syntax
while condition do
begin
  // code
end;

The ITC-Principle

A handy checklist for building a correct WHILE loop is the ITC-principle — three things that must all be true of your code, in this order:

StepWhat to check
InitialiseHas every variable used in the WHILE condition already been given a starting value before the loop is reached?
TestIs that condition re-checked at the top of every pass, deciding whether the body runs again?
ChangeDoes something inside the body actually update the variable(s) being tested? Without this step the condition can never turn False.
Avoid Infinite Loops

The counter must be initialised before the loop and incremented inside the loop — otherwise it runs forever and crashes your program. Also never put a ; straight after the do keyword — while condition do; creates an empty loop body, so the statement that was meant to change the condition is skipped, and the loop runs forever.

Delphi — while counter ≤ 5
var
  Counter: Integer;
begin
  Counter := 1;           // initialise BEFORE loop
  while Counter <= 5 do
  begin
    memOut.Lines.Add('Counter: ' + IntToStr(Counter));
    Inc(Counter);          // increment INSIDE loop
  end;
end;

WHILE — Reading user input until sentinel

Delphi — keep adding until user enters 0
var
  iNum, iTotal: Integer;
begin
  iTotal := 0;
  iNum   := StrToInt(InputBox('Input', 'Enter number (0 to stop):', ''));
  while iNum <> 0 do
  begin
    iTotal := iTotal + iNum;
    iNum   := StrToInt(InputBox('Input', 'Enter number (0 to stop):', ''));
  end;
  lblTotal.Caption := 'Total: ' + IntToStr(iTotal);
end;

Letting the User Interrupt a Loop While It Runs

A different situation arises when nobody knows how many times a loop should run until the user physically clicks a [Stop] Button partway through — a reaction game or a live counter are typical examples. This needs a Boolean variable that both the button that starts the loop and the button that stops it can share, so it must be declared in the private section of the form (giving it class scope) rather than inside a single procedure.

Delphi — a running counter the user can interrupt
private
  bRunning : boolean;   // shared by both button handlers below

procedure TForm1.btnGoClick(Sender: TObject);
var
  iTick : byte;
begin
  bRunning := True;
  iTick    := 0;
  while bRunning do
  begin
    Inc(iTick);
    memLog.Lines.Add(IntToStr(iTick));
    Sleep(300);                    // short pause so the numbers are readable
    Application.ProcessMessages;   // give the form a chance to react to the click
  end;
end;

procedure TForm1.btnHaltClick(Sender: TObject);
begin
  bRunning := False;
end;
Why Application.ProcessMessages matters here

A Delphi form normally deals with one event at a time, finishing the current event handler completely before looking at the next. While btnGoClick is stuck inside its loop, a click on [Halt] just waits in a queue rather than running immediately. Application.ProcessMessages is a command that tells the program to pause for a moment and clear that queue — handling any waiting clicks — before the loop carries on. Leave it out, and the [Halt] click is never processed until the loop finishes on its own, which defeats the purpose of having a stop button at all.

REPEAT … UNTIL Loop (Post-Conditional)

Runs the body first, then checks the condition. Guaranteed to run at least once. Loop continues while condition is false; stops when it becomes true.

We call it post-conditional ("post" = after) because it does the work first and asks the question afterwards. That is the opposite of the WHILE loop, and it is exactly what you want when the action must happen at least one time no matter what.

WHEN TO USE

Use REPEAT…UNTIL when the body must run at least once — like showing a menu and asking the user to choose, or asking for a valid mark and re-asking until they get it right. You always ask once, then keep asking until the answer is acceptable.

Syntax
repeat
  // code
until condition;

REPEAT follows the same three checks as the WHILE loop's ITC-principle, only in a swapped order — Initialise, Change, then Test — since the body always fires once before the condition is ever looked at. Lining the two loops up side by side shows how they really are opposites of each other:

While loopRepeat loop
Suited to situations where it is fine for the loop to run zero times.Suited to situations where the body must run at least once.
Keeps looping while the condition stays True.Keeps looping until the condition finally becomes True.
Order of checks: ITC — Initialise, Test, Change.Order of checks: ICT — Initialise, Change, Test.
Prefer >= over = in a termination test

Testing for an exact match can trap you in an infinite loop if the value ever skips straight past the target — for example a running score that jumps from 46 to 52 will never satisfy until iScore = 50. Writing until iScore >= 50 instead guarantees the loop will stop even if the value overshoots.

Delphi — repeat until i = 10
var
  i: Integer;
begin
  i := 1;
  repeat
    memOut.Lines.Add(IntToStr(i));
    i := i + 1;
  until i > 10;
end;

REPEAT — Validate input

Delphi — keep asking until valid mark
var
  iMark: Integer;
begin
  repeat
    iMark := StrToInt(InputBox('Mark', 'Enter mark (0-100):', ''));
    if (iMark < 0) OR (iMark > 100) then
      ShowMessage('Invalid! Enter 0-100');
  until (iMark >= 0) AND (iMark <= 100);
end;

Worked Example — Count, Average & Highest

One loop can gather several answers at once. Here we read marks until the user enters -1, and while looping we keep a counter, a running total and the highest so far — then work out the average at the end.

Delphi — statistics from a loop
var
  iMark, iCount, iTotal, iHighest : Integer;
  rAverage : Real;
begin
  iCount   := 0;      // initialise all three trackers before the loop
  iTotal   := 0;
  iHighest := 0;

  iMark := StrToInt(InputBox('Marks', 'Enter a mark (-1 to stop):', ''));
  while iMark <> -1 do
  begin
    Inc(iCount);                 // how many so far
    iTotal := iTotal + iMark;    // running total
    if iMark > iHighest then    // track the maximum
      iHighest := iMark;
    iMark := StrToInt(InputBox('Marks', 'Enter a mark (-1 to stop):', ''));
  end;

  if iCount > 0 then            // guard against dividing by zero
  begin
    rAverage := iTotal / iCount;
    memOut.Lines.Add('Count:   ' + IntToStr(iCount));
    memOut.Lines.Add('Average: ' + FloatToStrF(rAverage, ffFixed, 4, 1));
    memOut.Lines.Add('Highest: ' + IntToStr(iHighest));
  end
  else
    ShowMessage('No marks were entered.');
end;
The pattern

Initialise your trackers before the loop, update them inside it (add to the total, compare for the highest), and report after it. Always check iCount > 0 before dividing, or an empty run will crash with a divide-by-zero.

Comparison: Which Loop to Use?

SituationBest Loop
Print numbers 1 to 100for
Read until user types "stop"while or repeat
Must run at least once (e.g. menu)repeat
Unknown number of iterationswhile or repeat
Process each element in an arrayfor

Loop Control — How a Loop Is Controlled

Beyond picking FOR, WHILE or REPEAT, it is useful to describe what decides when a loop stops. This splits loops into two broad groups: definite repetition, where the number of passes can be worked out ahead of time, and indefinite repetition, where it cannot.

Counter Controlled Loops (Definite Repetition)

A counter controlled loop relies on a variable that starts at a known value, changes by a predictable amount on every pass, and is compared to a fixed target to decide whether to continue.

Because that change is predictable, you can always calculate in advance exactly how many times a counter controlled loop will run — a FOR loop is the most obvious example, but a WHILE or REPEAT loop built around a simple counter is counter controlled too.

Delphi — counter controlled WHILE loop: 8 times table
iRow := 1;
while iRow <= 10 do
begin
  iResult := iRow * 8;
  memOut.Lines.Add(IntToStr(iRow) + ' x 8 = ' + IntToStr(iResult));
  iRow := iRow + 1;
end; {while}

Sentinel Controlled Loops (Indefinite Repetition)

A sentinel controlled loop watches for a special "stop" value — a sentinel — typed in by the user. That value is only ever compared, never used in a calculation, since its whole job is to signal "no more data."

The "WHILE — Reading user input until sentinel" example further up this page is a sentinel controlled loop: 0 is the signal that tells it to stop. Since nobody can predict how many real numbers the user will enter before typing that sentinel, the number of passes is unknown in advance — which is why sentinel controlled loops fall under indefinite repetition.

Result Controlled Loops (Indefinite Repetition)

A result controlled loop keeps going until a particular outcome has actually happened — it is not driven by a counter reaching a target or a user typing a sentinel, but by whatever condition the program is watching for finally becoming true.

Delphi — spin a wheel of 8 prizes until the jackpot slot comes up
iSpins := 0;
repeat
  iSlot := Random(8) + 1;
  Inc(iSpins);
until iSlot = 8;
ShowMessage('Jackpot landed after ' + IntToStr(iSpins) + ' spins');

Nothing here counts down towards a known number of repeats, and there is no value the user types to signal "stop" — the loop simply keeps spinning until the result it is watching for (slot 8) actually comes up.

Nested Loops

A nested loop is simply a loop placed inside the body of another loop. Each time the outer loop takes one step, the inner loop runs through its entire range from start to finish before the outer loop is allowed to take its next step. The inner and outer loops don't have to be the same kind — a FOR loop can quite happily sit inside a WHILE loop, or inside another FOR loop.

Suppose an exam venue needs a code for every seat: a block letter ('A' to 'C'), a row number (1 to 3) and a seat letter within the row ('a' to 'c'). Three nested FOR loops can generate the complete list in one go.

Delphi — three nested FOR loops listing every seat code
procedure TfrmVenue.btnListSeatsClick(Sender: TObject);
var
  iRow : integer;
  cBlock, cSeat : char;
  iSeatCount : integer;
  sSeatCode : string;
begin
  iSeatCount := 0;
  for cBlock := 'A' to 'C' do       // outer loop
  begin
    for iRow := 1 to 3 do          // middle loop
    begin
      for cSeat := 'a' to 'c' do       // inner loop
      begin
        sSeatCode := cBlock + IntToStr(iRow) + cSeat;
        Inc(iSeatCount);
        memSeats.Lines.Add(sSeatCode);
      end; // for cSeat
    end; // for iRow
  end; // for cBlock
  memSeats.Lines.Add('Total seats = ' + IntToStr(iSeatCount));
end;
Tracing the order the loops fire

Follow the innermost loop first: cSeat runs all the way through 'a', 'b', 'c' before iRow is even allowed to move on to its next value. Only once iRow has itself been through 1, 2 and 3 — meaning the middle loop has fully finished for the current block — does cBlock step forward to its next letter. The resulting list reads A1a, A1b, A1c, A2a, A2b, A2c, A3a, A3b, A3c, B1a, … and finishes at Total seats = 27, since 3 blocks × 3 rows × 3 seats gives 27 combinations in total.