Alweer geen Excel

Pointers en dynamisch geheugen

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

Een programma draait, hoe je het ook wilt zien, uiteindelijk om het ophalen, muteren, opslaan en verplaatsen van informatie. Dat IT een afkorting is van Information Technology geeft al een hint. In veel programmeertalen vindt een vrij stevige abstractie plaats van de werkelijke bits en bytes waar de data uit bestaat, naar dat wat je als programmeur ziet. Talen als Python, Go en BASIC gebruiken variabelen om informatie mee op te slaan. De taal controleert waar je data blijft, het type van data en de interne representatie. In BASIC kan je met poke en peek wel direct bij het geheugen, maar dan word je ook volledig aan je lot overgelaten. Talen als C en Rust zitten dichter op het ijzer en maken meer vanzelfsprekend gebruik van het interne geheugen van de computer zelf. Verdeeld over Stack en Heap. In moderne omgevingen lijkt het alsof je nu rechtstreeks het geheugen aanspreekt, maar dat is schijn. Het operating system en de MMU zitten daar nog tussen. 

In Turbo Pascal met MS-DOS heb je een aardige mengeling. Je kan alles met variabelen doen en door gebruik te maken van je eigen types kan je behoorlijk flexibele datastructuren maken. Maar je kan ook gebruik maken van pointers, waarmee je direct toegang krijgt tot het geheugen. En omdat MS-DOS geen gebruik maakt van protected mode of iets dergelijks, zit je dan ook echt direct op het ijzer, zonder enige veiligheid. 

Variabelen in Pascal hebben een vaste plek in geheugen: globale variabelen in het data-segment, lokale variabelen op de stack. Dat werkt zolang je alles van tevoren weet. Maar soms wil je tijdens het draaien van je programma geheugen maken of weggooien, bijvoorbeeld voor een dynamische lijst. Daarvoor gebruik je pointers.

In Turbo Pascal is een Pointer letterlijk een segment:offset-adres. Je kunt er ook meteen een type aan hangen:

Type
  PInt = ^Integer;  { pointer naar een integer }

Var
  P: PInt;

Een pointer wijst niet vanzelf naar iets. Je moet er eerst geheugen bij zoeken.

Pascal reserveert bij het starten van een programma een heap. Daarin komt al het dynamische geheugen.
Uitgaande van de declaratie van P zojuist krijg je dit:

New(P);      { maakt ruimte voor een integer op de heap }
P^ := 42;    { schrijf in de integer waar P naar wijst }
Writeln(P^); { lees weer terug }
Dispose(P);  { geef het geheugen terug }

P^ betekent: wat er staat op de plek waar P naar wijst”.

Met New en Dispose reserveer je geheugen en geef je het weer vrij, met een pointer, een adres dus, als parameter.
Het is ook mogelijk blokken geheugen te reserveren.

Var
  Buf: Pointer;
Begin
  GetMem(Buf, 1024);  { vraag 1024 bytes }
  { ... }
  FreeMem(Buf, 1024);
End.

Dit werkt net als malloc/free in C. Je krijgt een stuk geheugen met een pointer en een gegeven omvang. Na gebruik geef je dat geheugen weer vrij.

Omdat een segment van een 80x86 maar 64K groot kan zijn en je verschillende geheugenmodellen kan kiezen bij het compileren, moet je rekening houden met twee soorten pointers:

  • Near pointer: 16-bit offset binnen het huidige data-segment
  • Far pointer: volledig segment:offset-adres.

In het "small" memory model zijn near pointers de standaard. Bij grotere programma's of datastructuren heb je far pointers nodig. Turbo Pascals Pointer type is far, zodat je overal in je adresruimte kunt komen.
Hoe ziet dat er bijvoorbeeld uit met een linked list?

Type
  PNode = ^TNode;
  TNode = Record
    Value: Integer;
    Next: PNode;
  End;

Var
  Head, N: PNode;
Begin
  New(Head);
  Head^.Value := 1;
  New(N);
  N^.Value := 2;
  Head^.Next := N;
  Writeln(Head^.Next^.Value);  { print 2 }
  Dispose(N);
  Dispose(Head);
End.

De toepassing hier is natuurlijk kolder, maar het laat wel zien hoe je in principe onbeperkt data in een structuur kwijt kan. 

Met pointers krijg je dezelfde flexibiliteit die C biedt. Maar Pascal is dan ook net zo gevaarlijk als C. Niet de memory safety van Rust, niet de garbage collector van Go, niet de abstractie van Python. En niet de bescherming van Linux, MacOS of Windows. 

Over C++ wordt gezegd: met C kan je je in je voet schieten, met C++ schiet je je hele been er af. Als je die vergelijking toepast op Pascal onder MS-DOS, kan je zeggen dat je met Turbo Pascal de grond onder je voeten uit kan schieten.

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.