Arrays. Geheugentoewijzing in C (malloc-functie) Dynamische geheugentoewijzing


#erbij betrekken void *malloc(size_t maat);

Beschrijving


Retourneert een pointer naar de eerste byte van het geheugengebied dat is toegewezen vanuit de heap


De functie malloc() retourneert een pointer naar de eerste byte van een geheugengebied met een groottegrootte dat is toegewezen vanuit de heap. Als er niet genoeg geheugen is om aan het verzoek te voldoen, wordt een null-pointer geretourneerd. Het is belangrijk om er altijd voor te zorgen dat de geretourneerde waarde geen nulaanwijzer is. Als u een nulaanwijzer probeert te gebruiken, resulteert dit meestal in een volledige systeemcrash.

Als u 16-bits programma's schrijft voor de 8086-processorfamilie (zoals de 80486 of Pentium), biedt uw compiler waarschijnlijk extra geheugentoewijzingsfuncties die rekening houden met het gesegmenteerde geheugenmodel dat door die processors wordt gebruikt wanneer ze in 16-bits modus draaien. . Dit kunnen bijvoorbeeld functies zijn die FAR-heapgeheugen toewijzen (dat zich buiten het standaardgegevenssegment bevindt). Deze functies kunnen verwijzingen toewijzen aan geheugen groter dan één segment en dergelijk geheugen vrijmaken.

leegte vrij(ongeldige *aanwijzer);

gebruikt om het geheugen vrij te maken waarnaar wordt verwezen door het pointer-argument. Eerst wordt geheugen toegewezen aan de applicatie, na voltooiing van het werk met geheugen moet het worden geretourneerd, en de vrije functie is verantwoordelijk voor deze terugkeer.

_mgrootte

De functie _msize retourneert de grootte van het geheugen dat is toegewezen vanuit de heap:

size_t_msize(ongeldig*);

argument is een verwijzing naar een geheugenblok. De functie _msize retourneert de geheugengrootte in bytes. size_t is een geheel getal zonder teken.

malloc

De malloc-functie wijst een geheugengebied van de heap toe (d.w.z. een vrij geheugengebied):

void* malloc(grootte_t);

het argument specificeert het aantal bytes dat uit het geheugen moet worden toegewezen. De malloc-functie retourneert een lege pointer naar het toegewezen geheugengebied; deze kan naar het gewenste type worden gegoten. Als er minder vrij geheugen is voor toewijzing dan gevraagd in size_t, retourneert de malloc-functie NULL.

Een voorbeeld van het werken met de malloc-functie:

