malloc și domeniul de aplicare

Mă străduiesc să-mi înfășez capul în jurul valorii de malloc în c - în special când trebuie să fie liber() 'd. Am obtinerea unor erori ciudate in gcc, cum ar fi:

... free (): dimensiunea următoare nevalidă (rapidă): ...

când încerc să eliberez un pointer de caractere. De exemplu, atunci când citiți dintr-un fișier de intrare, acesta se va prăbuși pe anumite linii atunci când faceți următoarele:

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
}

Am verificat lucruri evidente, cum ar fi x fiind NULL, dar nu este; ci doar se prăbușește pe linii aleatorii.

Dar întrebarea mea reală este - când trebuie să folosesc liber() ? Sau, probabil, mai corect, când NU ar trebui să folosesc gratuit? Ce se întâmplă dacă malloc este într-o funcție, și-am întoarce var care a folosit malloc ()? Ce zici într-o buclă pentru sau în timp? Are malloc-ing pentru o serie de struct are aceleași reguli ca și pentru un șir de caractere/caractere?

M-am adunat de la erorile pe care le primesc în gcc în urma unui accident de program că nu înțeleg malloc și nu-l înțeleg. Mi-am petrecut timpul de calitate cu Google și încă mai lovesc ziduri de cărămidă. Există resurse bune pe care le-ați găsit? Tot ce văd spune că ori de câte ori folosesc malloc, trebuie să folosesc gratuit. Dar apoi încerc asta și programul meu se prăbușește. Deci, poate că este diferită pe baza domeniului variabil? Are C eliberarea memoriei la sfârșitul unei buclă atunci când o variabilă este declarată în interiorul ei? La sfârșitul unei funcții?

Asa de:

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

dar:

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

Este corect?

Sper că înțeleg ...

1
tot ce vă malloc (), vă eliberați (o singură dată) atunci când nu mai trebuie să-l utilizați.
adăugat autor Mitch Wheat, sursa
ești malloc'ing zero octeți ...? bytes.com/topic/c/answers/578467- ce-malloc-0-should-return & zwnj; s EDIT: ) indicatorul, indiferent.
adăugat autor cwharris, sursa

7 răspunsuri

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.

Timpul numai în care aveți nevoie de alocare dinamică este atunci când aveți anumite date care trebuie să depășească orice domeniu de aplicare dat. Aceste date trebuie să fie alocate dinamic și, eventual, eliberate atunci când nu mai sunt necesare.

Primul exemplu de utilizare pentru acest lucru este lista dvs. tipică asociată . Nodurile listă nu pot fi, eventual, locale la niciun domeniu, dacă aveți de gând să aveți generice funcții de manipulare "insert/erase/find". Astfel, fiecare nod trebuie să fie alocat dinamic, iar funcțiile de manipulare a listei trebuie să se asigure că ele eliberează acele noduri care nu mai fac parte din listă.

În concluzie, alocarea variabilelor este fundamentală și în primul rând o chestiune de domeniu de aplicare . Dacă este posibil, păstrați totul automat și nu trebuie să faceți nimic. Dacă este necesar, utilizați alocarea dinamică și asigurați-vă că ați dezafectat manual ori de câte ori este cazul.

( Editați: După cum spune @Oli, este posibil să doriți să utilizați uneori alocarea dinamică într-un context strict local, deoarece majoritatea platformelor limitează dimensiunea variabilelor automate la o limită mult mai mică decât dimensiunea dinamică Gândiți-vă la "matrice uriașă". Depășirea spațiului disponibil pentru variabilele automate are, de obicei, un nume colorat, cum ar fi "depășirea grămadă" sau ceva similar.)

5
adăugat
+1 pentru sfaturi pentru a evita alocarea dinamică ori de câte ori este posibil.
adăugat autor R.., sursa
@OliCharlesworth: ah, da, un alt punct bun! Editat.
adăugat autor Kerrek SB, sursa
O explicație minuțioasă a momentului în care este (nu) potrivită pentru malloc
adăugat autor g33kz0r, sursa
Modul în care i-ai explicat a ajutat cu siguranță. Venind din PHP unde $ x = "some string"; , încercam să folosesc malloc înlocuitorul pentru alocare; este mult mai logic să o descriem ca alocare dinamică și nu automată
adăugat autor cegfault, sursa
O instanță de alocare dinamică care nu se limitează la scopul de a depăși este atunci când aveți nevoie de o matrice masivă (de exemplu, un milion de elemente) care ar deranja stivă.
adăugat autor Oliver Charlesworth, sursa

În general, fiecare apel la malloc trebuie să aibă un apel unul corespunzător free . (adică nu are nimic de-a face cu funcții sau bucle).


* Excepțiile la această regulă includ utilizarea unor funcții precum strdup , dar principiul este același.
3
adăugat
@xixonia: Un accident este cel mai bun scenariu și nu ceea ce ar trebui să așteptați. Cel mai rău caz este acela de a da o rădăcină de atacator.
adăugat autor R.., sursa
@xixonia: Terminat!
adăugat autor Oliver Charlesworth, sursa
@R .., toate acestea doar mă face să vreau să mă întorc în C :)
adăugat autor cwharris, sursa
Este important să rețineți că apelul free (...) de două ori ar putea duce la un accident.
adăugat autor cwharris, sursa

