Unterschied zwischen Malloc und Calloc?


780

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?



8
In C könnten Sie das oben genannte allgemeiner schreiben als:ptr = calloc(MAXELEMS, sizeof(*ptr));
chqrlie

7
Ein interessanter Beitrag über den Unterschied zwischen Calloc und Malloc + Memset vorpus.org/blog/why-does-calloc-exist
ddddavidee

2
@ddddavidee Auch ich habe diesen Blog gefunden, nachdem ich mit so vielen Antworten im Internet unzufrieden war. Nathaniel J. Smith verdient mehr als 100 SO-Punkte für seine Analyse.
Lebensbalance

Antworten:


851

calloc() gibt Ihnen einen Null-initialisierten Puffer, während malloc() der Speicher nicht initialisiert wird.

Bei großen Zuweisungen erhalten die meisten callocImplementierungen unter Mainstream-Betriebssystemen Seiten mit bekannten Nullen vom Betriebssystem (z. B. über POSIX mmap(MAP_ANONYMOUS)oder Windows VirtualAlloc), sodass sie nicht im Benutzerbereich geschrieben werden müssen. Auf diese Weise mallocerhält normal auch mehr Seiten vom Betriebssystem. callocnutzt nur die Garantie des Betriebssystems.

Dies bedeutet, dass der callocSpeicher weiterhin "sauber" und träge zugewiesen werden kann und das Kopieren beim Schreiben einer systemweit gemeinsam genutzten physischen Seite mit Nullen zugeordnet werden kann. (Angenommen, ein System mit virtuellem Speicher.)

Einige Compiler können sogar malloc + memset (0) für Sie in calloc optimieren. Sie sollten calloc jedoch explizit verwenden, wenn der Speicher als gelesen werden soll 0 .

Wenn Sie vor dem Schreiben nie Speicher lesen werden, verwenden mallocSie ihn, damit Sie (möglicherweise) schmutzigen Speicher aus der internen freien Liste erhalten, anstatt neue Seiten vom Betriebssystem abzurufen. (Oder anstatt einen Speicherblock auf der freien Liste für eine kleine Zuordnung auf Null zu setzen).


Eingebettete Implementierungen von callockönnen es auf sich callocselbst belassen, wenn kein Betriebssystem vorhanden ist, oder es ist kein ausgefallenes Mehrbenutzer-Betriebssystem, das Seiten auf Null setzt, um Informationslecks zwischen Prozessen zu stoppen.

Unter eingebettetem Linux könnte malloc mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS), das nur für einige eingebettete Kernel aktiviert ist, da es auf einem Mehrbenutzersystem unsicher ist.


224
Die * Alloc-Varianten sind ziemlich mnemonisch - Clear-Alloc, Memory-Alloc, Re-Alloc.
Cascabel

43
Verwenden Sie malloc (), wenn Sie alles festlegen möchten, was Sie im zugewiesenen Speicherplatz verwenden. Verwenden Sie calloc (), wenn Sie Teile der Daten nicht initialisieren möchten - und es wäre vorteilhaft, wenn die nicht gesetzten Teile auf Null gesetzt würden.
Jonathan Leffler

268
callocist nicht unbedingt teurer, da das Betriebssystem einige Tricks ausführen kann, um es zu beschleunigen. Ich weiß, dass FreeBSD, wenn es eine Leerlauf-CPU-Zeit erhält, diese verwendet, um einen einfachen Prozess auszuführen, der nur herumgeht und freigegebene Speicherblöcke auf Null setzt und Blöcke, die Prozesse verarbeiten, mit einem Flag markiert. Wenn Sie dies tun calloc, wird zuerst versucht, einen solchen vor Null gesetzten Block zu finden und ihn Ihnen einfach zu geben - und höchstwahrscheinlich wird er einen finden.
Pavel Minaev

