Pointers begrijpen en gebruiken in Delphi

Hoewel pointers niet zo belangrijk zijn in Delphi als in C of C ++, zijn ze zo'n "basis" tool dat bijna alles wat met programmeren te maken heeft op een of andere manier met pointers te maken heeft..

Het is om die reden dat je misschien leest hoe een string of object eigenlijk alleen maar een pointer is, of dat een event handler zoals OnClick eigenlijk een pointer is naar een procedure.

Aanwijzer naar gegevenstype

Simpel gezegd, een pointer is een variabele die het adres van alles in het geheugen bevat.

Om deze definitie te concretiseren, moet u er rekening mee houden dat alles wat een toepassing gebruikt, ergens in het geheugen van de computer is opgeslagen. Omdat een aanwijzer het adres van een andere variabele bevat, wordt gezegd dat die naar die variabele verwijst.

Meestal wijzen wijzers in Delphi op een specifiek type:

var
iValue, j: geheel getal; pIntValue: ^ geheel getal;
beginnen
iValue: = 2001; pIntValue: = @iValue;… j: = pIntValue ^;
einde
;

De syntaxis om een ​​gegevenstype van de aanwijzer te declareren gebruikt een caret (^). In de bovenstaande code is iValue een variabele van het type geheel getal en pIntValue is een aanwijzer van het type geheel getal. Aangezien een pointer niets meer is dan een adres in het geheugen, moeten we hieraan de locatie (adres) toewijzen van de waarde die is opgeslagen in de variabele variabel iValue.

De @ operator geeft het adres van een variabele terug (of een functie of procedure zoals hieronder te zien is). Gelijk aan de operator @ is Addr-functie. Merk op dat de waarde van pIntValue niet 2001 is.

In deze voorbeeldcode is pIntValue een getypte integer-aanwijzer. Een goede programmeerstijl is om getypte wijzers zoveel mogelijk te gebruiken. Het gegevenstype Pointer is een generiek pointertype; het vertegenwoordigt een pointer naar alle gegevens.

Merk op dat wanneer "^" wordt weergegeven na een pointervariabele, de verwijzing naar de pointer wordt verwijderd; dat wil zeggen, het retourneert de waarde die is opgeslagen op het geheugenadres van de aanwijzer. In dit voorbeeld heeft variabele j dezelfde waarde als iValue. Het lijkt erop dat dit geen doel heeft wanneer we iValue eenvoudig aan j kunnen toewijzen, maar dit stukje code ligt achter de meeste aanroepen naar Win API.

NIL-aanwijzers

Niet-toegewezen aanwijzingen zijn gevaarlijk. Omdat pointers ons rechtstreeks met het computergeheugen laten werken, kunnen we een fout bij toegangsfout krijgen als we proberen (per ongeluk) naar een beveiligde locatie in het geheugen te schrijven. Dit is de reden dat we altijd een pointer naar NIL moeten initialiseren.

NIL is een speciale constante die aan elke aanwijzer kan worden toegewezen. Wanneer nul aan een aanwijzer is toegewezen, verwijst de aanwijzer niets. Delphi presenteert bijvoorbeeld een lege dynamische array of een lange reeks als nulwijzer.

Karakterwijzers

De fundamentele typen PAnsiChar en PWideChar zijn verwijzingen naar AnsiChar- en WideChar-waarden. De generieke PChar vertegenwoordigt een pointer naar een Char-variabele.

Deze tekenaanwijzers worden gebruikt om tekenreeksen met nulpunt-beëindiging te manipuleren. Zie een PChar als een pointer naar een string met nulstand of naar de array die er een vertegenwoordigt.

Verwijzingen naar records

Wanneer we een record of ander gegevenstype definiëren, is het gebruikelijk om ook een pointer naar dat type te definiëren. Dit maakt het gemakkelijk om instanties van het type te manipuleren zonder grote blokken geheugen te kopiëren.

De mogelijkheid om verwijzingen naar records (en arrays) te hebben, maakt het veel eenvoudiger om gecompliceerde gegevensstructuren op te zetten als gekoppelde lijsten en bomen.

 type
pNextItem = ^ TLinkedListItem
TLinkedListItem = VermeldingsName: String; iValue: Integer; NextItem: pNextItem;
einde
;

Het idee achter gekoppelde lijsten is om ons de mogelijkheid te geven het adres op te slaan voor het volgende gekoppelde item in een lijst in een NextItem-recordveld.

Verwijzingen naar records kunnen ook worden gebruikt bij het opslaan van aangepaste gegevens voor bijvoorbeeld elk boomweergave-item.

Procedurele en methodische aanwijzingen

Een ander belangrijk pointerconcept in Delphi zijn procedure- en methode-pointers.

Aanwijzers die naar het adres van een procedure of functie verwijzen, worden procedurele verwijzingen genoemd. Methode pointers zijn vergelijkbaar met procedure pointers. In plaats van te wijzen op zelfstandige procedures, moeten ze echter wijzen op klassemethoden.

Method pointer is een pointer die informatie bevat over zowel de naam als het object dat wordt aangeroepen.

Aanwijzers en Windows API

Het meest voorkomende gebruik voor pointers in Delphi is een interface met C- en C ++ -code, inclusief toegang tot de Windows API.

Windows API-functies gebruiken een aantal gegevenstypen die mogelijk onbekend zijn bij de Delphi-programmeur. De meeste parameters bij het aanroepen van API-functies zijn verwijzingen naar een bepaald gegevenstype. Zoals hierboven vermeld, gebruiken we null-beëindigde tekenreeksen in Delphi bij het aanroepen van Windows API-functies.

In veel gevallen, wanneer een API-aanroep een waarde in een buffer of aanwijzer naar een gegevensstructuur retourneert, moeten deze buffers en gegevensstructuren door de toepassing worden toegewezen voordat de API-aanroep wordt gedaan. De SHBrowseForFolder Windows API-functie is een voorbeeld.

Aanwijzer en geheugentoewijzing

De echte kracht van pointers komt van de mogelijkheid om geheugen opzij te zetten terwijl het programma wordt uitgevoerd.

Dit stukje code zou genoeg moeten zijn om te bewijzen dat werken met pointers niet zo moeilijk is als het op het eerste gezicht lijkt. Het wordt gebruikt om de tekst (het bijschrift) van het besturingselement te wijzigen met de meegeleverde handgreep.

 procedure GetTextFromHandle (hWND: THandle);
var
pText: PChar; // een pointer naar char (zie hierboven)TextLen: geheel getal;
beginnen

haal de lengte van de tekst op
TextLen: = GetWindowTextLength (hWND);
geheugen toewijzen

GetMem (pText, TextLen); // neemt een wijzer
de tekst van het besturingselement ophalen
GetWindowText (hWND, pText, TextLen + 1);
toon de tekst
ShowMessage (String (pText))
geheugen vrijmaken
FreeMem (pText);
einde
;