C Programmering

malloc på c-språk

malloc på c-språk
Du kan komma hit av två skäl: antingen vill du dynamiskt tilldela innehåll, eller så vill du veta mer om hur malloc fungerar. I båda fallen är du på rätt plats! Dynamisk tilldelning är en process som händer mycket men i allmänhet använder vi den inte själva: de allra flesta programmeringsspråk hanterar minne åt dig eftersom det är ett svårt jobb och om du inte gör det ordentligt finns det säkerhetsmässiga konsekvenser.

Men om du gör C, C ++ eller monteringskod, eller om du implementerar en ny extern modul i ditt favoritprogrammeringsspråk, måste du hantera din dynamiska minnesallokering själv.

Vad är dynamisk fördelning? Varför jag behöver malloc?

Tja, i alla applikationer, när du skapar en ny variabel - det kallas ofta förklara en variabel - du behöver minne för att lagra det. Eftersom din dator är i modern tid kan den köra mer än ett program åt gången och så bör varje program berätta för ditt operativsystem (här Linux) att den behöver den mängden minne. När du skriver den här typen av kod:

#omfatta
#omfatta
#define DISK_SPACE_ARRAY_LENGTH 7
ogiltigt getFreeDiskSpace (int statsList [], size_t listLength)
lämna tillbaka;

