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.
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.
- Less code – printing the numbers 1 to 100 takes three lines with a loop instead of one hundred lines without one.
- Fewer mistakes – you write the instruction once, so there is only one place where a typo could hide.
- Flexibility – the same loop can run 5 times or 5 000 times just by changing one number, so your program copes with any size of data.
- Processing collections – loops let you visit every item in a list, every learner in a class, or every character in a string, one at a time.
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?
- FOR – use it when you know the exact number of repeats. Analogy: climbing a staircase with a known number of steps — you count "step 1, step 2…" up to the top.
- WHILE – use it when you do not know how many times, and you must check first before doing anything. Analogy: filling a glass of water — you keep checking "is it full yet?" before each pour, and if the glass was already full you never pour at all.
- REPEAT…UNTIL – use it when you do not know how many times, but you must do the action at least once and check afterwards. Analogy: asking someone for their PIN — you always ask once, then check if it was right, and ask again only if it was wrong.
Types of Loops
| Loop | Type | Use when… |
|---|---|---|
for … do | Unconditional (fixed) | You know exactly how many times |
while … do | Conditional (pre-test) | Repeat WHILE a condition is true — check first |
repeat … until | Conditional (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.
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.
for counter := lowest to highest do
begin
// code repeated each iteration
end;for i := 1 to 5 do
begin
memOut.Lines.Add(IntToStr(i));
end;FOR … DOWNTO (counting down)
for i := 5 downto 1 do
begin
memOut.Lines.Add(IntToStr(i));
end;FOR Loop — Running Total
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.
var
cLetter: char;
begin
for cLetter := 'B' to 'F' do
memOut.Lines.Add(cLetter);
end;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.
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.
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:
| Step | What to check |
|---|---|
| Initialise | Has every variable used in the WHILE condition already been given a starting value before the loop is reached? |
| Test | Is that condition re-checked at the top of every pass, deciding whether the body runs again? |
| Change | Does something inside the body actually update the variable(s) being tested? Without this step the condition can never turn False. |
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.
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
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.
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;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.
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.
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 loop | Repeat 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. |
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.
var
i: Integer;
begin
i := 1;
repeat
memOut.Lines.Add(IntToStr(i));
i := i + 1;
until i > 10;
end;REPEAT — Validate input
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.
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;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?
| Situation | Best Loop |
|---|---|
| Print numbers 1 to 100 | for |
| Read until user types "stop" | while or repeat |
| Must run at least once (e.g. menu) | repeat |
| Unknown number of iterations | while or repeat |
| Process each element in an array | for |
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.
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.
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.
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;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.