Verschil tussen malloc en calloc?

Wat is het verschil tussen doen:

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

of:

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

Wanneer is het een goed idee om calloc te gebruiken in plaats van malloc of omgekeerd?


Antwoord 1, autoriteit 100%

calloc()geeft je een op nul geïnitialiseerde buffer, terwijl malloc()het geheugen niet-geïnitialiseerd laat.

Voor grote toewijzingen zullen de meeste calloc-implementaties onder reguliere besturingssystemen pagina’s met een bekende nulwaarde van het besturingssysteem krijgen (bijv. via POSIX mmap(MAP_ANONYMOUS)of Windows VirtualAlloc) dus het hoeft ze niet in de gebruikersruimte te schrijven. Dit is hoe normaal mallocook meer pagina’s van het besturingssysteem krijgt; callocmaakt gewoon gebruik van de garantie van het besturingssysteem.

Dit betekent dat het calloc-geheugen nog steeds “schoon” en lui kan worden toegewezen, en copy-on-write kan worden toegewezen aan een systeembrede gedeelde fysieke pagina met nullen. (Uitgaande van een systeem met virtueel geheugen.)

Sommige compilers kunnen zelfs malloc + memset(0) voor u optimaliseren in calloc, maar u moet calloc expliciet gebruiken als u wilt dat het geheugen wordt gelezen als 0.

Als je het geheugen nooit gaat lezen voordat je het schrijft, gebruik dan malloczodat het je (mogelijk) vies geheugen kan geven van de interne vrije lijst in plaats van nieuwe pagina’s van het besturingssysteem te krijgen. (Of in plaats van een geheugenblok op de vrije lijst op nul te zetten voor een kleine toewijzing).


Embedded Implementations of callockan het overlaten tot calloczelf naar nul geheugen als er geen besturingssysteem is, of het is geen fancy multi-user OS die ZEROS-pagina’s stoppen Informatie lekt tussen processen.

Op Embedded Linux, Malloc zou mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS), die alleen is ingeschakeld voor sommige ingesloten kernels omdat het onveilig is op een multi-user-systeem.


Antwoord 2, Autoriteit 41%

Een minder bekend verschil is dat in besturingssystemen met optimistische geheugentoewijzing, zoals Linux, de aanwijzer, teruggekeerd door mallocniet ondersteund door het echte geheugen totdat het programma het daadwerkelijk aanraakt.

callocRaak inderdaad het geheugen aan (het schrijft nullen erop) en daarom zul je zeker zijn dat het besturingssysteem de toewijzing met daadwerkelijke RAM (of swap) is. Dit is ook de reden waarom het langzamer is dan MALLOC (niet alleen heeft het te nullen, het besturingssysteem moet ook een geschikt geheugengebied vinden door andere processen te wekken)

Zie bijvoorbeeld deze zo vraag voor verdere discussie over het gedrag van MALLOC


Antwoord 3, Autoriteit 13%

Eén vaak over het hoofd gezien voordeel van callocis dat (conformante implementaties van) het u zal helpen u te beschermen tegen getaloverloopkwetsbaarheden. Vergelijk:

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);

De eerste kan resulteren in een kleine toewijzing en daaropvolgende bufferoverloop, als countgroter is dan SIZE_MAX/sizeof *bar. Dit laatste zal in dit geval automatisch mislukken, aangezien een dergelijk groot object niet kan worden gemaakt.

Natuurlijk moet je misschien uitkijken naar niet-conforme implementaties die de mogelijkheid van overflow gewoon negeren… Als dit een probleem is op platforms die je target, moet je toch een handmatige test voor overflow uitvoeren .


Antwoord 4, autoriteit 4%

De documentatie zorgt ervoor dat de calloceruitziet als malloc, wat het geheugen gewoon op nul initialiseert; dit is niet het belangrijkste verschil! Het idee van callocis om copy-on-write semantiek te abstraheren voor geheugentoewijzing. Wanneer u geheugen toewijst met calloc, wordt het allemaal toegewezen aan dezelfde fysieke pagina die is geïnitialiseerd op nul. Wanneer een van de pagina’s van het toegewezen geheugen wordt geschreven naar een fysieke pagina, wordt deze toegewezen. Dit wordt vaak gebruikt om ENORME hash-tabellen te maken, bijvoorbeeld omdat de delen van hash die leeg zijn niet worden ondersteund door extra geheugen (pagina’s); ze verwijzen graag naar de enkele nul-geïnitialiseerde pagina, die zelfs tussen processen kan worden gedeeld.

