it-swarm.com.de

Unterschied zwischen Malloc und Calloc?

Was ist der Unterschied zwischen:

ptr = (char **) malloc (MAXELEMS * sizeof(char *));

oder:

ptr = (char **) calloc (MAXELEMS, sizeof(char*));

Wann ist es eine gute Idee, Calloc über Malloc zu verwenden oder umgekehrt?

726
user105033

calloc() initialisiert den Puffer auf Null, während malloc() den Speicher nicht initialisiert.

EDIT:

Das Löschen des Speichers kann einige Zeit in Anspruch nehmen, daher möchten Sie wahrscheinlich malloc() verwenden, wenn diese Leistung ein Problem darstellt. Wenn die Initialisierung des Speichers wichtiger ist, verwenden Sie calloc(). Mit calloc() können Sie beispielsweise einen Aufruf von memset() speichern.

804
Fred Larson

Ein weniger bekannter Unterschied besteht darin, dass in Betriebssystemen mit optimistischer Speicherzuordnung wie Linux der von malloc zurückgegebene Zeiger erst dann vom realen Speicher unterstützt wird, wenn das Programm ihn tatsächlich berührt.

calloc berührt in der Tat den Speicher (er schreibt Nullen darauf), und so können Sie sicher sein, dass das Betriebssystem die Zuordnung mit dem tatsächlichen RAM (oder Swap) unterstützt. Dies ist auch der Grund, warum es langsamer als malloc ist (es muss nicht nur auf Null gesetzt werden, das Betriebssystem muss auch einen geeigneten Speicherbereich finden, indem es möglicherweise andere Prozesse auslagert).

Siehe zum Beispiel diese SO Frage für eine weitere Diskussion über das Verhalten von malloc

352
Isak Savo

Ein häufig übersehener Vorteil von calloc ist, dass (konforme Implementierungen von) es Ihnen hilft, sich vor Schwachstellen durch Ganzzahlüberlauf zu schützen. Vergleichen Sie:

size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);

vs.

size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);

Ersteres kann zu einer winzigen Zuweisung und nachfolgenden Pufferüberläufen führen, wenn count größer als SIZE_MAX/sizeof *bar ist. Letzteres schlägt in diesem Fall automatisch fehl, da kein so großes Objekt erstellt werden kann.

Natürlich müssen Sie möglicherweise nach nicht konformen Implementierungen Ausschau halten, bei denen die Möglichkeit eines Überlaufs einfach ignoriert wird. Wenn dies auf den von Ihnen anvisierten Plattformen ein Problem darstellt, müssen Sie ohnehin einen manuellen Test auf Überlauf durchführen.

104
R..

In der Dokumentation sieht das Calloc wie ein Malloc aus, wodurch der Speicher nur auf Null gesetzt wird. Das ist nicht der Hauptunterschied! Die Idee von Calloc besteht darin, bei der Speicherzuweisung auf die Schreibkopie-Semantik zu verzichten. Wenn Sie mit calloc Speicher zuweisen, werden alle auf dieselbe physische Seite abgebildet, die mit Null initialisiert wurde. Wenn eine der Seiten des zugewiesenen Speichers in eine physische Seite geschrieben wird, wird dies zugewiesen. Dies wird oft verwendet, um GROSSE Hash-Tabellen zu erstellen, zum Beispiel, weil die Teile von Hash, die leer sind, nicht durch zusätzlichen Speicher (Seiten) gesichert werden. Sie verweisen glücklich auf die einzelne null-initialisierte Seite, die sogar zwischen Prozessen geteilt werden kann.

Jedes Schreiben in eine virtuelle Adresse wird einer Seite zugeordnet. Wenn diese Seite die Nullseite ist, wird eine andere physische Seite zugewiesen, die Nullseite wird dort kopiert und der Steuerungsfluss wird an den Clientprozess zurückgegeben. Dies funktioniert auf dieselbe Weise, wie Dateien mit Speicherzuordnung, virtueller Speicher usw. funktionieren. Es wird Paging verwendet.

Hier ist eine Optimierungsgeschichte zum Thema: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/

33
t0rakka

