Wat leer je in dit hoofdstuk?

Na dit hoofdstuk kan je:

uitleggen wat een loop en een iteratie zijn

de drie soorten loops onderscheiden: definite, indefinite en oneindig

loops schrijven met while, do while en for

een loop tracen en het juiste aantal iteraties tellen (off-by-one)

een oneindige loop herkennen en de scope in loops correct hanteren

geneste loops schrijven, in rijen en kolommen denken en het aantal iteraties berekenen

bewust omgaan met break en continue

Van branching naar herhalen

Met if konden we vertakken, maar niet teruggaan in ons algoritme.

Neem geld uit spaarpot
Wandel naar de dichtstbijzijnde bakker
Zolang de bakker toe is:
    Wandel naar de volgende bakker
Vraag om een brood
Betaal en keer huiswaarts

De test stuurt je nu terug naar een vorige plek in plaats van naar een stopbord.

Hoe vaak die zolang-stap draait weet je niet vooraf. Toch schrijf je ze maar één keer op.

Zonder loop typ je alles uit

Console.WriteLine("Ik zal niet spieken");
Console.WriteLine("Ik zal niet spieken");
Console.WriteLine("Ik zal niet spieken");
//...en zo nog 97 keer

Wil je die zin achteraf aanpassen, dan mag je honderd lijnen bijwerken en vergeet je er gegarandeerd eentje.

Elke ronde door een loop heet een iteratie.

Tip

Loops zitten in zowat elk programma dat je dagelijks gebruikt: je game tekent 60 keer per seconde een beeld, je mailprogramma overloopt alle nieuwe berichten, de zelfscankassa blijft scannen tot jij op afsluiten duwt.

Elke loop heeft drie zaken

Een startsituatie

een teller op 0, een variabele die nog leeg is

Een conditie

die getest wordt om te weten of er nog een iteratie volgt

Iets in het codeblok dat die conditie kan doen veranderen

de teller verhogen, nieuwe invoer vragen

Belangrijk

Vergeet je punt 3, dan blijft de conditie eeuwig waar en loopt je programma vast.

Soorten loops

De drie soorten loops.

Definite (counted)

aantal herhalingen vooraf gekend (getallen 0 tot 100)

Indefinite (sentinel)

input of een interne test bepaalt wanneer het stopt

Oneindig

stopt nooit (soms gewenst, zoals de game loop, vaak een bug)

Het bakkersalgoritme is een indefinite loop: het aantal gesloten bakkers ken je pas terwijl je aan het wandelen bent.

Loops in C#

while

draait 0 of meer keer

do while

draait minstens 1 keer

for

compacter wanneer je weet hoe vaak je moet herhalen

foreach

pas in hoofdstuk 12, wanneer we met objecten werken

Looptype Definite Indefinite Oneindig
while / do while x x x
for x

Tip

Met while kan je meer, en toch val je vaak terug op een for: die is compacter, en heel wat problemen zijn nu eenmaal definite loops.

While

De while-loop

int teller = 0;
while (teller < 100)
{
    teller++;
    Console.WriteLine(teller);
}

Zolang de conditie true is, draait het blok. Is ze meteen false, dan draait het blok nooit.

While-flowchart.

Belangrijk

De conditie zegt wanneer je doorgaat, niet wanneer je stopt. Onthoud dat, want straks bij de invoercontrole loopt het net daar mis.

Tracen: waarom staat 100 er nog bij?

int teller = 0;
while (teller < 100)
{
    teller++;
    Console.WriteLine(teller);
}

Deze loop toont 1 tot en met 100. Schrijf de rondes uit:

teller bij de test teller < 100 In de loop Op het scherm
0 true wordt 1 1
… … … …
99 true wordt 100 100
100 false loop stopt niets

Tip

Zo’n tabel uitschrijven heet een loop tracen. Loop je vast op een loop, teken dan met pen en papier de eerste twee en de laatste twee rondes uit. Dat gaat sneller dan gokken.

Niet enkel tellen: de sentinel

Een while mag evengoed een indefinite loop zijn. Geen teller te bespeuren:

int getal = 0;
while (getal != 666)
{
    Console.WriteLine("Geef een getal in (666 stopt):");
    getal = int.Parse(Console.ReadLine());
}

