C Programiranje

malloc na c jeziku

malloc na c jeziku
Ovdje možete doći iz dva razloga: ili želite dinamički dodijeliti sadržaj ili želite znati više o tome kako malloc radi. U oba slučaja, na pravom ste mjestu! Dinamična alokacija proces je koji se događa puno, ali uglavnom ga ne koristimo sami: velika većina programskih jezika upravlja memorijom umjesto vas, jer je to težak posao, a ako to ne napravite pravilno, postoje sigurnosne implikacije.

Međutim, ako radite C, C ++ ili kod za montažu ili ako implementirate novi vanjski modul u svoj omiljeni programski jezik, morat ćete sami upravljati dinamičkom dodjelom memorije.

Što je dinamičko dodjeljivanje? Zašto mi treba malloc?

Pa, u svim aplikacijama, kada kreirate novu varijablu - često se naziva proglašavanjem varijable - trebate memoriju da je pohranite. Kako je vaše računalo u moderno doba, istovremeno može pokretati više aplikacija, tako da bi svaka aplikacija trebala reći vašem OS-u (ovdje Linux) da mu treba ta količina memorije. Kada napišete ovu vrstu koda:

#include
#include
#define DISK_SPACE_ARRAY_LENGTH 7
poništi getFreeDiskSpace (int statsList [], size_t listLength)
povratak;