int main ()
/ * Innehåller ledigt diskutrymme under de senaste sju dagarna. * /
int freeDiskSpace [DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace (freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
returnera EXIT_SUCCESS;

FreeDiskSpace-arrayen behöver minne så att du måste be Linux om godkännande för att få lite minne. Eftersom det är uppenbart när du läser källkoden att du behöver en array med 7 int, ber kompilatorn automatiskt Linux om det, och det kommer att fördela det på stacken. Detta innebär i princip att detta lagring förstörs när du returnerar funktionen där variabeln deklareras. Det är därför du inte kan göra det:

#omfatta
#omfatta
#define DISK_SPACE_ARRAY_LENGTH 7
int * getFreeDiskSpace ()
int statsList [DISK_SPACE_ARRAY_LENGTH] = 0;
/ * VARFÖR GÖR VI DET?! statsList förstörs! * /
return statsList;

int main ()
/ * Innehåller ledigt diskutrymme under de senaste sju dagarna. * /
int * freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace ();
returnera EXIT_SUCCESS;

Du ser lättare problemet nu? Sedan vill du sammanfoga två strängar. I Python och JavaScript skulle du göra:

newStr = str1 + str2

Men som ni vet fungerar det inte så här i C. Så för att skapa en URL till exempel måste du sammanfoga två strängar, till exempel URL-sökväg och domännamn. I C har vi strcat, eller hur, men det fungerar bara om du har en matris med tillräckligt med utrymme för det.

Du kommer att bli frestad att veta längden på den nya strängen genom att använda strlen, och du skulle ha rätt. Men hur skulle du då be Linux att reservera denna okända mängd minne? Kompilatorn kan inte hjälpa dig: det exakta utrymmet du vill tilldela är bara känt vid körning. Det är precis där du behöver dynamisk tilldelning och malloc.

Skriva min första C-funktion med malloc

Innan du skriver kod, en liten förklaring: malloc låter dig tilldela ett visst antal byte för din applikationsanvändning. Det är väldigt enkelt att använda: du ringer malloc med det antal byte du behöver, och det returnerar en pekare till ditt nya område som Linux har reserverat för dig.

Du har bara 3 ansvarsområden:

  1. Kontrollera om malloc returnerar NULL. Det händer när Linux inte har tillräckligt med minne för att tillhandahålla.
  2. Frigör dina variabler när de inte har använts. Annars slösar du minne och det saktar ner din applikation.
  3. Använd aldrig minneszonen efter att du har frigjort variabeln.

Om du följer alla dessa regler går allt bra och dynamisk fördelning kommer att lösa många problem. Eftersom du väljer när du frigör minnet kan du också säkert returnera en variabel som tilldelats med malloc. Glöm inte att frigöra det!

Om du undrar hur du frigör en variabel, är det med gratisfunktionen. Ring det med samma pekare än malloc gav dig tillbaka, och minnet frigörs.

Låt mig visa dig med concat-exemplet:

#omfatta
#omfatta
#omfatta
/ *
* Glöm inte att kontrollera om returvärdet är NUL när du ringer till den här funktionen
* Om det inte är NULL måste du ringa gratis på den returnerade pekaren en gång värdet
* används inte längre.
* /
char * getUrl (const char * const baseUrl, const char * const toolPath)
size_t finalUrlLen = 0;
char * finalUrl = NULL;
/ * Säkerhetskontroll. * /
if (baseUrl == NULL || toolPath == NULL)
returnera NULL;

finalUrlLen = strlen (baseUrl) + strlen (toolPath);
/ * Glöm inte '\ 0', därav + 1. * /
finalUrl = malloc (sizeof (char) * (finalUrlLen + 1));
/ * Följ malloc-regler ... * /
if (finalUrl == NULL)
returnera NULL;

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

int main ()
char * googleImages = NULL;
googleImages = getUrl ("https: // www.Google.com "," / imghp ");
if (googleImages == NULL)
returnera EXIT_FAILURE;

sätter ("Verktygs-URL:");
sätter (googleImages);
/ * Det behövs inte längre, frigör det. * /
gratis (googleImages);
googleImages = NULL;
returnera EXIT_SUCCESS;

Så du ser ett praktiskt exempel för att använda dynamiska tilldelningar. Först undviker jag fallgropar som att ge getUrl returvärde direkt till sätter funktionen. Sedan tar jag mig också tid att kommentera och dokumentera det faktum att returvärdet ska frigöras ordentligt. Jag söker också efter NULL-värden överallt så att allt oväntat kan fångas säkert istället för att krascha med applikationen.

Slutligen tar jag extra hand om att frigöra variabeln och sedan sätta pekaren till NULL. Det undviker att bli frestad att använda - även av misstag - den nu frigjorda minneszonen. Men som du kan se är det enkelt att frigöra en variabel.

Du kanske märker att jag använde sizeof i malloc. Det gör det möjligt att veta hur många byte en char använder och klargör avsikten i koden så att den är mer läsbar. För char är sizeof (char) alltid lika med 1, men om du använder en array med int istället fungerar det exakt på samma sätt. Om du till exempel behöver boka 45 int, gör bara:

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

På det här sättet ser du snabbt hur mycket du vill tilldela, det är därför jag alltid rekommenderar dess användning.

Hur fungerar malloc under huven?

malloc och gratis är faktiskt funktioner som ingår i alla C-program som kommer att prata med Linux för dina räkning. Det underlättar också dynamisk tilldelning eftersom Linux i början inte tillåter dig att allokera variabler i alla storlekar.

Linux ger två sätt att få mer minne i själva verket: sbrk och mmap. Båda har begränsningar, och en av dem är: du kan bara fördela relativt stora belopp, till exempel 4096 byte eller 8192 byte. Du kan inte begära 50 byte som jag gjorde i exemplet, men du kan inte heller begära 5894 byte.

Detta har en förklaring: Linux måste hålla en tabell där den berättar vilken applikation som har reserverat vilken minneszon. Och den här tabellen använder också utrymme, så om varje byte behövde en ny rad i den här tabellen, skulle en stor andel minne behövas. Det är därför minnet delas upp i stora block med till exempel 4096 byte, och ungefär som att du inte kan köpa två och en halv apelsiner i en livsmedelsbutik, du kan inte be om halvblock.

Så malloc tar dessa stora block och ger dig en liten bit av dessa minnesblock när du kallar det. Om du har frigjort få variabler, men inte tillräckligt för att motivera att frigöra ett helt block, kan malloc-systemet behålla block och återvinna minneszoner när du ringer till malloc igen. Detta har fördelen att göra malloc snabbare, men minne som reserverats av malloc kan inte användas i någon annan applikation, medan programmet för närvarande inte använder det i verkligheten.

Men malloc är smart: om du ringer malloc för att tilldela 16 MiB eller en stor summa kommer malloc förmodligen att be Linux om fullständiga block dedikerade bara för den här stora variabeln genom att använda mmap. På det här sättet, när du ringer gratis, kommer det mer sannolikt att undvika slöseri med utrymme. Oroa dig inte, malloc gör ett sätt bättre jobb på återvinning än människor gör med vårt sopor!

Slutsats

Jag tror nu att du förstår bättre hur allt detta fungerar. Naturligtvis är dynamisk fördelning ett stort ämne och jag tror att vi kan skriva en fullständig bok om ämnet, men den här artikeln borde göra dig bekväm med konceptet både i allmänhet och med praktiska programmeringsråd.

Shadow of the Tomb Raider for Linux Tutorial
Shadow of the Tomb Raider är det tolfte tillskottet till Tomb Raider-serien - en action-äventyrsspelfranchise skapad av Eidos Montreal. Spelet mottogs...
Hur man förbättrar FPS i Linux?
FPS står för Bildrutor per sekund. FPS: s uppgift är att mäta bildfrekvensen i videouppspelningar eller spelprestanda. Med enkla ord betecknas antalet...
De bästa Oculus App Lab-spelen
Om du är Oculus-headsetägare måste du vara förtjust i sidoladdning. Sideladdning är processen för att installera icke-butiksinnehåll på ditt headset. ...