Zo’n stopwaarde heet een sentinel. De conditie mag ook complexer, met de logische operators uit hoofdstuk 5:

while (getal != 666 && pogingen < 10)

Belangrijk

getal krijgt een waarde vóór de loop. De test staat bovenaan en draait nog voor de gebruiker iets kon intikken. Die 0 dient enkel om de eerste test te laten slagen.

Oneindige loops

Bewust oneindig

while (true) { /* To infinity and beyond! */ }

Per ongeluk oneindig

int teller = 0;
while (teller < 10)
{
    Console.WriteLine(teller);
    teller--; // oeps, dit had teller++ moeten zijn
}
0
-1
-2
-3
…

Tip

Zorg dat de variabele uit je conditie effectief verandert, en in de juiste richting. Vastgelopen? Stop met de rode knop in Visual Studio, of pauzeer met Pause/Break.

Scope in loops

int teller = 1;
while (teller <= 10)
{
    int som = 0;     // FOUT: telkens terug op 0
    som = som + teller;
    teller++;
}
Console.WriteLine(som); // bestaat hier niet eens

Je verwacht 1, 3, 6, 10 en krijgt 1, 2, 3, 4. En buiten de accolades bestaat som gewoon niet: The name ‘som’ does not exist in the current context.

Belangrijk

Wil je een som bijhouden over de iteraties heen? Declareer som dan vóór de loop. En wat bevat teller na afloop? Niet 10, maar 11.

Do while

De do while-loop

int i = 10;
do
{
    i--;
    Console.WriteLine(i);
} while (i > 0);

Een do while draait minstens één keer: de conditie wordt pas na elke iteratie getest.

Do while-flowchart.

Waarschuwing

Let op de puntkomma na while (conditie);. Vergeten is een klassieke fout (bij een gewone while staat ze er niet).

While en do while naast elkaar

Op de flowchart is de ruit van plaats gewisseld.

De while en de do while naast elkaar.

Tel even mee

Welke getallen toont dit aftelprogramma precies?

int i = 10;
do
{
    i--;
    Console.WriteLine(i);
} while (i > 0);

9 tot en met 0. Dus niet 10 tot en met 1, en ook niet 10 tot en met 0.

9
8
7
6
5
4
3
2
1
0

Opmerking

Dezelfde val als bij de eerste while: we passen i aan vóór we hem tonen. Wil je 10 tot en met 1 zien, zet dan Console.WriteLine(i); vóór i--;.

Foute input opvangen

Blijven vragen tot de gebruiker a, b of c intikt. Denk in twee stappen.

Stap 1: wanneer is de invoer goed?

input == "a" || input == "b" || input == "c"

Stap 2: draai het om. De conditie zegt wanneer je doorgaat, dus zet er een ! voor:

string input;
do
{
    Console.WriteLine("Geef uw keuze: a, b of c");
    input = Console.ReadLine();
} while (!(input == "a" || input == "b" || input == "c"));

Even tussendoor: De Morgan

Dezelfde logica, anders geschreven:

!(input == "a" || input == "b" || input == "c")
input != "a" && input != "b" && input != "c"

Tip

De Wetten van De Morgan:

  • !(A && B) is hetzelfde als !A || !B
  • !(A || B) is hetzelfde als !A && !B

Welke van beide vormen je schrijft is persoonlijke smaak.

Waarom hier een do while?

Met een gewone while staat de test vooraan, en dan heeft input nog geen zinnige waarde. Twee omwegen, geen van beide fraai.

Omweg 1: de vraag één keer vóór de loop stellen, en nog eens erin.

Console.WriteLine("Geef uw keuze: a, b of c");
string input = Console.ReadLine();
while (input != "a" && input != "b" && input != "c") { /* ... */ }

Omweg 2: input een kunstmatige beginwaarde geven, enkel voor die eerste test.

string input = "";
while (input != "a" && input != "b" && input != "c") { /* ... */ }

Belangrijk

Declareer input vóór de loop: de test achteraan ligt buiten de accolades, dus in een andere scope.

For-loops

Van while naar for

Deze constructie komt zo vaak voor dat er een kortere schrijfwijze voor bestaat:

int i = 0;                 // startsituatie
while (i < 11)             // conditie
{
    Console.WriteLine(i);
    i = i + 2;             // dit doet de conditie veranderen
}

While en for naast elkaar