28
Ich bin der Meinung, dass Ihr Code nicht sicher genug ist, wenn Sie Malloc oder Calloc verwenden, wenn Ihr Code aufgrund von Zuweisungen ohne Initing standardmäßig "sicherer" wird. Die Verwendung von malloc ist ein guter Indikator dafür, dass die Daten initialisiert werden müssen. Ich verwende calloc nur in Fällen, in denen diese 0 Bytes tatsächlich von Bedeutung sind. Beachten Sie auch, dass calloc nicht unbedingt das tut, was Sie für Nicht-Zeichen-Typen denken. Niemand verwendet mehr Trap-Darstellungen oder Nicht-IEEE-Floats, aber das ist keine Entschuldigung dafür, dass Ihr Code wirklich portabel ist, wenn dies nicht der Fall ist.
Steve Jessop

18
@SteveJessop "Safer" ist nicht das richtige Wort. Ich denke, "Deterministisch" ist der bessere Begriff. Code, der deterministischer ist als Fehler, die vom Timing und den Datensequenzen abhängen, lässt sich leichter isolieren. Calloc ist manchmal ein einfacher Weg, um diesen Determinismus gegenüber einer expliziten Initialisierung zu erhalten.
Dennis

362

Ein weniger bekannter Unterschied besteht darin, dass in Betriebssystemen mit optimistischer Speicherzuweisung wie Linux der von zurückgegebene Zeiger mallocnicht durch echten Speicher gesichert wird, bis das Programm ihn tatsächlich berührt.

callocBerührt tatsächlich den Speicher (es schreibt Nullen darauf) und Sie werden sicher sein, dass das Betriebssystem die Zuordnung mit tatsächlichem 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 austauscht).

Siehe zum Beispiel diese SO-Frage für weitere Diskussionen über das Verhalten von Malloc


49
callocmuss keine Nullen schreiben. Wenn der zugewiesene Block hauptsächlich aus neuen Nullseiten besteht, die vom Betriebssystem bereitgestellt werden, können diese unberührt bleiben. Dies muss natürlich callocauf das Betriebssystem abgestimmt sein und nicht auf eine generische Bibliotheksfunktion malloc. Oder ein Implementierer könnte callocjedes Wort mit Null vergleichen, bevor er es auf Null setzt. Dies würde keine Zeit sparen, aber es würde vermeiden, die neuen Seiten zu verschmutzen.
R .. GitHub STOP HELPING ICE

3
@ R .. interessante Anmerkung. Aber gibt es solche Implementierungen in der Praxis in freier Wildbahn?
Isak Savo

10
Bei allen dlmallocähnlichen Implementierungen wird übersprungen, memsetob der Block über mmapneue anonyme Seiten (oder gleichwertige Seiten) abgerufen wurde . Normalerweise wird diese Art der Zuweisung für größere Chunks verwendet, beginnend bei 256 KB oder so. Ich kenne keine Implementierungen, die den Vergleich mit Null durchführen, bevor ich neben meiner eigenen Null schreibe.
R .. GitHub STOP HELPING ICE

1
omallocüberspringt auch die memset; callocmuss niemals Seiten berühren, die noch nicht von der Anwendung verwendet wurden (Seiten-Cache). Obwohl äußerst primitive callocImplementierungen unterscheiden.
Mirabilos

10
Der Calloc von glibc prüft, ob das Betriebssystem neuen Speicher erhält. Wenn ja, weiß es, dass es nicht geschrieben werden muss, da mmap (..., MAP_ANONYMOUS) Speicher zurückgibt, der bereits auf Null gesetzt ist.
Peter Cordes

112

Ein häufig übersehener Vorteil callocist, dass (konforme Implementierungen von) Sie vor Sicherheitslücken durch ganzzahligen Überlauf 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 Zuordnung und nachfolgenden Pufferüberläufen führen, wenn countes größer als ist SIZE_MAX/sizeof *bar. Letzteres schlägt in diesem Fall automatisch fehl, da ein so großes Objekt nicht 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 Plattformen, auf die Sie abzielen, ein Problem darstellt, müssen Sie ohnehin einen manuellen Test auf Überlauf durchführen.


17
Anscheinend war der arithmetische Überlauf der Grund für das OpenSSH-Loch im Jahr 2002. Guter Artikel von OpenBSD über die Gefahren dieses Problems mit speicherbezogenen Funktionen: undeadly.org/cgi?action=article&sid=20060330071917
Philip P.