Es gibt keinen Unterschied in der Größe des zugewiesenen Speicherblocks. calloc füllt den Speicherblock nur mit einem physischen Null-Bit-Muster. In der Praxis wird häufig davon ausgegangen, dass die in dem mit calloc zugewiesenen Speicherblock befindlichen Objekte einen Initialisierungswert haben, als ob sie mit dem Literal 0 initialisiert worden wären, dh Ganzzahlen sollten den Wert 0 haben, der schwebend ist -point-Variablen - Wert von 0.0, Zeiger - der entsprechende Nullzeigerwert und so weiter.

Aus pedantischer Sicht kann jedoch nur garantiert werden, dass calloc (sowie memset(..., 0, ...)) Objekte vom Typ unsigned char ordnungsgemäß initialisiert (mit Nullen). Für alles andere wird nicht garantiert, dass es ordnungsgemäß initialisiert wurde, und es kann so genanntes Trap-Darstellung enthalten, was undefiniertes Verhalten verursacht. Mit anderen Worten, für irgendeinen anderen Typ als unsigned char könnte das vorgenannte Muster mit allen Null-Bits einen unzulässigen Wert darstellen, nämlich eine Trap-Darstellung.

Später wurde in einem der Technical Corrigenda to C99-Standard das Verhalten für alle Integer-Typen definiert (was sinnvoll ist). Das heißt In der aktuellen C-Sprache können Sie formal nur Integer-Typen mit calloc (und memset(..., 0, ...)) initialisieren. Die Verwendung dieser Funktion zur Initialisierung von allem anderen führt im Allgemeinen zu undefiniertem Verhalten aus Sicht der C-Sprache.

In der Praxis funktioniert calloc, wie wir alle wissen :), aber ob Sie es verwenden möchten (unter Berücksichtigung der obigen Punkte), liegt bei Ihnen. Ich persönlich bevorzuge es, es vollständig zu vermeiden, verwende stattdessen malloc und führe meine eigene Initialisierung durch.

Schließlich ist ein weiteres wichtiges Detail, dass calloc erforderlich ist, um die endgültige Blockgröße intern durch Multiplizieren der Elementgröße mit der Anzahl der Elemente zu berechnen. Dabei muss calloc auf einen möglichen arithmetischen Überlauf achten. Dies führt zu einer nicht erfolgreichen Zuordnung (Nullzeiger), wenn die angeforderte Blockgröße nicht korrekt berechnet werden kann. In der Zwischenzeit versucht Ihre malloc -Version nicht, auf Überlauf zu achten. Es wird eine "unvorhersehbare" Menge an Speicher zugewiesen, falls ein Überlauf auftritt.

26
AnT

aus einem Artikel Benchmarking-Spaß mit calloc () und null Seiten am Blog von Georg Hager

Bei der Speicherzuweisung mit calloc () wird die angeforderte Speichermenge nicht sofort zugewiesen. Stattdessen werden alle Seiten, die zu dem Speicherblock gehören, durch etwas MMU Magie (Links unten) mit einer einzelnen Seite verbunden, die alle Nullen enthält. Wenn solche Seiten nur gelesen werden (was für die Arrays b, c und d in der ursprünglichen Version des Benchmarks zutraf), werden die Daten von der einzelnen Nullseite bereitgestellt, die natürlich in den Cache passt. Soviel zu speichergebundenen Schleifenkernen. Wenn eine Seite beschrieben wird (egal wie), tritt ein Fehler auf, die "echte" Seite wird zugeordnet und die Nullseite wird in den Speicher kopiert. Dies wird als Copy-on-Write bezeichnet, ein bekannter Optimierungsansatz (den ich in meinen C++ - Vorlesungen sogar mehrmals unterrichtet habe). Danach funktioniert der Null-Lese-Trick für diese Seite nicht mehr, und deshalb war die Leistung nach dem Einfügen der - vermeintlich redundanten - Init-Schleife so viel geringer.

20
Ashish Chavan

calloc ist im Allgemeinen malloc+memset bis 0

Es ist im Allgemeinen etwas besser, malloc+memset explizit zu verwenden, besonders wenn Sie etwas tun wie:

ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));