Bij de while liggen de drie stukken verspreid over de code, bij de for staan ze naast elkaar in de kop.

For: de drie delen

for (setup; finish test; update)
  1. setup (initializer): zet de teller op zijn beginwaarde (int i = 0)
  2. finish test (condition): de booleaanse test (i < 11)
  3. update (iterator): wat na elke iteratie gebeurt (i += 2)
for (int i = 0; i < 11; i += 2)
{
    Console.WriteLine(i);
}

De for-flowchart met de code erbij.

Tip

Typ for + tweemaal [tab] in Visual Studio voor een kant-en-klare for-loop.

De volgorde van de drie delen

De setup

loopt exact één keer, bij de start van de loop

De finish test

loopt vóór élke iteratie, dus ook vóór de allereerste

De update

loopt telkens ná het codeblok, niet ervoor

Omdat de test vooraan staat draait een for net als een while 0 of meer keer:

for (int i = 5; i < 3; i++)
{
    Console.WriteLine("Deze lijn zie je nooit.");
}

Tip

De teller heet meestal i, van index. Heb je er meerdere nodig, dan volgen j en k. Overloop je effectief rijen, noem hem dan gerust rij.

Stagiair Steven

Steven moet de getallen 1 tot en met 10 tonen. De A.I. gaf hem deze loop en hij plakt ze er meteen in:

for (int i = 1; i < 10; i++)
{
    Console.WriteLine(i);
}

“Van 1 tot 10, dat staat er toch?”, zegt hij. Tel even mee: welke getallen verschijnen er echt?

Stagiair Steven: wat liep er mis?

for (int i = 1; i < 10; i++)
{
    Console.WriteLine(i);
}
1
2
3
4
5
6
7
8
9

Opmerking

1 tot en met 9. De finish test i < 10 blijft waar zolang i kleiner is dan 10, dus bij i gelijk aan 10 stopt de loop nog net voor die laatste waarde. Wil Steven de 10 erbij, dan moet er i <= 10 staan (of i < 11). Zo’n vergissing van precies één te veel of te weinig heet een off-by-one-fout. Steven liet de A.I. de grens kiezen en telde zelf niet na.

Hoeveel keer loopt deze loop?

Header i neemt de waarden aan Aantal iteraties
for (int i = 0; i < 10; i++) 0 tot en met 9 10
for (int i = 1; i < 10; i++) 1 tot en met 9 9
for (int i = 1; i <= 10; i++) 1 tot en met 10 10
for (int i = 0; i <= 10; i++) 0 tot en met 10 11
for (int i = 10; i > 0; i--) 10 tot en met 1 10

Start je bij 0 en test je met <, dan staat het aantal iteraties letterlijk in de test. Start je bij 1, dan heb je <= nodig om even vaak te lopen.

Tip

De laatste rij telt af: de teller start op zijn hoogste waarde en de test draait mee om naar >. Met i < 10 zou daar niets gebeuren.

Scope van de teller

Schrijf je int i = 0 in de setup, dan hoort i bij de loop en verdwijnt hij erna:

for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i);
}
Console.WriteLine(i); // fout: 'i' does not exist in the current context

Heb je die eindwaarde nadien wél nodig, maak de variabele dan vóór de loop aan en laat de int weg:

int i;
for (i = 0; i < 10; i++) { /* ... */ }
Console.WriteLine(i); // toont 10

Tip

Kom je in die situatie terecht, vraag je dan eerst af of een while niet de duidelijkere keuze is.

Valkuil: een puntkomma achter de header

for (int i = 0; i < 10; i++);
{
    Console.WriteLine(i);
}

De loop krijgt een leeg codeblok: hij draait tien keer en doet tien keer niets. Het blok eronder hoort niet meer bij de loop.

Puntkomma achteraan?

if (conditie)

nee, fout

while (conditie)

nee, fout

} while (conditie)

ja, verplicht

for (setup; test; update)

nee, fout

Valkuil: de teller twee keer aanpassen

for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i);
    i++; // oeps, i gaat nu twee keer per ronde omhoog
}
0
2
4
6
8

Wil je stappen van 2, schrijf dan i += 2 in de header en laat de teller in het codeblok met rust.

Waarschuwing