/* Auteur: @author Subbotin B.P..h> #include #erbij betrekken int main(void) ( puts("Geheugen"); int *pointer; puts("om geheugen op te halen"); pointer = (int*)malloc(2 * sizeof(int)); int memorySize = _msize(pointer); printf("geheugengrootte = %dn", geheugengrootte); if(pointer == NULL) ( puts("Problemen"); return EXIT_FAILURE; ) free(pointer);

hier wordt geheugenruimte toegewezen voor een array bestaande uit twee elementen van het type int. Als de geheugentoewijzing succesvol is geweest, maken we dit geheugengebied vrij met behulp van de vrije functie.

Wij krijgen:

calloc

De calloc-functie wijst een geheugengebied toe en plaatst daarin een array, geïnitialiseerd met nullen:

void* calloc(grootte_t, grootte_t);

het eerste argument is het aantal elementen, en het tweede is de grootte in bytes van één element. Het product van de argumentwaarden geeft de grootte van het geheugengebied dat voor toewijzing wordt aangevraagd. De calloc-functie retourneert een lege pointer naar het toegewezen geheugengebied; deze kan naar het gewenste type worden gegoten. Als er minder vrij geheugen is voor toewijzing dan gevraagd, retourneert de calloc-functie NULL.

Een voorbeeld van het werken met de calloc-functie:

/* Auteur: @author Subbotin B.P..h> #include #erbij betrekken int main(void) ( puts("Geheugen"); int *pointer; puts("om geheugen op te halen"); pointer = (int*)calloc(2, sizeof(int)); int memorySize = _msize(pointer); printf("geheugengrootte = %dn", geheugengrootte); if(pointer == NULL) ( puts("Problemen"); return EXIT_FAILURE; ) free(pointer);

In het voorbeeld wordt geheugen toegewezen aan een array van het type int die twee elementen bevat. Deze elementen worden op nul geïnitialiseerd. Als de geheugentoewijzing succesvol is geweest, maken we dit geheugengebied vrij met behulp van de vrije functie.

Wij krijgen:

realloc

De realloc-functie verandert de grootte van een eerder toegewezen geheugengebied:

void* realloc(void*, size_t);

het eerste argument is een verwijzing naar het geheugengebied waarvan de grootte moet worden gewijzigd, het tweede argument specificeert de nieuwe grootte van het geheugengebied. Als deze grootte nul is en het eerste argument naar een bestaand geheugengebied verwijst, retourneert realloc NULL en wordt het oorspronkelijke geheugenblok waarnaar het eerste argument verwijst, vrijgegeven. Als er minder vrij geheugen is voor toewijzing dan gevraagd, retourneert de realloc-functie NULL, en zal het originele geheugenblok waarnaar wordt verwezen door het eerste argument behouden blijven en ongewijzigd blijven. De realloc-functie retourneert een lege pointer naar het toegewezen geheugengebied; deze kan naar het gewenste type worden gegoten.

Uw programma moet voldoende geheugen bieden om de gegevens die het gebruikt op te slaan. Sommige van deze geheugenlocaties worden automatisch toegewezen. We kunnen bijvoorbeeld declareren

char place = "Varkensleverbaai";

en er zal voldoende geheugen worden toegewezen om deze string te onthouden.

Of we kunnen specifieker zijn en een specifieke hoeveelheid geheugen aanvragen:

int-platen;

Deze beschrijving wijst 100 geheugenlocaties toe, die elk zijn ontworpen om een ​​geheel getal op te slaan.

De C-taal stopt daar niet. Hiermee kunt u extra geheugen toewijzen terwijl het programma actief is. Stel je bent bijvoorbeeld een conversatieprogramma aan het schrijven en je weet vooraf niet hoeveel gegevens je moet invoeren. U kunt de hoeveelheid geheugen toewijzen die u (zoals u denkt) nodig heeft, en indien nodig vervolgens meer geheugen aanvragen. In afb. 15.5 geeft een voorbeeld waarin de functie wordt gebruikt malloc() om precies dat te doen. Let ook op hoe zo'n programma pointers gebruikt.

/* voegt geheugen toe indien nodig */

#erbij betrekken

#define STOP " " /* signaal om invoer te stoppen */

#define BLOCK 100 /* geheugenbytes */

#define LIM 40 /* limietlengte van invoertekenreeks */

#define MAX 50 /* maximaal aantal invoerregels */

#define DRAMA 20000 /* lange vertraging */

char winkel; /* brongeheugenblok */

tekensymfonie; /* ingangsreeksontvanger */

char *einde; /* verwijst naar het einde van het geheugen */

teken *begint; /* verwijst naar het begin van regels */

int-index = 0; /* aantal in te voeren regels */

int-telling; /* balie */

char *malloc(); /* geheugentoewijzer */

begint = opslaan;

einde = begin + BLOK - 1;

puts("Noem verschillende symfonieorkesten.");

puts("Voer één voor één in: druk aan het begin op [enter]");

puts(" regels om je lijst compleet te maken. Oké, ik ben er klaar voor.");

while(strcmp(fgets(symph, LIM, stdin), STOP) != 0 && index< MAX)