Das ist besser, weil sizeof(Item) dem Compiler zur Kompilierungszeit bekannt ist und der Compiler es in den meisten Fällen durch die bestmöglichen Anweisungen ersetzt, um den Speicher auf Null zu setzen. Wenn dagegen memset in calloc vorkommt, wird die Parametergröße der Zuordnung nicht in den calloc-Code übersetzt, und es wird häufig real memset aufgerufen Enthält normalerweise Code zum byteweisen Auffüllen bis zur langen Grenze, als Zyklus zum Auffüllen des Speichers in sizeof(long) Chunks und schließlich zum byteweisen Auffüllen des verbleibenden Speicherplatzes. Auch wenn der Allokator klug genug ist, um einen aligned_memset aufzurufen, handelt es sich dennoch um eine generische Schleife.

Eine bemerkenswerte Ausnahme wäre, wenn Sie malloc/calloc eines sehr großen Teils des Speichers (einige power_of_two Kilobytes) ausführen. In diesem Fall kann die Zuweisung direkt vom Kernel aus erfolgen. Da Betriebssystem-Kernel normalerweise den gesamten Speicher auf Null setzen, den sie aus Sicherheitsgründen freigeben, kann es sein, dass Calloc ihn ohne zusätzliche Nullsetzung zurückgibt. Auch hier gilt: Wenn Sie nur etwas zuweisen, von dem Sie wissen, dass es klein ist, sind Sie mit malloc + memset in Bezug auf die Leistung möglicherweise besser dran.

11
virco

Unterschied 1:

malloc() weist normalerweise den Speicherblock zu und es wird ein Speichersegment initialisiert.

calloc() weist den Speicherblock zu und initialisiert den gesamten Speicherblock auf 0.

Unterschied 2:

Wenn Sie die malloc() -Syntax berücksichtigen, wird nur 1 Argument akzeptiert. Betrachten Sie das folgende Beispiel:

data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );

Beispiel: Wenn Sie 10 Speicherblöcke für den Int-Typ zuweisen möchten,

int *ptr = (int *) malloc(sizeof(int) * 10 );

Wenn Sie die calloc() -Syntax berücksichtigen, werden 2 Argumente benötigt. Betrachten Sie das folgende Beispiel:

data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));

Beispiel: Wenn Sie 10 Speicherblöcke für den Int-Typ zuweisen und alles auf NULL initialisieren möchten,

int *ptr = (int *) calloc(10, (sizeof(int)));

Ähnlichkeit:

Sowohl malloc() als auch calloc() geben standardmäßig void * zurück, wenn sie nicht vom Typ casted sind.!

8
Shivaraj Bhat

Es gibt zwei Unterschiede.
Erstens ist in der Anzahl der Argumente. malloc() akzeptiert ein einzelnes Argument (Speicher in Bytes erforderlich), während calloc() zwei Argumente benötigt.
Zweitens initialisiert malloc() den zugewiesenen Speicher nicht, während calloc() den zugewiesenen Speicher auf NULL initialisiert.

  • calloc() belegt einen Speicherbereich, die Länge ergibt sich aus dessen Parametern. calloc füllt den Speicher mit NULL und gibt einen Zeiger auf das erste Byte zurück. Wenn nicht genügend Speicherplatz gefunden wird, wird ein Zeiger NULL zurückgegeben.

Syntax: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);, d. H. ptr_var=(type *)calloc(n,s);

  • malloc() reserviert einen einzelnen Speicherblock von REQUSTED SIZE und gibt einen Zeiger auf das erste Byte zurück. Wenn die erforderliche Speichermenge nicht gefunden wird, wird ein Nullzeiger zurückgegeben.

Syntax: ptr_var=(cast_type *)malloc(Size_in_bytes); Die Funktion malloc() akzeptiert ein Argument, das die Anzahl der zuzuweisenden Bytes angibt, während die Funktion calloc() zwei Argumente akzeptiert, wobei eines die Anzahl der Elemente und das andere die Anzahl der Elemente ist Die Anzahl der zuzuweisenden Bytes für jedes dieser Elemente. Außerdem initialisiert calloc() den zugewiesenen Speicherplatz mit Nullen, während malloc() dies nicht tut.

7
Jainendra

Die Funktion calloc(), die im Header <stdlib.h> deklariert ist, bietet einige Vorteile gegenüber der Funktion malloc().

  1. Es ordnet Speicher als eine Anzahl von Elementen einer gegebenen Größe zu und
  2. Es initialisiert den zugewiesenen Speicher, so dass alle Bits Null sind.