Een for is bedoeld voor een definite loop. Wring je er een sentinel-loop in, dan blijft de update leeg (for (int getal = 0; getal != 666; )) en houd je enkel de omslachtige syntax over. Zulke code hoort in een while.

continue en break

for (int i = 1; i <= 10; i++)
{
    if (i == 5) continue;   // sla 5 over
    Console.WriteLine(i);
}

continue

stop de huidige iteratie, ga naar de volgende

break

stap meteen volledig uit de loop

Wat hier eigenlijk staat is “toon niets wanneer i gelijk is aan 5”, en dat schrijf je even goed zo:

if (i != 5) { Console.WriteLine(i); }

De goto-politie, deel 2

Olla!? Wat denken we dat we aan het doen zijn?

break en continue zijn de subtiele vrienden van goto. Probeer eerst je loop netjes te stoppen via een goede stopconditie. Met een continue in een while spring je bovendien zo over de verhoging van je teller heen, waarna je programma blijft hangen.

Tip

Wanneer is break wél oké? Bij zoek-en-stop: zodra je gevonden hebt wat je zocht, is verder zoeken zinloos. Gebruik het enkel als het je code echt duidelijker maakt.

Geneste loops

Nesting met een while

while (tellerA < 3)        // outer
{
    tellerA++;
    tellerB = 0;
    while (tellerB < 5)    // inner
    {
        tellerB++;
        Console.WriteLine($"A:{tellerA}, B:{tellerB}");
    }
}

Denk in rijen en kolommen: de outer loop overloopt de rijen, de inner de kolommen binnen zo’n rij.

Geneste loops.

Belangrijk

tellerB = 0 moet elke ronde gereset worden, anders blijft hij op 5 staan en draait de inner loop maar één keer.

Nesting met een for

for (int i = 1; i <= 3; i++)         // outer loop
{
    for (int j = 1; j <= 5; j++)     // inner loop
    {
        Console.WriteLine($"A:{i}, B: {j}");
    }
}

Dezelfde uitvoer, minder in de weg. Belangrijker: de reset zit gratis in de setup. Start de outer loop een nieuwe ronde, dan komt de volledige inner loop opnieuw aan de beurt, int j = 1 incluis.

Tip

Daarom worden geneste loops in de praktijk bijna altijd met een for geschreven: de vergeten reset kan je hier niet maken.

De volgorde van uitvoering

  1. Setup outer: i wordt 1 (één keer)
  2. Test outer: i <= 3
  3. Setup inner: j wordt 1 (elke ronde opnieuw)
  4. Test inner: j <= 5
  5. Codeblok van de inner loop
  6. Update inner: j++, terug naar 4
  7. Faalt de inner-test, dan pas i++, terug naar 2

De zeven stukken, genummerd in de volgorde waarin ze uitgevoerd worden.

Stappen 4, 5 en 6 draaien vijf keer voor er ook maar één keer aan stap 7 wordt toegekomen.

Rijen en kolommen op het scherm

for (int rij = 1; rij <= 5; rij++)
{
    for (int kolom = 1; kolom <= 5; kolom++)
    {
        Console.Write(rij * kolom + "\t");
    }
    Console.WriteLine();
}

Console.Write springt niet naar de volgende lijn, \t is een tab.

De outer loop gaat rij per rij naar beneden, de inner loop van links naar rechts.

Belangrijk

Die laatste Console.WriteLine(); staat binnen de outer loop, buiten de inner. Zet je ze in de inner loop, dan krijg je 25 lijnen met één getal. Zet je ze buiten de outer loop, dan komt alles op één lange lijn.

Geneste loops tellen

for (int i = 0; i < 10; i++)
{
    for (int j = 0; j < 5; j++)
    {
        Console.WriteLine("Hallo");
    }
}

Outer 10 keer, inner telkens 5 keer: 10 x 5 = 50 keer “Hallo”.

Waarschuwing

Elke extra laag vermenigvuldigt het werk. Twee loops van elk 1000 rondes leveren een miljoen uitvoeringen op, en met een derde erbij zit je aan een miljard.

En deze drie?

for (int i = 0; i < 3; i++)
    for (int j = 0; j < 10; j += 2)     // let op: j += 2
        for (int k = 0; k <= 6; k++)    // let op: k <= 6
            Console.WriteLine("Hallo");

Buitenste

3x

Middelste

