Im Weiteren lässt sich eine Variable vom Typ int*
genauso benutzen wie etwa eine Variable vom Typ int[10]
, indem etwa etwas in der folgenden Art geschrieben werden kann:
int n; ... n = ... ... int* as = new int[n]; as[2] = 42;
Das funktioniert, weil der Compiler weiß, was er bei einer solchen Anweisung zu tun hat; er muss einfach die unter as
gespeicherte Adresse laden, von dieser aus 8 Byte weiterspringen (wir wollen die 3. Stelle im Integer-Array, überspringen also 2 * 4 Byte) und an die entsprechende Stelle den Wert 42
schreiben. Schauen wir uns zum besseren Verständnis noch die konkrete Situation im Speicher an.
Natürlich benötigen wir nun 2 Speicherbereiche, nämlich den Stack und den Heap. Gehen wir von folgendem Code aus:
void f( int n ) { int* as = new int[n]; as[2] = 42; }
Wie wir aus einem früheren Artikel wissen, ergibt sich dafür für den Stack unmittelbar nach Aufruf der Funktion f
der folgende Aufbau mit den zugehörigen Variablen-Positionen; nehmen wir für n
zusätzlich einen Eingabewert von 5 an, leere Zellen enthalten beliebige Werte, die uns (noch) nicht weiter interessieren:
Adresse | Inhalt | Inhalt | Inhalt | Inhalt | |
---|---|---|---|---|---|
123450 | <– esp | ||||
123455 | <– as [= ebp – 4] | ||||
123458 | <– ebp | ||||
123462 | |||||
123466 | 05 | 00 | 00 | 00 | <– n |
… | … | … | … | … | |
123490 | <– bottom |
Der Heap im (frei angenommenen) Adressbereich 345678 sieht folgendermaßen aus (er enthält momentan noch keine für uns relevanten Werte):
Adresse | Inhalt | Inhalt | Inhalt | Inhalt | |
---|---|---|---|---|---|
345678 | |||||
345682 | |||||
345686 | |||||
345690 | |||||
345694 | |||||
… | … | … | … | … |
Gehen wir nun in der Funktion f
einen Schritt weiter, nach Ausführung der Anweisung int* as = new int[n];
. Nehmen wir an, dass der new
-Ausdruck den gewünschten Speicher (für 5 Integer-Werte) auf dem Heap ab der Adresse 345678
reserviert hat; Der Stack sieht dann folgendermaßen aus:
Adresse | Inhalt | Inhalt | Inhalt | Inhalt | |
---|---|---|---|---|---|
123450 | <– esp | ||||
123455 | 4E | 46 | 05 | 00 | <– as [= ebp – 4] |
123458 | <– ebp | ||||
123462 | |||||
123466 | 05 | 00 | 00 | 00 | <– n |
… | … | … | … | … | |
123490 | <– bottom |
Der Inhalt der Speicherzellen, welche as
entsprechen (nämlich 4E 46 05 00
) mag etwas seltsam aussehen, ist aber einfach zu verstehen: Zahlen werden im Speicher immer byteweise abgespeichert, und zwar auf regulären Prozessor-Architekturen in umgekehrter Reihenfolge der Bytes. Zur Notation greift man dabei meist auf die hexadezimale Schreibweise zurück, also die Notation der Zahlen in einem System zur Basis 16 (wir selber rechnen tagtäglich in einem System zur Basis 10; Binärzahlen sind zur Basis 2 notiert). Da wir nur über 10 Ziffern (0-9) verfügen, werden die fehlenden 6 “Ziffern” durch die Buchstaben A bis F dargestellt. Der Inhalt des Speichers entspricht also der Zahl 0x0005464E
(das 0x
markiert die hexadezimale Schreibweise), was genau der Zahl 345678 (die angenommene zurückgegebene Adresse) entspricht. So weit, so einfach.
Und wie sieht der Heap nun aus? Folgendermaßen (<-- *as
markiert die Speicheradresse, welche in as
gespeichert ist):
Adresse | Inhalt | Inhalt | Inhalt | Inhalt | |
---|---|---|---|---|---|
345678 | <– *as | ||||
345682 | |||||
345686 | |||||
345690 | |||||
345694 | |||||
… | … | … | … | … |
Wer jetzt keine Änderung entdeckt, liegt richtig – im Heap hat sich noch nichts getan. Das Reservieren von Speicher allein ändert prinzipiell nichts am Inhalt des reservierten Speichers, zumindest dann, wenn Speicher für ein Array im Heap reserviert wird (es kann auch Speicher für andere Dinge reserviert werden, aber das werden wir später noch sehen). Für echte Änderungen muss noch etwas in den Speicher geschrieben werden, so wie es durch den Ausdruck as[2] = 42;
passiert. Nach dessen Ausführung sieht der Heap folgendermaßen aus (im Stack hat sich natürlich nichts geändert):
Adresse | Inhalt | Inhalt | Inhalt | Inhalt | |
---|---|---|---|---|---|
345678 | <– *as | ||||
345682 | |||||
345686 | 2A | 00 | 00 | 00 | |
345690 | |||||
345694 | |||||
… | … | … | … | … |
Kommentare (8)