4
@KomradeP.: Interessant. Leider enthält der Artikel, den Sie verlinkt haben, gleich zu Beginn Fehlinformationen. Das Beispiel mit charist kein Überlauf, sondern eine implementierungsdefinierte Konvertierung, wenn das Ergebnis wieder einem charObjekt zugewiesen wird.
R .. GitHub STOP HELPING ICE

Es ist wahrscheinlich nur zu Illustrationszwecken da. Weil der Compiler das wahrscheinlich sowieso weg optimieren wird. Meins kompiliert in diesen Asm: Push 1.
Philip P.

1
@tristopia: Der Punkt ist nicht, dass der Code bei allen Implementierungen ausnutzbar ist, sondern dass er ohne zusätzliche Annahmen falsch ist und daher nicht korrekt / portabel verwendet wird.
R .. GitHub STOP HELPING ICE

3
@tristopia: Wenn Ihre Denkweise " size_t64-Bit ist, das ist also kein Problem" ist, ist dies eine fehlerhafte Denkweise, die zu Sicherheitslücken führen wird. size_tist ein abstrakter Typ, der Größen darstellt, und es gibt keinen Grund zu der Annahme, dass das beliebige Produkt einer 32-Bit-Zahl und eines size_t(Hinweis: sizeof *barkönnte bei einer 64-Bit-C-Implementierung im Prinzip größer als 2 ^ 32 sein!) passt size_t.
R .. GitHub STOP HELPING ICE

37

Die Dokumentation lässt das Calloc wie ein Malloc aussehen, das den Speicher nur auf Null initialisiert. Das ist nicht der Hauptunterschied! Die Idee von Calloc besteht darin, auf die Copy-on-Write-Semantik für die Speicherzuweisung zu verzichten. Wenn Sie mit calloc Speicher zuweisen, werden alle derselben physischen Seite zugeordnet, die auf Null initialisiert wird. Wenn eine der Seiten des zugewiesenen Speichers in eine physische Seite geschrieben wird, wird sie zugewiesen. Dies wird häufig verwendet, um RIESIGE Hash-Tabellen zu erstellen, da beispielsweise die leeren Hash-Teile nicht durch zusätzlichen Speicher (Seiten) gesichert werden. Sie verweisen glücklich auf die einzelne Seite mit der Nullinitialisierung, die sogar von Prozessen gemeinsam genutzt 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 genauso wie Speicherzuordnungsdateien, virtueller Speicher usw. 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/


26

Es gibt keinen Unterschied in der Größe des zugewiesenen Speicherblocks. callocFüllt einfach den Speicherblock mit einem physischen All-Null-Bit-Muster. In der Praxis wird häufig angenommen, dass die Objekte in dem mit zugewiesenen Speicherblock calloceinen Anfangswert haben, als ob sie mit einem Literal initialisiert worden wären 0, dh Ganzzahlen sollten den Wert von 0Gleitkommavariablen - Wert von 0.0Zeigern - den entsprechenden Nullzeigerwert haben , und so weiter.

Aus pedantischer Sicht wird jedoch calloc(wie auch memset(..., 0, ...)) nur garantiert, dass Objekte vom Typ (mit Nullen) ordnungsgemäß initialisiert werden unsigned char. Es wird nicht garantiert, dass alles andere ordnungsgemäß initialisiert wird, und es kann eine sogenannte Trap-Darstellung enthalten , die zu undefiniertem Verhalten führt. Mit anderen Worten, für jeden anderen Typ als unsigned chardas oben erwähnte All-Null-Bit-Muster könnte ein unzulässiger Wert eine Trap-Darstellung darstellen.

Später wurde in einer der technischen Berichtigungen zum C99-Standard das Verhalten für alle Ganzzahltypen definiert (was sinnvoll ist). Das heißt, formal können Sie in der aktuellen C-Sprache nur ganzzahlige Typen mit calloc(und memset(..., 0, ...)) initialisieren . Die Verwendung zum Initialisieren von anderen Elementen im allgemeinen Fall führt aus Sicht der C-Sprache zu undefiniertem Verhalten.

In der Praxis callocfunktioniert, wie wir alle wissen :), aber ob Sie es verwenden möchten (unter Berücksichtigung der oben genannten), liegt bei Ihnen. Ich persönlich bevorzuge es, es vollständig zu vermeiden, mallocstattdessen zu verwenden und meine eigene Initialisierung durchzuführen.

