wake-up-neo.com

Wann sollte ich malloc in C verwenden und wann nicht?

Ich verstehe, wie malloc () funktioniert. Meine Frage ist, ich werde so etwas sehen:

#define A_MEGABYTE (1024 * 1024)

char *some_memory;
size_t size_to_allocate = A_MEGABYTE;
some_memory = (char *)malloc(size_to_allocate);
sprintf(some_memory, "Hello World");
printf("%s\n", some_memory);
free(some_memory);

Ich habe die Fehlerprüfung der Kürze halber weggelassen. Meine Frage ist, können Sie nicht einfach das oben Genannte tun, indem Sie einen Zeiger auf einen statischen Speicher im Speicher initialisieren? vielleicht:

char *some_memory = "Hello World";

An welchem ​​Punkt müssen Sie den Speicher tatsächlich selbst zuweisen, anstatt die Werte zu deklarieren/initialisieren, die Sie beibehalten müssen?

90
randombits
char *some_memory = "Hello World";

erstellt einen Zeiger auf eine Zeichenfolgenkonstante. Das bedeutet, dass sich die Zeichenfolge "Hello World" irgendwo im schreibgeschützten Teil des Speichers befindet und Sie nur einen Zeiger darauf haben. Sie können die Zeichenfolge als schreibgeschützt verwenden. Sie können nicht daran Änderungen vornehmen. Beispiel:

some_memory[0] = 'h';

Bittet um Ärger.

Auf der anderen Seite

some_memory = (char *)malloc(size_to_allocate);

ordnet diesem zugewiesenen Speicher ein Zeichenarray (eine Variable) und einige_Speicherpunkte zu. Dieses Array kann nun sowohl gelesen als auch geschrieben werden. Sie können jetzt Folgendes tun:

some_memory[0] = 'h';

und der Inhalt des Arrays ändert sich zu "Hallo Welt"

128
codaddict

Für genau dieses Beispiel ist malloc von geringem Nutzen.

Der Hauptgrund, warum malloc benötigt wird, ist, wenn Sie Daten haben, deren Lebensdauer sich vom Codebereich unterscheidet. Ihr Code ruft malloc in einer Routine auf, speichert den Zeiger irgendwo und ruft schließlich free in einer anderen Routine auf.

Ein zweiter Grund ist, dass C nicht wissen kann, ob auf dem Stapel noch genügend Speicherplatz für eine Zuordnung vorhanden ist. Wenn Ihr Code 100% robust sein muss, ist es sicherer, malloc zu verwenden, da Ihr Code die fehlgeschlagene Zuordnung erkennen und damit umgehen kann.

36

malloc ist ein wunderbares Tool, um zur Laufzeit Speicher zuzuweisen, neu zuzuweisen und freizugeben, im Vergleich zu statischen Deklarationen wie Ihrem Hello World-Beispiel, die zur Kompilierungszeit verarbeitet werden und daher nicht in der Größe geändert werden können.

Malloc ist daher immer dann nützlich, wenn Sie mit Daten beliebiger Größe arbeiten, z. B. mit dem Lesen von Dateiinhalten oder mit Sockets, und wenn Sie die Länge der zu verarbeitenden Daten nicht kennen.

Natürlich ist malloc in einem trivialen Beispiel wie dem, das Sie angegeben haben, nicht das magische "richtige Werkzeug für den richtigen Job", aber für komplexere Fälle (zum Beispiel das Erstellen eines Arrays beliebiger Größe zur Laufzeit) ist dies der einzige Weg gehen.

15
moritz

Wenn Sie die genaue Größe des zu verwendenden Speichers nicht kennen, benötigen Sie eine dynamische Zuordnung (malloc). Ein Beispiel könnte sein, wenn ein Benutzer eine Datei in Ihrer Anwendung öffnet. Sie müssen den Inhalt der Datei in den Speicher einlesen, aber natürlich kennen Sie die Dateigröße nicht im Voraus, da der Benutzer die Datei zur Laufzeit sofort auswählt. Grundsätzlich benötigen Sie malloc, wenn Sie die Größe der Daten, mit denen Sie arbeiten, nicht im Voraus kennen. Zumindest ist das einer der Hauptgründe für die Verwendung von malloc. In Ihrem Beispiel mit einer einfachen Zeichenfolge, deren Größe Sie zum Zeitpunkt der Kompilierung bereits kennen (und die Sie nicht ändern möchten), macht es wenig Sinn, diese dynamisch zuzuweisen.


Leicht vom Thema abweichend, aber ... Sie müssen sehr vorsichtig sein, um keine Speicherlecks zu verursachen, wenn Sie malloc verwenden. Betrachten Sie diesen Code:

int do_something() {
    uint8_t* someMemory = (uint8_t*)malloc(1024);

    // Do some stuff

    if ( /* some error occured */ ) return -1;

    // Do some other stuff

    free(someMemory);
    return result;
}

Sehen Sie, was mit diesem Code nicht stimmt? Es gibt eine bedingte return-Anweisung zwischen malloc und free. Auf den ersten Blick mag es in Ordnung erscheinen, aber denken Sie darüber nach. Wenn ein Fehler auftritt, kehren Sie zurück, ohne den zugewiesenen Speicherplatz freizugeben. Dies ist eine häufige Ursache für Speicherverluste.

Natürlich ist dies ein sehr einfaches Beispiel, und es ist sehr leicht, den Fehler hier zu erkennen, aber stellen Sie sich Hunderte von Codezeilen vor, die mit Zeigern, mallocs, frees und allen Arten der Fehlerbehandlung übersät sind . Die Dinge können sehr schnell wirklich chaotisch werden. Dies ist einer der Gründe, warum ich in bestimmten Fällen modernes C++ gegenüber C sehr bevorzuge, aber das ist ein ganz anderes Thema.

Wenn Sie also malloc verwenden, stellen Sie immer sicher, dass Ihr Speicher mit der größtmöglichen Wahrscheinlichkeit freed ist.

7
adam10603
char *some_memory = "Hello World";
sprintf(some_memory, "Goodbye...");

ist illegal, String-Literale sind const.

Dadurch wird ein 12-Byte-Char-Array auf dem Stack oder global zugewiesen (je nachdem, wo es deklariert ist).

char some_memory[] = "Hello World";

Wenn Sie Platz für weitere Manipulationen lassen möchten, können Sie festlegen, dass das Array größer sein soll. (Bitte legen Sie nicht 1 MB auf den Stapel.)

#define LINE_LEN 80

char some_memory[LINE_LEN] = "Hello World";
strcpy(some_memory, "Goodbye, sad world...");
printf("%s\n", some_memory);
6
ephemient

Ein Grund für die Zuweisung des Speichers ist, dass Sie ihn zur Laufzeit ändern möchten. In diesem Fall kann ein Malloc oder ein Puffer auf dem Stapel verwendet werden. Das einfache Beispiel der Zuweisung von "Hello World" zu einem Zeiger definiert einen Speicher, der "normalerweise" zur Laufzeit nicht geändert werden kann.

5
Mark Wilkins