Elk schrijven naar virtueel adres wordt toegewezen aan een pagina, als die pagina de nulpagina is, wordt een andere fysieke pagina toegewezen, de nulpagina wordt daar gekopieerd en de besturingsstroom wordt teruggestuurd naar het clientproces. Dit werkt op dezelfde manier als aan het geheugen toegewezen bestanden, virtueel geheugen, enz. het maakt gebruik van paging.

Hier is een optimalisatieverhaal over het onderwerp:
http://blogs .fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/


Antwoord 5, autoriteit 3%

Er is geen verschil in de grootte van het toegewezen geheugenblok. callocvult het geheugenblok gewoon met een fysiek all-zero-bits patroon. In de praktijk wordt vaak aangenomen dat de objecten die zich in het geheugenblok bevinden dat is toegewezen met calloceen beginwaarde hebben alsof ze zijn geïnitialiseerd met letterlijke 0, dwz gehele getallen moeten de waarde 0, drijvende-kommavariabelen – waarde van 0.0, pointers – de juiste null-pointerwaarde, enzovoort.

Vanuit een pedant oogpunt echter, is het alleen gegarandeerd dat calloc(evenals memset(..., 0, ...)) correct wordt geïnitialiseerd ( met nullen) objecten van het type unsigned char. Al het andere is niet gegarandeerd correct geïnitialiseerd en kan de zogenaamde trap-representatiebevatten, die ongedefinieerd gedrag veroorzaakt. Met andere woorden, voor elk ander type dan unsigned charkan het bovengenoemde all-zero-bits-patroon een illegale waarde vertegenwoordigen, de trap-representatie.

Later, in een van de technische correcties op de C99-standaard, werd het gedrag gedefinieerd voor alle typen integers (wat logisch is). D.w.z. formeel kun je in de huidige C-taal alleen integer-typen initialiseren met calloc(en memset(..., 0, ...)). Als je het gebruikt om iets anders te initialiseren, leidt dit in het algemeen tot ongedefinieerd gedrag, vanuit het oogpunt van C-taal.

In de praktijk werkt calloc, zoals we allemaal weten :), maar of je het wilt gebruiken (gezien het bovenstaande) is aan jou. Persoonlijk vermijd ik het liever volledig, gebruik in plaats daarvan mallocen voer mijn eigen initialisatie uit.

Ten slotte is een ander belangrijk detail dat callocnodig is om de uiteindelijke blokgrootte internte berekenen door de elementgrootte te vermenigvuldigen met het aantal elementen. Terwijl hij dat doet, moet callocletten op mogelijke rekenkundige overloop. Het zal resulteren in een mislukte toewijzing (null pointer) als de gevraagde blokgrootte niet correct kan worden berekend. Ondertussen doet uw malloc-versie geen poging om te kijken naar overflow. Het zal een “onvoorspelbare” hoeveelheid geheugen toewijzen voor het geval er een overloop optreedt.


Antwoord 6, autoriteit 2%

uit een artikel Benchmarkingplezier met calloc( ) en nul pagina’sop Georg Hager’s Blog

Bij het toewijzen van geheugen met calloc(), wordt de gevraagde hoeveelheid geheugen niet meteen toegewezen. In plaats daarvan zijn alle pagina’s die tot het geheugenblok behoren, door een of andere MMU-magie verbonden met een enkele pagina die allemaal nullen bevat (links hieronder). Als dergelijke pagina’s alleen worden gelezen (wat gold voor arrays b, c en d in de originele versie van de benchmark), worden de gegevens geleverd vanaf de enkele nulpagina, die – natuurlijk – in de cache past. Tot zover de geheugengebonden loop-kernels. Als er naar een pagina wordt geschreven (hoe dan ook), treedt er een fout op, wordt de “echte” pagina toegewezen en wordt de nulpagina naar het geheugen gekopieerd. Dit wordt copy-on-write genoemd, een bekende optimalisatiebenadering (die ik zelfs meerdere keren heb geleerd in mijn C++-colleges). Daarna werkt de zero-read-truc niet meer voor die pagina en daarom waren de prestaties zo veel lager na het invoegen van de – zogenaamd overbodige – init-lus.


Antwoord 7

callocis over het algemeen malloc+memsettot 0

Het is over het algemeen iets beter om malloc+memsetexpliciet te gebruiken, vooral als je zoiets doet als:

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

Dat is beter omdat sizeof(Item)bekend is bij de compiler tijdens het compileren en de compiler zal het in de meeste gevallen vervangen door de best mogelijke instructies om het geheugen op nul te zetten. Aan de andere kant, als memsetplaatsvindt in calloc, wordt de parametergrootte van de toewijzing niet gecompileerd in de calloc-code en echte memsetwordt vaak aangeroepen, wat normaal gesproken code zou bevatten om byte-by-byte te vullen tot een lange grens, dan cyclus om het geheugen te vullen in sizeof(long)chunks en tenslotte byte -by-byte vullen van de resterende ruimte. Zelfs als de allocator slim genoeg is om een aligned_memsetaan te roepen, zal het nog steeds een generieke lus zijn.

Een opmerkelijke uitzondering zou zijn wanneer je malloc/calloc van een zeer groot stuk geheugen (sommige power_of_twee kilobytes) doet, in welk geval de toewijzing rechtstreeks vanuit de kernel kan worden gedaan. Omdat OS-kernels doorgaans al het geheugen dat ze om veiligheidsredenen weggeven, op nul zetten, kan slim genoeg calloc het gewoon teruggeven zonder extra nulstelling. Nogmaals – als je alleen iets toewijst waarvan je weet dat het klein is, ben je misschien beter af met malloc+memset qua prestaties.


Antwoord 8

Er zijn twee verschillen.
Ten eerste zit het in het aantal argumenten. malloc()heeft één argument nodig (geheugen vereist in bytes), terwijl calloc()twee argumenten nodig heeft.
Ten tweede initialiseert malloc()het toegewezen geheugen niet, terwijl calloc()het toegewezen geheugen initialiseert naar NUL.

  • calloc()wijst een geheugengebied toe, de lengte is het product van zijn parameters. callocvult het geheugen met NUL’s en geeft een pointer terug naar de eerste byte. Als het niet genoeg ruimte kan vinden, retourneert het een NULLpointer.

Syntaxis: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
bijv. ptr_var=(type *)calloc(n,s);

  • malloc()wijst een enkel geheugenblok van REQUESTED SIZE toe en retourneert een pointer naar de eerste byte. Als het de gevraagde hoeveelheid geheugen niet kan vinden, retourneert het een null-pointer.

Syntaxis: ptr_var=(cast_type *)malloc(Size_in_bytes);
De functie malloc()heeft één argument, namelijk het aantal toe te wijzen bytes, terwijl de functie calloc()twee argumenten nodig heeft, waarvan één het aantal elementen is, en de andere is het aantal bytes dat voor elk van die elementen moet worden toegewezen. Bovendien initialiseert calloc()de toegewezen ruimte op nullen, terwijl malloc()dat niet doet.


Antwoord 9

Verschil 1:

malloc()wijst gewoonlijk het geheugenblok toe en het is een geïnitialiseerd geheugensegment.

calloc()wijst het geheugenblok toe en initialiseert het hele geheugenblok op 0.

Verschil 2:

Als je de syntaxis malloc()overweegt, is er maar 1 argument nodig. Beschouw het volgende voorbeeld hieronder:

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

Bijvoorbeeld: als u 10 blokken geheugen wilt toewijzen aan het type int,

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

Als u de syntaxis calloc()overweegt, zijn er 2 argumenten nodig. Beschouw het volgende voorbeeld hieronder:

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

Bijvoorbeeld: als u 10 blokken geheugen wilt toewijzen aan het type int en dat alles op ZERO wilt initialiseren,

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

Overeenkomst:

Zowel malloc()als calloc()retourneren standaard void* als ze niet van het type casted zijn.!


Antwoord 10

malloc()en calloc()zijn functies uit de C-standaardbibliotheek die dynamische geheugentoewijzing mogelijk maken, wat betekent dat ze beide geheugentoewijzing tijdens runtime toestaan.

Hun prototypes zijn als volgt:

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

Er zijn hoofdzakelijk twee verschillen tussen de twee:

  • Gedrag: malloc()wijst een geheugenblok toe, zonder het te initialiseren, en het lezen van de inhoud van dit blok zal resulteren in afvalwaarden. calloc()daarentegen wijst een geheugenblok toe en initialiseert het naar nullen, en het lezen van de inhoud van dit blok resulteert uiteraard in nullen.

  • Syntaxis: malloc()heeft 1 argument nodig (de grootte die moet worden toegewezen), en calloc()heeft twee argumenten nodig (aantal toe te wijzen blokken en grootte van elk blok).

De geretourneerde waarde van beide is een verwijzing naar het toegewezen geheugenblok, indien succesvol. Anders wordt NULLgeretourneerd, wat aangeeft dat de geheugentoewijzing is mislukt.

Voorbeeld:

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));

Dezelfde functionaliteit als calloc()kan worden bereikt met malloc()en 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)); 

Merk op dat malloc()bij voorkeur wordt gebruikt boven calloc()omdat het sneller is. Als het initialiseren van de waarden op nul moet worden ingesteld, gebruikt u in plaats daarvan calloc().


Antwoord 11

De functie calloc()die is gedeclareerd in de kop <stdlib.h>biedt een aantal voordelen ten opzichte van de malloc()functie.

  1. Het wijst geheugen toe als een aantal elementen van een bepaalde grootte, en
  2. Het initialiseert het geheugen dat is toegewezen, zodat alle bits zijn
    nul.

Antwoord 12

Aantal blokken:
malloc()wijst een enkel blok van het gevraagde geheugen toe,
calloc()wijst meerdere blokken van het gevraagde geheugen toe

Initialisatie:
malloc()– wist en initialiseert het toegewezen geheugen niet.
calloc()– initialiseert het toegewezen geheugen met nul.

Snelheid:
malloc()is snel.
calloc()is langzamer dan malloc().

Argumenten & Syntaxis:
malloc()heeft 1 argument:

  1. bytes

    • Het aantal toe te wijzen bytes

calloc()heeft 2 argumenten:

  1. lengte

    • het aantal geheugenblokken dat moet worden toegewezen
  2. bytes

    • het aantal bytes dat aan elk geheugenblok moet worden toegewezen
void *malloc(size_t bytes);         
void *calloc(size_t length, size_t bytes);      

Wijze van geheugentoewijzing:
De functie mallocwijst geheugen van de gewenste ‘grootte’ toe uit de beschikbare heap.
De functie callocwijst geheugen toe ter grootte van wat gelijk is aan ‘num *size’.

Betekenis van naam:
De naam mallocbetekent “geheugentoewijzing”.
De naam callocbetekent “aaneengesloten toewijzing”.


Antwoord 13

Een nog niet genoemd verschil: groottelimiet

void *malloc(size_t size)kan maximaal SIZE_MAXtoewijzen.

void *calloc(size_t nmemb, size_t size);kan ongeveer SIZE_MAX*SIZE_MAXtoewijzen.

Deze mogelijkheid wordt niet vaak gebruikt in veel platforms met lineaire adressering. Dergelijke systemen beperken calloc()met nmemb * size <= SIZE_MAX.

Beschouw een type van 512 bytes genaamd disk_sectoren code wil veelsectoren gebruiken. Hier kan code maximaal SIZE_MAX/sizeof disk_sectorsectoren gebruiken.

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

Overweeg het volgende dat een nog grotere toewijzing mogelijk maakt.

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

Als zo’n systeem nu zo’n grote toewijzing kan leveren, is een andere zaak. De meeste vandaag niet. Toch is het al vele jaren het geval toen SIZE_MAX65535 was. Gezien de wet van Moore, vermoed dat dit zal gebeuren rond 2030 met bepaalde geheugenmodellen met SIZE_MAX == 4294967295en geheugenpools in de 100 GBytes.


Antwoord 14

Zowel mallocals callocwijzen geheugen toe, maar callocinitialiseert alle bits op nul, terwijl mallocdat niet doet t.

Calloc zou equivalent kunnen zijn aan malloc + memsetmet 0 (waarbij memset de gespecificeerde geheugenbits op nul zet).

Dus als initialisatie naar nul niet nodig is, kan het gebruik van malloc sneller zijn.

Other episodes