1 / 35

Dynamischer Speicher

Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen wird (nach dem Aufruf der Funktion), ist dieser Speicherbereich automatisch wieder freigegeben (nicht mehr reserviert). Beispiel:.

grady
Download Presentation

Dynamischer Speicher

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. DynamischerSpeicher

  2. In einer Funktion wird z.B. mit der Deklarationint i;Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen wird (nach dem Aufruf der Funktion), ist dieser Speicherbereich automatisch wieder freigegeben (nicht mehr reserviert).

  3. Beispiel:

  4. void f(){ int myfeld[10]; //... } int main(){ f(); //... } Erst wenn f aufgerufen wird, wird Speicher für myfeld auf dem Stack reserviert. Wieviel Byte sind dies ? 10 · Speicherbedarf (integer) Nach dem Aufruf wird dieser Speicherplatz automatisch (ohne Zutun des Programmmierers) wieder freigegeben.

  5. Beispiel:Man will die von einem Anwender (über Tastatur eingegebene) bestimmte Anzahl von Zahlen in einem Feld abspeichern.

  6. int main(){ int myfeld[1000]; //... } Welchen Nachteil hat dies bezüglich des Speicherplatzverbrauchs Der Anwender kann weniger Speicher – als reserviert – verbrauchen (z.B. bei Eingabe nur einer Zahl). Dies ist dann Speicherverschwendung. Um dies zu vermeiden kann der Anwender – während der Laufzeit des Programms – so viel Speicher reservieren, wie er benötigt. Im Gegensatz zum Beispiel oben wird diese Reservierung nicht beim Compilieren, sondern während der Programmlaufs gemacht und heißt deshalb dynamischer Speicher(reservierung).

  7. Realisierung in C++

  8. int main(){ int anz, zahl, i; int *panf; cout << "Anzahl eingeben:"; cin >> anz; panf = new int[anz]; cout << "Zahlen eingeben:"; for(i=0; i<anz; i++){ cin >> zahl; *(panf+i)=zahl; } // panf[i]=zahl delete panf; } eingelesener Wert wird in anz gespeichert Reserviert dynamisch Speicher: für ein Feld von anz integer-Werten gibt Speicher wieder frei Mögliche (gleichwertige) Formen des Zugriffs panf zeigt auf das erste Element des Feldes

  9. int main(){ int anz, zahl, i; int *panf; cout << "Anzahl eingeben:"; cin >> anz; panf = new int[anz]; cout << "Zahlen eingeben:"; for(i=0; i<anz; i++){ cin >> zahl; *(panf+i)=zahl; } //... Annahme: anz = 2 WelchenWert hat panf an dieser Stelle des Programmms ? In der 1. Spalte stehen die Adressen der Variablen panf 020 ... ... ... In der 2. Spalte stehen die Inhalte der Adressen (Werte der Variablen)

  10. int main(){ int anz, zahl, i; int *panf; cout << "Anzahl eingeben:"; cin >> anz; panf = new int[anz]; cout << "Zahlen eingeben:"; for(i=0; i<anz; i++){ cin >> zahl; *(panf+i)=zahl; } //... Was veranlasst diese Anweisungen ? Auf die (Anfangs)Adresse dieses Speicherbereichs hat der Programmierer keinen Einfluß. Diese legt der Compiler bzw. Programmlader fest. panf 020 ... ? Es wird im Arbeitsspeicher Platz für 2 integer-Zahlen reserviert und die (Anfangs)Adresse dieses Speicherbereichs der Variable panf zugewiesen. ... ...

  11. int main(){ int anz, zahl, i; int *panf; cout << "Anzahl eingeben:"; cin >> anz; panf = new int[anz]; cout << "Zahlen eingeben:"; for(i=0; i<anz; i++){ cin >> zahl; *(panf+i)=zahl; } //... 0700 ? Annahme:Die 1. über Tastatur eingegebene Zahl sei 17 und die 2. eingegebene Zahl sei 13.Was bewirkt dann jeweils (insgesamt zweimal) diese Anweisung ? ? ? ? ? ? ? zeigt auf: ? panf 020 ... 0700 ... ... Speicherreservierung für 2 integer-Zahlen,die z.B. bei der Adresse 0700 beginnen

  12. int main(){ int anz, zahl, i; int *panf; cout << "Anzahl eingeben:"; cin >> anz; panf = new int[anz]; cout << "Zahlen eingeben:"; for(i=0; i<anz; i++){ cin >> zahl; *(panf+i)=zahl; } //... 0700 0017 0704 0013 panf 020 ... 0700 ... ...

  13. Man kann auch für Objekte dynamisch Speicher allokieren:

  14. int main(){ Konto *pk; pk = new Konto; // Anweisungen delete pk; } new reserviert dynamisch Speicher. Die Anfangsadresse des dynamischen Speichers wird in einem Zeiger festgehalten, damit man später darauf zugreifen kann. Zusätzlich wird automatisch der Konstruktor aufgerufen. Falls kein Speicher mehr allokiert werden kann, bekommt pk den Wert NULL, den sogenannten Nullzeiger, zugewiesen. Dieser Nullzeiger zeigt auf kein Objekt ! delete gibt den dynamisch erzeugten Speicher wieder frei. Zusätzlich wird automatisch der Destruktor aufgerufen. Falls pk gleich NULL ist, wird keine Operation ausgeführt. In der schließenden Klammer } wird kein Destruktor aufgerufen, da pk eine Zeigervariable ist.

  15. Ein weiteres Beispiel:

  16. Die Klasse Bank hat u.a. das Attribut art (Datentyp char), in dem gespeichert ist, ob ein Konto einem Mitarbeiter gehört (‘M‘), oder einer fremden Person (‘F‘).

  17. Die zugehörigen Methoden, die diesen Modus setzen bzw. lesen heissen (aus Platzgründen verkürzt):setMgetM

  18. class Bank { private: char art; ... public: void setM(...) ... }; In art wird die Art des Mitarbeiters gespeichert, also: 'M' oder 'F'

  19. Annahme:Ein Objekt der Klasse Bank sei 100 Byte groß.

  20. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); pi = new int; pk = new Konto; pkk = new Konto[anz]; ... Hier wird nachher jeweils der Anfang des dynamischen Speichers (in einem Zeiger) festgehalten. Zufallszahl die folgenden 3 Befehle reservieren Speicher für: einen integer-Wert für ein Objekt der Klasse Konto für ein Feld von anz Objekten der Klasse Konto

  21. Annahmen: anz = 2 Speicherplatz Konto: 100 Byte int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); pi = new int; pk = new Konto; pkk = new Konto[anz]; Welchen Wert haben pi, pk, pkk an dieser Stelle des Programmms ? In der 1. Spalte stehen die Adressen der Variablen pi 0100 ... ... ... pk 0120 In der 2. Spalte stehen die Inhalte der Adressen (Werte der Variablen) ... ... 0140 pkk

  22. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); pi = new int; pk = new Konto; pkk = new Konto[anz]; Was veranlasst diese Anweisung ? Auf die (Anfangs)Adresse des reservierten Speichers hat der Programmierer keinen Einfluß. Dies legt der Compiler (bzw. Programmlader fest). pi 100 ... ? Es wird im Arbeitsspeicher Platz für eine integer-Zahl reserviert und die (Anfangs)Adresse dieses Speicherbereichs der Variable pi zugewiesen. ... ... pk 120 ? ... ... 140 ? pkk

  23. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); pi = new int; pk = new Konto; pkk = new Konto[anz]; 0500 ? ? ? ? zeigt auf: pi 0100 ... 0500 ... ... Speicherreservierung für ein integer, das z.B. bei der Adresse 0500 beginnt pk 0120 ? ... ... 0140 ? pkk

  24. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); pi = new int; pk = new Konto; pkk = new Konto[anz]; 0500 ? ? ? ? ? 0504 ... ... zeigt auf: ? pi 0100 ... 0500 ... ... pk 0120 0504 Speicherreservierung für ein Objekt der Klasse Konto (hier: 100 Byte) ... ... 0140 ? pkk

  25. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); pi = new int; pk = new Konto; pkk = new Konto[anz]; 0504 ? Speicherreservierung für ein Feld der Länge 2 mit Objekten der Klasse Konto (hier: 2*100 Byte) ... ... ? ? 0604 ... ... ? pi 0100 ... 0500 ? 0704 ... ... zeigt auf: ... pk 0120 0504 ... ... ... ? 0140 0604 pkk

  26. *pi = 5; (*pk).setM('M'); // pk->setM('M'); (*(pkk+1)).setM('F'); // pkk[1].setM('F'); // (pkk+1)->setM('F'); delete pi; delete pk; delete [] pkk; } 0504 ? ... ... ? ? 0604 ... ... ? pi 0100 ... 0500 ? 0704 ... ... ... pk 0120 0504 ... ... ... ? 0140 0604 pkk

  27. *pi = 5; (*pk).setM('M'); // pk->setM('M'); (*(pkk+1)).setM('F'); // pkk[1].setM('F'); // (pkk+1)->setM('F'); delete pi; delete pk; delete [] pkk; } 0500 0005 Bemerkung: Die Zahl (hier 5) wird in den zur Verfügung stehenden 32 Bit gespeichert (in welchen Bits die einzelnen Ziffern der Zahl stehen, interessiert uns hier nicht). pi 0100 ... 0500 ... ... pk 0120 0504 ... ... gleiche Befehle, nur anders geschrieben 0140 0604 pkk

  28. *pi = 5; (*pk).setM('M'); // pk->setM('M'); (*(pkk+1)).setM('F'); // pkk[1].setM('F'); // (pkk+1)->setM('F'); delete pi; delete pk; delete [] pkk; } 0504 ‘M‘ ... ... 0604 ? ? ... ... ? pi 0100 ... 0500 ? 0704 ... ... ... pk 0120 0504 ... ... ... gleiche Befehle, nur anders geschrieben ? 0140 0604 pkk

  29. *pi = 5; (*pk).setM('M'); // pk->setM('M'); (*(pkk+1)).setM('F'); // pkk[1].setM('F'); // (pkk+1)->setM('F'); delete pi; delete pk; delete [] pkk; } 0504 ‘M‘ ... ... 0604 ? ? ... ... ? pi 0100 ... 0500 ‘F‘ 0704 ... ... ... pk 0120 0504 ... ... ... ? 0140 0604 pkk

  30. Was macht das gleiche Programm, aber ohne die folgenden Anweisungen:pi = new int;pk = new Konto;pkk = new Konto[anz];

  31. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); *pi = 5; (*pk).setM('M'); // pk->setM('M'); (*(pkk+1)).setM('F'); // pkk[1].setM('F'); // (pkk+1)->setM('F'); ... Welchen Wert hat pi z.B. an dieser Stelle des Programms ?

  32. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); *pi = 5; (*pk).setM('M'); (*(pkk+1)).setM('F'); ? bedeutet: irgendein unbekannter, zufälliger Wert. Zum Beispiel: 0815 pi 0100 ... ? ... ... pk 0120 ... ... ... 0140 ... pkk

  33. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); *pi = 5; (*pk).setM('M'); (*(pkk+1)).setM('F'); Was steht an der Adresse 0815 im Arbeitsspeicher ? Der Programmier weiß es nicht, denn er hat an dieser Adresse keinen Speicherplatz reservieren lassen und diesen entsprechend belegt. pi 0100 ... 0815 Im "schlimmsten" Fall könnte an der Adresse 0815 zum Beispiel... ... ... pk 0120 ... ... ... Ein Teil des Betriebssystems beginnen ! 0140 ... pkk

  34. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); *pi = 5; (*pk).setM('M'); (*(pkk+1)).setM('F'); 0815 Teil des Betr. Syst. pi 0100 ... 0815 ... ... pk 0120 ... ... ... 0140 ... pkk

  35. int main(){ int anz; int *pi; Konto *pk, *pkk; anz = rand(); *pi = 5; (*pk).setM('M'); (*(pkk+1)).setM('F'); 0815 5 0 0 0 pi 0100 ... 0815 Analoges gilt auch für die folgenden Anweisungen ... ... pk 0120 ... Dieser Teil des Betriebssystems wird überschrieben ... ... 0140 ... pkk

More Related