( if(strlen(symph) > einde - begin)

( /* acties als er onvoldoende geheugen is om de ingevoerde gegevens te onthouden */

puts("Wacht even. Ik zal proberen wat extra geheugen te vinden.");

einde = begin + BLOK - 1;

voor(telling = 0; telling< DRAMA; count++);

puts("Er zijn er een paar gevonden!"); )

strcpy(begint, symph);

start = start + strlen(symph) + 1;

als(++index< MAX)

printf("Dit is %d. Ga verder als je wilt.n", index); )

puts("Oké, dit is wat ik heb:");

voor(telling = 0; telling< index; count ++)

zet(start);

RIJST. 15.5. Een programma dat geheugen op aanvraag toevoegt.

Hier is een voorbeeld van het programma:

Noem enkele symfonieorkesten.

Voer ze één voor één in; druk aan het begin op [enter].

lijnen om onze lijst compleet te maken. Oké, ik ben er klaar voor.

Symfonie van San Francisco.

Dit is 1. Ga verder als je wilt.

Chicago-symfonie

Dit is 2. Ga verder als je wilt.

Berliner Philharmoniker

Dit is 3. Ga verder als je wilt.

Kamer Moskou

Dit is 4. Ga verder als je wilt. Symfonie van Londen

Dit is een 5. Ga door als je wilt. Wiener Philharmoniker

Wacht even. Ik zal proberen extra geheugen te vinden.

Ik heb er een paar gevonden!

Dit is 6. Ga verder als je wilt.

Pittsburgh-symfonie

Dit is 7. Ga verder als je wilt.

Oké, dit is wat ik heb:

Symfonie van San Francisco

Chicago-symfonie

Berliner Philharmoniker

Kamer Moskou

Symfonie van Londen

Wiener Philharmoniker

Pittsburgh-symfonie

Laten we eerst eens kijken wat de functie doet malloc(). Er is een geheel getal zonder teken nodig dat het aantal vereiste bytes geheugen vertegenwoordigt. Dus, malloc(BLOK) vereist 100 bytes. De functie retourneert een verwijzing naar het type verkoold naar het begin van een nieuw geheugenblok. Wij hebben de beschrijving gebruikt

char *malloc();

om de compiler daarvoor te waarschuwen malloc() retourneert een verwijzing naar het type verkoold. Daarom hebben we de waarde van deze pointer aan het array-element toegewezen begint met behulp van de operator

begint = malloc(BLOK);

Oké, laten we nu eens kijken naar een programmaontwerp waarbij alle originele tekenreeksen op rij in een grote array worden opgeslagen winkel. Wij willen gebruiken begint om naar het begin van de eerste regel te verwijzen, begint[l]- de tweede regel, etc. In het tussenstadium voert het programma de regel in de array in symf. Wij gebruikten fgets() in plaats van krijgt() om de invoerreeks te beperken tot de lengte van de array symf.

RIJST. 15.6. Opeenvolgende symph-lijnen geschreven naar de winkelarray.

Voordat u kopieert symf V winkel, moeten we kijken of er nog voldoende ruimte voor is. Wijzer einde verwijst naar het einde van het geheugen en de huidige waarde begint verwijst naar het begin van ongebruikt geheugen. We kunnen dus het verschil tussen deze twee wijzers vergelijken met de lengte symf en bepaal of er voldoende geheugen over is.

Als er niet genoeg ruimte is, bellen we malloc() om extra geheugen voor te bereiden. Wij installeren begint naar het begin van een nieuw geheugenblok, a einde- aan het einde van een nieuw blok. Merk op dat we geen naam hebben voor dit nieuwe geheugen. Het is bijvoorbeeld geen extensie winkel. We hebben alleen aanduidingen voor verwijzingen die naar het nieuwe geheugengebied verwijzen.

Wanneer het programma wordt uitgevoerd, wordt naar elke nieuwe rij verwezen door een element van de pointer-array begint. Er zijn wat lijnen binnen winkel, anderen in een of meer nieuwe geheugengebieden.

Maar zolang we aanwijzingen hebben, kunnen we met strings werken, zoals het afdrukgedeelte van het programma ons laat zien.

