Programmeren, de basis/De controlestructuren

Uit Wikibooks

Via controlestructuren kan je de manier waarop je programma wordt uitgevoerd beïnvloeden. We baseren ons voor dit hoofdstuk op de oefening met de prijsofferte, waarbij we gebruikmaken van zaken die al bepaald zijn, zoals de constanten en variabelen.

Nassi-Schneidermann diagrammen, kortweg NS-diagrammen of ook wel structogrammen genoemd, zijn een goed middel om algoritmen voor te stellen, doordat het automatisch leidt tot gestructureerd werken. In onderstaand schema worden de verscheidene controlestructuren, samen met hun overeenkomstige NS-diagrammen weergegeven.

Sequentie of opeenvolging[bewerken]

Een opeenvolging van opdrachten betekent dat als de eerste van die opdrachten wordt uitgevoerd ook de opdrachten die volgen zullen worden uitgevoerd. Voorlopig gaan we hier niet verder op ingaan, daar sequenties heel makkelijk herkend kunnen worden, daar ze tussen de andere controlestructuren inzitten.

Keuze of selectie (conditioneel verloop)[bewerken]

Enkelvoudig[bewerken]

NS-diagram
Pseudocode
VBA
PHP
Als <voorwaarde> Dan
<instructie 1>
<instructie 2>
...
<instructie n>
If <voorwaarde> Then
<instructie 1>
<instructie 2>
...
<instructie n>

End If

if (<voorwaarde>) {
<instructie 1>;
<instructie 2>;
...
<instructie n>;

}

Tweevoudig[bewerken]

NS-diagram
Pseudocode
VBA
PHP
Als <voorwaarde> Dan
<instructie 1>
<instructie 2>
...
<instructie n>

Anders

<instructie a>
<instructie b>
<instructie ...>
If <voorwaarde> Then
<instructie 1>
<instructie 2>
<instructie n>

Else

<instructie a>
<instructie b>
<instructie ...>

End If

if (<voorwaarde>) {
<instructie 1>;
<instructie 2>;
<instructie n>;

} else {

<instructie a>;
<instructie b>;
<instructie ...>;

}

Meervoudig[bewerken]

NS-diagram
Pseudocode
VBA
PHP
Selecteer Geval <variabele>
Geval <expressielijst 1>
<instructieblok 1>
Geval <expressielijst 2>
<instructieblok 2>
Select Case <variabele>
Case: <expressielijst 1>
<instructieblok 1>
Case <expressielijst 2>
<instructieblok 2>

End Select

switch (<variabele>) {
case <expressielijst 1>:
<instructieblok 1>
case <expressielijst 2>:
<instructieblok 2>

}

Herhaling of iteratie (lusverloop)[bewerken]

Begrensd[bewerken]

Het kopieercentrum[bewerken]

Stel dat je vier kopieën van een blad nodig hebt. Wellicht zal je het volgende stappenplan in een kopieercentrum niet gebruiken:

  • Gebruiker stopt blad in kopieerapparaat.
  • Gebruiker drukt op de kopie-knop.
  • Kopieertoestel maakt kopie en geeft het blad terug aan de gebruiker.
  • Gebruiker stopt blad in kopieerapparaat.
  • Gebruiker drukt op de kopie-knop.
  • Kopieertoestel maakt kopie en geeft het blad terug aan de gebruiker.
  • Gebruiker stopt blad in kopieerapparaat.
  • Gebruiker drukt op de kopie-knop.
  • Kopieertoestel maakt kopie en geeft het blad terug aan de gebruiker.
  • Gebruiker stopt blad in kopieerapparaat.
  • Gebruiker drukt op de kopie-knop.
  • Kopieertoestel maakt kopie en geeft het blad terug aan de gebruiker.

Je zou nog kunnen stellen dat dit voor vier kopieën makkelijk te doen is, maar voor honderd is dit niet vol te houden. Beter is onderstaand algoritme:

  1. Gebruiker stopt blad in kopieerapparaat
  2. Gebruiker stelt '100' in als 'aantal kopieën'.
  3. Het kopieertoestel maakt een beeldbestand van het blad.
  4. Het kopieertoestel maakt een kopie a.d.h.v. het beeldbestand.
  5. Het kopieertoestel vermindert het nog te maken kopiëen met 1
  6. Keer terug naar stap 4, zolang het aantal te maken kopieën nog geen 0 is.

Doordat we bepaalde stappen herhalen spreken we hier dan ook over een 'herhaling'. Omdat het aantal stappen op voorhand gekend is, spreken we meer specifiek over een 'begrensde herhaling'.

Tellen en de tafels van vermenigvuldiging[bewerken]

Stel dat je een computer wil laten tellen tot vier, dan kan dat gemakkelijk met onderstaande (pseudo)code.

  1. print 1
  2. print 2
  3. print 3
  4. print 4