5x (0, 2, 4, 6, 8)

Binnenste

7x (0 t/m 6)

Samen: 3 x 5 x 7 = 105 keer.

Als de inner loop van de outer afhangt

for (int rij = 1; rij <= 5; rij++)
{
    for (int kolom = 1; kolom <= rij; kolom++)
    {
        Console.Write("*");
    }
    Console.WriteLine();
}
*
**
***
****
*****

Waarschuwing

De test van de inner loop gebruikt hier rij. De inner loop draait dus 1, 2, 3, 4 en 5 keer: samen 15 sterretjes, en niet 5 x 5 = 25. Zodra de teller van de outer loop in de header van de inner opduikt, mag je niet meer zomaar vermenigvuldigen.

Valstrik: for met while erin

Hoe vaak verschijnt “Hallo”?

int teller = 0;
for (int j = 0; j < 4; j++)
{
    while (teller < 10)
    {
        Console.WriteLine("Hallo");
        teller++;
    }
}

Slechts 10 keer, niet 40! Na de eerste ronde staat teller al op 10 en draait de while nooit meer.

Belangrijk

Een for reset zijn teller gratis bij de setup; een while niet. Zet teller = 0; in de for-body om wel 40 keer te draaien.

break in geneste loops

break haalt je enkel uit de huidige loop. Uit beide springen doe je met een booleaanse vlag in de condities:

bool gevonden = false;
for (int i = 1; i <= 10 && !gevonden; i++)
{
    for (int j = 1; j <= 10 && !gevonden; j++)
    {
        if (i * j == 12)
        {
            Console.WriteLine($"Gevonden: {i} x {j}");
            gevonden = true;
        }
    }
}
Gevonden: 2 x 6

Zodra gevonden op true staat falen beide tests. De reden om te stoppen staat in de conditie zelf, waar een lezer ze verwacht.

Welke loop kies je?

Welke loop kiezen we?

Blijf wel kritisch over de opgave: de vereisten bepalen uiteindelijk je keuze.

De bekendste loop: de game loop

Elke game draait op een grote loop die blijft lopen tot het spel gedaan is:

bool gameOver = false;
while (!gameOver)
{
    // 1. Input verwerken
    // 2. Update (de spelwereld aanpassen)
    // 3. Render (op het scherm tekenen)
    System.Threading.Thread.Sleep(50); // 4. Even wachten
}

Input

Update

Render

Wachten

en opnieuw

Tientallen keren per seconde.

Een balletje dat stuitert

int x = 3, y = 3;     // positie
int xv = 1, yv = 1;   // snelheid (velocity)
while (true)
{
    x += xv;
    y += yv;
    if (x <= 0 || x >= Console.WindowWidth - 1)  xv = -xv;  // bots tegen de zijkant
    if (y <= 0 || y >= Console.WindowHeight - 1) yv = -yv;  // bots tegen boven/onder

    Console.Clear();
    Console.SetCursorPosition(x, y);
    Console.Write("O");
    System.Threading.Thread.Sleep(50);
}

Tip

Met enkel een lus, Console.SetCursorPosition en Thread.Sleep maak je al animatie. Console saai? Valt dus reuze mee.

Conclusie

Een loop herhaalt code; elke ronde is een iteratie

while (0 of meer keer) en do while (minstens 1 keer; let op de ;)

for is compact wanneer je een teller bijhoudt: setup, finish test, update

Let op oneindige loops, op off-by-one en op de scope van variabelen

Tel geneste loops door de iteraties te vermenigvuldigen, behalve wanneer de inner loop de teller van de outer gebruikt

Spaarzaam met break: schrijf liever een deftige stopconditie

Tip

Volgende halte: methoden, om je code op te delen in herbruikbare blokken.

Live: hoe warm is het nu?

We vragen het weer aan een website en laten een loop het werk doen.

Een website die tekst terugstuurt

                Geheel bewolkt
       .--.     +12(9) °C
    .-(    ).   ↖ 29 km/h
   (___.__)__)  10 km
                0.0 mm

https://wttr.in/Antwerpen

curl wttr.in/Antwerpen

Een website is ook maar een programma dat tekst terugstuurt. Kan ons programma die tekst ook vragen?

Drie regels magie