Schließlich ist ein weiteres wichtiges Detail callocerforderlich, um die endgültige Blockgröße intern zu berechnen , indem die Elementgröße mit der Anzahl der Elemente multipliziert wird. Achten Sie dabei callocauf einen möglichen arithmetischen Überlauf. Dies führt zu einer nicht erfolgreichen Zuordnung (Nullzeiger), wenn die angeforderte Blockgröße nicht korrekt berechnet werden kann. In der Zwischenzeit mallocunternimmt Ihre Version keinen Versuch, auf Überlauf zu achten. Für den Fall eines Überlaufs wird eine "unvorhersehbare" Speichermenge zugewiesen.


Gemäß dem Absatz "Ein weiteres wichtiges Detail": Das scheint memset(p, v, n * sizeof type);ein Problem zu sein, da es n * sizeof typemöglicherweise überlaufen kann. Ich denke, ich muss eine for(i=0;i<n;i++) p[i]=v;Schleife für robusten Code verwenden.
chux

Es wäre hilfreich, wenn es ein Standardmittel gäbe, mit dem Code behaupten könnte, dass eine Implementierung All-Bits-Null als Nullzeiger verwenden muss (andernfalls wird die Kompilierung abgelehnt), da es Implementierungen gibt, die andere Nullzeigerdarstellungen verwenden, dies jedoch sind vergleichsweise selten; Code, der auf solchen Implementierungen nicht ausgeführt werden muss, kann schneller sein, wenn Calloc () oder Memset zum Initialisieren von Zeigerarrays verwendet werden können.
Supercat

@chux Nein, wenn ein Array mit nElementen vorhanden ist, bei denen ein Element die Größe hat sizeof type, n*sizeof typekann es nicht überlaufen, da die maximale Größe eines Objekts kleiner als sein muss SIZE_MAX.
12431234123412341234123

@ 12431234123412341234123 Wahr über eine Array Größe <= SIZE_MAX, doch gibt es keine Arrays hier. Der von calloc()can zurückgegebene Zeiger zeigt auf den zugewiesenen Speicher als überschreitet SIZE_MAX. Viele Implementierungen beschränken das Produkt der 2 Argumente auf calloc()aufSIZE_MAX , aber die C - Spezifikation verhängen nicht , dass die Grenze.
chux

21

aus einem Artikel Benchmarking-Spaß mit calloc () und null Seiten in Georg Hagers Blog

Bei der Zuweisung von Speicher mit calloc () wird die angeforderte Speichermenge nicht sofort zugewiesen. Stattdessen werden alle Seiten, die zum Speicherblock gehören, durch eine MMU-Magie mit einer einzelnen Seite verbunden, die alle Nullen enthält (Links unten). Wenn solche Seiten nur gelesen werden (was in der Originalversion des Benchmarks für die Arrays b, c und d zutraf), werden die Daten von der einzelnen Nullseite bereitgestellt, die natürlich in den Cache passt. Soviel zu speichergebundenen Loop-Kerneln. 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). Nachdem,


Wo ist der Link?
Rupesh Yadav.

2
Die erste Antwortzeile enthält einen Link zu Georg Hagers Blog.
Ashish Chavan

11

callocist in der Regel malloc+memsetzu 0

Es ist im Allgemeinen etwas besser, malloc+memsetexplizit zu verwenden , insbesondere wenn Sie etwas tun wie:

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

Das ist besser, weil sizeof(Item)es dem Compiler zur Kompilierungszeit bekannt ist und der Compiler es in den meisten Fällen durch die bestmöglichen Anweisungen auf Null Speicher ersetzt. Auf der anderen Seite wird, wenn dies memsetgeschieht calloc, die Parametergröße der Zuordnung nicht im callocCode kompiliert , und es memsetwird häufig real aufgerufen, das normalerweise Code enthält, um Byte für Byte bis zur langen Grenze aufzufüllen, als Zyklus zum Füllen Speicherplatz insizeof(long) Blöcken auffüllen und schließlich byteweise den verbleibenden Speicherplatz ausfüllen. Selbst wenn der Allokator intelligent genug ist, um einige aufzurufen, handelt aligned_memsetes sich immer noch um eine generische Schleife.