Wil je hem echter tot 100 laten tellen, dan zou je ook 100 regels code moeten schrijven. Zoiets is niet efficiënt. Beter is:

  1. totaal is 100
  2. teller is 1
  3. print teller
  4. verhoog de teller
  5. zolang de teller kleiner is dan het totaal, ga naar stap 3

Deze oefening kan je uitbreiden om de tafels van vermenigvuldiging te laten berekenen.

Een overzicht[bewerken]

NS-diagram
Pseudocode
VBA
PHP
Voor <variabele>= … tot …
<instructieblok>
For <teller>= begin To einde
<instructieblok>

Next

for ( … ; … ; … ) {
<instructieblok 1>

}

Voorwaardelijk herhaling met beginvoorwaarde[bewerken]

NS-diagram
Pseudocode
VBA
PHP
Zolang <voorwaarde>
<instructieblok>
Do While <voorwaarde>
<instructieblok>

Loop

while (<voorwaarde>) {
<instructieblok>

}

NS-diagram
Pseudocode
VBA
PHP
Totdat <voorwaarde>
<instructieblok>
Do Until <voorwaarde>
<instructieblok>

Loop


Voorwaardelijk herhaling met eindvoorwaarde[bewerken]

NS-diagram
Pseudocode
VBA
PHP
Doe
<instructieblok>

Zolang <voorwaarde>

Do
<instructieblok>

Loop While <voorwaarde>

do {
<instructieblok>

} while (<voorwaarde>)


NS-diagram
Pseudocode
VBA
PHP
Doe
<instructieblok>

Totdat <voorwaarde>

Do
<instructieblok>

Loop Until <voorwaarde>

Genest[bewerken]

Dit is een combinatie van sequenties, keuzes en/of herhalingen.

Hieronder zie je in pseudocode een voorbeeld, waarbij een begrensde herhaling genest is binnen een enkelvoudige keuze.

Als <voorwaarde> Dan
	<instructie 1>
	<instructie 2>
	Voor <variabele>= … tot …
		<instructieblok>
	<instructie 3>


Oefeningen[bewerken]

Taalrapport[bewerken]

We kunnen deze probleemstelling als volgt formuleren:

Als ptnTotaal > 50 Dan

toon afbeelding geslaagd
boodschap = "Proficiat, je bent geslaagd!"

Anders

toon afbeelding niet geslaagd
boodschap = "Jammer, je bent niet geslaagd. Je zal nog flink moeten studeren!"

Tekstvak met kleur[bewerken]

Select Geval txtKleur

Geval "rood"
maak achtergrond rood
Geval "groen"
maak achtergrond groen
Geval "geel"
maak achtergrond geel
Geval "blauw"
maak achtergrond blauw
Geval "zwart"
maak achtergrond zwart

Prijsofferte[bewerken]

Keuze of selectie (conditioneel verloop)[bewerken]

Enkelvoudig[bewerken]

Het aantal termijnen mag niet meer dan 12 (de constante maxAantalTermijnen) bedragen. Als deze overschreden wordt moet een gepaste boodschap verschijnen:

'Declareren variabelen
termijn als reëel getal
aantalTermijnen als geheel getal
boodschap als tekst

aantalTermijnen = teBetalen / termijn

Als aantalTermijnen > maxAantalTermijnen Dan

termijn = teBetalen / maxAantalTermijnen
'Voorbeeld: De termijn van 12 maanden is overschreden. De termijn 136,15 EUR wordt gebruikt.
boodschap = "De termijn van " & maxAantalTermijnen & " maanden is overschreden. De termijn " & termijn & " EUR wordt gebruikt."
toon boodschap

Als je de oefening leest merk je ook een keuze bij de ouderdom van het huis (de drempelwaarde om over een oud huis te spreken is 20 jaar en wordt voorgesteld door de constante drempelOudHuis. Dit levert bij een oud huis een BTW-waarde op van 6 % (btwOudHuis) en bij een nieuw huis een BTW-waarde van 21 %). Schematisch voorgesteld wordt dit:

Als ouderdomHuis > drempelOudHuis Dan

BTW = btwOudHuis

Als ouderdomHuis <= drempelOudHuis Dan

BTW = btwNieuwHuis

Het zou op deze manier weliswaar werken, maar toch kan het beter. De ouderdom van het huis wordt namelijk twee keer gecontroleerd. Als een huis echter ouder is dan 20 jaar, dan volgt daar onmiddellijk uit dat het niet jonger zal zijn dan 20 jaar. Omgekeerd geldt ook dat als een huis niet ouder is dan 20 jaar, dit automatisch betekent dat het jonger moet zijn dan 20 jaar.

Voor dit onderdeel is het beter om gebruik te maken van een tweevoudige i.p.v. een enkelvoudige keuze.

Tweevoudig[bewerken]

Voor de ouderdom van het huis kunnen we dus beter gebruikmaken van een tweevoudige keuze, wat de uitvoer van ons programma sneller zal maken:

