Wann sollte ich malloc in C verwenden und wann nicht?

Lesezeit: 8 Minuten

Benutzeravatar von randombits
Zufallsbits

Ich verstehe, wie malloc() funktioniert. Meine Frage ist, ich werde Dinge wie diese 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 Obige 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?

  • Betreff: Ich habe die Fehlerprüfung der Kürze halber weggelassen – leider zu viele Programmierer Fehlerprüfung weglassen weil sie es nicht erkennen malloc() kann scheitern!

    – Andreas

    7. August 2015 um 9:16 Uhr

char *some_memory = "Hello World";

erstellt einen Zeiger auf eine String-Konstante. Das bedeutet, dass die Zeichenfolge “Hello World” irgendwo im schreibgeschützten Teil des Speichers sein wird und Sie nur einen Zeiger darauf haben. Sie können die Zeichenfolge schreibgeschützt verwenden. Du kann nicht Änderungen daran vornehmen. Beispiel:

some_memory[0] = 'h';

Bittet um Ärger.

Auf der anderen Seite

some_memory = (char *)malloc(size_to_allocate);

weist ein char-Array (eine Variable) zu und some_memory zeigt auf diesen zugewiesenen Speicher. Jetzt kann dieses Array sowohl gelesen als auch geschrieben werden. Sie können jetzt Folgendes tun:

some_memory[0] = 'h';

und der Inhalt des Arrays ändert sich zu “hello World”

  • Nur zur Verdeutlichung, so sehr ich diese Antwort mag (ich habe Ihnen +1 gegeben), Sie können dasselbe ohne malloc() tun, indem Sie einfach ein Zeichenarray verwenden. So etwas wie: char some_memory[] = “Hallo”; etwas_Erinnerung[0] = ‘W’; wird auch funktionieren.

    – Zufallsbits

    26. Dezember 2009 um 17:45 Uhr

  • Du hast recht. Du kannst das. Wenn Sie malloc() verwenden, wird der Speicher zur Laufzeit dynamisch zugewiesen, sodass Sie die Array-Größe zur Kompilierungszeit nicht festlegen müssen, und Sie können sie mit realloc() vergrößern oder verkleinern. Keines dieser Dinge kann getan werden, wenn Sie dies tun: char some_memory[] = “Hallo”; Hier können Sie zwar den Inhalt des Arrays ändern, seine Größe ist jedoch festgelegt. Abhängig von Ihren Anforderungen verwenden Sie also eine der drei Optionen: 1) Zeiger auf char const 2) dynamisch zugewiesenes Array 3) feste Größe, zur Kompilierzeit zugewiesenes Array.

    – codaddict

    26. Dezember 2009 um 18:03 Uhr

  • Um zu betonen, dass es schreibgeschützt ist, sollten Sie schreiben const char *s = "hi"; Wird das nicht eigentlich von der Norm gefordert?

    – Bis Theis

    20. Juni 2010 um 1:16 Uhr


  • @Till, nein, weil Sie einen Zeiger deklariert haben, der auf die Basisadresse des Zeichenfolgenliterals “hi” initialisiert wurde. s können völlig legal neu zugewiesen werden, um auf ein nicht konstantes Zeichen zu zeigen. Wenn Sie einen konstanten Zeiger auf eine schreibgeschützte Zeichenfolge wünschen, benötigen Sie const char const* s;

    – Rob11311

    8. Juni 2014 um 22:10 Uhr

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 unterscheiden muss. 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 Stack 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 dann erkennen kann, dass die Zuordnung fehlgeschlagen ist, und damit umgehen kann.

  • Speicherlebenszyklen und die damit verbundene Frage, wann und wie sie freigegeben werden, sind ein wichtiges Thema bei vielen gängigen Bibliotheken und Softwarekomponenten. Sie haben normalerweise eine gut dokumentierte Regel: “Wenn Sie einen Zeiger auf übergeben Dies eine meiner Routinen, du musst sie mallociert haben. Ich werde es im Auge behalten und es freigeben, wenn ich damit fertig bin.“ Eine häufige Quelle böser Fehler besteht darin, einen Zeiger auf statisch zugewiesenen Speicher an eine solche Bibliothek zu übergeben. Wenn die Bibliothek versucht, ihn freizugeben, das Programm stürzt ab Ich habe kürzlich viel Zeit damit verbracht, einen Fehler wie den zu beheben, den jemand anderes geschrieben hat.

    – Bob Murphy

    26. Dezember 2009 um 17:45 Uhr

  • Wollen Sie damit sagen, dass malloc() nur dann praktisch verwendet wird, wenn es ein Codesegment gibt, das während der Programmlebensdauer mehrmals aufgerufen wird, das mehrmals aufgerufen wird und “bereinigt” werden muss, da malloc () wird von free() begleitet? Zum Beispiel in einem Spiel wie Glücksrad, wo nachdem Sie erraten und die Eingabe in ein bestimmtes char-Array eingefügt haben, dass das malloc()-große Array für die nächste Vermutung freigegeben werden kann?

    – Smith genügt

    6. November 2013 um 2:19 Uhr

  • Die Lebensdauer der Daten ist in der Tat der eigentliche Grund, malloc zu verwenden. Angenommen, ein abstrakter Datentyp wird durch ein Modul dargestellt, deklariert einen Listentyp und Routinen zum Hinzufügen/Löschen von Elementen aus der Liste. Diese Elementwerte müssen in den dynamisch zugewiesenen Speicher kopiert werden.

    – Rob11311

    8. Juni 2014 um 22:17 Uhr

  • @Bob: Diese bösen Fehler machen die Konvention, dass der Allocator Speicher freigibt, weit überlegen, schließlich können Sie ihn recyceln. Angenommen, Sie haben Speicher mit calloc zugewiesen, um die Lokalität von Referenzen zu verbessern, wodurch die fehlerhafte Natur dieser Bibliotheken offengelegt wird, da Sie nur einmal für den gesamten Block free aufrufen müssen. Glücklicherweise musste ich keine Bibliotheken verwenden, die angeben, dass Speicher “mallociert” werden soll. Dies ist keine POSIX-Tradition und würde sehr wahrscheinlich als Fehler angesehen werden. Wenn sie “wissen”, dass Sie malloc verwenden müssen, warum erledigt das die Bibliotheksroutine dann nicht für Sie?

    – Rob11311

    8. Juni 2014 um 22:27 Uhr

