malloc en bereik

Ik worstel om mijn hoofd rond malloc in c te wikkelen - specifiek wanneer het vrij() moet zijn. Ik krijg rare fouten in gcc zoals:

... gratis (): ongeldig volgend formaat (snel): ...

wanneer ik een char pointer probeer te bevrijden. Wanneer u bijvoorbeeld vanuit een invoerbestand leest, crasht het op bepaalde regels als u het volgende doet:

FILE *f = fopen(file,"r");
char x[256];
while(1) {
    if(fgets(x,sizeof x,f)==NULL) break;
    char *tmp = some_function_return_char_pointer(x); //OR malloc(nbytes);
   //do some stuff
    free(tmp);//this is where I get the error, but only sometimes
}

Ik heb gecontroleerd op voor de hand liggende dingen, zoals x NULL zijn, maar dat is het niet; het crasht gewoon op willekeurige lijnen.

Maar mijn echte vraag is - wanneer moet ik gratis() gebruiken? Of, waarschijnlijk correcter, wanneer mag ik NIET gratis gebruiken? Wat als malloc in een functie zit en ik de var terugzet die malloc() gebruikte? Hoe zit het met een voor of tijdlus? Heeft mallocing voor een array van struct dezelfde regels als voor een string/char pointer?

Ik verzamel van de fouten die ik in gcc krijg bij een programmacrash dat ik gewoon geen malloc en gratis begrijp. Ik heb mijn quality time doorgebracht met Google en ik raak nog steeds met bakstenen muren. Zijn er goede bronnen die je hebt gevonden? Alles wat ik zie zegt dat wanneer ik malloc gebruik, ik gratis moet gebruiken. Maar dan probeer ik dat en mijn programma loopt vast. Dus misschien is het anders op basis van de scope van een variabele? Lost C het geheugen op aan het einde van een lus wanneer een variabele erin wordt gedeclareerd? Aan het einde van een functie?

Zo:

for(i=0;i<100;i++) char *x=malloc(n);//no need to use free(x)?

maar:

char *x;
for(i=0;i<100;i++) {
    x=malloc(n);
    free(x); //must do this, since scope of x greater than loop?
}

Is dat juist?

Hopelijk begrijp ik het ...

1
alles wat je malloc (), je bent (een keer) vrij als je het niet langer nodig hebt.
toegevoegd de auteur Mitch Wheat, de bron
ben je malloc'ing nul bytes ...? bytes.com/topic/c/answers/578467- what-malloc-0-should-return & zwnj; s EDIT: besefte dat dit niet uitmaakt, want je kunt nog steeds gratis (... ) de wijzer, ongeacht.
toegevoegd de auteur cwharris, de bron

7 antwoord

malloc() is C's dynamic allocator. You have to understand the difference between automatic (scoped) and dynamic (manual) variables.

Automatic variables live for the duration of their scope. They're the ones you declare without any decoration: int x;

Most variables in a C program should be automatic, since they are local to some piece of code (e.g. a function, or a loop), and they communicate via function calls and return values.

De alleen tijd die u nodig hebt voor dynamische toewijzing, is wanneer u gegevens hebt die een bepaald bereik moeten overleven. Dergelijke gegevens moeten dynamisch worden toegewezen en uiteindelijk worden vrijgegeven wanneer dit niet langer nodig is.

Het primaire voorbeeld hiervan is uw typische gekoppelde lijst . De lijstknooppunten kunnen onmogelijk lokaal zijn voor een bereik als u generieke "invoeg/wis/zoek" -lijstmanipulatiefuncties wilt hebben. Elk knooppunt moet dus dynamisch worden toegewezen en de functies voor lijstmanipulatie moeten ervoor zorgen dat ze de knooppunten bevrijden die niet langer deel uitmaken van de lijst.

Samenvattend, variabele toewijzing is fundamenteel en primair een kwestie van reikwijdte . Houd alles zo mogelijk automatisch en je hoeft niets te doen. Gebruik zonodig dynamische toewijzing en zorg ervoor dat u de toewijzing handmatig opheft wanneer dat nodig is.

