2010-09-24 10 views
5

Ich bin mir dessen bewusst folgendes:Wie kann man Speicher in C allokieren und wie unterscheiden sie sich?

  • malloc
  • calloc
  • realloc

Was sind die Unterschiede zwischen diesen beiden? Warum scheint malloc fast ausschließlich verwendet zu werden? Gibt es Verhaltensunterschiede zwischen Compilern?

+1

Vergessen Sie nicht über [variable length arrays] (http://stackoverflow.com/questions/2759294/variable-length-array) :) –

Antwort

12

malloc reserviert Speicher. Der Inhalt des Speichers bleibt unverändert (gefüllt mit dem, was vorher da war).

calloc reserviert Speicher und setzt den Inhalt auf Nur-Nullen.

realloc ändert die Größe eines vorhandenen zugewiesenen Speicherblocks oder kopiert den Inhalt eines vorhandenen Speicherblocks in einen neu zugewiesenen Block der angeforderten Größe und hebt dann die Zuweisung des alten Blocks auf.

Offensichtlich ist realloc eine Sonderfall-Situation. Wenn Sie keinen alten Speicherblock zum Ändern der Größe (oder zum Kopieren und Freigeben) haben, gibt es keinen Grund, sie zu verwenden. Der Grund dafür, dass malloc normalerweise anstelle von calloc verwendet wird, liegt daran, dass Laufzeitkosten für das Festlegen des Speichers auf Nur-Nullen entstehen. Wenn Sie planen, den Speicher sofort mit nützlichen Daten zu füllen (wie es üblich ist), hat das keinen Sinn es zuerst zu löschen.

Diese Funktionen sind alle Standard und verhalten sich zuverlässig über Compiler hinweg.

+2

'calloc' ist besonders nützlich für die Zuordnung von Arrays von Strukturen, da es dauert 2 Argumente: 'calloc (num_of_items, size_of_item)'. Es ist mehr Arbeit, ein solches Array mit nützlichen Daten zu füllen (wie Tyler sagt), also gibt es ein faires Argument zugunsten der zusätzlichen Kosten, um den Speicher auf einen bekannten (Null-) Wert zu initialisieren. –

+2

"calloc" hat auch den Vorteil, die Multiplikation für Sie durchzuführen, so dass es bei einer nicht fehlerhaften Implementierung überprüft und bei Überlauf fehlschlägt. –

+0

Sie haben 'strdup' oder' asprintf' nicht erwähnt, die auch Speicher zuweisen. – abelenky

1

calloc wahrscheinlich ist ebenso etwas umgesetzt ähnlich wie:

void * calloc(size_t nmemb, size_t size) { 
     size_t len = nmemb * size); 
     void * ptr = malloc(len); 
     if (ptr) { 
      return memset(ptr, 0, len); 
     } 
     return ptr; 
} 

So fügt es nur eine mehrfach vor und eine klare nach dem malloc.

malloc könnte (aber wahrscheinlich nicht immer) implementiert, wie:

void * malloc(size_t size) { 
     return realloc(NULL, size); 
} 

, da Sie einen NULL-Zeiger wie der vorherige Zeiger passieren realloc, aber malloc ist höchstwahrscheinlich nicht so implementiert, da wäre es Verlangsamen Sie alle mallocs und da Realloc wahrscheinlich malloc verwendet. Die wichtigste Information über Realloc ist, dass es oft in der Lage ist, die tatsächliche Größe des Speicherblocks zu ermitteln, den eine der Heap-Allokationsroutinen zurückgibt, und festzustellen, ob der Block bereits groß genug ist oder in einigen Fällen, wenn er vorhanden ist Am besten versuchen Sie, den Block zu verkleinern oder zu verschieben.

void realloc(void * ptr, size_t size) { 
    size_t alen = MALLOC_LENGTH_OF(ptr); // this just stands for some method of determining 
            // the size of the block that was allocated, and could 
            // be looking it up in a table or looking at a place 
            // several bytes before the pointer, or some other 
            // implementation specific thing 
    if (0 == size) { 
     free(ptr); 
     return NULL; 
    } 
    if (alen >= size) { 
     return ptr; // big enough, and not worrying about it being too big 
    } 
    void new_ptr = malloc(size); // since I said that malloc most likely isn't 
           // implemented using realloc using malloc here is ok 
    if (new_ptr && ptr) { 
     memcpy(new_ptr, ptr, alen); 
    } 
    free(ptr); 
    return new_ptr; 
} 