Console.OutputEncoding = System.Text.Encoding.UTF8;
HttpClient web = new HttpClient();
string antwoord = web.GetStringAsync("https://wttr.in/Antwerpen?format=3").Result;
Console.WriteLine(antwoord);
Antwerpen: 🌦️ +13°C

UTF8: anders worden ° en de emoji’s vraagtekens

HttpClient: een browser zonder scherm

.Result: het programma wacht tot het antwoord binnen is

De zaal kiest de stad

Console.Write("Stad (of stop): ");
string stad = Console.ReadLine();
while (stad != "stop")
{
    string url = "https://wttr.in/" + stad + "?format=3";
    string antwoord = web.GetStringAsync(url).Result;
    Console.WriteLine(antwoord);

    Console.Write("Stad (of stop): ");
    stad = Console.ReadLine();
}
Stad (of stop): Gent
Gent: ⛅️ +13°C
Stad (of stop): Tokio
Tokio: ☀️ +19°C
Stad (of stop): stop

Van tekst naar getal

string url = "https://wttr.in/" + stad + "?format=%t&m";
string antwoord = web.GetStringAsync(url).Result;    // "+13°C"
int temp = Convert.ToInt32(antwoord.Replace("°C", ""));

Console.Write(stad + " ");
for (int i = 0; i < temp; i++)
{
    Console.Write("█");
}
Console.WriteLine($" {temp}°C");
Antwerpen █████████████ 13°C
Tokio ███████████████████ 19°C

En in Oymyakon, Siberië?

Negatief? Neem de absolute waarde

if (temp < 0)
{
    Console.ForegroundColor = ConsoleColor.Cyan;
}
else
{
    Console.ForegroundColor = ConsoleColor.Red;
}
for (int i = 0; i < Math.Abs(temp); i++)
{
    Console.Write("█");
}
Console.ResetColor();
Antwerpen █████████████ 13°C
Oymyakon █████████████ -13°C

Rij tegen rij

Europa

Afrika

Azië

Amerika

Oceanië

int aantal = 0;
int warmste = -100;
string warmsteStad = "";
while (stad != "stop")
{
    // ... temperatuur ophalen en balk tekenen ...
    if (temp > warmste)
    {
        warmste = temp;
        warmsteStad = stad;
    }
    aantal++;
    // ... volgende stad vragen ...
}
Console.WriteLine($"Warmste van {aantal}: {warmsteStad} ({warmste}°C)");

En als de stad niet bestaat?

Stad (of stop): Xyzzyqq
Unhandled exception. System.AggregateException: One or more errors occurred.
(Response status code does not indicate success: 500 (Internal Server Error).)

De server antwoordt met een fout, en ons programma valt om. Opvangen doen we in H18 met exceptions.

Live: de treinreis-simulator

Alles uit dit hoofdstuk in één programma, stap voor stap.

De opdracht

Een trein rijdt langs stations (elk 5 km uit elkaar). Aan elk station stappen passagiers in en uit (de gebruiker geeft het in). Hou bij:

het totaal aantal passagiers

de totale afstand in km

Combineer alles uit dit hoofdstuk:

een while of for over de stations

een for voor laadbeurten van goederen

Random voor onverwachte gebeurtenissen (sneeuw, bandieten, …)

Eerst een plan

Rijden

Station

Uit en in

Laden

Pech?

volgend station

Elke stap is een stukje code dat al draait voor de volgende begint.

Stap 1: rijden langs de stations

Console.Write("Hoeveel stations? ");
int stations = Convert.ToInt32(Console.ReadLine());
int afstand = 0;
for (int station = 1; station <= stations; station++)
{
    for (int km = 1; km <= 5; km++)
    {
        Console.Write("==");
        System.Threading.Thread.Sleep(200);
    }
    afstand += 5;
    Console.WriteLine($"> Station {station} ({afstand} km)");
}
Hoeveel stations? 3
==========> Station 1 (5 km)
==========> Station 2 (10 km)
==========> Station 3 (15 km)

Stap 2: in- en uitstappen

int aanBoord = 0;
int totaalPassagiers = 0;
// ... in de for, aan het station:
int uitstappers;
do
{
    Console.Write($"  {aanBoord} aan boord. Uitstappen: ");
    uitstappers = Convert.ToInt32(Console.ReadLine());
} while (uitstappers < 0 || uitstappers > aanBoord);
Console.Write("  Instappen: ");
int instappers = Convert.ToInt32(Console.ReadLine());
aanBoord = aanBoord - uitstappers + instappers;
totaalPassagiers += instappers;
==========> Station 2 (10 km)
  4 aan boord. Uitstappen: 7
  4 aan boord. Uitstappen: 1
  Instappen: 2

