Alweer geen Excel

De diepte in met functies en procedures

Arnout van Kempen schrijft in deze rubriek over pret maken met computers. Hij gaat aan de slag met Pascal.

Tot nu toe hebben we procedures en functies vooral gebruikt om een programma op te knippen in behapbare brokken. Maar er zit meer onder de motorkap. Turbo Pascal 6 geeft een aantal mogelijkheden die pas echt krachtig worden als je de details begrijpt: hoe parameters worden doorgegeven, hoe variabelen op de stack belanden en wat er gebeurt als een procedure zichzelf aanroept. 

Parameterpassing: by value, var, const

Standaard kopieert Pascal de waarde van een parameter naar de stack van de procedure. Dit heet by value. Verander je binnen de procedure iets aan de parameter, dan blijft de oorspronkelijke variabele buiten de procedure onaangetast. 

Program ByValueDemo; 

Procedure Verdubbel(N: Integer);
Begin
  N := N * 2;
  Writeln('Binnen procedure: ', N);
End;

Var
  X: Integer;
Begin
  X := 10;
  Verdubbel(X);
  Writeln('Buiten procedure: ', X);
End.

De uitvoer:
Binnen procedure: 20
Buiten procedure: 10

Met het sleutelwoord Var geef je daarentegen een verwijzing door: de procedure werkt direct op het geheugenadres van de variabele.

Program ByVarDemo;

Procedure Verdubbel(var N: Integer);
Begin
  N := N * 2;
  Writeln('Binnen procedure: ', N);
End;

Var
  X: Integer;
Begin
  X := 10;
  Verdubbel(X);
  Writeln('Buiten procedure: ', X);
End.

Nu is de uitvoer buiten de procedure ook 20 geworden. Met Var geef je dus de variabele zelf door aan de procedure, zonder Var alleen de waarde.

Turbo Pascal heeft nog een vreemde manier om informatie door te geven aan een procedure, de typed constant. Die declareer je ongeveer hetzelfde als een gewone constante, maar het is geen constante. Het is een variabele met een beginwaarde bij declaratie, die vervolgens binnen het blok waar deze gedeclareerd is, beschikbaar blijft. Hoe werkt dat? Nou, zo:

Program TypedConstDemo;

Procedure TelOp(N: Integer);
Const
  Som: Integer = 0;  { typed constant, onthoudt zijn waarde }
Begin
  Som := Som + N;
  Writeln('Huidige som = ', Som);
End;

Begin
  TelOp(5);
  TelOp(10);
  TelOp(20);
End.

De waarde die je optelt bij Som geef je door als waarde, immers zonder Var, maar het is de typed constant Som die hier opvalt. Gedeclareerd binnen de procedure, blijft deze zijn waarde behouden tussen aanroepen en kan dus bij iedere nieuwe procedure aanroep worden gemuteerd. De output is dus niet, zoals wellicht logisch lijkt: 5, 10, 20, maar: 5, 15, 35

Ten slotte nog een populair trucje in veel programmeertalen: recursie. Een functie kan zichzelf aanroepen. Meestal wordt dat gedemonstreerd met de reeks van Fibonacci of met faculteiten. Laten we die laatste nemen, wat is een faculteit? 

n! = 1 als n = 1 en n! = n * (n-1)! als n > 1. 

In die definitie zit de recursie al ingebakken en dat zie je ook terug in Pascal. 

Program FaculteitRecursie;

Function Fac(N: Integer): LongInt;
Begin
  If N = 1 then
    Fac := 1
  else
    Fac := N * Fac(N-1);
End;

Begin
  Writeln('5! = ', Fac(5));
End.

Het is een mooie, recursieve uitwerking, maar dat heeft wel een pittig nadeel. Iedere keer dat de functie zichzelf aanroept groeit de stack, omdat nieuwe data moet worden bewaard van de aanroepende functie. De ruimte voor die stack is beperkt, dus je krijgt al snel een stack overflow. Een minder elegante, maar aanzienlijk efficiëntere benadering is dan ook

Program FaculteitIteratie;

Function Fac(N: Integer): LongInt;
Var
  I: Integer;
  Resultaat: LongInt;
Begin
  Resultaat := 1;
  For I := 2 to N do
    Resultaat := Resultaat * I;
  Fac := Resultaat;
End;

Begin
  Writeln('5! = ', Fac(5));
End.

Arnout van Kempen is naast computernerd ook directeur compliance & risk bij aaff. Hij schrijft op persoonlijke titel.

Gerelateerd

reacties

Reageer op dit artikel

Spelregels debat

    Aanmelden nieuwsbrief

    Ontvang elke werkdag (maandag t/m vrijdag) de laatste nieuwsberichten, opinies en artikelen in uw mailbox.

    Bent u NBA-lid? Dan kunt u zich ook aanmelden via uw ledenprofiel op MijnNBA.nl.