home *** CD-ROM | disk | FTP | other *** search
- "realloc"-Implementation (toolbox-Praxis 4'91)
-
- Mehr Dynamik für Turbo Pascal
-
- von Gerd Cebulla
-
-
- Die Verwaltung größerer Datenmengen
- läßt sich in der Regel nur mit Hilfe
- von dynamischen Variablen bewerkstelli-
- gen.
- Was Turbo Pascal fehlt, ist ein Befehl,
- der die Größe des für eine dynamische
- Variable belegten Speicherbereichs
- nachträglich verändert -- sozusagen
- eine "Dynamisierung der dynamischen
- Speicherverwaltung". Eine solche Funk-
- tion hat übrigens jeder x-beliebige C-
- Compiler unter dem Namen "realloc" im-
- plementiert. Die Unit "Realloc"
- implementiert die dynamische Freigabe
- von Speicher für Turbo Pascal.
-
- Zur Verwaltung von dynamischem
- Speicher stellt Turbo Pascal dem Pro-
- grammierer mit den Standardprozeduren
- New/Dispose und GetMem/FreeMem sowie
- Mark/Release auch alle nötigen Hilfs-
- mittel zur Verfügung.
-
- Wirklich alle? Nehmen wir einmal an,
- Sie schreiben eine Textverarbeitung.
- Normalerweise wird das in Form einer
- doppelt verketteten Liste von Zeigern
- auf Strings (respektive Char-Arrays)
- realisiert. Nun werden vom Anwender
- hemmungslos Zeichen eingefügt oder ge-
- löscht sowie Zeilen umgebrochen -- die
- Länge einer Zeile ist also laufenden
- Änderungen unterworfen.
-
- Diesem Problem könnte man dadurch be-
- gegnen, daß man für jede Zeile von
- vornherein die maximal mögliche Anzahl
- Zeichen (z. B. 80) reserviert. Diese
- Methode stellt jedoch nicht nur eine
- gigantische Speicherplatzverschwendung
- dar, sondern hat auch noch den Nachteil
- mangelnder Flexibilität -- nach Murphys
- Gesetzen hat garantiert der übernächste
- Anwender einen DIN-A3-Drucker und benö-
- tigt mindestens 120 Zeichen pro Zei-
- le...
-
- Es hilft alles nichts -- wir müssen den
- Speicherplatz dynamisch verwalten. Un-
- ter Turbo Pascal muß dazu zunächst ein
- Speicherbereich mit der neuen Größe
- belegt, sodann der Inhalt der alten
- dynamischen Variable umkopiert und
- schließlich der alte Speicherplatz
- freigegeben werden. Das sieht dann un-
- gefähr so aus:
-
- GetMem(PNeu, NeueGroesse);
- IF NeueGroesse < AlteGroesse THEN
- Groesse := NeueGroesse
- ELSE
- Groesse := AlteGroesse;
- Move(P^, PNeu^, Groesse);
- FreeMem(P, AlteGroesse);
- P := PNeu;
-
- Das ist erstens recht umständlich,
- zweitens wird temporär für ein und die-
- selbe Variable gleich zweimal Speicher-
- platz belegt, was bei größeren Arrays
- durchaus zu Problemen führen kann; vor
- allem aber ist diese Methode extrem
- rechenaufwendig -- schließlich müssen
- bei jeder Größenänderung soundso viele
- Byte in einen anderen Speicherbereich
- kopiert werden.
-
- Bei einem Turbo-Pascal-Programm liegt
- der Heap oberhalb aller Code- und Da-
- tensegmente. Bei jedem Aufruf von "New"
- bzw. "GetMem" wird an der niedrigsten
- verfügbaren Adresse Speicherplatz re-
- serviert; der Heap wächst also von un-
- ten nach oben. Wenn bei der Freigabe
- einer dynamischen Variable ein "Loch"
- im Heap entsteht, trägt Turbo die
- Start- und Endadresse des Lochs in die
- sogenannte Fragmentliste ein. Die Frag-
- mentliste befindet sich am oberen Ende
- des Programmspeichers und wächst von
- oben nach unten.
-
- Zur Verwaltung des Heap deklariert die
- Laufzeitbibliothek von Turbo-Pascal
- einige globale Variable: "HeapOrg" ist
- ein Zeiger auf den Heapanfang,
- "HeapPtr" zeigt auf den Beginn des
- freien Heap, und "FreePtr" enthält die
- Startadresse der Fragmentliste. Mit
- diesem Rüstzeug ausgestattet, können
- wir uns daran machen, eine Funktion zur
- nachträglichen Veränderung der Größe
- einer dynamischen Variablen zu schrei-
- ben.
-
-
- Diese Funktion -- nennen wir sie "Chan-
- geMem" -- benötigt drei Argumente: ei-
- nen Zeiger auf die dynamische Variable,
- die derzeitige Größe der Variable und
- die gewünschte neue Größe. Wenn die
- neue Größe kleiner als die alte ist,
- ist die Sache einfach: Wir brauchen
- lediglich den nicht mehr benötigten
- Speicherplatz freizugeben, das heißt,
- in die Fragmentliste einzutragen.
-
- Soll der belegte Speicherplatz dagegen
- vergrößert werden, schaut "ChangeMem"
- zunächst in der Fragmentliste nach, ob
- oberhalb der dynamischen Variable genug
- Platz verfügbar ist. Ist das der Fall,
- wird dieser Bereich belegt; andernfalls
- ermittelt "ChangeMem" den freien Be-
- reich unterhalb der dynamischen Varia-
- ble. Reicht dieser aus, wird er belegt
- und der Inhalt der Variable auf eine
- entsprechend niedrigere Adresse ko-
- piert.
-
- Schlägt auch dieser Versuch fehl,
- bleibt nur noch die übliche Methode:
- Reservierung eines Speicherbereichs mit
- der neuen Größe, Kopieren der Variable
- und anschließende Freigabe des alten
- Bereichs.
-
- Die Funktion "ChangeMem" ist in der
- Unit "ReAlloc" implementiert. Der Auf-
- ruf geschieht wie folgt:
-
- PNeu := ChangeMem(P, AlteGroesse,
- NeueGroesse);
-
- Als Funktionsergebnis wird ein Zeiger
- auf die neue Adresse der dynamischen
- Variable zurückgeliefert. Falls auf dem
- Heap nicht mehr genug Platz verfügbar
- ist, wird der Wert "NIL" zurückgegeben,
- vorausgesetzt daß Sie eine eigene Heap-
- Fehlerbehandlung installiert haben;
- siehe dazu das Kapitel "Interne De-
- tails" im Referenzhandbuch.
-
- (wr)
-
-
-