Als ouderdomHuis > drempelOudHuis Dan
    BTW = btwOudHuis
Anders
    BTW = btwNieuwHuis

Voor het bepalen van de verplaatsingskosten merken we ook een keuze:

Als provincieKlant = Oost-Vlaanderen Dan
    verplaatsingskosten = kostNrOVl
Als provincieKlant = West-Vlaanderen Dan
    verplaatsingskosten = kostNrWVl
Als provincieKlant = Antwerpen Dan
    verplaatsingskosten = kostNrAnt
Als provincieKlant = Limburg Dan
    verplaatsingskosten = kostNrLi

Hier maken we echter opnieuw de fout dat we vier keer controleren in welke provincie de klant woont, dus dat kan beter.

Als provincieKlant = Oost-Vlaanderen Dan
    verplaatsingskosten = kostNrOVl
Anders
    Als provincieKlant = West-Vlaanderen Dan
        verplaatsingskosten = kostNrWVl
    Anders
        Als provincieKlant = Antwerpen Dan
            verplaatsingskosten = kostNrAnt
        Anders
            Als provincieKlant = Limburg Dan
                verplaatsingskosten = kostNrLi

De code is nu optimaler, dan daarnet, maar ze blijkt toch redelijk ingewikkeld om te lezen. Het zou veel overzichtelijker zijn mochten we gebruikmaken van de meervoudige selectie.

Meervoudig[bewerken]
Selecteer Geval provincieKlant
    Geval Oost-Vlaanderen
        verplaatsingskosten = kostNrOVl
    Geval West-Vlaanderen
        verplaatsingskosten = kostNrWVl
    Geval Antwerpen
        verplaatsingskosten = kostNrAnt
    Geval Limburg
        verplaatsingskosten = kostNrLi

Alhoewel net hetzelfde wordt gedaan als bij de geneste tweevoudige keuze leest bovenstaande code toch stukken vlotter. Zelfs als er later provincies worden bijgevoegd blijft de code even overzichtelijk.

Herhaling of iteratie (lusverloop)[bewerken]

Begrensd[bewerken]

Er bestaat helaas geen bestaande functie om een stuk tekst automatisch van boven naar beneden te laten verschijnen. Na iedere letter zou er een alineamarkering moeten komen. Het aantal keren dat we dit moeten doen wordt bepaald door het aantal letters in het woord. We zitten dus duidelijk met een begrensde herhaling.

Voor teller = 1 tot familienaam.lengte
    vertikaleFamilienaam = vertikaleFamilienaam & familienaam.letterOpPositie(teller) & enter

Merk op dat we vertikaleFamilienaam = vertikaleFamilienaam... schrijven, omdat anders de bestaande waarde van vertikaleFamilienaam steeds wordt overschreven. Dit zou betekenen dat enkel de laatste letter van de familienaam (gevolgd door een alineamarkering) zou opgeslaan worden.

Voorwaardelijk (met zolang-beginvoorwaarde)[bewerken]

Bij de enkelvoudige keuze werd de correcte termijn al berekend (nl. rekening houden met een maximum aantal termijnen van 24 maanden). Voor het opstellen van het afbetalingsplan hebben we nood aan een voorwaardelijke herhaling. We moeten immers steeds de termijn optellen bij de voorgaande termijn, totdat het bedrag dat moest betaald worden bereikt wordt.

Het kan natuurlijk zijn dat de laatste maand iets minder dan de termijn betaald moet worden. Om dit te controleren hebben we nood aan een enkelvoudige keuze. Voor de duidelijkheid vermelden we dit direct bij dit gedeelte i.p.v. bij de enkelvoudige keuze.

voorlopigBedrag als getal = 0
maand als getal = 1

Zolang voorlopigBedrag < teBetalen
    voorlopigBedrag = voorlopigBedrag + termijn
    afbetalingsplan = afbetalingsplan & "maand " & maand & ": " & voorlopigBedrag & enter
    maand = maand + 1

'De eventuele nog te betalen termijn moeten we er nog bijplaatsen
Als teBetalen - voorlopigBedrag > 0 Dan
    afbetalingsplan = afbetalingsplan & "maand " & maand & ": " & teBetalen - voorlopigBedrag & enter

Dit was een voorwaardelijke herhaling met een zolang-beginvoorwaarde. We konden dit echter net zo goed neergeschreven hebben met een totdat-beginvoorwaarde, een zolang-eindvoorwaarde of een totdat-eindvoorwaarde. Dit valt echter buiten het bereik van deze cursus.

Genest[bewerken]

Een geneste controlestructuur betekent dat meerdere controlestructuren in elkaar verweven zitten. Dit hebben we al gezien bij de tweevoudige keuze, waarbij we de verplaatsingskosten moesten berekenen. Niets houdt ons echter tegen om bv. een tweevoudige keuze te plaatsen binnen een begrensde herhaling. Oefeningen hierop vallen echter buiten het bereik van deze cursus.

Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.