Eine bemerkenswerte Ausnahme wäre, wenn Sie malloc / calloc eines sehr großen Speicherblocks (einige Potenzen von zwei Kilobyte) ausführen. In diesem Fall kann die Zuweisung direkt vom Kernel aus erfolgen. Da Betriebssystem-Kernel normalerweise den gesamten Speicher, den sie aus Sicherheitsgründen freigeben, auf Null setzen, gibt Calloc ihn möglicherweise ohne zusätzliche Nullung zurück. Nochmals: 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.


+1 für die Erinnerung, dass eine generische Implementierung einer Funktionalität in einer Systembibliothek nicht unbedingt schneller ist als dieselbe Operation im Benutzercode.
Patrick Schlüter

1
Es gibt auch einen zweiten Punkt, der calloc()langsamer macht als malloc(): die Multiplikation für die Größe. calloc()ist erforderlich, um eine generische Multiplikation zu verwenden (wenn size_t64 Bit sind, sogar die sehr kostspielige 64-Bit * 64-Bit = 64-Bit-Operation), während das malloc () häufig eine Kompilierungszeitkonstante hat.
Patrick Schlüter

4
glibc calloc hat einige Klugheiten, um zu entscheiden, wie der zurückgegebene Block am effizientesten gelöscht werden soll, z. B. muss manchmal nur ein Teil davon gelöscht werden, und es muss auch eine nicht gerollte Löschung bis zu 9 * sizeof (size_t) gelöscht werden. Speicher ist Speicher, das Löschen von 3 Bytes gleichzeitig wird nicht schneller sein, nur weil Sie ihn dann zum Halten verwenden werden struct foo { char a,b,c; };. callocist immer besser als malloc+ memset, wenn Sie immer die gesamte malloced-Region löschen wollen . callochat auch eine sorgfältige, aber effiziente Überprüfung auf int-Überlauf bei Elementen der Größe *.
Peter Cordes

8

Unterschied 1:

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

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

Unterschied 2:

Wenn Sie die malloc()Syntax berücksichtigen , wird nur 1 Argument benötigt. 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 Typ int 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 Typ int zuweisen und all das auf NULL initialisieren möchten,

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

Ähnlichkeit:

Beide malloc()und calloc()geben standardmäßig void * zurück, wenn sie nicht typisiert sind.!


Und warum unterscheiden Sie data_type und cast_type?
Ausverkauft

7

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

  • calloc()Wenn ein Speicherbereich zugewiesen wird, ist die Länge das Produkt seiner Parameter. callocfüllt den Speicher mit NULL und gibt einen Zeiger auf das erste Byte zurück. Wenn nicht genügend Speicherplatz gefunden wird, wird ein NULLZeiger zurückgegeben.

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

  • malloc()ordnet einen einzelnen Speicherblock mit der Größe REQUSTED SIZE zu und gibt einen Zeiger auf das erste Byte zurück. Wenn die erforderliche Speichermenge nicht gefunden werden kann, wird ein Nullzeiger zurückgegeben.

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


6

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

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

6

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

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 Müllwerten. calloc()ordnet andererseits einen Speicherblock zu und initialisiert ihn mit Nullen, und das Lesen des Inhalts dieses Blocks führt offensichtlich zu Nullen.

  • Syntax: malloc()Nimmt 1 Argument (die zuzuweisende Größe) und calloc()zwei Argumente (Anzahl der zuzuordnenden 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 Speicherzuordnungsfehler 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));

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

// 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 dies malloc()vorzugsweise verwendet wird, calloc()da es schneller ist. Wenn die Werte auf Null initialisiert werden sollen, verwenden Sie calloc()stattdessen.


5

Ein noch nicht erwähnter Unterschied: Größenbeschränkung

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

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

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

