C Programmeren

malloc in c taal

malloc in c taal
Je kunt hier om twee redenen komen: of je wilt dynamisch inhoud toewijzen, of je wilt meer weten over hoe malloc werkt. In beide gevallen ben je hier aan het juiste adres! Dynamische toewijzing is een proces dat veel voorkomt, maar over het algemeen gebruiken we het zelf niet: de overgrote meerderheid van de programmeertalen beheert het geheugen voor u omdat het een zware klus is en als u het niet goed doet, heeft dit gevolgen voor de veiligheid.

Als u echter C-, C++- of assemblagecode gebruikt, of als u een nieuwe externe module in uw favoriete programmeertaal implementeert, moet u uw dynamische geheugentoewijzing zelf beheren.

Wat is dynamische toewijzing?? Waarom ik malloc nodig heb?

Welnu, in alle toepassingen, wanneer u een nieuwe variabele maakt - het wordt vaak het declareren van een variabele genoemd - je hebt geheugen nodig om het op te slaan. Aangezien uw computer in de moderne tijd is, kan deze meer dan één applicatie tegelijk uitvoeren en daarom moet elke applicatie uw besturingssysteem vertellen (hier Linux) dat het die hoeveelheid geheugen nodig heeft. Wanneer u dit soort code schrijft:

#include
#include
#define DISK_SPACE_ARRAY_LENGTH 7
void getFreeDiskSpace(int statsList[], size_t listLength)
terugkeer;

int hoofd()
/* Bevat de vrije schijfruimte van de afgelopen 7 dagen. */
int freeDiskSpace[DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace(freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
retourneer EXIT_SUCCESS;

De freeDiskSpace-array heeft geheugen nodig, dus je moet Linux om goedkeuring vragen om wat geheugen te krijgen. Omdat het echter duidelijk is bij het lezen van de broncode dat je een array van 7 int nodig hebt, vraagt ​​de compiler er automatisch om Linux en het zal het op de stapel toewijzen. Dit betekent in feite dat deze opslag wordt vernietigd wanneer u de functie retourneert waarin de variabele is gedeclareerd. Dat is waarom je dat niet kunt doen:

#include
#include
#define DISK_SPACE_ARRAY_LENGTH 7
int* getFreeDiskSpace()
int statsList[DISK_SPACE_ARRAY_LENGTH] = 0;
/* WAAROM DOEN WE DAT?! statsList wordt VERNIETIGD! */
retourstatistiekenLijst;

int hoofd()
/* Bevat de vrije schijfruimte van de afgelopen 7 dagen. */
int *freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace();
retourneer EXIT_SUCCESS;

Je ziet nu gemakkelijker het probleem? Vervolgens wil je twee strings samenvoegen. In Python en JavaScript zou je het volgende doen:

newStr = str1 + str2

Maar zoals je weet werkt het in C niet zo. Dus om bijvoorbeeld een URL te bouwen, moet je twee strings samenvoegen, zoals het URL-pad en de domeinnaam. In C hebben we strcat, juist, maar het werkt alleen als je een array hebt met voldoende ruimte ervoor.

Je zult in de verleiding komen om de lengte van de nieuwe string te weten door strlen te gebruiken, en je zou gelijk hebben. Maar hoe zou je Linux dan vragen om deze onbekende hoeveelheid geheugen te reserveren?? Compiler kan je niet helpen: de exacte ruimte die je wilt toewijzen is alleen bekend tijdens runtime. Dat is precies waar je dynamische toewijzing nodig hebt, en malloc.

Mijn eerste C-functie schrijven met malloc

Voordat u code schrijft, een kleine uitleg: met malloc kunt u een specifiek aantal bytes toewijzen voor uw toepassingsgebruik. Het is heel eenvoudig te gebruiken: je roept malloc aan met het aantal bytes dat je nodig hebt, en het retourneert een verwijzing naar je nieuwe gebied dat Linux voor je heeft gereserveerd.

Je hebt slechts 3 verantwoordelijkheden:

  1. Controleer of malloc NULL retourneert. Dat gebeurt wanneer Linux niet genoeg geheugen heeft om te voorzien.
  2. Bevrijd uw variabelen als ze eenmaal niet gebruikt zijn. Anders verspil je geheugen en vertraagt ​​het je applicatie.
  3. Gebruik de geheugenzone nooit nadat u de variabele hebt vrijgemaakt.

Als je al deze regels volgt, zal alles goed gaan en zal dynamische toewijzing je veel problemen oplossen. Omdat u kiest wanneer u het geheugen vrijmaakt, kunt u ook veilig een variabele retourneren die is toegewezen met malloc. Vergeet het gewoon niet te bevrijden!

Als je je afvraagt ​​hoe je een variabele vrijmaakt, is dat met de gratis functie. Noem het met dezelfde aanwijzer dan dat malloc je terugbracht, en het geheugen is vrij.

Laat me je laten zien met het concat-voorbeeld:

#include
#include
#include
/*
* Vergeet bij het aanroepen van deze functie niet te controleren of de retourwaarde NULL is
* Als het niet NULL is, moet u gratis bellen op de geretourneerde aanwijzer zodra de waarde
* wordt niet meer gebruikt.
*/
char* getUrl(const char* const baseUrl, const char* const toolPath)
size_t finalUrlLen = 0;
char* finalUrl = NULL;
/* Veiligheidscontrole. */
if (baseUrl == NULL || toolPath == NULL)
retourneer NULL;

finalUrlLen = strlen(baseUrl) + strlen(toolPath);
/* Vergeet de '\0' niet, vandaar de + 1. */
finalUrl = malloc(sizeof(char) * (finalUrlLen + 1));
/* Volgens malloc-regels... */
if (finalUrl == NULL)
retourneer NULL;

strcpy(finalUrl, basisUrl);
strcat(finalUrl, toolPath);
eind-URL teruggeven;

int hoofd()
char* googleImages = NULL;
googleImages = getUrl("https://www.google.com", "/imghp");
if (googleImages == NULL)
retourneer EXIT_FAILURE;

puts("Tool-URL:");
zet(googleImages);
/* Het is niet langer nodig, gratis het. */
gratis (googleImages);
googleImages = NULL;
retourneer EXIT_SUCCESS;

U ziet dus een praktisch voorbeeld voor het gebruik van dynamische toewijzingen. Ten eerste vermijd ik valkuilen zoals het rechtstreeks geven van getUrl-retourwaarde aan puts-functie. Vervolgens neem ik ook de tijd om commentaar te geven en te documenteren dat de retourwaarde correct moet worden vrijgemaakt. Ik controleer ook overal op NULL-waarden, zodat iets onverwachts veilig kan worden opgevangen in plaats van de toepassing te laten crashen.

Ten slotte besteed ik extra zorg aan het vrijmaken van de variabele en stel ik de aanwijzer vervolgens in op NULL. Dat voorkomt dat u in de verleiding komt om - zelfs per ongeluk - de nu vrijgekomen geheugenzone te gebruiken. Maar zoals je kunt zien, is het gemakkelijk om een ​​variabele vrij te maken.

Het is je misschien opgevallen dat ik sizeof heb gebruikt in malloc. Het maakt het mogelijk om te weten hoeveel bytes een char gebruikt en verduidelijkt de bedoeling in de code, zodat het beter leesbaar is. Voor char is sizeof(char) altijd gelijk aan 1, maar als je in plaats daarvan een array van int gebruikt, werkt het precies op dezelfde manier. Als u bijvoorbeeld 45 int moet reserveren, doet u het volgende:

fileSizeList = malloc(sizeof(int) * 45);

Op deze manier zie je snel hoeveel je wilt toewijzen, daarom raad ik het gebruik ervan altijd aan.

Hoe werkt malloc onder de motorkap?

malloc en free zijn in feite functies die zijn opgenomen in alle C-programma's die namens jou met Linux zullen praten. Het maakt dynamische toewijzing ook gemakkelijker, omdat Linux je in het begin niet toestaat variabelen van elke grootte toe te wijzen.

Linux biedt eigenlijk twee manieren om meer geheugen te krijgen: sbrk en mmap. Beide hebben beperkingen, en een daarvan is: je kunt alleen relatief grote hoeveelheden toewijzen, zoals 4.096 bytes of 8.192 bytes. Je kunt geen 50 bytes aanvragen zoals ik deed in het voorbeeld, maar je kunt ook geen 5.894 bytes aanvragen.

Dit heeft een verklaring: Linux moet een tabel bijhouden waarin staat welke applicatie welke geheugenzone heeft gereserveerd. En deze tabel gebruikt ook ruimte, dus als elke byte een nieuwe rij in deze tabel nodig zou hebben, zou een groot deel van het geheugen nodig zijn. Daarom wordt het geheugen opgesplitst in grote blokken van bijvoorbeeld 4.096 bytes, en net zoals je geen 2 sinaasappels en een half in een supermarkt kunt kopen, kun je niet om halve blokken vragen.

Dus malloc neemt deze grote blokken en geeft je een klein stukje van deze geheugenblokken wanneer je het noemt. En als je weinig variabelen hebt vrijgemaakt, maar niet genoeg om het vrijmaken van een heel blok te rechtvaardigen, kan het malloc-systeem blokken behouden en geheugenzones recyclen wanneer je malloc opnieuw aanroept. Dit heeft het voordeel dat malloc sneller wordt, maar geheugen dat door malloc is gereserveerd, kan niet in een andere toepassing worden gebruikt, terwijl het programma het momenteel in werkelijkheid niet gebruikt.

Maar malloc is slim: als je malloc belt om 16 MiB of een groot bedrag toe te wijzen, zal malloc waarschijnlijk Linux vragen om volledige blokken speciaal voor deze grote variabele met behulp van mmap. Op deze manier, als u gratis belt, vermijdt u waarschijnlijk die verspilling van ruimte. Maak je geen zorgen, malloc doet het veel beter met recyclen dan mensen met ons afval!

Conclusie

Ik denk dat je nu beter begrijpt hoe dat allemaal werkt. Natuurlijk is dynamische toewijzing een groot onderwerp en ik denk dat we een volledig boek over het onderwerp kunnen schrijven, maar dit artikel zou u vertrouwd moeten maken met het concept, zowel in het algemeen als met praktische programmeeradviezen.

OSD-overlay tonen in Linux-apps en -games op volledig scherm
Het spelen van games op volledig scherm of het gebruik van apps in de modus volledig scherm zonder afleiding kan u afsnijden van relevante systeeminfo...
Top 5 Game Capture-kaarten
We hebben allemaal gezien en genoten van streaming gameplays op YouTube. PewDiePie, Jakesepticye en Markiplier zijn slechts enkele van de beste gamers...
Hoe een spel op Linux te ontwikkelen
Tien jaar geleden zouden niet veel Linux-gebruikers voorspellen dat hun favoriete besturingssysteem ooit een populair spelplatform voor commerciële vi...