Benutzeravatar von moritz
Moritz

malloc ist ein wunderbares Werkzeug zum Zuweisen, Neuzuordnen und Freigeben von Speicher zur Laufzeit, im Vergleich zu statischen Deklarationen wie Ihrem Hallo-Welt-Beispiel, die zur Kompilierzeit 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 zu tun haben, z. B. beim Lesen von Dateiinhalten oder beim Umgang mit Sockets, und Sie sich der Länge der zu verarbeitenden Daten nicht bewusst sind.

In einem trivialen Beispiel wie dem von Ihnen gegebenen ist malloc natürlich nicht das magische “richtige Werkzeug für den richtigen Job”, aber für komplexere Fälle (z. B. das Erstellen eines Arrays beliebiger Größe zur Laufzeit) ist es die einzige Möglichkeit gehen.

Benutzeravatar von notadam
notadam

Wenn Sie die genaue Größe des zu verwendenden Speichers nicht kennen, benötigen Sie eine dynamische Zuweisung (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, kennen aber natürlich die Größe der Datei nicht im Voraus, da der Benutzer die Datei zur Laufzeit an Ort und Stelle auswählt. Also im Grunde braucht man 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 malloc. In Ihrem Beispiel mit einer einfachen Zeichenfolge, deren Größe Sie bereits zur Kompilierzeit kennen (und Sie sie nicht ändern möchten), ist es nicht sinnvoll, diese dynamisch zuzuweisen.


Etwas off-topic, aber … Sie müssen sehr vorsichtig sein, um bei der Verwendung keine Speicherlecks zu erzeugen malloc. 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 an diesem Code falsch ist? Dazwischen gibt es eine bedingte return-Anweisung malloc und free. Es mag auf den ersten Blick in Ordnung erscheinen, aber denken Sie darüber nach. Wenn ein Fehler auftritt, werden Sie zurückkehren, ohne den zugewiesenen Speicher freizugeben. Dies ist eine häufige Ursache für Speicherlecks.

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

Also wann immer Sie es verwenden mallocStellen Sie immer sicher, dass Ihr Gedächtnis so gut wie möglich ist freed wie möglich.

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

ist illegal, String-Literale sind es const.

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

char some_memory[] = "Hello World";

Wenn Sie Raum für weitere Manipulationen lassen möchten, können Sie angeben, dass das Array größer dimensioniert werden soll. (Bitte legen Sie jedoch 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);

Benutzeravatar von Mark Wilkins
Markus Wilkins

Ein Grund, warum es notwendig ist, den Speicher zuzuweisen, ist, wenn Sie ihn zur Laufzeit ändern möchten. In diesem Fall kann ein Malloc oder ein Puffer auf dem Stack verwendet werden. Das einfache Beispiel der Zuweisung von „Hello World“ an einen Zeiger definiert Speicher, der „normalerweise“ zur Laufzeit nicht geändert werden kann.

1420560cookie-checkWann sollte ich malloc in C verwenden und wann nicht?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy