|
|
new dient zur Reservierung eines Speicherbereichs und delete dient zur Freigabe des so reservierten Speichers.
new erhält als Operand den Datentyp, für den der Speicher reserviert werden soll. Als Ergebnis liefert new einen Zeiger auf den reservierten Speicherbereich zurück. Dieser zurückgelieferte Zeiger besitzt immer den richtigen Datentyp, so dass keine Typkonvertierung notwendig ist.
|
// main() Funktion int main() { long *ptr; // Zeiger auf long-Datum ... // Speicher für ein long Datum reservieren ptr = new long; ... } |
Konnte new aus irgend welchen Gründen nicht den angeforderten Speicher reservieren, so wird eine Exception (Ausnahme) vom Typ bad_alloc ausgelöst und das Programm (bis jetzt) beendet. Was Exceptions sind und wie Sie auf eine solche Exception reagieren können, das erfahren Sie später noch ausführlich.
new kann aber nicht nur Speicher für "einfache" Daten reservieren, sondern auch für Felder. Soll Speicher für einfache Felder (nicht Objektfelder, das folgt gleich noch) reserviert werden, so erfolgt die Angabe der Feldgröße nach dem Datentyp des Feldes innerhalb von eckigen Klammern. Im nachfolgenden Beispiel wird Speicher für ein short-Feld mit 10 Elementen reserviert.
|
// main() Funktion int main() { short *ptr; // Zeiger auf short-Datum ... // Speicher für ein Feld mit 10 short reservieren ptr = new short[10]; ... } |
|
Vielmehr wird folgender Vorgang ablaufen: Anstelle eines Feldes wird nur Speicher für eine einfaches Datum des entsprechenden Datentyps reserviert. Und dieses Datum wird dann mit dem Wert initialisiert, der innerhalb der runden Klammer angegeben ist. Sie haben damit sozusagen einen Konstruktor für eine einfaches Datum aufgerufen! Im obigen Beispiel wird also Platz für ein short-Datum reserviert und der reservierte Speicher mit 10 initialisiert. |
Soll für mehrdimensionale Felder Speicher reserviert werden, so muss dieses in mehreren Schritten erfolgen. Der 'Trick' dabei besteht darin, dass zuerst ein Zeigerfeld (also ein Feld welches nur Zeiger enthält) reserviert wird. Dieses Zeigerfeld repräsentiert die 'Zeilen'. Anschließend werden dann in diesem Zeigerfeld die Speicheradressen für die Spaltenfelder abgelegt. Sehen wir uns diesen Vorgang nun Schritt für Schritt an:
Der Zugriff auf die einzelnen Elemente des mehrdimensionalen Feldes erfolgt in der üblichen Art und Weise (mehrfache Indizierung).
|
// Feld mit 3x2 Elementen für die Aufnahme von float-Zahlen reservieren const int ROW=3; const int COLUMN=2; // Schritt 1: Zeiger auf Zeiger definieren float **ppArray; // main() Funktion int main() { // Schritt 2: Zeigerfeld für 3 float-Zeiger reservieren ppArray = new float*[ROW]; // Schritt 3: Spaltenfelder reservieren for (int i=0; i<ROW; i++) ppArray[i] = new float[COLUMN]; ... // Zugriff dann wie gewohnt ppArray[iRow][iCol] = ...; } |
|
|
Damit genug der zur Reservierung von Speicher. Sehen wir uns jetzt an, wie Sie den reservierten Speicher wieder freigeben wenn Sie ihn nicht mehr benötigen.
Die Freigabe des mittels new reservierten Speicherbereichs erfolgt mit dem delete Operator. Wurde Speicher für 'einfache' Daten (keine Felder) reserviert, so erhält delete als Operanden den von new zurückgelieferten Zeiger. Wurde dagegen Speicher für ein Feld reserviert, so muss nach dem delete Operator zunächst eine leere eckige Klammer stehen und erst danach der von new zurückgelieferte Zeiger. Vergessen Sie diese leere eckige Klammer, so meldet Ihnen der Compiler keinen Fehler! Bei Felder von einfachen Datentypen, d.h. keine Objekte, wird der reservierte Speicher auch korrekt freigegeben. Warum bei der Freigabe des Speichers von Objektfeldern diese eckigen Klammern so wichtig sind, das erfahren Sie in der nächsten Lektion über dynamische Objekte. Vergessen Sie daher niemals die eckigen Klammer beim delete von Feldern.
|
int main() { // Speicher für einen long reservieren und wieder freigeben long *pData = new long; ... delete pData; // Speicher für char-Feld reservieren und wieder freigeben char *pArray = new char[30]; ... delete [] pArray; } |
Auch hier werden wir uns noch kurz ansehen, wie Sie den vorhin reservierten Speicher für ein 2-dimensionales Feld wieder freigeben. Bei der Freigabe des Speichers müssen Sie quasi die Reihenfolge der Reservierungsanweisungen umdrehen, d.h. Sie müssen zuerst den Speicher für die Spaltenfelder freigeben und dann zum Schluss den Speicher für das Zeigerfeld. Beachten Sie beim delete Operator die leeren eckigen Klammern. Wird haben es hier mit Feldern zu tun!
|
// Feld mit 3x2 Elementen für die Aufnahme von float-Zahlen reservieren const int ROW=3; const int COLUMN=2; // Schritt 1: Zeiger auf Zeiger definieren float **ppArray; // main() Funktion int main() { // Reservierung des 2-dimimensionalen Feldes wie oben dargestellt ... // Zuerst Spaltenfelder freigeben for (int i=0; i<ROW; i++) delete [] ppArray[i]; // Und Zeigerfeld freigeben delete [] ppArray; } |
|
|
Und noch ein Hinweis:
|
|
|
|
Aus wie vielen Zufallszahlen soll |
|
// Beispiel zu new und delete // Zuerst Dateien einbinden #include <iostream> #include <cstdlib> // main() Funktion int main() { unsigned int noOfValues; // Anzahl der Zufallszahlen double sum; // Summe aller Zufallszahlen unsigned int loop; // Schleifenzähler int *pValues; // Zeiger auf Feld mit Zufallszahlen // Anzahl der Zufallszahlen einlesen std::cout << "Aus wie vielen Zufallszahlen soll\n"; std::cout << "der Mittelwert berechnet werden ?"; std::cin >> noOfValues; // Feld für Zufallszahlen reservieren pValues = new int[noOfValues]; // Feld mit Zufallszahlen belegen for (loop=0; loop<noOfValues; loop++) pValues[loop] = rand() % 100; // Nun alle Zahlen im Feld aufsummieren sum = 0; for (loop=0; loop<noOfValues; loop++) sum += (double)pValues[loop]; // Mittelwert berechnen und ausgeben std::cout << "Der Mittelwert ist: " << sum/noOfValues << std::endl; // Feld auch wieder löschen delete [] pValues; } |
Die Datei names.txt enthält eine Liste mit Namen (enthalten auch Leerzeichen!) die einzulesen sind. Die Anzahl der in der Datei enthaltenen Namen ist als erster Eintrag (short-Datentyp) in der Datei mit abgespeichert. Lesen Sie alle Namen in ein entsprechend großes string-Feld ein und geben Sie die Namen zu Kontrolle aus.
Legen Sie dazu zunächst die Datei names.txt mit folgendem Inhalt an:
![]() 11 Baisch, Robert Reusch, Bernhard Werner, Jutta Schroff, Rosina Stauss, Guenther Mueller, Andrea Herrmann, Fritz Baumann, Marion Maier, Klaus Rapp, Rose Neuhaus, Ursula |
|
Baisch, Robert |