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
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Stack | der Speicher für lokale Variablen, er wächst mit jedem Aufruf | |
| Stackframe | der Stack-Abschnitt eines einzelnen Funktionsaufrufs | |
| Heap | der Speicher, den Sie selbst anfordern und zurückgeben | |
| malloc | fordert eine Zahl von Bytes vom Heap an | malloc(20) |
| free | gibt einen reservierten Block zurück | free(zeiger) |
| Speicherleck | reservierter 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
| Schritt | Der Stack, unten nach oben | Was geschieht |
|---|---|---|
| 1 | main | Das Programm startet in main |
| 2 | main, summe | main ruft summe auf, ein neuer Frame liegt oben |
| 3 | main | summe ist fertig, sein Frame ist weg |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Der Stack im Modell
# 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
mkdir -p ~/csys && cd ~/csysHier 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
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.cHier 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
gcc -o leben leben.cHier 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
./lebenHier 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
#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
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.cHier 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
gcc -o plaetze plaetze.cHier 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
./plaetzeHier 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
# 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.