Zo wordt het gebruikt malloc(). Maar stel dat je met geheugen wilt werken int, niet verkoold. Je kunt het hier ook gebruiken malloc(). Zo werkt het:

char *malloc(); /* nog steeds beschreven als een verwijzing naar char */

int *nieuwmem;

newmem = (int *) malloc(l00); /* gebruik de type casting-bewerking */

Opnieuw zijn 100 bytes vereist. De type cast-bewerking converteert de door een pointer geretourneerde waarde naar een type verkoold, naar een verwijzing naar een type int. Als, zoals in ons systeem, int neemt twee bytes geheugen in beslag, wat betekent dat nieuwmem + 1 zal de pointer met twee bytes verhogen, d.w.z. naar het volgende gehele getal verplaatsen. Dit betekent ook dat 100 bytes kunnen worden gebruikt om 50 gehele getallen op te slaan.

Een andere mogelijkheid voor het toewijzen van geheugen wordt gegeven door de functie te gebruiken calloc():

char *calloc();

lang *nieuwmem;

newmem = (lang *) calloc(100, groottevan(lang));

Leuk vinden malloc() functie calloc() retourneert een verwijzing naar verkoold. U moet de operator type cast gebruiken als u een ander type wilt onthouden. Deze nieuwe functie heeft twee argumenten, die beide gehele getallen zonder teken moeten zijn. Het eerste argument bevat het aantal benodigde geheugenlocaties. Het tweede argument is de grootte van elke cel in bytes. In ons geval lang

Elke keer dat de pointer werd geïnitialiseerd, werd het adres van een of andere variabele gebruikt. Dit was te wijten aan het feit dat de C++-taalcompiler automatisch geheugen toewijst voor het opslaan van variabelen en met behulp van een pointer kunt u zonder gevolgen met dit toegewezen gebied werken. Er zijn echter malloc() en free() functies waarmee u indien nodig geheugen kunt toewijzen en vrijmaken. Deze functies bevinden zich in de bibliotheek en hebben de volgende syntaxis:

leegte* malloc(size_t); // geheugentoewijzingsfunctie
leegte vrij(void* memblock); // geheugenvrijgavefunctie

Hier is size_t de grootte van het toegewezen geheugengebied in bytes; void* is een algemeen pointertype, d.w.z. niet gebonden aan een specifiek type. Laten we eens kijken hoe deze functies werken aan de hand van het voorbeeld van het toewijzen van geheugen aan 10 elementen van het dubbele type.

Lijst 4.3. Dynamische array-programmering.