6
Vipin Diwakar

Ein noch nicht genannter Unterschied: Größenbeschränkung

void *malloc(size_t size) kann nur bis zu SIZE_MAX zuweisen.

void *calloc(size_t nmemb, size_t size); kann bis zu SIZE_MAX*SIZE_MAX zuordnen.

Diese Funktion wird auf vielen Plattformen mit linearer Adressierung nicht häufig verwendet. Solche Systeme begrenzen calloc() mit nmemb * size <= SIZE_MAX.

Stellen Sie sich einen 512-Byte-Typ mit der Bezeichnung disk_sector vor und der Code möchte viele Sektoren verwenden. Hier kann Code nur bis zu SIZE_MAX/sizeof disk_sector Sektoren verwenden.

size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);

Beachten Sie Folgendes, was eine noch größere Zuordnung ermöglicht.

size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);

Ob nun ein solches System eine so große Allokation liefern kann, ist eine andere Frage. Die meisten werden heute nicht. Es ist jedoch schon seit vielen Jahren aufgetreten, als SIZE_MAX 65535 war. Angesichts Moores Gesetz wird vermutet, dass dies um 2030 bei bestimmten Speichermodellen mit SIZE_MAX == 4294967295 und Speicherpools in den 100 auftreten wird von GByte.

5
chux

malloc() und calloc() sind Funktionen aus der C-Standardbibliothek, die eine dynamische Speicherzuweisung ermöglichen, dh, beide ermöglichen die Speicherzuweisung zur Laufzeit.

Ihre Prototypen sind wie folgt:

void *malloc( size_t n);
void *calloc( size_t n, size_t t)

Es gibt hauptsächlich zwei Unterschiede zwischen den beiden:

  • Verhalten: malloc() weist einen Speicherblock zu, ohne ihn zu initialisieren, und das Lesen des Inhalts dieses Blocks führt zu Abfallwerten. calloc() hingegen weist einen Speicherblock zu und initialisiert ihn mit Nullen, und das Lesen des Inhalts dieses Blocks führt offensichtlich zu Nullen.

  • Syntax: malloc() benötigt 1 Argument (die zuzuweisende Größe), und calloc() benötigt zwei Argumente (Anzahl der zuzuweisenden Blöcke und Größe jedes Blocks).

Der Rückgabewert von beiden ist bei Erfolg ein Zeiger auf den zugewiesenen Speicherblock. Andernfalls wird NULL zurückgegeben, um den Speicherzuweisungsfehler anzuzeigen.

Beispiel:

int *arr;

// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int)); 

// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));

Dieselbe Funktionalität wie calloc() kann mit malloc() und memset() erreicht werden:

// allocate memory for 10 integers with garbage values   
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int)); 

Beachten Sie, dass malloc() vorzugsweise anstelle von calloc() verwendet wird, da dies schneller ist. Wenn eine Nullinitialisierung der Werte gewünscht wird, verwenden Sie stattdessen calloc().

4
elmiomar

Anzahl der Blöcke:
malloc () Weist einen einzelnen Block des angeforderten Speichers zu.
calloc () Weist mehrere Blöcke des angeforderten Speichers zu

Initialisierung:
malloc () löscht und initialisiert den zugewiesenen Speicher nicht.
calloc () initialisiert den zugewiesenen Speicher mit Null.

Geschwindigkeit:
Die Geschwindigkeit von malloc () ist schnell.
calloc () Geschwindigkeit ist vergleichsweise langsam.

Syntex:

void *malloc(size_t size);                   // syntex for malloc() function
void *calloc(size_t num, size_t size);       // syntex for calloc() function

Argument:
Wenn Sie die Syntax von malloc () berücksichtigen, wird nur 1 Argument verwendet.
Wenn Sie die calloc () - Syntax berücksichtigen, werden 2 Argumente benötigt.

Art der Speicherzuordnung ::
Die Funktion malloc () weist dem verfügbaren Heap Speicher der gewünschten 'Größe' zu.
Die Funktion calloc () weist einen Speicher zu, der der Größe von "num * size" entspricht.

Bedeutung beim Namen:
Der Name malloc steht für Memory Allocation.
Der Name calloc bedeutet zusammenhängende Zuordnung.

0
Majbah Habib