Dynamischer Speicher und Struktur

Slides:



Advertisements
Ähnliche Präsentationen
Einführung in die Programmiersprache C/C++
Advertisements

Imperative Programmierung
Vorbereitung: struct knoten { int x; struct knoten *l, *r; } *b, *bh, **bp; b: Zeiger auf Wurzel bh: Hilfszeiger bp: Zeiger auf Zeiger auf knoten b bp.
Funktionen, Felder und Parameter-übergabe
Funktionen.
Forschungszentrum caesar
Verzweigung oder bedingte Anweisung Weiter mit PP.
Sequentielle Liste - Array
Indirekte Adressierung
FH-Hof Indirekte Adressierung Richard Göbel. FH-Hof Einfache Speicherung von Daten Eine "einfache" Deklaration definiert direkt eine Speicherplatz für.
SWITCH - Anweisung.
SWITCH - Anweisung.
Datentyp- umwandlung. Literale sind: Bezeichner mit einem festen Wert wie z.B:
Dateien. Eine Datei wird in C++ als ein Stream, also als ein Objekt einer bestimmten Klasse dargestellt.
REKURSION + ITERATION. Bemerkung: Die in den folgenden Folien angegebenen "Herleitungen" sind keine exakten Beweise, sondern Plausibilitätsbetrachtungen.
Strukturen. In einer Struktur kann eine beliebige Anzahl von Komponenten (Daten) mit unterschiedlichen Datentypen (im Gegensatz zu Feldern) zusammengefaßt.
ARRAY oder FELD oder VEKTOR
Dynamischer Speicher. Ein Vergleich aus dem täglichen Leben...
Funktionen.
Ein Beispiel in Java.
Dynamisches Array als "verkettete Liste". Ein Vergleich.
Pointer. Grundsätzliches: Im Arbeitsspeicher werden Daten gespeichert. Um auf die Daten eindeutig zugreifen zu können, werden diesen Daten Adressen zugeordnet.
Klassenvariable. Da man für jede Kuh bzw. jede Henne auf dem Markt den gleichen Preis für ein Liter Milch, bzw. den gleichen Preis für ein Ei bekommt,
WHILE - Anweisung.
Objekte werden als Adressen (Referenzen) übergeben. Dies führt manchmal zu unerwarteten Ergebnissen...
Parameterübergabe von zweidimensionalen Feldern in Funktionen.
Polymorphie (Vielgestaltigkeit)
Assoziationen (Beziehungen). Zwischen Objekten kann es eine Beziehung geben.
Polymorphie (Vielgestaltigkeit)
Objekte und Arbeitsspeicher
V AdresseWert public static void main(...){ int[] v; v=new int[2]; } Was veranlasst diese Anweisung im Arbeitsspeicher ? Es wird im Arbeitsspeicher.
FOR Anweisung.
Der Präprozessor. Bevor der Compiler das Programm in Maschinencode übersetzt (nur dieser kann von der CPU, dem Herz des Computers, bearbeitet werden)
FOR Anweisung. Aufgabe : Ausgabe aller ganzen Zahlen von 0 bis 100 auf dem Bildschirm.
DO...WHILE Anweisung.
Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen.
ARRAY oder FELD oder VEKTOR
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 7 Claudio Moraga, Gisbert Dittrich FBI Unido
Vorbereitung: struct SX { int x; struct SX *p; } *px, *ph; px: Zeiger auf Listen- anfang ph: Hilfszeiger px = NULL; px zeigt auf leere Liste px.
Verkettete Liste Visualisierung. New-Operator Mit dem New-Operator kann zur Laufzeit (dynamisch) Speicherplatz reserviert und angelegt werden Vorteil:
EDV1 - Komplexe Datentypen
Einführung in Visual C++
Arrays,Strings&Pointer in C/C++
Inhalt danach. inhalt danach inhalt danach inhalt danach inhalt danach inhalt danach.
Einfach verkettete Listen (OOP)
Wichtige Fachausdrücke in C
Informatik Grundlagen, WS04, Seminar 11
Programmieren in C Zeichen-/Stringfunktionen Dynamischer Speicher
Einführung in die Programmiersprache C 3.Tag Institut für Mathematische Optimierung - Technische Universität Braunschweig.
Einführung in die Programmierung
Einführung in die Programmiersprache C 4
Programmierung 1. Einführung Seite 1
Programmieren in C Dynamische Listen / Bäume
Learning By Doing Ausnahmebehandlung Exceptions (Ausnahmebehandlung) Typische Fehlverhalten zur Laufzeit: s. Buch S. 287ff -Verwendung von null-Objekten.
Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.
early binding (frühe Bindung) late binding (späte Bindung)
Installation, Konfiguration, Online stellen, Zugriff © by Lars Koschinski 2003.
C Tutorium – Memory Management – Knut Stolze. 2 Agenda Einführung in die Speicherverwaltung Stack vs. Heap Malloc Free Sizeof Tipps/Hinweise.
Funktionen. Aufgabe : Eingabe zweier Zahlen ---> Minimum bestimmen Dann nochmals Eingabe zweier Zahlen ---> Minimum bestimmen.
Dynamisches Array als "verkettete Liste". Ein Vergleich.
Pointer. Grundsätzliches: Im Arbeitsspeicher werden Daten gespeichert. Um auf die Daten eindeutig zugreifen zu können, werden diesen Daten Adressen zugeordnet.
Funktionen, Felder und Parameter- übergabe. Funktionsaufruf mit Feld als Parameter: Parameter = Name des Feldes.
1 // Verkettete Liste 2 // demonstriert verkettete Listen und // Rekursion // (Einfügen am "Fuß") // #include struct Liste { int Element; Liste *weiter;
Tutorium Software-Engineering SS14 Florian Manghofer.
FOR Anweisung. Aufgabe : Ausgabe aller ganzen Zahlen von 0 bis 100 auf dem Bildschirm.
Strukturen (Eigenschaften) Strukturen dienen zur Zusammenfassung mehrerer Komponenten verschiedener Typen zu einer Einheit, die dann mit gemeinsamen Namen.
Pointer. * und &  Bei der Definition int var1; ○ // „normale“ Variable int *var2; ○ // Zeiger auf einen Integer int *var2 = NULL; ○ // … incl. Initialisierung.
ESP Tutorium Studienassistent: Ewald Moitzi Gruppe 1.
Dynamisches Array als "verkettete Liste"
Arrays in C Ein Array ist eine Variable, die aus einer Anzahl von Elementen des gleichen Datentyps besteht, die aufeinanderfolgend im Speicher liegen.
 Präsentation transkript:

Dynamischer Speicher und Struktur

Beispiel:

In einem Test-Programm werden die Anzahl, die Länge, Breite und Höhe mehrerer Räume gespeichert. Der Anwender gibt die Anzahl der abzuspeichernden Räume ein. Die Länge, Breite und Höhe werden vorläufig (zu Testzwecken) durch das Programm festgelegt.

Ein Raum wird durch folgende Struktur realisiert:

struct dtraum{ int l; int b; int h; };

Realisieren Sie das Programm durch ein Feld, dessen einzelne Elemente jeweils eine Struktur bilden.

#include "stdafx.h" #include <malloc.h> struct dtraum{ int l; int b; int h; }; // gleich geht es weiter...

printf("Anzahl eingeben =\n"); scanf("%d",&anz); int main(){ int anz,i; struct dtraum v[1000]; printf("Anzahl eingeben =\n"); scanf("%d",&anz); for(i=0;i<anz;i++){ v[i].l=i; v[i].b=i+10; v[i].h=i+20; } Welchen Nachteil hat dieses Programm bezüglich des Speicherplatzverbrauchs Der Anwender kann mehr Speicher – als reserviert – verbrauchen. (z.B. bei Eingabe von 2000 für anz). Dies ist dann “Unerlaubte Speicherbenutzung“ Der Anwender kann weniger Speicher – als reserviert – verbrauchen (z.B. bei Eingabe von 1 für anz). 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 des Programmlaufs gemacht und heißt deshalb dynamischer Speicher(reservierung).

Die Funktion malloc kann während der Laufzeit des Programms eine gewünschte Menge Speicher (vom Betriebssystem) organisieren. Welche Angabe braucht man dann, um auf diesen Speicher zuzugreifen ?

Man braucht die Anfangsadresse dieses reservierten Speicherbereichs Man braucht die Anfangsadresse dieses reservierten Speicherbereichs. Die Funktion malloc liefert diese Anfangsadresse zurück.

Beispiel:

int main(){ int. pint; pint = (int. ) malloc(3 int main(){ int *pint; pint = (int *) malloc(3*sizeof(int)); // pint = (int *) malloc(12); } malloc verlangt, daß man - durch den cast Operator (..) - den Datentyp angibt, auf den die Anfangsadresse des Speicherbereichs zeigt reserviert Speicher für 3 * Speicherbedarf(integer) nicht empfehlenswert: falls man weiß wieviel Speicher 3 Integer belegen, könnte man auch die Anzahl der Bytes direkt angeben Anfangsadresse des reservierten Speichers

Realisieren Sie das vorige Programm, in dem die Räume in einem Feld abgespeichert wurden, durch die Verwendung von dynamischem Speicher.

#include "stdafx.h" #include <malloc.h> struct dtraum{ int l; int b; int h; }; // gleich geht es weiter...

printf("Anzahl eingeben\n\n"); scanf("%d",&anz); int main(){ int i; int anz=0; struct dtraum *pr; printf("Anzahl eingeben\n\n"); scanf("%d",&anz); pr = (struct dtraum *) malloc (anz*sizeof(struct dtraum)); Hier wird nachher der Anfang des dynamischen Speichers (in einem Zeiger) festgehalten. reserviert Speicher für... Welchen Wert hat pr an dieser Stelle ? berechnet den Speicherbedarf von der Struktur dtraum : 3 · Speicherbedarf(integer) = 12 Byte pr 0100 0100 ? Annahme: Die Variable pr werde an der Adresse 0100 gespeichert. anz Speicherelemente mit dem Datentyp struct dtraum

gleiche Befehle, nur anders geschrieben ... pr = (struct dtraum *) malloc (anz*sizeof(struct dtraum)); for(i=0;i<anz;i++){ (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } Annahme: anz = 2 pr 0100 0100 ? gleiche Befehle, nur anders geschrieben

... pr = (struct dtrau (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } 0500 ? ... ? 0504 ? ... ? 0508 ? ... ? 0512 ? ... ? Annahme: Speicherbereich beginnt bei Adresse 0500 0516 ? ... pr 0100 0100 0500 ? 0520 ? Speicherreservierung für : 2 · sizeof(dtraum) = 2 · 3 · 4 Byte. ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 0 · 12) 0500 ? ... ? 0504 ? ... ? 0508 ? ... ? 0512 ? ... ? 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 0 · 12) 0500 0 0 ... 0504 ? ... ? 0508 ? ... ? 0512 ? ... ? 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 0 · 12) 0500 0 0 ... 0504 ? ... ? 0508 ? ... ? 0512 ? ... ? 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 0 · 12) 0500 0 0 ... 0504 1 0 ... 0508 ? ... ? 0512 ? ... ? 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 0 · 12) 0500 0 0 ... 0504 1 0 ... 0508 ? ... ? 0512 ? ... ? 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 0 · 12) 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 ? ... ? 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 1 · 12) 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 ? ... ? 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 1 · 12) 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 0 1 ... 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 1 · 12) 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 0 1 ... 0516 ? ... pr 0100 0100 0500 ? 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 1 · 12) 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 0 1 ... 0516 1 1 ... pr 0100 0100 0500 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 1 · 12) 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 0 1 ... 0516 1 1 ... pr 0100 0100 0500 0520 ? ... ?

... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } *(0500 + 1 · 12) 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 0 1 ... 0516 1 1 ... pr 0100 0100 0500 0520 2 1 ...

reservierten Speicher wieder freigeben ... pr = (struct dtraum (anz*sizeof(st for(i=0;i<anz;i++) (*(pr+i)).l=i; // (pr+i)->l=i; // pr[i].l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } reservierten Speicher wieder freigeben 0500 0 0 ... 0504 1 0 ... 0508 2 0 ... 0512 0 1 ... 0516 1 1 ... pr 0100 0100 0500 0520 2 1 ... free(pr);

WICHTIG: Die Verwendung von malloc sollte immer wie folgt geschehen:

// z.B. Anweisungen // siehe oben... free(pr); } if(pr != NULL){ pr = (struct dtraum *) malloc (anz*sizeof(struct dtraum)); if(pr != NULL){ // z.B. Anweisungen // siehe oben... free(pr); } Wenn pr den Wert NULL (0) hat bedeutet dies: Vom Betriebssystem kann kein Speicher mehr reserviert werden, weil z.B. schon vorher im Programm viel Speicher reserviert wurde.

if(pr != NULL){ // Anweisungen // ... free(pr); } pr->l=100; pr = (struct dtraum *) malloc (anz*sizeof(struct dtraum)); if(pr != NULL){ // Anweisungen // ... free(pr); } Was geschieht, wenn nach der Freigabe des reservierten Speichers auf diesen Speicher zugegriffen wird? pr->l=100; printf("%d", pr->l); Es kann (muss aber nicht) zur Laufzeit eine Fehlermeldung erscheinen (übliche blaue Fenster...). Wenn keine Fehlermeldung erscheint, kann sich dieser Fehler später im Programm sehr unangenehm bemerkbar machen...

Was macht das gleiche Programm, aber ohne die Anweisung: pr = (struct dtraum *) malloc (anz*sizeof(struct dtraum));

printf("Anzahl eingeben\n\n"); scanf("%d",&anz); int main(){ int i; int anz=0; struct dtraum *pr; printf("Anzahl eingeben\n\n"); scanf("%d",&anz); for(i=0;i<anz;i++){ (*(pr+i)).l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } Welchen Wert hat pr an dieser Stelle des Programms ? ? bedeutet: irgendein unbekannter, zufälliger Wert. Zum Beispiel: 0815 pr 0100 0100 ?

printf("Anzahl eingeben\n\n"); scanf("%d",&anz); int main(){ int i; int anz=0; struct dtraum *pr; printf("Anzahl eingeben\n\n"); scanf("%d",&anz); for(i=0;i<anz;i++){ (*(pr+i)).l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } 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. Als schlimmer Fall könnte an der Adresse 0815 zum Beispiel... ein Teil des Betriebssystems stehen! pr 0100 0100 0815

int main(){ int i; int anz=0; struct dtraum *pr; printf("Anzahl ein scanf("%d",&anz); for(i=0;i<anz;i++){ (*(pr+i)).l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } 0815 Teil 0816 des 0817 Betr. 0818 Syst. pr 0100 0100 0815

for(i=0;i<anz;i++){ (*(pr+i)).l=i; (pr+i)->b=i+10; int main(){ int i; int anz=0; struct dtraum *pr; printf("Anzahl ein scanf("%d",&anz); for(i=0;i<anz;i++){ (*(pr+i)).l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } 0815 0816 0 0 0 0 0817 0818 Dieser Teil des Betriebssystems wird überschrieben pr 0100 0100 0815

Hier das ganze Programm...

#include "stdafx. h" #include <malloc. h> struct dtraum{. int l; #include "stdafx.h" #include <malloc.h> struct dtraum{ int l; int b; int h; }; int main(){ int i; int fehler=0; int anz=0; struct dtraum *pr; printf("Bitte Anzahl der Raeume eingeben =\n"); scanf("%d",&anz); pr = (struct dtraum *) malloc (anz*sizeof(struct dtraum)); if(pr!=NULL){ for(i=0;i<anz;i++){ (pr+i)->l=i; (pr+i)->b=i+10; (pr+i)->h=i+20; } free(pr); }

if(pr==NULL) printf("Es gibt keinen freien Speicher mehr"); if(pr==NULL) printf("Es gibt keinen freien Speicher mehr"); // Nur zum Test: Zugriff auf freigegebenen Speicher pr->l=100; printf("%d", pr->l); return 0; }

Übungsaufgaben: Siehe Aufgabenblatt