C Programmering

malloc på c sprog

malloc på c sprog
Du kan komme her af to grunde: enten vil du dynamisk tildele indhold, eller du vil vide mere om, hvordan malloc fungerer. I begge tilfælde er du på det rigtige sted! Dynamisk allokering er en proces, der sker meget, men generelt bruger vi det ikke selv: langt de fleste programmeringssprog styrer hukommelsen for dig, da det er et hårdt job, og hvis du ikke gør det ordentligt, er der sikkerhedsimplikationer.

Men hvis du laver C, C ++ eller samlingskode, eller hvis du implementerer et nyt eksternt modul på dit foretrukne programmeringssprog, skal du selv administrere din dynamiske hukommelsesallokering.

Hvad er dynamisk fordeling? Hvorfor har jeg brug for malloc?

Nå, i alle applikationer, når du opretter en ny variabel - det kaldes ofte at erklære en variabel - du har brug for hukommelse for at gemme det. Da din computer er i de moderne dage, kan den køre mere end en applikation ad gangen, og så skal hver applikation fortælle dit operativsystem (her Linux) at den har brug for den mængde hukommelse. Når du skriver denne type kode:

#omfatte
#omfatte
#definer DISK_SPACE_ARRAY_LENGTH 7
ugyldigt getFreeDiskSpace (int statsList [], size_t listLength)
Vend tilbage;