Stellen Sie sich einen Typ von 512 Bytes vor, der aufgerufen wird, disk_sectorund Code möchte viele Sektoren verwenden. Hier kann Code nur bis zu SIZE_MAX/sizeof disk_sectorSektoren 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 ein solches System eine so große Zuordnung liefern kann, ist eine andere Sache. Die meisten heute werden nicht. Es ist jedoch seit vielen Jahren aufgetreten, als SIZE_MAXes 65535 war. Angesichts des Gesetzes von Moore besteht der Verdacht, dass dies um 2030 bei bestimmten Speichermodellen mit SIZE_MAX == 4294967295und Speicherpools in 100 GByte auftreten wird.


2
Im Allgemeinen kann size_t die Größe der größten Art von Objekt halten, die ein Programm verarbeiten kann. Es ist unwahrscheinlich, dass ein System, bei dem size_t 32 Bit beträgt, eine Zuordnung von mehr als 4294967295 Byte verarbeiten kann, und ein System, das Zuweisungen dieser Größe verarbeiten kann, würde mit ziemlicher Sicherheit size_tgrößer als 32 Bit sein. Die Frage ist nur, ob die Verwendung callocmit Werten, deren Produkt überschreitet SIZE_MAX, zu Null führen kann, anstatt einen Zeiger auf eine kleinere Zuordnung zurückzugeben.
Supercat

Stimmen Sie Ihrer Verallgemeinerung zu , aber die C-Spezifikation erlaubt calloc()Zuordnungen, die überschritten werden SIZE_MAX. Es ist in der Vergangenheit mit 16-Bit size_tpassiert, und da sich der Speicher weiter verbilligt, sehe ich keinen Grund, warum dies in Zukunft nicht passieren kann, auch wenn es nicht üblich ist .
Chux - Wiedereinsetzung Monica

1
Der C-Standard ermöglicht es dem Code, eine Zuordnung anzufordern, deren Größe größer ist SIZE_MAX. Es ist sicherlich nicht erforderlich, dass es einen Umstand gibt, unter dem eine solche Zuweisung erfolgreich sein könnte. Ich bin mir nicht sicher, ob es einen besonderen Vorteil hat, wenn Implementierungen, die solche Zuweisungen nicht verarbeiten können, zurückgegeben werden müssen NULL(insbesondere angesichts der Tatsache, dass einige Implementierungen häufig mallocRückgabezeiger auf Speicherplatz haben, der noch nicht festgeschrieben ist und möglicherweise nicht verfügbar ist, wenn Code tatsächlich versucht, ihn zu verwenden es).
Supercat

Wenn es in der Vergangenheit Systeme gegeben hat, deren verfügbarer Adressierungsbereich die größte darstellbare Ganzzahl überschritten hat, sehe ich keine realistische Möglichkeit, dass dies jemals wieder auftritt, da dies eine Speicherkapazität von Milliarden Gigabyte erfordern würde. Selbst wenn Moores Gesetz weiterhin gelten würde, würde es doppelt so lange dauern, von dem Punkt, an dem 32 Bit nicht mehr ausreichen, von dem Punkt, an dem 64 Bit nicht mehr ausreichen, zu dem Punkt zu gelangen, an dem 32 Bit nicht mehr ausreichen 't.
Supercat

1
Warum sollte eine Implementierung , die eine einzige Zuweisung von mehr als 4G aufnehmen kann nicht definieren size_tzu uint64_t?
Supercat

2

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:
malloc () ist schnell.
calloc () ist langsamer als malloc ().

Argumente & Syntax:
malloc () akzeptiert 1 Argument:

  1. Bytes

    • Die Anzahl der zuzuweisenden Bytes

calloc () akzeptiert 2 Argumente:

  1. Länge

    • die Anzahl der zuzuweisenden Speicherblöcke
  2. Bytes
    • die Anzahl der Bytes, die in jedem Speicherblock zugewiesen werden sollen
void *malloc(size_t bytes);         
void *calloc(size_t length, size_t bytes);      

Art der Speicherzuordnung:
Die Malloc-Funktion weist dem verfügbaren Heap Speicher der gewünschten 'Größe' zu.
Die Calloc-Funktion weist einen Speicher zu, der der Größe von 'num * size' entspricht.

Bedeutung auf Name:
Der Name Malloc bedeutet "Speicherzuordnung".
Der Name calloc bedeutet "zusammenhängende Zuordnung".

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.