În general, fiecare indicator care este întotdeauna returnat de malloc() trebuie în cele din urmă să fie transmis la free() . Domeniul variabilei în care stocați indicatorul în nu afectează acest lucru, deoarece chiar și după ce variabila nu mai este în domeniul de aplicare, memoria cu care indicatorul indică spre el va fi încă alocată până când apelați free() pe acesta.

2
adăugat

Ei bine, domeniul de memorie malloc'd se află între apelurile către malloc și free sau altfel până când procesul este oprit (adică când OS se curăță pentru proces). Dacă nu apelați niciodată free veți obține o scurgere de memorie. Acest lucru s-ar putea întâmpla atunci când adresa pe care o puteți trece la free iese din domeniul de aplicare înainte de a-l folosi de fapt - este ca și cum ați pierde cheile pentru mașină, mașina este încă acolo, dar nu o puteți conduce cu adevărat . Eroarea pe care o obțineți este cel mai probabil fie pentru că funcția returnează un pointer la o memorie care nu a fost alocată utilizând malloc , fie returnează un pointer nul pe care îl transmiteți free nu poți să faci.

1
adăugat
Strict vorbind, cuvântul din C este "durata de stocare", nu "durata de viață". :-)
adăugat autor R.., sursa
@OliverCharlesworth, oh cuvintele de lupta :: apare popcorn ::
adăugat autor user1717828, sursa
Adică "viață", nu "domeniu de aplicare". Domeniul de aplicare se aplică identificatorilor, nu obiectelor.
adăugat autor Oliver Charlesworth, sursa
@R ..: Nu, chiar vreau sa spun "viata"; a se vedea 6.2.4 clauza 2.
adăugat autor Oliver Charlesworth, sursa

Ar trebui să eliberați memoria atunci când nu mai aveți acces la ea. Nu trebuie să eliberați memoria dacă o veți accesa. Acest lucru vă va face multă durere.

0
adăugat

malloc (n) alocă n octeți de memorie dintr-o locație de memorie numită heap și apoi returnează un vid tip * void. Memoria este alocată în timpul rulării. Odată ce ați alocat o memorie dinamic, domeniul de aplicare nu contează atâta timp cât păstrați un indicator cu acesta (sau adresa specifică). De exemplu:

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

Această funcție alocă pur și simplu o memorie din heap egală cu n întregi și returnează un pointer la prima locație. Pointerul poate fi utilizat în funcția de asteptare așa cum doriți. SCOPUL nu contează atâta timp cât indicatorul este cu dvs.

(p) returnează memoria în heap.

Singurul lucru pe care trebuie să-l amintiți este să-l eliberați ca și cum nu îl eliberați și pierdeți valoarea adresei sale, va avea loc o scurgere de memorie. Este așa că, în conformitate cu sistemul de operare, încă mai folosiți memoria, deoarece nu l-ați eliberat și se va produce o scurgere de memorie.

De asemenea, după eliberare trebuie doar să setați valoarea indicelui la null astfel încât u să nu îl folosiți din nou, deoarece aceeași memorie poate fi alocată din nou oricând pentru un alt scop ....

Deci, tot ce trebuie să faceți este să fiți atent ...

Sper ca ajuta!

0
adăugat

Dacă nu doriți scurgere de memorie , trebuie să eliberați memoria de la malloc.

Poate fi foarte complicat. De exemplu, dacă //face unele lucruri are un continuă , liberul va fi sărit și va duce la scurgeri de memorie. Este complicat, așa că am partajat_ptr în C ++; și zvonuri că salariul programatorului C este mai mare decât programatorul C ++.

Uneori nu ne pasă de scurgeri de memorie. Dacă memoria deține ceva care este necesar pe toată durata de viață a execuției, puteți alege să nu îl eliberați. Exemplu: un șir pentru variabila de mediu.

PS: Valgrind este un instrument pentru a ajuta la detectarea bug-urilor de memorie. Este deosebit de util pentru scurgeri de memorie.

0
adăugat
Dacă colegii mei vor lăsa o scurgere de memorie în codul bibliotecii, voi ridica un bilet și îi voi face să o repare ...
adăugat autor Oliver Charlesworth, sursa
Nu, nu putem, ne putem clarifica memoria în mod corespunzător.
adăugat autor Oliver Charlesworth, sursa
Neglijarea pentru a elibera ceva doar pentru că este o viață este întreaga execuție este o practică foarte slabă. Pentru început, vă înmugurează ieșirea de la Valgrind cu erori.
adăugat autor Oliver Charlesworth, sursa
Sunt de acord. Dar trebuie să trăim cu asta.
adăugat autor Cha Cha, sursa
Nu numai dacă sunteți singurul care scrie coduri și nu utilizați nici o bibliotecă. Realitatea este codul colegilor tăi așa; iar bibliotecile la care te bazezi nu pot elibera memoria.
adăugat autor Cha Cha, sursa
Bine, ai un punct. Voi convinge colegii mei să elibereze memoria pentru putenv (strdup (...)). Voi încerca să-i fac să lucreze. Mulțumesc.
adăugat autor Cha Cha, sursa