( Bewerken: Zoals @Oli zegt, kunt u de dynamische toewijzing soms ook in een strikt lokale context gebruiken, omdat de meeste platforms de grootte van automatische variabelen beperken tot een veel kleinere limiet dan de dynamische grootte geheugen. Denk aan "enorme reeks". Het overschrijden van de beschikbare ruimte voor automatische variabelen heeft meestal een kleurrijke naam zoals "stapeloverschrijding" of iets dergelijks.)

5
toegevoegd
+1 voor het advies om dynamische toewijzing te vermijden waar mogelijk.
toegevoegd de auteur R.., de bron
@OliCharlesworth: ah, ja, nog een goed punt! Bewerkt.
toegevoegd de auteur Kerrek SB, de bron
Geweldige verklaring van wanneer het (niet) geschikt is om malloc te gebruiken
toegevoegd de auteur g33kz0r, de bron
De manier waarop je het hebt uitgelegd, heeft zeker geholpen. Afkomstig van PHP waar $ x = "some string"; , ik probeerde te gebruiken malloc heeft de vervanging voor toewijzing; het is veel logischer om het te beschrijven als dynamische, en niet automatische, toewijzing
toegevoegd de auteur cegfault, de bron
Een voorbeeld van dynamische toewijzing dat niet te hoog is om te overleven, is wanneer u een enorme array (bijvoorbeeld een miljoen elementen) nodig heeft die de stapel zou vernietigen.
toegevoegd de auteur Oliver Charlesworth, de bron

Over het algemeen moet elke aanroep van malloc één bijbehorende aanroep naar gratis hebben. * Dit heeft niets te maken met bereik (dat wil zeggen niets te maken met functies of loops).


* Uitzonderingen op deze regel zijn onder andere het gebruik van functies zoals strdup , maar het principe is hetzelfde.
3
toegevoegd
@xixonia: een crash is het beste scenario en niet wat u zou verwachten. Het ergste geval is het geven van een aanvaller root.
toegevoegd de auteur R.., de bron
@xixonia: gedaan!
toegevoegd de auteur Oliver Charlesworth, de bron
@R .., dit zorgt er allemaal voor dat ik terug wil naar C :)
toegevoegd de auteur cwharris, de bron
Het is belangrijk om hier op te merken dat het tweemaal bellen van gratis (...) kan leiden tot een crash.
toegevoegd de auteur cwharris, de bron

Globaal gesproken moet elke aanwijzer die ooit wordt geretourneerd door malloc() uiteindelijk worden doorgegeven aan gratis() . Het bereik van de variabele waarin u de aanwijzer in opslaat, heeft hier geen invloed op, omdat zelfs nadat de variabele niet langer in scope is, het geheugen waarnaar de aanwijzer verwijst, nog steeds wordt toegewezen totdat u gratis() erop.

2
toegevoegd

Welnu, de reikwijdte van het malloc'd-geheugen ligt tussen aanroepen van malloc en gratis of anders totdat het proces is gestopt (dat is het moment waarop OS het proces opschoont). Als u nooit gratis belt, krijgt u een geheugenlek. Dat kan gebeuren wanneer het adres dat u kunt doorgeven aan gratis buiten de scope valt voordat u het daadwerkelijk hebt gebruikt - dat is als het verliezen van uw sleutels voor de auto, de auto is er nog steeds, maar u kunt er niet echt mee rijden . De fout die u krijgt is hoogstwaarschijnlijk omdat de functie een aanwijzer retourneert naar een geheugen dat niet is toegewezen met malloc of het geeft een lege aanwijzer die u doorgeeft aan gratis , die je kunt niet doen.

1
toegevoegd
Strikt genomen is het woord in C "opslagduur", niet "levensduur". :-)
toegevoegd de auteur R.., de bron
@OliverCharlesworth, oh snelle vechtwoorden :: pops popcorn ::
toegevoegd de auteur user1717828, de bron
Je bedoelt "levenslang", niet "bereik". Toepassingsgebied is van toepassing op ID's, niet op objecten.
toegevoegd de auteur Oliver Charlesworth, de bron
@R ..: Nee, ik bedoel echt "levensduur"; zie 6.2.4, lid 2.
toegevoegd de auteur Oliver Charlesworth, de bron