#erbij betrekken
#erbij betrekken
int hoofd()
{
dubbel* ptd;
ptd = (dubbel *)malloc(10 * groottevan(dubbel));
als(ptd != NULL)
{
for(int i = 0;i ptd[i] = i;
) else printf(“Kan geen geheugen toewijzen.”);
gratis(ptd);
retour 0;
}

Wanneer de functie malloc() wordt aangeroepen, wordt het vereiste geheugengebied berekend om 10 dubbele elementen op te slaan. Om dit te doen, gebruikt u de functie sizeof(), die het aantal bytes retourneert dat nodig is om één dubbel element op te slaan. Vervolgens wordt de waarde ervan vermenigvuldigd met 10 en het resultaat is het volume voor 10 dubbele elementen. In gevallen waarin om de een of andere reden de opgegeven hoeveelheid geheugen niet kan worden toegewezen, retourneert de functie malloc() NULL. Deze constante is gedefinieerd in verschillende bibliotheken, waaronder en. Als de functie malloc() een verwijzing naar het toegewezen geheugengebied retourneert, d.w.z. niet gelijk is aan NULL, dan wordt er een lus uitgevoerd waarin de waarden voor elk element worden geschreven. Wanneer het programma afsluit, wordt de functie free() aangeroepen, waardoor het eerder toegewezen geheugen vrijkomt. Formeel maakt een programma geschreven in C++ na voltooiing automatisch al het eerder toegewezen geheugen vrij en kan de functie free() in dit geval worden weggelaten. Wanneer u complexere programma's schrijft, moet u echter vaak meerdere keren geheugen toewijzen en weer vrijgeven. In dit geval speelt de functie free() een grote rol, omdat Geheugen dat niet wordt vrijgemaakt, kan niet worden hergebruikt, wat zal resulteren in onnodige verspilling van computerbronnen.

Het gebruik van pointers is “geërfd” van de C-taal. Om het proces van het wijzigen van parameters te vereenvoudigen, introduceert C++ het concept van een referentie. Een referentie is een alias (of tweede naam) die programma's kunnen gebruiken om naar een variabele te verwijzen. Om een ​​link in een programma te declareren, gebruikt u het &-teken voor de naam ervan. Het bijzondere aan het gebruik van links is de noodzaak om ze onmiddellijk na declaratie te initialiseren, bijvoorbeeld:

int var;
int &var2 = var;

Hier wordt een referentie met de naam var2 gedeclareerd, die wordt geïnitialiseerd door de variabele var. Dit betekent dat de var-variabele een eigen alias var2 heeft, waardoor elke wijziging in de waarden van de var-variabele mogelijk is. Het voordeel van het gebruik van verwijzingen in plaats van pointers is dat ze moeten worden geïnitialiseerd, zodat de programmeur er altijd zeker van is dat de var2-variabele werkt met een toegewezen geheugengebied en niet met een willekeurig gebied, wat mogelijk is bij het gebruik van pointers. In tegenstelling tot pointers wordt een referentie slechts één keer geïnitialiseerd, wanneer deze wordt gedeclareerd. Opnieuw initialiseren zal resulteren in een compileerfout. Dit garandeert een betrouwbaar gebruik van links, maar vermindert de flexibiliteit van het gebruik ervan. Meestal worden verwijzingen gebruikt als functieargumenten om doorgegeven variabelen binnen functies te wijzigen. Het volgende voorbeeld demonstreert het gebruik van een dergelijke functie:

Lijst 4.4. Een voorbeeld van het gebruik van links.

void swap(int& a, int& b)
{
int temperatuur = a;
een = b;
b = temperatuur;
}
int hoofd()
{
int agr1 = 10, arg2 = 5;
ruil(arg1, arg2);
retour 0;
}

In dit voorbeeld gebruikt de functie swap() twee argumenten, die verwijzingen zijn naar twee variabelen. Met behulp van de referentienamen a en b worden de variabelen arg1 en arg2, gedefinieerd in de functie main() en doorgegeven als parameters aan de functie swap(), gemanipuleerd. Het voordeel van de functie swap() (die verwijzingen gebruikt in plaats van verwijzingen naar variabelen) is dat deze ervoor zorgt dat de functie de juiste typen variabelen als argumenten gebruikt, in plaats van enige andere informatie, en dat verwijzingen correct worden geïnitialiseerd voordat ze worden gebruikt. Dit wordt door de compiler in de gaten gehouden wanneer deze programmatekst omzet in objectcode en er verschijnt een foutmelding als het gebruik van verwijzingen onjuist is. In tegenstelling tot pointers kunnen de volgende bewerkingen niet worden uitgevoerd met verwijzingen:

U kunt het adres van een link niet achterhalen met de adresoperator in C++;
u kunt geen pointer aan een link toewijzen;
je kunt referentiewaarden niet vergelijken met C++-vergelijkingsoperatoren;
U kunt geen rekenkundige bewerkingen uitvoeren op een referentie, bijvoorbeeld het toevoegen van een offset;

  • aanwijzer beschrijven (type * aanwijzer; );
  • bepaal de grootte van de array;
  • Wijs een geheugengedeelte toe om de array op te slaan en wijs het adres van dit geheugengedeelte toe aan de pointer.

Om geheugen toe te wijzen in C++, kunt u de nieuwe operator of de C-taalfuncties gebruiken - calloc, malloc, realloc. Alle functies bevinden zich in de stdlib.h-bibliotheek.

5.2.1 malloc-functie

De malloc-functie wijst een aaneengesloten stuk geheugenbytes toe en retourneert een pointer naar de eerste byte van dat stuk. De aanroep van de functie ziet er als volgt uit:

void* malloc(size_t maat);

waarbij grootte een geheel getal zonder teken 1 is size_t is een basistype geheel getal zonder teken van de C/C++-taal, dat zo is gekozen dat het de maximale grootte van een theoretisch mogelijke array van welk type dan ook kan opslaan. Op een 32-bits besturingssysteem is size_t een 32-bits getal zonder teken (maximale waarde 2 32 - 1), op een 64-bits besturingssysteem is het een 64-bits getal zonder teken (maximale waarde 2 64 - 1)., die de grootte van het toegewezen geheugen in bytes bepaalt. Als de geheugenreservering succesvol is geweest, retourneert de functie een variabele van het type void*, die kan worden geconverteerd naar elk gewenst pointertype. Als er geen geheugen kan worden toegewezen, retourneert de functie een lege pointer NULL.

Bijvoorbeeld,

dubbel *h; //Beschrijf een pointer om te verdubbelen. intk; cin>>k; //Voer een geheel getal k in. //Wijs een geheugengebied toe om k elementen van het dubbele type op te slaan. //Het adres van deze sectie wordt opgeslagen in de variabele h. h=(dubbel *) malloc (k* grootte van (dubbel)); //h - adres van het begin van de geheugensectie, //h + 1, h + 2, h + 3, etc. - adressen van daaropvolgende elementen van dubbel type

5.2.2 calloc-functie

De calloc-functie is ontworpen om geheugen toe te wijzen en te wissen.

void * calloc(size_t num, size_t size);

Met behulp van de functie wordt een geheugensectie toegewezen waarin een aantal elementen van groottebytes elk worden opgeslagen. Alle elementen van het geselecteerde gebied worden op nul gezet. De functie retourneert een verwijzing naar het toegewezen gebied of NULL als geheugen niet kan worden toegewezen.

Bijvoorbeeld,

zweven *h; //Beschrijf een aanwijzer om te zweven. int k; cin>>k; //Voer een geheel getal k in. //Wijs een geheugengebied toe om k elementen van het float-type op te slaan. //Het adres van deze sectie wordt opgeslagen in de variabele h. h=(zweven *) calloc (k, grootte van (zweven)); //h is het adres van het begin van de geheugensectie, //h + 1, h + 2, h + 3, etc. zijn de adressen van daaropvolgende elementen van het float-type.

5.2.3 realloc-functie

De realloc-functie wijzigt de grootte van een eerder toegewezen geheugenlocatie. De functie is als volgt toegankelijk:

void *realloc(void *p, maat_t maat);

waarbij p een verwijzing is naar het geheugengebied waarvan de grootte moet worden gewijzigd in size . Als het adres van een geheugengebied verandert als gevolg van de functie, wordt als resultaat het nieuwe adres geretourneerd. Als de werkelijke waarde van de eerste parameter NULL is, werkt de realloc-functie op dezelfde manier als de malloc-functie, dat wil zeggen dat deze een geheugengebied van bytesgrootte toewijst.

5.2.4 Gratis functie

De gratis functie wordt gebruikt om toegewezen geheugen vrij te maken. Ze spreken haar als volgt aan:

leegte vrij(leegte *p);

waarbij p een verwijzing is naar een geheugenlocatie die eerder is toegewezen door malloc, calloc of realloc.

5.2.5 Operators nieuw en verwijderd

De C++-taal heeft de nieuwe operators die moeten worden toegewezen en verwijderd om een ​​stukje geheugen vrij te maken.

Om geheugen toe te wijzen aan n elementen van hetzelfde type, heeft de nieuwe operator de vorm [