Allen ist gemeinsam, dass die Größe des zur Verfügung gestellten Speicherplatzes von vornherein festgelegt ist. Oft benötigt man aber Speicherplatz, dessen Größe nicht bereits zur Compile-Zeit bekannt ist, weil er z.B. von Benutzereingaben abhängt. Für diese Fälle braucht man eine dynamische Speicherzuweisung (engl.: dynamic memory allocation).
C bietet dafür Funktionen in der Standardbibliothek, die man mit #include <stdlib.h> in das eigene Programm einbindet. Dort finden wir u.a. die beiden wichtigsten Funktionen malloc() und free(). malloc() hat einen Parameter: die Größe des zu reservierenden Speichers. Die Funktion liefert einen void-Pointer zurück, der auf den Anfang des reservierten Speichers zeigt. Ein void-Pointer ist im Grunde eine Speicheradresse. Von welchem Typ die Daten im reservierten Speicher sein sollen, davon weiß malloc() nichts. Das Ergebnis wird einfach per type cast in den gewünschten Datentyp umgewandelt; dazu schreibt man den Datentyp einfach in Klammern vor den Funktionsaufruf:
Code: Alles auswählen
char *characters = (char *) malloc(200);
Sobald der Speicher nicht mehr benötigt wird, muss er mit der Funktion free() wieder freigegeben werden. Tut man das nicht, dann enstehen sog. Speicherlecks, also Speicher, der dauerhaft reserviert bleibt und nicht mehr für andere sinnvolle Aufgaben verwendet werden kann. free() ist komplementär zu malloc(), d.h. zu jedem malloc()-Aufruf muss es einen korrespondierenden free()-Aufruf geben. Zum Freigeben des zuvor angeforderten Speichers muss man free() den Pointer übergeben, den malloc() zurückgeliefert hat. Man muss des Ergebnis des malloc()-Aufrufs also immer in einer Pointer-Variablen speichern, damit man später free() aufrufen kann.
Im folgenden kleinen Beispiel wollen wir eine Zeichenkette mit einer Anzahl Sternen aufbauen, die der Benutzer vorgibt. Wir speichern die Datei als testmalloc.c.
Code: Alles auswählen
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i, n, result;
char *buffer;
printf("Wieviele Sterne? ");
scanf("%d", &i);
buffer = (char*) malloc(i + 1); // ein Byte extra für das String-Ende-Zeichen
if (buffer != NULL) { // sonst haben wir keinen Speicher bekommen
buffer[i] = '\0'; // String-Ende-Zeichen setzen
while(i--) {
buffer[i] = '*'; // String mit Sternchen füllen
}
printf("%s\n", buffer);
free(buffer); // Wichtig! Speicher wieder freigeben
result = EXIT_SUCCESS;
}
else {
result = EXIT_FAILURE;
}
return result;
}
Code: Alles auswählen
zcc +cpm -subtype=pcw80 -compiler=sccz80 -DAMALLOC -create-app testmalloc.c -o malloc.com
Wird die ausführbare Datei mit malloc gestartet, dann fragt das Programm nach der gewünschten Anzahl von Sternen. Gibt man z.B. 15 ein, dann wird Speicher für 16 Bytes reserviert, ein String mit 15 Sternen aufgebaut und anschließend per printf() ausgegeben.
Hier binden wir die Header-Datei stdlib.h ein, die ihrerseits malloc.h inkludiert. In diesem Beispiel hätte es genügt, nur malloc.h einzubinden, allerdings hätten dann die Konstanten EXIT_SUCCESS und EXIT_FAILURE nicht zur Verfügung gestanden.
Im Zusammenhang mit malloc() wird oft der Operator sizeof verwendet. Er dient dazu, den Speicherbedarf eines Datentyps zur Compile-Zeit zu bestimmen. Das funktioniert mit jedem in C deklarierten Datentyp, also auch mit komplexen Datentypen wie structs. Möchte man Speicher für zehn float-Variablen reservieren, dann geht das folgendermaßen:
Code: Alles auswählen
float *floatVars = (float*) malloc(20 * sizeof(float));
Für den Zugriff auf die einzelnen float-Variablen kann man auch die Array-Schreibweise verwenden. Möchte man die dritte float-Variable, also die mit dem Index 2, auf den Wert 5.3 setzen, dann geht das so:
Code: Alles auswählen
floatVars[2] = 5.5;