C Programiranje

malloc v jeziku c

malloc v jeziku c
Sem lahko pridete iz dveh razlogov: ali želite dinamično dodeliti vsebino ali pa želite izvedeti več o tem, kako deluje malloc. V obeh primerih ste na pravem mestu! Dinamično dodeljevanje je postopek, ki se zgodi veliko, vendar ga na splošno ne uporabljamo sami: velika večina programskih jezikov upravlja s pomnilnikom, saj je to težko delo in če tega ne storite pravilno, obstajajo varnostne posledice.

Če uporabljate C, C ++ ali montažno kodo ali če v svojem najljubšem programskem jeziku implementirate nov zunanji modul, boste morali dinamično dodelitev pomnilnika upravljati sami.

Kaj je dinamično dodeljevanje? Zakaj rabim malloc?

No, v vseh aplikacijah, ko ustvarite novo spremenljivko - pogosto se imenuje razglasitev spremenljivke - za shranjevanje potrebujete pomnilnik. Ker je vaš računalnik v današnjem času, lahko hkrati zažene več aplikacij, zato mora vsaka aplikacija sporočiti vašemu OS (tukaj Linux) da potrebuje toliko pomnilnika. Ko pišete tovrstno kodo:

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

int main ()
/ * Vsebuje prosti prostor na disku v zadnjih 7 dneh. * /
int freeDiskSpace [DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace (freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
vrni EXIT_SUCCESS;

Polje freeDiskSpace potrebuje pomnilnik, zato boste morali Linux prositi za odobritev, da dobite nekaj pomnilnika. Ker pa je pri branju izvorne kode očitno, da boste potrebovali polje 7 int, ga prevajalnik samodejno prosi za Linux in ga bo dodal v sklad. To v bistvu pomeni, da se ta pomnilnik uniči, ko vrnete funkcijo, kjer je spremenljivka deklarirana. Zato tega ne morete storiti:

#include
#include
#define DISK_SPACE_ARRAY_LENGTH 7
int * getFreeDiskSpace ()
int statsList [DISK_SPACE_ARRAY_LENGTH] = 0;
/ * ZAKAJ TO DELIMO?! statsList bo UNIŠČEN! * /
return statsList;

int main ()
/ * Vsebuje prosti prostor na disku v zadnjih 7 dneh. * /
int * freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace ();
vrni EXIT_SUCCESS;

Zdaj težavo vidite lažje? Nato želite združiti dva niza. V Pythonu in JavaScript bi naredili:

newStr = str1 + str2

A kot veste, v C ne deluje tako. Če želite na primer zgraditi URL, morate združiti dva niza, na primer pot URL-ja in ime domene. V C smo strcat, kajne, vendar deluje le, če imate matriko z dovolj prostora za to.

Skušali boste vedeti dolžino novega niza z uporabo strlena in imeli bi prav. Toda kako bi potem zahtevali, da Linux rezervira to neznano količino pomnilnika? Prevajalnik vam ne more pomagati: natančen prostor, ki ga želite dodeliti, je znan samo med izvajanjem. To je točno tam, kjer potrebujete dinamično dodelitev in malloc.

Pisanje moje prve funkcije C z malloc

Pred pisanjem kode, malo razlage: malloc vam omogoča, da dodelite določeno število bajtov za uporabo vaše aplikacije. Zares je preprost za uporabo: pokličete malloc s številom bajtov, ki ga potrebujete, in vrne kazalec na vaše novo območje, ki ga je Linux rezerviral za vas.

Imate samo 3 odgovornosti:

  1. Preverite, ali malloc vrne NULL. To se zgodi, ko Linux nima dovolj pomnilnika.
  2. Osvobodite spremenljivke, ko jih ne boste uporabili. V nasprotnem primeru boste izgubili spomin in to bo upočasnilo vašo aplikacijo.
  3. Nikoli ne uporabljajte pomnilniškega območja, potem ko ste sprostili spremenljivko.

Če upoštevate vsa ta pravila, bo šlo vse v redu in dinamična dodelitev vam bo rešila številne težave. Ker sami izberete, ko osvobodite pomnilnik, lahko tudi varno vrnete spremenljivko, dodeljeno z malloc. Samo, ne pozabite ga osvoboditi!

Če se sprašujete, kako osvoboditi spremenljivko, je to s funkcijo free. Pokličite ga z istim kazalcem, kot vam ga je vrnil malloc, in pomnilnik se sprosti.

Naj vam pokažem primer concat:

#include
#include
#include
/ *
* Ko kličete to funkcijo, ne pozabite preveriti, ali je vrnjena vrednost NULL
* Če ni NULL, morate pri vrnjenem kazalcu enkrat poklicati free
* se ne uporablja več.
* /
char * getUrl (const char * const baseUrl, const char * const toolPath)
size_t finalUrlLen = 0;
char * finalUrl = NULL;
/ * Varnostni pregled. * /
if (baseUrl == NULL || toolPath == NULL)
vrni NULL;

finalUrlLen = strlen (baseUrl) + strlen (toolPath);
/ * Ne pozabite na '\ 0', torej + 1. * /
finalUrl = malloc (sizeof (char) * (finalUrlLen + 1));
/ * Po pravilih malloc… * /
če (finalUrl == NULL)
vrni NULL;

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

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

postavlja ("URL orodja:");
postavlja (googleImages);
/ * Ni več potrebno, osvobodite ga. * /
brezplačno (googleImages);
googleImages = NULL;
vrni EXIT_SUCCESS;

Torej vidite praktičen primer uporabe dinamičnih dodelitev. Najprej se izognem pastem, kot je dajanje vrnjene vrednosti getUrl naravnost v funkcijo put. Nato si vzamem čas tudi za komentar in dokumentiram dejstvo, da je treba vrnjeno vrednost pravilno sprostiti. Povsod preverjam tudi vrednosti NULL, tako da lahko vse nepričakovane varno ujamemo, namesto da zrušimo aplikacijo.

Na koncu še dodatno poskrbim za sprostitev spremenljivke in nato nastavitev kazalca na NULL. S tem se izognete skušnjavi - tudi po pomoti - zdaj osvobojenega spominskega območja. A kot vidite, je enostavno spremenljivko sprostiti.

Morda boste opazili, da sem v mallocu uporabil sizeof. Omogoča vedeti, koliko bajtov uporablja char, in pojasnjuje namen kode, tako da je bolj berljiva. Za char je sizeof (char) vedno enak 1, če pa namesto tega uporabite matriko int, deluje popolnoma enako. Če želite na primer rezervirati 45 int, samo naredite:

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

Na ta način hitro vidite, koliko želite dodeliti, zato vedno priporočam njegovo uporabo.

Kako deluje malloc pod pokrovom?

malloc in free sta pravzaprav funkciji, vključeni v vse programe C, ki se bodo v vašem imenu pogovarjali z Linuxom. Olajšala bo tudi dinamično dodeljevanje, ker Linux na začetku ne dovoljuje dodelitve spremenljivk vseh velikosti.

Linux dejansko ponuja dva načina za pridobitev več pomnilnika: sbrk in mmap. Oba imata omejitve, ena izmed njih pa je: dodeliš lahko le razmeroma velike količine, na primer 4.096 bajtov ali 8.192 bajtov. Ne morete zahtevati 50 bajtov, kot sem jaz v primeru, lahko pa tudi 5.894 bajtov.

To ima razlago: Linux mora voditi tabelo, kjer pove, katera aplikacija je rezervirala katero pomnilniško območje. In ta tabela uporablja tudi prostor, tako da če bi vsak bajt potreboval novo vrstico v tej tabeli, bi bil potreben velik delež pomnilnika. Zato je spomin razdeljen na velike bloke, na primer 4096 bajtov, in podobno, kot da v trgovini ne morete kupiti 2 pomaranč in pol, ne morete zahtevati pol blokov.

Malloc bo torej vzel te velike bloke in vam dal majhen del teh pomnilniških blokov, kadar koli ga pokličete. Če ste sprostili le nekaj spremenljivk, vendar ne dovolj, da bi upravičili sprostitev celotnega bloka, lahko sistem malloc ob ponovnem klicu malloca obdrži bloke in reciklira pomnilniške cone. To ima prednost, da malloc pospeši, vendar pomnilnika, ki ga rezervira malloc, ni mogoče uporabiti v nobeni drugi aplikaciji, medtem ko ga program v resnici trenutno ne uporablja.

Toda malloc je pameten: če pokličete malloc, da dodeli 16 MiB ali velik znesek, bo malloc z uporabo mmap verjetno vprašal Linux za celotne bloke, namenjene samo tej veliki spremenljivki. Tako se boste, če pokličete brezplačno, bolj verjetno izognili tej izgubi prostora. Ne skrbite, malloc pri recikliranju opravlja boljše delo kot ljudje pri naših smeteh!

Zaključek

Mislim, da zdaj bolje razumete, kako vse to deluje. Seveda je dinamična dodelitev velika tema in mislim, da lahko na to temo napišemo celo knjigo, toda ta članek bi vas moral osredotočiti na koncept tako na splošno kot tudi s praktičnimi nasveti za programiranje.

Namestite najnovejšo strategijo igre OpenRA v Ubuntu Linux
OpenRA je Libre / Free Real Time strateški stroj, ki poustvarja zgodnje igre Westwood, kot je klasična Command & Conquer: Red Alert. Porazdeljeni modi...
Namestite najnovejši Dolphin Emulator za Gamecube & Wii v Linux
Dolphin Emulator vam omogoča igranje izbranih iger Gamecube in Wii na osebnih računalnikih Linux (PC). Dolphin Emulator je prosto dostopen in odprtok...
Kako uporabljati GameConqueror Cheat Engine v Linuxu
Članek zajema vodnik o uporabi varalnice GameConqueror v Linuxu. Številni uporabniki, ki igrajo igre v sistemu Windows, pogosto uporabljajo aplikacijo...