# 4.4 Dynamischer Speicher

Quelle: https://inf.zone/lectures/4-memory/short-4-4-dynamischer-speicher/

## Video

[Video ansehen (1080p)](https://videos.inf.zone/3eb0352b52a56e76/short-4-4-dynamischer-speicher-1080p.mp4) · [Video (720p)](https://videos.inf.zone/3eb0352b52a56e76/short-4-4-dynamischer-speicher-720p.mp4) · [Video (480p)](https://videos.inf.zone/3eb0352b52a56e76/short-4-4-dynamischer-speicher-480p.mp4) · [Video auf YouTube](https://youtu.be/_sp22gUwNfY)

## Hinweise zu diesem Video

**Einordnung**

- Das Muster zum Kopieren eines Strings mit `malloc` und `strcpy` zeigt kein Short. Es ist Basis-Code und steht in den Notes 4.
- Die Extra-Minuten empfehlen, für Speichergrößen konsequent `size_t` zu verwenden. `size_t` als eigenes Thema ist Hintergrund (Notes 4.5); Eingaben zu prüfen, bevor Sie Speicher anfordern, gehört zur Basis.

## Material

- [Folien](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf)
- Folien und Transkript: unten auf dieser Seite

## Folien und Transkript

*Folientext aus den PDF-Folien, darunter jeweils der gesprochene Text des Videos. Der gesprochene Text ist maschinell transkribiert und nachkorrigiert, kann aber noch Fehler enthalten; im Video sprechen abwechselnd Prof und eine AI-Figur, die Sprecherwechsel sind nicht markiert. Die Zuordnung zu den Folien ist ungefähr. Die Zeitangaben verlinken auf die Stelle im Video (YouTube). Maßgeblich sind Video und Folien.*

### Folie 1 — Dynamische Speicherverwaltung

[Folie 1 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=1)

#### Transkript

**[Video 00:00–00:30](https://www.youtube.com/watch?v=_sp22gUwNfY&t=0)**

Dies ist Inf-Einf-B. Heute dynamische Speicherallokation. Willkommen zu einem der spannendsten Themen der Programmierung überhaupt, der dynamischen Speicherverwaltung. Heute lüften wir endlich den Schleier und Sie lernen, wie echte Programmierer mit Speicher umgehen. Ich sehe da hinten schon die ersten Freudentränen fließen. Freudentränen? Wirklich? Das ist ja großartig. Ich wusste, die Studierenden teilen meine Begeisterung für Speichermanagement. Naja, ich glaube, Freudentränen ist vielleicht nicht das richtige Wort.

### Folie 2

[Folie 2 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=2)

Bisher haben wir Zeiger nur auf eine Art verwendet: Wir haben mit ihnen auf Variablen gezeigt, die bereits in unserem System existieren.

Das bedeutet, wir müssen beim Kompilieren schon genau wissen, wie viel Speicher unser Programm benötigen wird.

Was aber, wenn wir die benötigte Speichermenge erst während der Programmausführung erfahren?

Wie bekommen wir dann Zugriff auf zusätzlichen Speicher?

#### Transkript

**[Video 00:00–00:30](https://www.youtube.com/watch?v=_sp22gUwNfY&t=0)**

Sagen wir mal.

**[Video 00:30–01:10](https://www.youtube.com/watch?v=_sp22gUwNfY&t=30)**

Vielleicht sind es bei denen eher die Flashbacks von den Pointer-Übungen. Oh, oh, das tut mir leid. Dann aktiviere ich heute meinen Erkläre es so gut es geht-Modus. Versprochen, am Ende der Vorlesung wird malloc Ihr neuer Lieblingsbefehl sein. Keine Sorge, meine Kollegin ist manchmal ein bisschen überenthusiastisch, aber sie erklärt eigentlich ganz gut. Und für alle, die nach dem Video völlig verwirrt sind, Sie wissen ja, wo Sie mich finden können. Also gut, schalten wir einen Gang runter und fangen ganz von vorne an. Was wissen wir bereits über Zeiger? Also bisher war das Leben mit Zeigern ja noch recht überschaubar, sozusagen wie auf dem sprichwörtlichen Ponyhof, auf dem man einfach auf die Pferde zeigt, die schon da sind. Aber jetzt wird es richtig spannend.

**[Video 01:10–01:25](https://www.youtube.com/watch?v=_sp22gUwNfY&t=70)**

Übersetzung? Jetzt wird's kompliziert. Bisher mussten wir dem Compiler schon beim Kompilieren genau sagen, wie viel Platz wir brauchen. Das ist, als müsste man morgens schon wissen, wie viel man mittags essen wird. Aber was ist, wenn wir erst zur Laufzeit erfahren, wie viel Speicher wir brauchen?

**[Video 01:25–02:03](https://www.youtube.com/watch?v=_sp22gUwNfY&t=85)**

Was, wenn der Benutzer die Menge bestimmt? Was, wenn? Ich glaube, Sie haben es jetzt verstanden, dass es hier ums variable Speichermanagement geht. Natürlich, natürlich. Lassen Sie uns anschauen, wie wir dieses spannende Problem lösen können. Die Lösung für unser Problem liegt in der dynamischen Speicherallokation. Dabei verwenden wir Zeiger, um auf Speicher zuzugreifen, den wir erst während der Programmausführung anfordern. Dieser Speicher kommt aus einem speziellen Bereich, dem sogenannten Heap. Entschuldige kurz, wir haben bisher immer von Pointern gesprochen, nicht von Zeigern. Oh, stimmt. Das passt ja auch viel besser. Wir sagen ja auch Stack und Heap statt Stapel und Halde.

**[Video 02:03–02:41](https://www.youtube.com/watch?v=_sp22gUwNfY&t=123)**

Eigentlich finde ich die englischen Fachbegriffe sowieso präziser. Ja, das ist ja auch eine ganz bewusste Entscheidung. Die Eindeutschung von solchen Informatikkonzepten mutet nämlich nicht nur oft seltsam an. Sie erschwert ja auch das Lesen in englischsprachigen Dokumenten. Also gut, bisher haben wir nur mit dem Stack gearbeitet. Dort leben sozusagen alle unsere gewöhnlichen Variablen. Der Heap dagegen ist wie ein großer Speicherpool, aus dem wir nach Bedarf schöpfen können. Noch mal anders gesagt: Der Stack ist also der Bereich für alle Variablen, die wir bisher mit normalen Deklarationen wie int x oder char c angelegt haben. Alle Variablen, denen wir direkt einen Namen geben, landen automatisch auf dem Stack.

### Folie 3 — Dynamische Speicherverwaltung

[Folie 3 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=3)

Wir können Zeiger verwenden, um zur Laufzeit auf dynamisch allokierten Speicher zuzugreifen.

Dieser dynamisch allozierte Speicher kommt aus einem Speicherbereich, den man Heap nennt.

Bisher haben wir ausschließlich mit Speicher aus einem Bereich gearbeitet, den man Stack nennt.

#### Transkript

**[Video 02:41–02:50](https://www.youtube.com/watch?v=_sp22gUwNfY&t=161)**

Der Heap dagegen wird uns neue Möglichkeiten eröffnen, die wir gleich kennenlernen werden. Hier sehen Sie die Speicheraufteilung eines Programms. Die Bereiche für Heap und Stack wachsen aufeinander zu.

**[Video 02:50–03:28](https://www.youtube.com/watch?v=_sp22gUwNfY&t=170)**

Wie Sie hier im Diagramm sehen können, der Heap wächst von oben nach unten, also von den niedrigeren Speicheradressen zu den höheren. Der Stack von unten nach oben, also haben die ersten Variablen, die wir auf dem Stack speichern, eine höhere Adresse als die, die wir später dort ablegen. Den Platz im Heap können wir dynamisch nutzen.

### Folie 4 — Speicher-Layout eines Programms

[Folie 4 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=4)

„text“

Initialisierte Daten

Uninitialisierte Daten

Heap

Stack

Umgebungsvariablen

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 5 — Dynamische Speicherverwaltung

[Folie 5 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=5)

Um dynamisch allokierten Speicher zu erhalten, verwenden wir die C-Standardbibliotheksfunktion malloc(), der wir als Parameter die gewünschte Anzahl an Bytes übergeben.

Nach erfolgreicher Speicheranforderung gibt malloc einen Pointer auf diesen Speicherbereich zurück.

Falls malloc keinen Speicher bereitstellen kann, gibt es NULL zurück.

#### Transkript

**[Video 02:50–03:28](https://www.youtube.com/watch?v=_sp22gUwNfY&t=170)**

Jetzt wird es konkret. Um dynamischen Speicher anzufordern, nutzen wir die Funktion malloc. Der Name steht übrigens für Memory Allocation. Diese Funktion erwartet von uns einen Parameter, die Anzahl der Bytes, die wir benötigen. Wenn alles gut geht, gibt malloc einen Pointer auf den neu reservierten Speicherbereich zurück. Diesen Pointer können wir dann verwenden, um auf den Speicher zuzugreifen.

**[Video 03:28–04:04](https://www.youtube.com/watch?v=_sp22gUwNfY&t=208)**

Es kann auch sein, dass malloc gar keinen Speicher bereitstellen kann. Dann bekommen wir den Wert 0 zurück. Darauf müssen wir in unserem Code unbedingt prüfen. In der Praxis sehen wir aber trotzdem leider oft Code, der diese Null-Prüfung vergisst. Das kann zu schwer auffindbaren Fehlern führen. Absolut richtig. Deswegen sollten wir uns direkt angewöhnen: Nach jedem malloc kommt eine Null-Überprüfung. Lassen Sie uns das an einem konkreten Beispiel zeigen.

### Folie 6 — Statische versus dynamische Allokation von Speicher

[Folie 6 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=6)

```text
// Integer statisch anlegen (auf dem Stack)
int x;

// Integer dynamisch anlegen (im Heap)
int *px = malloc(4);

// besser: sizeof verwenden
int *px = malloc(sizeof(int));
```

#### Transkript

**[Video 03:28–04:04](https://www.youtube.com/watch?v=_sp22gUwNfY&t=208)**

Schauen wir uns ein einfaches Beispiel an. Bisher haben wir einen Integer so angelegt: int x. Das reserviert Platz auf dem Stack. Wenn wir dagegen dynamisch Speicher für einen int anfordern wollen, schreiben wir int

**[Video 04:04–04:24](https://www.youtube.com/watch?v=_sp22gUwNfY&t=244)**

Stern px gleich malloc vier. Die vier schreiben wir dorthin, weil das die Anzahl der Bytes ist, die ein Integer im Speicher benötigt. Noch besser ist es allerdings sizeof zu verwenden. Das macht unseren Code portabler. Die Größe eines Integers ist nicht auf allen Rechnersystemen vier Byte und weil man ja vielleicht nicht weiß, wo das Programm am Ende überall laufen wird.

**[Video 04:24–05:01](https://www.youtube.com/watch?v=_sp22gUwNfY&t=264)**

Ist es besser, portablen Code zu schreiben, der überall lauffähig ist? Was wir dadurch bekommen, ist ein Pointer auf einen Speicherbereich im Heap, der groß genug für einen Integer ist.

### Folie 7 — Statische und dynamische Allokation von Arrays variabler Größe

[Folie 7 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=7)

```text
// Integer vom User einlesen
int x = get_int();

// Array von Floats auf dem Stack
float stack_array[x];

// Array von Floats auf dem Heap
float* heap_array = malloc(x * sizeof(float));
```

#### Transkript

**[Video 04:24–05:01](https://www.youtube.com/watch?v=_sp22gUwNfY&t=264)**

Beachten Sie: Der Pointer selbst liegt auf dem Stack, nur der Speicher, auf den er zeigt, liegt im Heap. Lassen Sie uns als nächstes anschauen, wie wir das auf Arrays erweitern können. Jetzt wird es interessant. Nehmen wir an, ein Benutzer gibt eine Zahl ein und wir wollen ein Array dieser Größe erstellen. Mit C99 können wir übrigens auch auf dem Stack ein Array variabler Größe anlegen: float stack\_array x.

**[Video 05:01–05:35](https://www.youtube.com/watch?v=_sp22gUwNfY&t=301)**

Ich mache hier übrigens ab und zu kleine Pausen, nicht weil mir der Speicher ausgeht, sondern damit der Professor die Chance hat, mich zu korrigieren. Das ist aber nett von dir. Aber mach dir keine Sorgen, bei Fehlern greife ich schon ein. Perfekt. Also zurück zum Heap. Mit float heap\_array gleich malloc x mal sizeof float erstellen wir ein dynamisches Array. Wir multiplizieren die gewünschte Anzahl Elemente mit der Größe eines float-Werts, um den benötigten Speicherplatz zu berechnen. Der wesentliche Unterschied zum Stack-Array ist: Der Heap-Speicher bleibt bestehen, bis wir ihn explizit wieder freigeben. Das führt uns zum nächsten wichtigen Thema. Moment mal.

**[Video 05:35–05:57](https://www.youtube.com/watch?v=_sp22gUwNfY&t=335)**

Ich glaube, hier müssen wir noch mal kurz innehalten. Die Studierenden könnten sich nämlich jetzt fragen, wozu braucht man jetzt überhaupt malloc, wenn wir mit C99 auch Arrays von variablen Größen auf dem Stack anlegen können? Das war jetzt von dir nicht besonders klug, dass du es an dieser Stelle dieses Detail erwähnt hast. Du wolltest doch, dass die Studierenden die dynamische Speicherverwaltung toll finden, so toll wie du sie findest. Das wird ihnen jetzt nicht besonders leicht fallen.

**[Video 05:57–06:33](https://www.youtube.com/watch?v=_sp22gUwNfY&t=357)**

Ah, danke für den Hinweis. Das muss ich dann unbedingt noch einmal klarer erklären. Der Stack hat nämlich zwei wichtige Einschränkungen. Erstens ist er in der Größe begrenzt. Bei großen variablen Arrays stoßen wir da schnell an Grenzen. Zweitens, und das ist noch wichtiger, Stack-Variablen existieren nur innerhalb ihrer Funktion.

### Folie 8 — Zu beachten bei dynamisch allokiertem Speicher

[Folie 8 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=8)

Wichtig: Dynamisch allokierter Speicher wird nicht automatisch freigegeben, wenn die Funktion endet, in der er angefordert wurde.

Wenn Sie den Speicher nicht explizit freigeben, führt das zu einem Memory Leak, was die Systemleistung beeinträchtigen kann.

Wenn Sie mit dynamisch alloziertem Speicher fertig sind, müssen Sie ihn mit free() freigeben.

#### Transkript

**[Video 05:57–06:33](https://www.youtube.com/watch?v=_sp22gUwNfY&t=357)**

Sobald die Funktion endet, ist der Speicher weg. Der Heap dagegen erlaubt uns, Speicher anzufordern, der auch über Funktionsgrenzen hinweg erhalten bleibt. Das bedeutet, wir können in einer Funktion Speicher allozieren, diesen einer anderen Funktion übergeben und der Speicher bleibt verfügbar, solange wir ihn brauchen. Da sehen Sie es. Der Heap ist nämlich doch viel toller als der Stack.

**[Video 06:33–07:12](https://www.youtube.com/watch?v=_sp22gUwNfY&t=393)**

Also lassen Sie uns als nächstes anschauen, wie wir diesen Speicher wieder freigeben können. Jetzt kommen wir zu einem absolut kritischen Punkt. Im Gegensatz zum Stack-Speicher wird Heap-Speicher nicht automatisch aufgeräumt. Wenn eine Funktion endet, ist der Speicher, den wir mit malloc angefordert haben, immer noch für uns reserviert, egal ob wir ihn noch brauchen oder nicht. Wenn wir diesen Speicher nicht explizit wieder freigeben, entsteht ein sogenanntes Memory Leak, ein Speicherleck. Das bedeutet, unser Programm behält Speicher, den es gar nicht mehr braucht.

### Folie 9 — Zu beachten bei dynamisch allokiertem Speicher

[Folie 9 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=9)

```text
char* word = malloc(50 * sizeof(char));
// mit word arbeiten
// fertig – free nicht vergessen!
free(word);
```

#### Transkript

**[Video 06:33–07:12](https://www.youtube.com/watch?v=_sp22gUwNfY&t=393)**

Die Lösung ist die Funktion free. Mit ihr geben wir dem System den Speicher zurück, wenn wir ihn nicht mehr benötigen. Lassen Sie mich das an einem konkreten Beispiel demonstrieren. Hier sehen wir ein typisches Beispiel.

**[Video 07:12–07:29](https://www.youtube.com/watch?v=_sp22gUwNfY&t=432)**

Wir reservieren Speicher für einen String mit maximal 50 Zeichen. Beachten Sie, wie wir wieder sizeof verwenden. Das macht den Code portabler. Nachdem wir mit dem String gearbeitet haben, zum Beispiel Text eingelesen oder verarbeitet haben, geben wir den Speicher mit free wieder frei. Der Pointer liegt auf dem Stack und verschwindet automatisch.

**[Video 07:29–08:08](https://www.youtube.com/watch?v=_sp22gUwNfY&t=449)**

Aber der Speicher, auf den er zeigt, muss explizit freigegeben werden. Genau. Ich glaube, jetzt wäre ein guter Zeitpunkt, die drei goldenen Regeln im Umgang mit dynamischem Speicher zu präsentieren, oder? Absolut. Diese drei Regeln sind wirklich fundamental. Erstens: Jeder malloc-Aufruf braucht irgendwann sein entsprechendes free. Das ist wie beim Aufräumen: Was ausgepackt wurde, muss auch wieder eingepackt werden. Zweitens: Nur malloc-Speicher darf mit free freigegeben werden. Stack-Variablen oder andere Speicherbereiche sind tabu für free. Und drittens: Ein Speicherblock darf nur einmal freigegeben werden. Mehrfaches free führt zu undefiniertem Verhalten. Am besten schauen wir uns das an einem konkreten Beispiel an. Wir werden sehen, was passiert.

**[Video 08:08–08:41](https://www.youtube.com/watch?v=_sp22gUwNfY&t=488)**

Wenn wir Pointer kopieren und dann mit dem Speicher arbeiten, lassen wir uns dieses Beispiel Schritt für Schritt anschauen. Zunächst haben wir drei Deklarationen: eine Integer-Variable, einen Pointer, der erstmal nirgendwohin zeigt, und einen Pointer, der auf einen dynamisch allozierten Integerspeicherbereich zeigt. In der Visualisierung sehen wir den Integer als grünes Quadrat. Der liegt auf dem Stack. Daneben haben wir die helleren Quadrate für unsere Pointer, wobei der zweite bereits auf einen Speicherbereich im Heap zeigt. Schauen wir uns an, was passiert, wenn wir diese Pointer manipulieren. Mit a gleich Kaufmannsund m

**[Video 08:41–08:57](https://www.youtube.com/watch?v=_sp22gUwNfY&t=521)**

Lassen wir jetzt den Pointer a auf unsere Stack-Variable m zeigen. Sehen Sie, wie sich der Pfeil von a zur Variable m erstreckt? Das ist klassische statische Pointer-Nutzung, wie wir sie bereits kennen. Was besonders wichtig ist: Hier zeigt a auf den Stack, während b auf den Heap zeigt.

**[Video 08:57–09:35](https://www.youtube.com/watch?v=_sp22gUwNfY&t=537)**

Beides ist völlig legitim. Ein Pointer kann auf beliebige Speicherbereiche zeigen, solange diese gültig sind. Man sieht es ihm nicht an. Also höchstens, wenn man sich die gespeicherten Adressen ansieht und grob weiß, von wo bis wo der Stack geht. Schauen wir uns als nächstes an, was passiert, wenn wir a gleich b ausführen. Was nun passiert ist, dass a nun auf denselben Heap-Bereich zeigt wie b. Der ursprüngliche Pfeil von a zu m existiert nicht mehr. Die Referenz haben wir überschrieben. Jetzt haben wir eine interessante Situation: Zwei Pointer zeigen auf denselben dynamisch allozierten Speicherbereich. Das ist völlig in Ordnung, aber es bedeutet auch, dass wir besonders vorsichtig sein müssen, wenn wir später free aufrufen.

**[Video 09:35–10:13](https://www.youtube.com/watch?v=_sp22gUwNfY&t=575)**

Vielleicht kurz zur Klarstellung: Wenn wir jetzt über einen der Pointer den Wert ändern, sehen wir die Änderung auch über den anderen Pointer, oder? Genau. Lassen mich das demonstrieren, indem ich m einen Wert zuweise und dann über einen der Pointer den Heap-Speicher manipuliere. Mit m gleich zehn setzen wir den Wert unserer Stackvariable auf zehn. Beachten Sie: Obwohl a früher einmal auf m zeigte, hat diese Zuweisung keinen Einfluss auf den Bereich, auf den a jetzt zeigt. Der Heap-Bereich, auf den sowohl a als auch b zeigen, ist von dieser Zuweisung völlig unberührt. Jetzt führen wir Stern b gleich m plus zwei aus. Dadurch sehen wir, wie wir über einen der Pointer den Heap-Speicher verändern können.

**[Video 10:13–10:27](https://www.youtube.com/watch?v=_sp22gUwNfY&t=613)**

Dabei nehmen wir den Wert von m, addieren zwei dazu und speichern das Ergebnis, also zwölf, im Heap-Speicher. Da sowohl a als auch b auf diesen Speicherbereich zeigen, würde Stern a uns jetzt ebenfalls den Wert zwölf liefern. Dies ist ein wichtiges Konzept: Der Wert im Heap.

**[Video 10:27–11:06](https://www.youtube.com/watch?v=_sp22gUwNfY&t=627)**

kann über jeden Pointer manipuliert werden, der darauf zeigt. Dabei spielt es keine Rolle, ob wir Stern a oder Stern b verwenden. Es ist derselbe Speicherbereich. So, jetzt nicht das Aufräumen vergessen. Was passiert, wenn wir den Speicher freigeben? Mit free b geben wir den Heap-Speicher frei. Der Speicherbereich steht damit dem System wieder zur Verfügung. Aber Achtung: Die Pointer a und b existieren noch. Sie zeigen nur auf einen Bereich, den wir nicht mehr nutzen dürfen. Ja, das ist eine häufige Fehlerquelle. Nach dem free zeigen die Pointer immer noch auf die gleiche Adresse, aber der Speicher gehört uns ja gar nicht mehr. Man nennt solche Pointer auch dangling Pointer. Sie baumeln sozusagen ins Leere. Am besten setzt man Pointer nach free gleich auf null.

**[Video 11:06–11:40](https://www.youtube.com/watch?v=_sp22gUwNfY&t=666)**

Dann kann man durch den Absturz, der ja dann passiert, wenn man auf den Pointer versehentlich nochmal zugreift, wenigstens erkennen, dass man irgendwo im Code noch einen Fehler hat. Eine sehr gute Praxis. Lassen Sie uns zum Abschluss noch sehen, was passiert, wenn wir trotzdem versuchen, über einen dieser Pointer auf den freigegebenen Speicher zuzugreifen. Hier sehen wir den kritischen Fehler. Wir versuchen mit Stern a gleich elf auf Speicher zuzugreifen, den wir bereits freigegeben haben. Das führt zu undefiniertem Verhalten. Es könnte scheinbar funktionieren, abstürzen oder seltsame Fehler verursachen. Solche Zugriffe auf freigegebenen Speicher sind besonders tückisch.

**[Video 11:40–11:56](https://www.youtube.com/watch?v=_sp22gUwNfY&t=700)**

Weil sie manchmal zunächst zu funktionieren scheinen. Der Speicherbereich könnte ja noch unverändert sein, aber wir haben keine Garantie dafür. So, das war's. Wir haben die dynamische Speicherallokation doch jetzt eigentlich wirklich gut rübergebracht, oder? Hach, ist sie nicht schön?

### Folie 10 — Drei Goldene Regeln

[Folie 10 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=10)

1. Jeder Speicherblock, den Sie mit malloc() anfordern, muss später mit free() freigegeben werden.

2. Nur Speicher, den Sie mit malloc() angefordert haben, darf mit free() freigegeben werden.

3. Geben Sie einen Speicherblock nicht mehr als einmal mit free() frei.

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 11

[Folie 11 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=11)

```text
m
```

```text
int m;
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 12

[Folie 12 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=12)

```text
m
```

```text
a
```

```text
int m;
int* a;
```

> Vorwiegend grafische Folie; die extrahierten Beschriftungen ersetzen die Abbildung nicht.

#### Transkript

> Zuordnung unsicher: wenige gemeinsame Textmerkmale; anhand der benachbarten Folien eingeordnet.

**[Video 11:40–11:56](https://www.youtube.com/watch?v=_sp22gUwNfY&t=700)**

Na ja.

### Folie 13

[Folie 13 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=13)

```text
m
```

```text
a
```

```text
b
```

```text
int m;
int* a;
int* b = malloc(sizeof(int));
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 14

[Folie 14 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=14)

```text
m
```

```text
a
```

```text
b
```

```text
int m;
int* a;

int* b = malloc(sizeof(int));
a = &m;
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 15

[Folie 15 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=15)

```text
m
```

```text
a
```

```text
b
```

```text
int m;
int* a;

int* b = malloc(sizeof(int));
a = &m;
a = b;
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 16

[Folie 16 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=16)

```text
10
```

```text
m
```

```text
a
```

```text
b
```

```text
int m;
int* a;

int* b = malloc(sizeof(int));
a = &m;
a = b;
m = 10;
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 17

[Folie 17 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=17)

```text
10
```

```text
12
```

```text
m
```

```text
a
```

```text
b
```

```text
int m;
int* a;

int* b = malloc(sizeof(int));
a = &m;
a = b;
m = 10;
*b = m + 2;
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 18

[Folie 18 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=18)

```text
10
```

```text
m
```

```text
a
```

```text
b
```

```text
int m;
int* a;

int* b = malloc(sizeof(int));
a = &m;
a = b;
m = 10;
*b = m + 2;
free(b);
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 19

[Folie 19 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=19)

```text
10
```

```text
11
```

```text
m
```

```text
a
```

```text
b
```

```text
int m;
int* a;

int* b = malloc(sizeof(int));
a = &m;
a = b;
m = 10;
*b = m + 2;
free(b);
*a = 11;  // Gefahr!
```

#### Transkript

*Kein Transkriptabschnitt eindeutig dieser Folie zugeordnet. Möglicherweise eine Aufbau-/Grafikfolie oder eine Abweichung zwischen PDF und Video.*

### Folie 20

[Folie 20 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=20)

E X T R A S I N 3 M I N U T E N FRAGEN – ANTWORTEN – RÄTSEL UND KURZE ZUSAMMENFASSUNG

#### Transkript

**[Video 11:56–12:29](https://www.youtube.com/watch?v=_sp22gUwNfY&t=716)**

Die reinen Fakten sind jetzt nicht besonders schwer zu verstehen. Die echten Probleme kommen doch dann erst später, wenn man sich durch ungünstige Code-Organisation halt eine Welt gebaut hat, wo man keinen Überblick mehr hat. Ach, das ist dann aber nicht mehr unser Problem. Die Konzepte sind gut, man muss sie halt richtig verwenden. Ja, da muss ich dir aber deutlich widersprechen. Genau diese Einstellung ist es ja, die zu den Problemen führt, die wir in der Praxis sehen. Wir dürfen doch die Studierenden mit diesen Herausforderungen nicht allein lassen, oder? Hast recht. Das war etwas kurz gedacht von mir. Lass uns wenigstens in den drei extra Minuten das Verständnis der Grundlagen absichern. Hast du ein paar gute Fragen vorbereitet?

### Folie 21 — Was sind die drei goldenen Regeln der dynamischen Speicherverwaltung?

[Folie 21 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=21)

1. Jeder malloc()-Aufruf braucht ein korrespondierendes free().

2. Nur mit malloc() allozierter Speicher darf mit free() freigegeben werden.

3. Speicher darf nur einmal freigegeben werden.

#### Transkript

**[Video 12:29–13:06](https://www.youtube.com/watch?v=_sp22gUwNfY&t=749)**

Aber natürlich. Also hier eine Frage zur Wiederholung: Was sind die drei goldenen Regeln der dynamischen Speicherverwaltung? Ich mache mal eine kurze Pause, damit Sie selbst nachdenken können. Die erste Regel war: Jeder malloc-Aufruf braucht sein korrespondierendes free. Die zweite: Nur Speicher, den wir mit malloc angefordert haben, darf mit free freigegeben werden. Und die dritte: Ein Speicherblock darf nur einmal freigegeben werden. Ja, eine gute erste Frage. Das sind wirklich die Grundlagen, die wirklich sitzen müssen. Ich habe da auch was vorbereitet.

### Folie 22

[Folie 22 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=22)

```c
char* format_log_entry(int timestamp, const char* message) {
    char* entry = malloc(1024);  // Platz für Zeitstempel + Nachricht
    snprintf(entry, 1024, "[%d] %s", timestamp, message);
    return entry;
}

void process_log_entry(char* entry) {
    // Verarbeite Log-Eintrag...
    if(strstr(entry, "ERROR") != NULL) {
        store_error_entry(entry);
    }
}

int main() {
    const char* messages[] = {
	"System started", "ERROR: Invalid input", /* ... */};

    for(int i = 0; i < 1000000; i++) {
        char* entry = format_log_entry(i, messages[i % 4]);
        process_log_entry(entry);
    }
}
```

#### Transkript

**[Video 12:29–13:06](https://www.youtube.com/watch?v=_sp22gUwNfY&t=749)**

Schauen wir: Wir haben hier ein etwas subtileres Problem.

**[Video 13:06–13:28](https://www.youtube.com/watch?v=_sp22gUwNfY&t=786)**

Schauen Sie sich das am besten mal in Ruhe an. Die Funktion format\_log\_entry alloziert bei jedem Aufruf 1024 Bytes für einen formatierten Log-Eintrag. Bei einer Million Durchläufe ist das schon ein Gigabyte RAM. Und es wird ja noch schlimmer. Was passiert eigentlich, wenn store\_error\_entry den Pointer speichert, um später darauf zuzugreifen?

**[Video 13:28–14:05](https://www.youtube.com/watch?v=_sp22gUwNfY&t=808)**

Dann haben wir nicht nur einen Speicherleck, sondern auch noch potenzielle Zugriffe auf ungültigen Speicher.

### Folie 23

[Folie 23 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=23)

```c
void format_log_entry(int timestamp, const char* message,
				char* buffer, size_t bufsize) {
    snprintf(buffer, bufsize, "[%d] %s", timestamp, message);
}

int main() {
    const char* messages[] = {
	"System started", "ERROR: Invalid input", /* ... */};
    
    char* entry = malloc(1024);

    for(int i = 0; i < 1000000; i++) {
        format_log_entry(i, messages[i % 4], entry, 1024);
        process_log_entry(entry);
    }
    free(entry);
}
```

#### Transkript

> Zuordnung unsicher: wenige gemeinsame Textmerkmale; anhand der benachbarten Folien eingeordnet.

**[Video 13:28–14:05](https://www.youtube.com/watch?v=_sp22gUwNfY&t=808)**

Eine bessere Struktur wäre diese hier.

### Folie 24 — Parameter von malloc: size\_t

[Folie 24 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=24)

```text
// Meistens kein Problem:
int count = 1000;
int* data = malloc(count * sizeof(int)); // Kleine Allokation

// Könnte problematisch werden:
int count = user_input(); // Was, wenn count negativ ist?
int* data = malloc(count * sizeof(int)); // Negativer Wert wird zu riesigem unsigned!

// Besser:
size_t count = validate_user_input(); // Stellt sicher: count ist positiv
int* data = malloc(count * sizeof(int));
```

malloc erwartet `size_t` als Parameter. `size_t` ist der korrekte Typ für Speichergrößen: garantiert groß genug für max. Objektgröße auf der Plattform, für die das Programm kompiliert wird.

`size_t` ist unsigned, d.h. keine negativen Größen möglich.

Achtung: –1 wird zu 4 GB wenn als unsigned interpretiert.

#### Transkript

**[Video 13:28–14:05](https://www.youtube.com/watch?v=_sp22gUwNfY&t=808)**

Auch das sollten Sie sich in Ruhe ansehen. Das demonstriert ein wichtiges Prinzip: Funktionen sollten transparent sein in ihrer Speichernutzung. Wenn Sie Speicher brauchen, sollten Sie ihn übergeben bekommen, nicht selbst allozieren. Vielleicht noch ein wichtiges Detail, das oft übersehen wird: Welchen Typ erwartet malloc eigentlich als Parameter? Ah, genau. Malloc erwartet size_t, keinen int.

**[Video 14:05–14:44](https://www.youtube.com/watch?v=_sp22gUwNfY&t=845)**

Das ist wichtig, weil size\_t garantiert groß genug ist, um die maximale Objektgröße auf der jeweiligen Plattform darzustellen. Bei int könnte es dagegen zu einem Überlauf kommen. In den meisten Fällen macht man sich darüber keine Gedanken. Wenn man tausend Integer-Werte allozieren will, funktioniert das auch mit normalen int-Werten problemlos. Aber es gibt doch auch Fälle, wo es schon vorher zu einem Problem wird, oder? Ein klassischer Fall ist Benutzereingabe. Nehmen wir an, wir fragen den User, wie viele Werte er eingeben möchte. Wenn wir nicht prüfen, ob die Eingabe negativ ist und diese negative Zahl an malloc übergeben, passiert etwas Gefährliches. Der negative Integer-Wert wird zu einem riesigen unsigned int. Kannst du das vielleicht noch mal kurz erklären?

**[Video 14:44–15:00](https://www.youtube.com/watch?v=_sp22gUwNfY&t=884)**

Klar, wenn auf einem 32-Bit-System jemand -1 eingibt und wir das ungeprüft an malloc weitergeben, wird daraus plötzlich ein Versuch, vier Gigabyte zu allokieren. Der Grund ist, dass -1 als Integer das Bitmuster 0xFFFFFFFF hat.

**[Video 15:00–15:37](https://www.youtube.com/watch?v=_sp22gUwNfY&t=900)**

Was als unsigned interpretiert dann eben die größtmögliche positive Zahl ergibt, also etwas mehr als vier Milliarden. Und das kann sogar zu Sicherheitslücken führen, wie Sie vielleicht in einer anderen Vorlesung irgendwann einmal erfahren werden. Genau, deswegen sollten wir Benutzereingaben immer validieren und für Speichergrößen konsequent size\_t verwenden. Das macht auch gleich klar: Hier geht es um Speichergrößen, die können nicht negativ sein.

### Folie 25 — Pointer auf freigegebenen Speicher nicht mehr verwenden

[Folie 25 als PDF](https://inf.zone/download/lectures/4-memory/4.4-dynamischer-speicher.pdf#page=25)

Dynamischer Speicher kommt vom Heap (malloc)

Stack-Speicher verschwindet am

Speicherallokation sollte transparent sein (Verantwortlichkeiten klar)

Funktionsende

automatisch

Heap-Speicher muss

Vorsicht bei Speichergrößen: size\_t verwenden

explizit freigegeben

werden (free)

> Bildinhalte sind nicht transkribiert; siehe Originalfolie.

#### Transkript

> Zuordnung unsicher: wenige gemeinsame Textmerkmale; anhand der benachbarten Folien eingeordnet.

**[Video 15:00–15:37](https://www.youtube.com/watch?v=_sp22gUwNfY&t=900)**

Damit kommen wir für heute zum Ende. Und glaubst du, dass unsere Studierenden nun genauso begeistert von der Speicherverwaltung sind wie du? Okay, ich verstehe jetzt besser, warum die Tränen in den Augen der Studierenden vielleicht doch keine Freudentränen waren.

**[Video 15:37–16:09](https://www.youtube.com/watch?v=_sp22gUwNfY&t=937)**

Dynamische Speicherverwaltung ist halt wie Mensch ärgere dich nicht. Nur dass die Figuren manchmal auf einmal vom Brett verschwinden und man dann nicht weiß, wann und wohin. Ich glaube eher wie Jonglieren mit Messern. Alles was in der Luft ist, muss man auch wieder auffangen. Oh, oder wie beim Dating, da musste ich auch committen. Zu jedem malloc gehört ein free. Apropos Dating und Memory Management, da gibt es auch noch mehr Parallelen. Also Singles haben ja quasi einen Nullpointer, wobei manche haben erst mal vielleicht auch einen dangling Pointer. Das vertiefen wir dann vielleicht, wenn die Kamera aus ist.

**[Video 16:09–16:20](https://www.youtube.com/watch?v=_sp22gUwNfY&t=969)**

Bis bald. Dies war Inf-Einf-B.