Malloc wird mehr verwendet, weil es am einfachsten ist. Programmierer können ihre Zuweisungen oft groß genug machen, um damit zu beginnen, dass sie sich keine Sorgen machen müssen, dass sie ihre Größe mit Realloc ändern können, und es ist oft nicht nötig, den Speicher zu löschen.

Es gibt verschiedene Verhaltensweisen zwischen verschiedenen Bibliotheken, und Sie können sogar Programme mit anderen Versionen verknüpfen, nur um dieses unterschiedliche Verhalten zu vermeiden (normalerweise ohne den Compiler zu ändern).

Einige malloc-Bibliotheken dienen zum Debuggen und zur Fehlererkennung. Andere bieten möglicherweise eine bessere Leistung.Einige sind dafür optimiert, Speicher für mehrere verschiedene Threads gleichzeitig zuzuweisen, und vermeiden, dass die verschiedenen Threads den gesamten Heap sperren müssen, um eine Zuweisung durchzuführen oder frei.

Alle von ihnen sollten jedoch aus Sicht der Anwendungen die gleiche Semantik bieten.

+0

stimme ab für die Verwendung von geschweiften Klammern in der gleichen Zeile wie der Block!(nicht wirklich tho) – Firoso

+0

@Firoso: Das macht _diff_ produzieren bessere Ausgabe beim Vergleich von Versionen, sowie schrumpft den Code. Da ich auch geschweifte Klammern um einen Zeilenblock verwende, hilft es wirklich, sie in die gleiche Zeile wie den Blocköffnungscode zu setzen. – nategoose

+0

Wenn Sie auf die Option diff -p verweisen, glaube ich, dass die Heuristik eine Zeile mit einem Funktionsnamen enthält, wenn sie Buchstaben in Spalte 1 enthält. – ninjalj

3

Neben denen, die Sie erwähnen (einige sind Erweiterungen):

  • Variablen auf dem Stapel sind auch dynamisch zugewiesen. Rekursion ist eine Möglichkeit, diese zuzuweisen und zu verwenden.
  • C99 hat Arrays variabler Länge (wie BlueRaja erwähnt).
  • Auf einigen Systemen haben Sie sogar einen alloca Aufruf, mit dem Sie Chunks variabler Länge im Stackframe zuweisen können.
  • POSIX verfügt über eine Zuordnung von Speichersegmenten und Dateien mit Kombinationen von shm_open oder open und mmap.
  • SysV IPC hat shmget etc ruft
+0

Windows verfügt auch über Möglichkeiten, Speicher zwischen Prozessen freizugeben und Dateien im Speicher abzulegen. – RBerteig

2

Eine Methode Speicher zuzuweisen, die nicht erwähnt worden ist, ist alloca(size_t size) die Größe Byte Speicherplatz auf dem aktuellen Stack-Frame behält und gibt automatisch den Speicher wieder, wenn Sie den Stapel verlassen Rahmen.

0

malloc: sagen wir, Sie haben ptr = (int *) malloc (10); Dies ordnet 10 zusammenhängende Bytes Speicherplatz zu und die Adresse des ersten Bytes wird in Zeigervariable ptr gespeichert. Der zugewiesene Speicher enthält jetzt den Wert für den Papierkorb.
Also, wenn ich von 0 bis 3 variiert scanf ("% d", ptr + i); speichert 4 Ganzzahlen an 4 zusammenhängenden Standorten. ptr hat die Adresse der ersten ganzen Zahl, ptr + 1 hat die Adresse der 2. Nummer und so weiter. Daher printf ("% d", atstrick (ptr + i)); werden entsprechende Werte gedruckt. Im Gegensatz zu Speicher, der für Variablen und Arrays reserviert ist, ist dynamisch zugewiesen kein Name zugeordnet. Wie oben zu sehen.

calloc: Es ist ähnlich wie malloc außer zwei Differenz: 1. Deklaration: ptr = (int *) calloc (5, sizeof (int)); Hier haben wir zwei Argumente, 5 ist keine von Blöcken zugewiesen und 2. Argument ist gleich 4 Bytes. Dies entspricht ptr = (int *) malloc (5 * sizeof (int)); 2.In Calloc-Speicher, der anfänglich zugewiesen wird, ist kein Müll, aber es ist 0. Sowohl Malloc als auch Calloc geben NULL zurück, wenn nicht genügend Speicher im Heap verfügbar ist.