int main ()
/ * Indeholder ledig diskplads de sidste 7 dage. * /
int freeDiskSpace [DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace (freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
returner EXIT_SUCCESS;

FreeDiskSpace-arrayet har brug for hukommelse, så du bliver nødt til at bede Linux om godkendelse for at få noget hukommelse. Da det imidlertid er indlysende, når du læser kildekoden, at du har brug for en matrix på 7 int, beder compileren automatisk Linux om det, og den tildeler den på stakken. Dette betyder grundlæggende, at dette lager bliver ødelagt, når du returnerer den funktion, hvor variablen er deklareret. Derfor kan du ikke gøre det:

#omfatte
#omfatte
#define DISK_SPACE_ARRAY_LENGTH 7
int * getFreeDiskSpace ()
int statsList [DISK_SPACE_ARRAY_LENGTH] = 0;
/ * HVORFOR Gør vi det?! statsList ødelægges! * /
return statsList;

int main ()
/ * Indeholder ledig diskplads de sidste 7 dage. * /
int * freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace ();
returner EXIT_SUCCESS;

Du ser lettere problemet nu? Derefter vil du sammenkæde to strenge. I Python og JavaScript ville du gøre:

newStr = str1 + str2

Men som du ved, i C fungerer det ikke sådan. Så for at oprette en URL for eksempel skal du sammenkæde to strenge, såsom URL-sti og domænenavn. I C har vi strcat, ikke, men det fungerer kun, hvis du har en matrix med plads nok til det.

Du vil blive fristet til at kende længden af ​​den nye streng ved at bruge strlen, og du ville have ret. Men hvordan skulle du så bede Linux om at reservere denne ukendte mængde hukommelse? Compiler kan ikke hjælpe dig: det nøjagtige rum, du vil tildele, er kun kendt under kørsel. Det er præcis, hvor du har brug for dynamisk tildeling og malloc.

At skrive min første C-funktion ved hjælp af malloc

Inden du skriver kode, en lille forklaring: malloc giver dig mulighed for at allokere et bestemt antal byte til din applikationsbrug. Det er virkelig nemt at bruge: du kalder malloc med det antal bytes, du har brug for, og det returnerer en markør til dit nye område, som Linux har reserveret til dig.

Du har kun 3 ansvarsområder:

  1. Kontroller, om malloc returnerer NULL. Det sker, når Linux ikke har nok hukommelse til at levere.
  2. Frigør dine variabler, når de først er ubrugte. Ellers spilder du hukommelse, og det sænker din applikation.
  3. Brug aldrig hukommelseszonen, når du har frigivet variablen.

Hvis du følger alle disse regler, vil alt gå godt, og dynamisk fordeling vil løse dig mange problemer. Fordi du vælger, hvornår du frigør hukommelsen, kan du også sikkert returnere en variabel, der er allokeret med malloc. Bare glem ikke at frigøre det!

Hvis du spekulerer på, hvordan du frigør en variabel, er det med den gratis funktion. Kald det med samme markør, end malloc returnerede dig, og hukommelsen frigøres.

Lad mig vise dig med konkateksemplet:

#omfatte
#omfatte
#omfatte
/ *
* Når du kalder på denne funktion, skal du ikke glemme at kontrollere, om returværdien er NULL
* Hvis det ikke er NULL, skal du ringe gratis til den returnerede markør, når værdien
* bruges ikke længere.
* /
char * getUrl (const char * const baseUrl, const char * const toolPath)
size_t finalUrlLen = 0;
char * finalUrl = NULL;
/ * Sikkerhedskontrol. * /
hvis (baseUrl == NULL || toolPath == NULL)
returnere NULL;

finalUrlLen = strlen (baseUrl) + strlen (toolPath);
/ * Glem ikke '\ 0', deraf + 1. * /
finalUrl = malloc (sizeof (char) * (finalUrlLen + 1));
/ * Efter malloc-regler ... * /
hvis (finalUrl == NULL)
returnere NULL;

strcpy (finalUrl, baseUrl);
strcat (finalUrl, toolPath);
return finalUrl;

int main ()
char * googleImages = NULL;
googleImages = getUrl ("https: // www.google.com "," / imghp ");
hvis (googleImages == NULL)
returner EXIT_FAILURE;

sætter ("Værktøjs-URL:");
sætter (googleImages);
/ * Det er ikke længere nødvendigt, frigør det. * /
gratis (googleImages);
googleImages = NULL;
returner EXIT_SUCCESS;

Så du ser et praktisk eksempel på brug af dynamiske allokeringer. Først undgår jeg faldgruber som at give getUrl returværdi lige til sætter-funktionen. Derefter tager jeg mig også tid til at kommentere og dokumentere, at returværdien skal frigøres ordentligt. Jeg kontrollerer også for NULL-værdier overalt, så alt uventet kan fanges sikkert i stedet for at gå ned på applikationen.

Endelig tager jeg ekstra forsigtighed med at frigøre variablen og derefter sætte markøren til NULL. Det undgår at blive fristet til at bruge - selv ved en fejltagelse - den nu frigjorte hukommelseszone. Men som du kan se, er det let at frigøre en variabel.

Du bemærker muligvis, at jeg brugte størrelse i malloc. Det giver mulighed for at vide, hvor mange byte en char bruger, og tydeliggør hensigten i koden, så den er mere læsbar. For char er sizeof (char) altid lig med 1, men hvis du bruger et array af int i stedet, fungerer det nøjagtigt på samme måde. For eksempel, hvis du har brug for at reservere 45 int, skal du bare gøre:

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

På denne måde kan du hurtigt se, hvor meget du vil allokere, derfor anbefaler jeg altid brugen.

Hvordan fungerer malloc under emhætten?

malloc og gratis er faktisk funktioner inkluderet i alle C-programmer, der vil tale med Linux på dine vegne. Det gør også dynamisk tildeling lettere, fordi Linux ikke giver dig mulighed for at allokere variabler i alle størrelser i starten.

Linux giver to måder at få mere hukommelse faktisk: sbrk og mmap. Begge har begrænsninger, og en af ​​dem er: du kan kun tildele relativt store beløb, såsom 4.096 bytes eller 8.192 bytes. Du kan ikke anmode om 50 byte som jeg gjorde i eksemplet, men du kan heller ikke anmode om 5.894 byte.

Dette har en forklaring: Linux skal holde en tabel, hvor den fortæller, hvilken applikation der har reserveret hvilken hukommelseszone. Og denne tabel bruger også plads, så hvis hver byte havde brug for en ny række i denne tabel, ville der være brug for en stor del af hukommelsen. Derfor er hukommelsen opdelt i store blokke på for eksempel 4.096 bytes, og meget som om du ikke kan købe 2 og en halv appelsin i en købmand, kan du ikke bede om halv blokke.

Så malloc tager disse store blokke og giver dig et lille stykke af disse hukommelsesblokke, når du kalder det. Hvis du også har frigjort få variabler, men ikke nok til at retfærdiggøre frigørelse af en hel blok, kan malloc-systemet muligvis beholde blokke og genbruge hukommelseszoner, når du ringer til malloc igen. Dette har fordelen ved at gøre malloc hurtigere, men hukommelse reserveret af malloc kan ikke bruges i nogen anden applikation, mens programmet i øjeblikket ikke bruger det i virkeligheden.

Men malloc er smart: hvis du ringer til malloc for at tildele 16 MiB eller et stort beløb, vil malloc sandsynligvis bede Linux om fulde blokke dedikeret kun til denne store variabel ved hjælp af mmap. På denne måde, når du ringer gratis, vil det mere sandsynligt undgå spild af plads. Bare rolig, malloc gør et bedre arbejde med genbrug end mennesker gør med vores affald!

Konklusion

Jeg tror nu, du bedre forstår, hvordan alt dette fungerer. Selvfølgelig er dynamisk fordeling et stort emne, og jeg tror, ​​vi kan skrive en komplet bog om emnet, men denne artikel skal gøre dig fortrolig med konceptet både generelt og med praktiske programmeringsråd.

Bedste spilkonsolemulatorer til Linux
Denne artikel viser en liste over populære spilkonsolemuleringssoftware, der er tilgængelig til Linux. Emulation er et softwarekompatibilitetslag, der...
Bedste Linux Distros til spil i 2021
Linux-operativsystemet er kommet langt fra dets originale, enkle, serverbaserede udseende. Dette operativsystem er forbedret enormt i de senere år og ...
Sådan registreres og streames din gaming-session på Linux
Tidligere blev spil kun betragtet som en hobby, men med tiden oplevede spilindustrien en enorm vækst med hensyn til teknologi og antallet af spillere....