Stap 3: goederen laden

Random rnd = new Random();
int kisten = 0;
// ... in de for, aan het station:
int laden = rnd.Next(0, 4);
Console.Write($"  {laden} kisten laden: ");
for (int k = 1; k <= laden; k++)
{
    Console.Write("[#] ");
    System.Threading.Thread.Sleep(300);
}
Console.WriteLine();
kisten += laden;
  3 kisten laden: [#] [#] [#]
  0 kisten laden:

Stap 4: pech onderweg

int vertraging = 0;
// ... in de for, aan het station:
int kans = rnd.Next(1, 11);
if (kans == 1)
{
    Console.WriteLine("  Sneeuw! 10 minuten vertraging.");
    vertraging += 10;
}
else if (kans == 2)
{
    Console.WriteLine("  Bandieten! Ze stelen alle kisten.");
    kisten = 0;
}

1 kans op 10 op sneeuw, 1 kans op 10 op bandieten.

Eindstation

// ... na de for:
Console.WriteLine($"Aangekomen na {afstand} km.");
Console.WriteLine($"{totaalPassagiers} passagiers vervoerd, {kisten} kisten geleverd.");
Console.WriteLine($"Vertraging: {vertraging} minuten.");
Aangekomen na 25 km.
14 passagiers vervoerd, 6 kisten geleverd.
Vertraging: 10 minuten.

Wat staat er binnen de loop, en wat erbuiten?

Meer weten

Kennisclips

Alle kennisclips van H6: 12 korte clips over while, do while, invoer controleren, for, off-by-one, break en continue en geneste loops

Oefeningen H6 · Quizlet flashcards

Zie verder

Hoe doen andere programmeertalen hetzelfde? En een korte zoek-de-fout, om zo kritisch mogelijk naar code te leren kijken.

Zie verder: do-while bestaat niet overal

De do while ken je terug in C, C++, Java en JavaScript. Python heeft hem niet. Iets dat minstens één keer draait, bootst men er na met while True + break:

while True:
    keuze = input("Geef uw keuze: a, b of c ")
    if keuze in ("a", "b", "c"):
        break

In Python ben je dus vaak verplicht om break te gebruiken waar C# een nette stopconditie achteraan de do while toelaat.

Zie verder: de for-loop elders

De drie-delige for komt uit C en is bijna letterlijk overgenomen door C++, Java en JavaScript:

for (int i = 0; i < 11; i += 2) {
    System.out.println(i);
}

In C-code duikt ook for(;;) op: alle drie de delen mogen leeg blijven, wat een oneindige loop oplevert. Dat mag in C# evengoed, al schrijft zowat iedereen daar while(true).

Zie verder: tellen in Python

Python kent geen teller-met-conditie: je loopt er altijd over iets. Tellen doe je met range:

for i in range(0, 11, 2):   # van 0 tot (niet incl.) 11, stap 2
    print(i)

Losse setup, conditie en update zijn er dus niet, die zitten verstopt in range. Dat werkt enkel als je vooraf weet over welke reeks je loopt.

Zie verder: zoek de fout

Onderstaande Java-code wil de getallen 1 tot en met 5 onder elkaar tonen, maar het programma blijft draaien en stopt nooit. Wat loopt er mis?

int i = 1;
while (i <= 5)
{
    System.out.println(i);
}

Opmerking

De variabele i uit de testconditie wordt nergens in de loop aangepast. i blijft dus altijd 1, de test i <= 5 blijft eeuwig true en je krijgt een oneindige loop die telkens 1 print. Voeg i++; toe binnen de accolades, dan loopt de teller op tot de test faalt.

Samenvattende poster

Alles uit dit hoofdstuk op één A4.

Download de poster als pdf

Twee uur wachten op een rooster

Twee uur gewacht op een rooster dat klaar was na

4

minuten.

Na twee uur: crash, maar het rooster lag er wel

Nooit gestopt met zoeken

Een loop die zijn stopconditie nooit haalde.