Lässt es sich mit cremefarbenem Papier, einer Tönung, mehr Kontrast oder größerer Schrift besser lesen? Wählen Sie Ihre Farben und Ihre Schrift, einmalig für alle Seiten.

Kostenlose Lektion

Stack und Heap in C

Nach dieser Lektion: Ich kann sagen, wo eine Variable lebt und was malloc und free tun.

Lektion, 60 Min.7 BefehleLab für Compilerbau und Rechnerarchitektur: gcc, flex, bison und RISC-V in einer VM

Wo lebt eine Variable in C?

In C lebt jede Variable entweder auf dem Stack oder auf dem Heap. Der Stack räumt sich selbst auf, den Heap räumen Sie selbst auf.

Ein Programm für ein Theater liest zum Beispiel die Plätze eines Abends ein, deren Zahl erst beim Start bekannt ist. Dafür reicht eine lokale Variable nicht, und genau dafür gibt es malloc.

Am Ende dieser Lektion

Notiz

Ich kann sagen, wo eine Variable lebt und was malloc und free tun.

Schlüsselwörter

BegriffWas er bedeutetBeispiel
Stackder Speicher für lokale Variablen, er wächst mit jedem Aufruf
Stackframeder Stack-Abschnitt eines einzelnen Funktionsaufrufs
Heapder Speicher, den Sie selbst anfordern und zurückgeben
mallocfordert eine Zahl von Bytes vom Heap anmalloc(20)
freegibt einen reservierten Block zurückfree(zeiger)
Speicherleckreservierter Speicher, der nie zurückgegeben wird

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Der Stack hat einen Frame je Funktionsaufruf

Ruft eine Funktion eine andere auf, legt C einen neuen Stackframe oben auf den Stack. Er hält die lokalen Variablen und die Parameter dieses Aufrufs.

Endet die Funktion, verschwindet ihr Frame, und ihre Variablen sind weg. Eine lokale Variable lebt also genau so lange wie ihr Aufruf. Eine mit static lebt dagegen so lange wie das Programm.

Beispiel: main ruft summe auf

SchrittDer Stack, unten nach obenWas geschieht
1mainDas Programm startet in main
2main, summemain ruft summe auf, ein neuer Frame liegt oben
3mainsumme ist fertig, sein Frame ist weg

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Der Stack im Modell

Code: python
# Modell: der Stack ist eine Liste von Frames, der letzte ist oben
stack = []
stack.append("main")
print(stack)
stack.append("summe")          # main ruft summe auf
print(stack)
stack.pop()                    # summe ist fertig, sein Frame verschwindet
print(stack)
# Fuegen Sie vor dem pop einen Aufruf von "zinsen" in summe hinzu.

In den Arbeitsordner wechseln

Befehl
mkdir -p ~/csys && cd ~/csys

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Ein Programm mit lokaler und static-Variable schreiben

Befehl
printf '#include <stdio.h>\n\nint lokal(void) {\n    int zaehler = 0;\n    zaehler++;\n    return zaehler;\n}\n\nint bleibend(void) {\n    static int zaehler = 0;\n    zaehler++;\n    return zaehler;\n}\n\nint main(void) {\n    printf("lokal:");\n    for (int i = 0; i < 3; i++) printf(" %%d", lokal());\n    printf("\\nstatic:");\n    for (int i = 0; i < 3; i++) printf(" %%d", bleibend());\n    printf("\\n");\n    return 0;\n}\n' > leben.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Das Programm übersetzen

Befehl
gcc -o leben leben.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Zählen lassen

Befehl
./leben

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Mit malloc fordern Sie Speicher vom Heap an

Der Heap ist ein großer Speicherbereich, aus dem Sie mit malloc(n) einen Block von n Bytes anfordern. Sie bekommen einen Zeiger darauf oder NULL, wenn nichts mehr frei ist.

Der Block lebt, bis Sie ihn mit free zurückgeben. Das Programm unten fordert Platz für fünf Zahlen an, füllt ihn, summiert ihn und gibt ihn frei.

Das Programm plaetze.c

Code: c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int anzahl = 5;
    int *plaetze = malloc(anzahl * sizeof(int));
    if (plaetze == NULL) {
        return 1;
    }
    for (int i = 0; i < anzahl; i++) {
        plaetze[i] = (i + 1) * 10;
    }
    int summe = 0;
    for (int i = 0; i < anzahl; i++) {
        summe = summe + plaetze[i];
    }
    printf("Summe %d, Platz 3: %d\n", summe, plaetze[2]);
    free(plaetze);
    return 0;
}

Das Programm in eine Datei schreiben

Befehl
printf '#include <stdio.h>\n#include <stdlib.h>\n\nint main(void) {\n    int anzahl = 5;\n    int *plaetze = malloc(anzahl * sizeof(int));\n    if (plaetze == NULL) {\n        return 1;\n    }\n    for (int i = 0; i < anzahl; i++) {\n        plaetze[i] = (i + 1) * 10;\n    }\n    int summe = 0;\n    for (int i = 0; i < anzahl; i++) {\n        summe = summe + plaetze[i];\n    }\n    printf("Summe %%d, Platz 3: %%d\\n", summe, plaetze[2]);\n    free(plaetze);\n    return 0;\n}\n' > plaetze.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Das Programm übersetzen

Befehl
gcc -o plaetze plaetze.c

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Das Programm starten

Befehl
./plaetze

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Speicherleck und Zugriff nach free sind Fehler

Vergessen Sie free, bleibt der Block bis zum Programmende reserviert. Das ist ein Speicherleck. Ein Server, der bei jeder Anfrage leckt, füllt irgendwann den ganzen Speicher.

Der umgekehrte Fehler ist ein Zugriff nach free. Der Zeiger zeigt noch hin, aber der Block kann längst anderen gehören. In C ist das Ergebnis undefiniert, wir zeigen es nur im Modell.

Ein Zugriff nach free im Modell

Code: python
# Modell: der Heap hat acht Bytes, eine Adresse ist ein Index
heap = bytearray(8)
bestellung = 0                 # malloc: der Zeiger zeigt auf Adresse 0
heap[bestellung] = 17
# free(bestellung): der Block gilt als frei, die Bytes bleiben liegen
rechnung = 0                   # das naechste malloc bekommt denselben Block
heap[rechnung] = 99
print(heap[bestellung])        # der alte Zeiger sieht jetzt den neuen Wert

Ein häufiger Fehler

Warnung

Viele glauben, free lösche den Block und setze den Zeiger auf NULL. free gibt den Block nur zurück. Der Zeiger zeigt weiter dorthin. Setzen Sie ihn nach free selbst auf NULL, dann ist ein Zugriff leichter zu erkennen.

Über dieses Lab und seinen Quellcode: Lab für Compilerbau und Rechnerarchitektur: gcc, flex, bison und RISC-V in einer VM

Sie unterrichten eine Gruppe? Weisen Sie dieses Modul Ihren Studierenden zu, mit Handbuch für Lehrende, automatisch geprüften Aufgaben und einem Lab für jede Person.