9. Dynamische Speicherverwaltung - oth

Werbung
9. Dynamische Speicherverwaltung
Dynamische Speicherverwaltung
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-1
9. Dynamische Speicherverwaltung
Wiederholung:
Verwendung von dynamischen Datenobjekten (Variablen,
Strukturen, ...)
ist nur auf Basis des Zugriffs zu den
Datenobjekten über die Zeiger möglich.
Eine statische Variable ist eine Variable, die in einem Programm
definiert und später durch ihren Bezeichner verwendet wird. Sie
wird statisch genannt, weil sie während der ganzen Abarbeitung
der Funktion (des Blocks), zu der (dem) sie gehört, existiert; d.h.
ihr wird Speicherplatz für ganze Abarbeitungszeit zugeordnet.
Demgegenüber kann eine Variable auch dynamisch während der
Abarbeitung einer Funktion erzeugt und vernichtet werden (ohne
jede Beziehung zur statischen Struktur des Programms). Solche
Variablen heissen deshalb dynamische Variablen.
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-2
9. Dynamische Speicherverwaltung
Zugriff zu den dynamischen Datenobjekten ist nur über Zeiger
(indirekt) möglich:
Prinzip:
ZEIGER
DYN. VARIABLE
ADRESSE
INHALT
Zeiger ist eine Hilfsvariable, die die Adresse des Datenobjektes
enthält und über diese Adresse auf das Datenobjekt verweist.
Beispiel:
pa
a
&a
INHALT
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-3
9. Dynamische Speicherverwaltung
Prinzip der Verwendung von dynamischen Objekten
► Entsprechende Zeiger (Zeiger auf entsprechende Datentypen) klassisch (statisch) definieren
► Speicherplatz anfordern (reservieren) – dynamische
Objekte erzeugen
► Daten auf dynamische Datenobjekte entsprechend (über
die Zeiger) abspeichern
► Daten über Zeiger bearbeiten, Ergebnisse ausgeben
► Dynamische Datenobjekte löschen (vernichten), Speicherplatz freigeben
► Inhalte von Zeigern löschen (wenn nötig)
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-4
9. Dynamische Speicherverwaltung
Funktionen für Speicherreservierung und Speicherfreigabe
malloc() – reserviert Speicherplatz einer bestimmten Größe
char *zeichenfeld;
int *za;
. . .
za = (int*) malloc (sizeof(int));
zeichenfeld = (char*) malloc (20*sizeof(char) + 1);
calloc() – reserviert Speicherplaz für ein Feld und
initialisiert diesen Bereich
char
*zeichenfeld;
double *zahlen;
. . .
zeichenfeld = (char*) calloc (20, sizeof(char));
zahlen = (double*) calloc (10, sizeof(double));
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-5
9. Dynamische Speicherverwaltung
realloc() – erweirtert oder verkleinert einen reservierten
Speicherplatz (reallocate)
zeichenfeld = (char*) realloc (zeichenfeld, 80);
zahlen = (double*) realloc (zahlen, 100);
free() – gibt den Speicherbereich frei, der mit einer der
obigen Funktionen reserviert wurde
free (zeichenfeld);
free (zahlen);
zeichenfeld = zahlen = NULL;
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-6
9. Dynamische Speicherverwaltung
Beispiel:
/*
Programm C14_0.c - Demonstration der dynamischen Speicherverwaltung
*/
#include <stdio.h>
main ()
{
char *zeichenfeld, *e_zeichen, *z1, *z2; /*
char zeichenkette[] = "
int
Definitionen von Zeigern
Zeichenkette eingeben:
*za, *zb, *zc, i;
*/
";
/* Speicherplatzresevierungen */
za = (int *) malloc (sizeof (int));
zb = (int *) malloc (sizeof (int));
zc = (int *) malloc (sizeof (int));
e_zeichen = (char *) malloc (sizeof (char));
zeichenfeld = (char *) malloc (20 * sizeof (char) + 1);
z2 = (char *) malloc (strlen (zeichenkette) + 1);
strcpy (z2, zeichenkette);
/* Daten auf dynamische Daten- */
printf ("\n%s", z2);
/*
objekte abspeichern
*/
gets (zeichenfeld);
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-7
9. Dynamische Speicherverwaltung
printf ("\n
Variable
a
eingeben:
");
scanf ("%i", za);
printf ("\n
Variable
b
eingeben:
");
scanf ("%i", zb);
*zc = *za + *zb;
/*
einfache Datenverarbeitungen
*/
/*
je zwei Zeichen wechseln
*/
Ausgabe von Ergebnissen
*/
z1 = zeichenfeld;
for (i=0; i<19; i+=2) {
*e_zeichen = *z1;
*(z1++) = *(z1+1);
*(z1++) = *e_zeichen;
}
printf ("\n
/*
Ergebnisse: %s , %i \n\n", zeichenfeld, *zc);
free (za);
free (zb);
/*
Speicherplatzfreigabe
*/
free (zc);
free (zeichenkette);
free (e_zeichen);
free (z2);
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-8
9. Dynamische Speicherverwaltung
Typische Applikationen
a) Lineare verkettete Listen
► einfach verkettete
L
► doppelt verkettete
L
b) Baumstrukturen
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-9
9. Dynamische Speicherverwaltung
Lineare, einfach verkettete Listen
Algebraische Repräsentation:
L = [ e1, e2, e3, . . . , en-1, en ]
Graphische Repräsentation:
L
e1
e2
e3
en-1
en
Listenelemente enthalten
► Datenobjekte (direkter Zugriff – für einfache Datenobjekte)
► Zeiger auf Datenobjekte (indirekter Zugriff – für strukturierte
Datenobjekte)
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-10
9. Dynamische Speicherverwaltung
Beispiel 1: Fünf isolierte dynamische Datenobjekte
z1
z2
15
z3
25
z4
35
z5
45
55
Programm:
int
*z1, *z2, *z3, *z4, *z5;
. . .
z1 = (int*) malloc (sizeof(int));
z2 = (int*) malloc (sizeof(int));
. . .
z5 = (int*) malloc (sizeof(int));
scanf("%i", z1); scanf("%i", z2); scanf("%i", z3); ...
oder
scanf ("%i %i %i %i %i", z1, z2, z3, z4, z5);
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-11
9. Dynamische Speicherverwaltung
Beispiel 2: Fünf dynamische Datenobjekte in einer einfach
verketteten Liste, Werte direkt in Elementen
L
w1
w2
w3
w4
w5
Programm:
struct list_el {
int wert;
struct list_el *next;
} ;
main () {
struct list_el *L=NULL, *hilf;
int i;
/*
Struktur Listenelement
/*
nur Schablone
/*
zwei Zeiger
/* Zähler
*/
*/
*/
*/
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-12
9. Dynamische Speicherverwaltung
for (i=1; i<=5; i++) {
/* Erzeugung und Eingabe
hilf = (struct list_el *) malloc (sizeof(list_el));
scanf ("%i", &hilf->wert);
hilf -> next = L;
*/
L = hilf;
}
hilf = L;
while (hilf)
/*
Ausgabe
*/
{
printf (" . . . %i", hilf -> wert);
hilf = hilf -> next;
}
while (L) {
hilf = L;
/*
Speicherfreigabe
*/
L = L -> next;
free (hilf);
}
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-13
9. Dynamische Speicherverwaltung
Beispiel 3: Fünf dynamische Datenobjekte in einer einfach
verketteten Liste, Werte in eigenen Elementen
L
w1
w2
w3
w4
w5
Programm:
typedef struct list_el {
/*
int *wert;
struct list_el *next;
} item, *Pitem;
main () {
Pitem L = NULL, hilf;
int i;
Struktur Listenelement
/*
*/
Typdefinitionen
*/
/*
*/
*/
zwei Zeiger
/* Zähler
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-14
9. Dynamische Speicherverwaltung
for (i=1; i<=5; i++)
{
/*
Erzeugung und Eingabe
*/
hilf = (Pitem) malloc (sizeof(item));
hilf->wert = (int*) malloc (sizeof(int));
scanf ("%i", hilf->wert);
hilf -> next = L;
L = hilf;
}
hilf = L;
/*
while (hilf)
Ausgabe
*/
Speicherfreigabe
*/
{
printf (" . . . %i", *hilf -> wert);
hilf = hilf -> next;
}
while (L)
{
/*
hilf = L;
L = L -> next;
free (hilf->wert);
free (hilf);
}
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-15
9. Dynamische Speicherverwaltung
Das erste Programm mit dynamischen Datenobjekten
#include <stdio.h>
main () {
typedef struct element *P_element;
typedef struct element {
int value;
P_element next;
} ELEM;
P_element
L;
L = (P_element) malloc (sizeof(ELEM));
L -> value = 5;
L -> next = NULL;
printf ("
L -> value = %d \n\n", L -> value);
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-16
9. Dynamische Speicherverwaltung
#include <stdio.h>
#define NEW(PP)
((PP) = (PITEM)malloc(sizeof(ITEM)))
#define TEST(PP) if (NEW(PP) == NULL) {printf("Memory error\n"); return;}
typedef struct item {
/*
structure item
*/
/*
new types
*/
int val;
struct item *next;
} ITEM, *PITEM;
main()
{
int i, n;
PITEM current, first, prev;
printf ("Enter a positive integer value: ");
scanf ("%d", &n);
if (n < 1) {
printf ("
Number must be positive! \n");
return;
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-17
9. Dynamische Speicherverwaltung
TEST(first)
/* create the list */
current = first;
first->val = 1;
for (i=2; i<=n; i++) {
TEST(current->next)
current = current->next;
current->val = i;
}
current->next = NULL;
/* remove elements divisible by 3 */
for (prev = current = first; current != NULL;
prev = current, current = current->next)
if (current->val % 3 == 0) {
prev->next = current->next;
free((PITEM)current);
current = prev;
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-18
9. Dynamische Speicherverwaltung
/* display what is left */
for (current = first; current != 0; current = current->next)
printf ("\n%d\n", current->val);
/* remove the list */
for (prev = current = first; current != NULL;
prev = current, current = current->next)
free ((PITEM) prev);
first = current;
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-19
9. Dynamische Speicherverwaltung
#include <stdio.h>
#define N 20
struct item {
int zahl;
char text[N];
struct item *next;
};
int anzahl;
struct item *P;
int main ()
{
char buffer[N], zeichen = '\0';
void menu(), init(), insert(), delete(), read(), ausgabe(), destroy();
printf ("\n\t\t
IMPLEMENTIERUNG DER LISTE \n\n");
anzahl = 0;
menu ();
zeichen = getchar();
getchar();
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-20
9. Dynamische Speicherverwaltung
while (zeichen != 'e')
{
switch (zeichen) {
case 'd': delete();
break;
case 'e': destroy();
break;
case 'i': init();
break;
case 'l': printf ("\n Alle Listenelemente auflisten: \n\n");
ausgabe();
break;
case 'n': printf ("\n Gebe den Text für das %d.Element ein:
",
anzahl+1);
scanf("%s", buffer);
insert (buffer);
getchar();
break;
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-21
9. Dynamische Speicherverwaltung
case 'r': printf ("\n Inhalt des letzten Listenelements ist: ");
read (buffer);
printf (" %s\n", buffer);
break;
default:
zeichen = '\0';
}
if (zeichen == 'e') break;
else {
menu ();
zeichen = getchar();
getchar();
}
}
printf ("\n Demonstration Ende \n\n");
return 0;
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-22
9. Dynamische Speicherverwaltung
void menu ()
{
printf ("\n Gewünschte Funktion wählen:\n\n");
printf ("
Initialisierung
. . . . . . . . . . . .
printf ("
Ein neues Element eingeben (insert)
. .
n \n");
printf ("
Element löschen (delete) . . . . . . . .
d \n");
printf ("
Ausgabe des letzten Elements (read)
. .
r \n");
printf ("
Ganze Liste auflisten
. . . . . . . . .
l \n");
printf ("
Programm beenden . . . . . . . . . . . .
e \n");
printf ("\n Das entsprechende Zeichen eingeben:
i \n");
");
}
void init ()
{
anzahl = 0;
P = NULL;
printf ("\n Neue Liste \n");
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-23
9. Dynamische Speicherverwaltung
void insert (char *buf)
{
int i; struct item *Q;
Q = malloc (sizeof (struct item));
Q->zahl = ++anzahl;
strcpy (Q->text, buf);
Q->next = P;
P = Q;
printf ("\n Element
*%s*
wurde eingefügt \n", buf);
}
void delete (void)
{
struct item *Q;
if (P != NULL) {
Q = P;
P = P->next;
printf ("\n Element
*%s*
wurde gelöscht\n", Q->text);
free (Q);
anzahl--;
}
else
printf ("\n !!!
Leere Liste
!!! \n");
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-24
9. Dynamische Speicherverwaltung
void read (char *buf)
{
int i;
strcpy (buf, P->text);
}
void ausgabe (void)
{
int i;
struct item *Q;
Q = P;
printf (" Anzahl von Listenlementen:
for (i=0; i<anzahl; i++)
printf ("\n
%d\n", anzahl);
{
%d.Element = %s\n", Q -> zahl, Q -> text);
Q = Q -> next;
}
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-25
9. Dynamische Speicherverwaltung
void destroy (void)
{
struct item *Q;
while (P != NULL) {
Q = P;
P = P->next;
printf ("\n Element
*%s*
wurde gelöscht\n", Q->text);
free (Q);
anzahl--;
}
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-26
9. Dynamische Speicherverwaltung
Baumstrukturen – mehrfach verzweigte Strukturen
Bäume – binäre
– n-äre (z.B. Quadtrees)
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-27
9. Dynamische Speicherverwaltung
Binäre Suchbäume
Kurt
Franz
Rolf
Dieter
Erich
Hans
Leo
W Werner
Karl
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-28
9. Dynamische Speicherverwaltung
Ein neues Element „Sepp“ einfügen:
Kurt
Franz
Rolf
Dieter
Erich
Hans
Leo
W Werner
Karl
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-29
9. Dynamische Speicherverwaltung
Ein neues Element „Sepp“ einfügen:
Kurt
Franz
Rolf
Dieter
Erich
Hans
Leo
Karl
W Werner
Sepp
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-30
9. Dynamische Speicherverwaltung
Das Element „Hans“ löschen:
Kurt
Franz
Rolf
Dieter
Erich
Hans
Leo
Karl
W Werner
Sepp
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-31
9. Dynamische Speicherverwaltung
Das Element „Hans“ löschen:
Kurt
Franz
Rolf
Dieter
Erich
Karl
Leo
W Werner
Sepp
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-32
9. Dynamische Speicherverwaltung
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
struct knoten
{
knoten *links, *rechts;
char *inhalt;
} ;
// diesmal Zeiger auf String
/* Neues Element erzeugen: */
knoten * erzeugeknoten ( const char * name )
{
knoten *p;
p = new knoten;
p->links = p->rechts = NULL;
p->inhalt = new char [strlen (name) + 1];
// Speicher fuer String anfordern
strcpy (p->inhalt, name);
return p;
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-33
9. Dynamische Speicherverwaltung
/* Geordnetes Einfuegen eines neuen Elements in den Baum: */
/* Verwendung der Rekursion! */
void suche ( const char *name, knoten * & baum )
{
int i;
if (baum == NULL)
// Ende der Rekursion
{
baum = erzeugeknoten (name);
// Einfuegen des Elements
return;
}
if ( (i=strcmp (name, baum->inhalt) ) < 0 )
suche ( name, baum->links );
// Suche links
else if (i>0)
suche ( name, baum->rechts );
// Suche rechts
else
cout << "Name " << name << " ist bereits vorhanden\n";
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-34
9. Dynamische Speicherverwaltung
/* Ausgeben des gesamten Baums mit Anzeige der Tiefe: */
void ausgeben (const knoten * baum, const int tiefe)
{
if (baum)
//
!= NULL
{
ausgeben ( baum -> links, tiefe + 1 );
cout << setw(5*tiefe) << " " << baum->inhalt << '\n';
ausgeben ( baum -> rechts, tiefe + 1 );
}
}
/* Loeschen eines Baumelements: */
void loesche ( const char * name, knoten * & baum )
{
int i;
knoten * p1;
// merkt das zu loeschende Element
knoten **p2;
// sucht Ersatzelement (call by reference)
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-35
9. Dynamische Speicherverwaltung
/* suchen des zu loeschenden Elements */
if (baum == NULL)
// Ende der Rekursion
{
cout << "Element wurde nicht gefunden\n";
return;
}
if ( (i=strcmp (name, baum->inhalt) ) < 0 )
loesche ( name, baum->links );
else if (i>0)
loesche ( name, baum->rechts );
else
{
// zu ersetzender Knoten ist gefunden
p1 = baum;
if (p1->rechts == NULL)
// ein Nachfolger ist NULL
baum = p1->links;
else if (p1->links == NULL)
// ein Nachfolger ist NULL
baum = p1->rechts;
else
// beide Nachfolger sind nicht NULL
{
// komplexer Fall, Ersatzelement suchen
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-36
9. Dynamische Speicherverwaltung
p2 = &(p1->links);
// linker Nachfolger
while ( (*p2)->rechts != NULL)
// bis zum rechten Ende
p2 = &(*p2)->rechts;
// jetzt zeigt *p2 auf das Ersatzelement
// es folgt die neue Verkettung
baum = *p2;
*p2 = (*p2)->links;;
baum->links = p1->links;
baum->rechts = p1->rechts;
}
/* Element kann geloescht werden: */
delete p1->inhalt;
// Speicher fuer String!!!
delete p1;
// Speicher fuer Element
}
}
int main () {
knoten * root = NULL;
const int N = 80;
char name[N];
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-37
9. Dynamische Speicherverwaltung
cout << "\nGeordnetes Einfuegen und Loeschen in einem Baum\n"
<< "Namen eingeben. Ende ist leerer String!\n";
cin.getline ( name, N-1 );
while ( strlen(name) != 0 )
{
suche ( name, root );
cin.getline ( name, N );
}
cout << "\nAusgabe des Baums:\n";
ausgeben (root, 0);
cout << "\nWelcher Name soll geloescht werden?\n";
cin.getline (name, N);
loesche ( name, root );
cout << "\nAusgabe des neuen Baums:\n";
ausgeben (root, 0);
return 0;
}
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-38
9. Dynamische Speicherverwaltung
Zusammenfassung
► Statische Datenobjekte (Variablen) haben einen Wert, einen Namen und
einen Speicherplatz.
► Dynamische Datenobjekte (Variablen) haben nur einen Wert und einen
Speicherplatz.
► Zugriff zu den dynamischen Datenobjekten ist nur über Zeiger möglich.
► Zeiger-Variablen (Pointer-Variablen) enthalten immer die Adresse des
Datenobjektes, auf das sie verweisen, und sie können statisch oder
dynamisch definiert werden.
► Ein dynamisches Datenobjekt erzeugen:
Zeiger statisch oder dynamisch definieren
Speicherplatz anfordern
Daten abspeichern
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-39
9. Dynamische Speicherverwaltung
► Das existierende dynamische Datenobjekt vernichten:
Daten bearbeiten und anderswohin abspeichern oder löschen
Speicherplatz freigeben
Zeiger löschen oder vernichten (wenn dynamisch erzeugt wurde)
► Verkettete Listen –
Einfach oder doppelt verkettete lineare Strukturen
Zeiger für den Zugriff zur Liste soll (meistens statisch) definiert werden
Alle Listenelementen werden dynamisch erzeugt
► Baumstrukturen –
Mehrfach verzweigte (nichtlineare) Strukturen
Zeiger für den Zugriff zum Baum soll (meistens statisch) definiert werden
Alle Baumelementen werden dynamisch erzeugt
► Für beide Typen von dynamischen Datenstrukturen gilt:
Ein neues Element mit einem Hilfszeiger erzeugen
Alle notwendigen Daten (meistens Zeiger) auf das Element abspeichern
Das Element auf entsprechendem Ort der Struktur (Liste, Baum) einfügen
________________________________________________________________________________________________________________________________
V. Matoušek: Informationsverarbeitung / FH Regensburg
9-40
Herunterladen