U moet geheugen vrijmaken als u het niet langer gebruikt. U moet het geheugen niet vrijmaken als u er toegang tot krijgt. Dit zal je veel pijn bezorgen.

0
toegevoegd

malloc (n) wijst n bytes geheugen toe uit een geheugenlocatie met de naam heap en retourneert vervolgens een void * -type aanwijzer ernaar. Het geheugen wordt tijdens runtime toegewezen. Zodra u dynamisch een geheugen hebt toegewezen, maakt het bereik er niet meer uit zolang u er een aanwijzer bij houdt (of het adres ervan specifiek). Bijvoorbeeld:

int* allocate_an_integer_array(int n)
{
    int* p = (int*) (malloc(sizeof(int)*n));
    return p;
}

Deze functie wijst eenvoudigweg het geheugen van de heap toe aan n gehele getallen en retourneert een aanwijzer naar de eerste locatie. De aanwijzer kan worden gebruikt in de aanroepfunctie zoals u dat wilt. De SCOPE maakt niet uit zolang de aanwijzer bij u is ..

free (p) retourneert het geheugen naar de heap.

Het enige dat je moet onthouden is om het te bevrijden alsof je het niet bevrijdt en de waarde van zijn adres verliest, er zal een geheugenlek komen. Het is zo omdat volgens OS je nog steeds het geheugen gebruikt omdat je het nog niet hebt vrijgegeven en er een geheugenlek zal optreden ..

Stel ook na het vrijgeven de waarde van de wijzer in op nul, zodat u hem niet opnieuw gebruikt, omdat hetzelfde geheugen op een ander tijdstip opnieuw kan worden toegewezen voor een ander doel ....

Dus alles wat je hoeft te doen is voorzichtig zijn ...

Hoop dat het helpt!

0
toegevoegd

Als u geen geheugenlek wilt, moet u het geheugen van malloc vrijmaken.

Het kan heel lastig zijn. Als de //wat dingen doen een doorgaan heeft, wordt de gratis overgeslagen en leidt dit tot geheugenlekken. Het is lastig, dus we hebben shared_ptr in C ++; en het gerucht gaat dat het salaris van C-programmeur hoger is dan C ++ -programmeur.

Soms kan het geheugenlek ons ​​niet schelen. Als het geheugen iets vasthoudt dat gedurende de hele levensduur van de uitvoering nodig is, kun je ervoor kiezen om het niet te bevrijden. Voorbeeld: een tekenreeks voor omgevingsvariabele.

PS: Valgrind is een hulpmiddel om geheugenbugs te detecteren. Vooral handig voor geheugenlekken.

0
toegevoegd
Als mijn collega's een geheugenlek achterlaten in de bibliotheekcode, vraag ik een kaartje en laat ze het repareren ...
toegevoegd de auteur Oliver Charlesworth, de bron
Nee dat doen we niet, we kunnen eenvoudig ons geheugen op de juiste manier opruimen.
toegevoegd de auteur Oliver Charlesworth, de bron
Verwaarlozing om iets te bevrijden, alleen maar omdat het leven is, is het geheel van uitvoering een zeer slechte gewoonte. Om te beginnen laat het je Valgrind-uitvoer vol zitten met fouten.
toegevoegd de auteur Oliver Charlesworth, de bron
Daar ben ik het mee eens. Maar daar moeten we mee leven.
toegevoegd de auteur Cha Cha, de bron
U bent niet alleen als u de enige bent die codes schrijft en geen enkele bibliotheek gebruikt. De werkelijkheid is de code van je collega's als deze; en de bibliotheken waarop u vertrouwt, maken het geheugen mogelijk niet vrij.
toegevoegd de auteur Cha Cha, de bron
Oké, je hebt gelijk. Ik ga mijn collega's overtuigen om de herinnering vrij te maken voor putenv (strdup (...)). Ik zal proberen ze te laten werken. Dank je.
toegevoegd de auteur Cha Cha, de bron