int main ()
/ * Sadrži slobodni prostor na disku u posljednjih 7 dana. * /
int freeDiskSpace [DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace (freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
povratak EXIT_SUCCESS;

Polju freeDiskSpace potrebna je memorija, pa ćete trebati pitati Linux za odobrenje da biste dobili malo memorije. Međutim, kako je očito prilikom čitanja izvornog koda da će vam trebati niz od 7 int, kompajler ga automatski traži Linux i dodijelit će ga na stog. To u osnovi znači da se ta pohrana uništava kada vratite funkciju u kojoj je varijabla deklarirana. Zato to ne možete učiniti:

#include
#include
#define DISK_SPACE_ARRAY_LENGTH 7
int * getFreeDiskSpace ()
int statsList [DISK_SPACE_ARRAY_LENGTH] = 0;
/ * ZAŠTO TO RADIMO?! statsList će se UNIŠTITI! * /
return statsList;

int main ()
/ * Sadrži slobodni prostor na disku u posljednjih 7 dana. * /
int * freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace ();
povratak EXIT_SUCCESS;

Sada lakše vidite problem? Zatim želite spojiti dva niza. U Pythonu i JavaScriptu trebali biste učiniti:

newStr = str1 + str2

Ali kao što znate, u C-u to ne ide ovako. Dakle, da biste, na primjer, izgradili URL, trebate spojiti dva niza, poput puta URL-a i imena domene. U C-u smo strcat, zar ne, ali to djeluje samo ako imate niz s dovoljno mjesta za to.

Doći ćete u iskušenje da saznate duljinu novog niza pomoću strlena i bili biste u pravu. Ali onda, kako biste tražili da Linux rezervira ovu nepoznatu količinu memorije? Prevoditelj vam ne može pomoći: točan prostor koji želite dodijeliti poznat je samo tijekom izvođenja. Upravo tu vam treba dinamička alokacija i malloc.

Pisanje moje prve C funkcije pomoću malloca

Prije pisanja koda, malo objašnjenje: malloc vam omogućuje da dodijelite određeni broj bajtova za upotrebu vaše aplikacije. Zaista je jednostavan za upotrebu: zovete malloc s brojem bajtova koji vam treba i vraća pokazivač na vaše novo područje koje je Linux rezervirao za vas.

Imate samo 3 odgovornosti:

  1. Provjerite vraća li malloc NULL. To se događa kada Linux nema dovoljno memorije za pružanje.
  2. Oslobodite varijable jednom neiskorištene. Inače ćete izgubiti memoriju i usporit će vašu aplikaciju.
  3. Nikada ne koristite memorijsku zonu nakon što ste oslobodili varijablu.

Ako se budete držali svih ovih pravila, sve će proći u redu, a dinamična dodjela riješit će vam mnoge probleme. Budući da vi odabirete kada oslobađate memoriju, također možete sigurno vratiti varijablu dodijeljenu s malloc-om. Samo, ne zaboravite ga osloboditi!

Ako se pitate kako osloboditi varijablu, to je s besplatnom funkcijom. Nazovite ga istim pokazivačem nego što vam je vratio malloc i memorija se oslobađa.

Dopustite mi da vam pokažem primjer concat:

#include
#include
#include
/ *
* Kada pozivate ovu funkciju, ne zaboravite provjeriti je li povratna vrijednost NULL
* Ako nije NULL, morate vratiti free na vraćenom pokazivaču jednom kad vrijednost
* više se ne koristi.
* /
char * getUrl (const char * const baseUrl, const char * const toolPath)
size_t finalUrlLen = 0;
char * finalUrl = NULL;
/ * Sigurnosna provjera. * /
if (baseUrl == NULL || toolPath == NULL)
povratak NULL;

finalUrlLen = strlen (baseUrl) + strlen (toolPath);
/ * Ne zaboravite na '\ 0', dakle + 1. * /
finalUrl = malloc (veličina (char) * (finalUrlLen + 1));
/ * Slijedeći malloc pravila ... * /
if (finalUrl == NULL)
povratak NULL;

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

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

stavlja ("URL alata:");
stavlja (googleImages);
/ * Više nije potrebno, oslobodite ga. * /
besplatno (googleImages);
googleImages = NULL;
povratak EXIT_SUCCESS;

Dakle, vidite praktični primjer korištenja dinamičkih alokacija. Prvo, izbjegavam zamke poput davanja povratne vrijednosti getUrl ravno u funkciju putova. Zatim, uzimam vremena da komentiram i dokumentiram činjenicu da bi povratna vrijednost trebala biti ispravno oslobođena. Također svugdje provjeravam jesu li vrijednosti NULL, tako da se sve neočekivano može sigurno uhvatiti umjesto da sruši aplikaciju.

Na kraju, vodim dodatnu brigu o oslobađanju varijable, a zatim postavljanju pokazivača na NULL. Time se izbjegava napasti koristiti - čak i pogreškom - sada oslobođenu memorijsku zonu. Ali kao što vidite, varijablu je lako osloboditi.

Možda ćete primijetiti da sam u mallocu koristio sizeof. Omogućuje znati koliko bajtova char koristi i pojašnjava namjeru u kodu kako bi bio čitljiviji. Za char je sizeof (char) uvijek jednak 1, ali ako umjesto toga koristite niz int, to funkcionira na potpuno isti način. Na primjer, ako trebate rezervirati 45 int, samo učinite:

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

Na ovaj način brzo vidite koliko želite dodijeliti, zato uvijek preporučujem njegovu upotrebu.

Kako djeluje malloc ispod haube?

malloc i free zapravo su funkcije uključene u sve C programe koji će u vaše ime razgovarati s Linuxom. Olakšat će i dinamičku dodjelu jer vam Linux na početku ne dopušta dodjelu varijabli svih veličina.

Linux zapravo nudi dva načina za dobivanje više memorije: sbrk i mmap. Oba imaju ograničenja, a jedno od njih je: možete dodijeliti samo relativno velike iznose, poput 4.096 bajta ili 8.192 bajta. Ne možete zatražiti 50 bajtova kao što sam to učinio u primjeru, ali također ne možete zahtijevati 5.894 bajta.

Ovo ima objašnjenje: Linux mora voditi tablicu u kojoj govori koja je aplikacija rezervirala koju memorijsku zonu. A i ova tablica koristi prostor, pa ako bi svaki bajt trebao novi redak u ovoj tablici, trebao bi biti velik udio memorije. Zbog toga se memorija dijeli na velike blokove od, na primjer, 4.096 bajtova, i slično kao što ne možete kupiti 2 naranče i pol u namirnici, ne možete tražiti pola blokova.

Dakle, malloc će uzeti ove velike blokove i dat će vam mali dio tih memorijskih blokova kad god ga nazovete. Isto tako, ako ste oslobodili nekoliko varijabli, ali nedovoljno da opravdate oslobađanje cijelog bloka, sustav malloc može zadržati blokove i reciklirati memorijske zone kad ponovno pozovete malloc. To ima prednost što brži malloc, međutim memorija koju rezervira malloc ne može se koristiti u bilo kojoj drugoj aplikaciji, dok je program trenutno ne koristi u stvarnosti.

Ali malloc je pametan: ako pozovete malloc da dodijeli 16 MiB ili veliku količinu, malloc će vjerojatno tražiti od Linuxa cjelovite blokove namijenjene samo ovoj velikoj varijabli pomoću mmap-a. Na ovaj će način, kada nazvate besplatnim, vjerojatnije izbjeći gubitak prostora. Ne brinite, malloc obavlja puno bolji posao u recikliranju nego što to ljudi rade s našim smećem!

Zaključak

Mislim da sada bolje razumiješ kako sve to funkcionira. Naravno, dinamička alokacija velika je tema i mislim da o njoj možemo napisati cjelovitu knjigu, ali ovaj bi vam članak trebao pružiti ugodu s konceptom općenito i sa praktičnim savjetima za programiranje.

Bitka za Wesnoth 1.13.6 Razvoj objavljen
Bitka za Wesnoth 1.13.6 objavljeno prošlog mjeseca, šesto je razvojno izdanje u izdanju 1.13.x series i donosi niz poboljšanja, ponajviše korisničkog ...
Kako instalirati League Of Legends na Ubuntu 14.04
Ako ste ljubitelj League of Legends, ovo je prilika za vas da testirate League of Legends. Imajte na umu da je LOL podržan na PlayOnLinux ako ste kori...
Instalirajte najnoviju strategiju igre OpenRA na Ubuntu Linux
OpenRA je Libre / Free Real Time strateški pokretač igre koji stvara rane Westwoodove igre poput klasične Command & Conquer: Red Alert. Distribuirani ...