[AVR-GCC] Lista jednokierunkowa problem...

May 16, 2007 7 Replies

Witam, zrobilem sobie buffor do UARTa, cos na styl listy jednokierunkowej. strukturka bufora:



typedef struct TxFrame_t { struct TxFrame_t *next; size_t len; uint8_t *data; uint16_t CrcValue; }TxFrame_t;



dynamicznie przydzielam przez malloc miejsce na ramke bufora oraz dynamicznie miejsce na dane (wskaznik data). wszystko dziala fajnie tworzenie ramki, zapisywanie do niej danych wysylanie. Zaszla jednak potrzeba kasowania calego bufora wraz przydzielona pamiecia na dane i tu mam problem.



funkcja ktora powinna to robic ... powinna zwolnic cala zarezerwowana pamiec od konca bufora a w/g AVRStudio nie robi tego ... zapetla sie na wyszukiwaniu ostatniego rekordu.



bool DeleteTxBuff (TxFrame_t *first) { TxFrame_t *tmp = NULL; if (Uart0Status == Tx_Busy || first == NULL) return false;



do { tmp = first; while (tmp->next != NULL) tmp = tmp->next; //idz do ostatniej ramki



free(((TxFrame_t *)tmp)->data); // zwalnia pamiec danych free((TxFrame_t *)tmp); // zwalnia pamiec ramki bufora } while (first);



return true; }



co jest nie tak? podejzewam ze free zle wywoluje ale nie wiem w czym blad.



U¿ytkownik "Pawel K" snipped-for-privacy@kpw.qs.pl> napisa³ w wiadomo¶ci news:f2ems0$fdp$ snipped-for-privacy@inews.gazeta.pl...

Zapêtla siê, bo wywo³anie free() nie zeruje warto¶ci przekazanego wska¼nika. Ciekawe, czy w ogóle na tej li¶cie jest jakikolwiek NULL, na którym pêtla mog³aby siê zatrzymaæ (skoro nie zerujesz ich przy zwalnianiu, to mo¿e i nie zerujesz przy inicjalizacji...).

Dalej, first i tmp to niezale¿ne zmienne. Instrukcja while (first) {} przy braku modyfikacji first w pêtli i niezerowej warto¶ci first oznacza pêtlê nieskoñczon±.

Dalej, po co te konwersje w wywo³aniu free? Przecie¿ tmp jest typu TxFrame_t*.

Problemów sporo jak na tak krótki kod...

Pozdrawiam, Przemys³aw Szeremiota

Przemysław Szeremiota pisze:

to co dokladnie robi free()? Myslalem ze zeruje wskaznik, nie myle z obszarem wskazywanym. Przy inicjacji zeruje prewencyjnie wskazniki. Na koncu bufora, ostatni rekord ->next jest NULL, takze ma sie na czym zatrzymac.

zapetla mi sie na

while (tmp->next != NULL) tmp = tmp->next;

ale dopiero po ktoryms przejsciu ... wydaje mi sie ze zle wywoluje free() bo wskazniki mi sie nie zeruja tylko bzduty sie tam wpisuja.

To zauwazylem, ale bufor ma 5 ramek a wywala sie przy zwalnianiu jakiejs srodkowej.

to pozostalosc po zdefiniowaniu tmp jako volatile, kompilator wywalal niezgodnosc typow ...

free zwalnia wcze¶niej zaalokowany blok pamiêci. Taki blok mo¿e byæ pó¼niej ponownie zajêty przez malloc. Próba odwo³ania siê do free'niêtego wska¼nika albo:

- wywali program (na PC-cie, na mikrokontrolerze skutki mog± byæ dziwne)

- zwróci bzdury

- zwróci ostatni± zawarto¶æ istniej±cej tam kiedy¶ zmiennej

Natomiast free NIE zeruje wska¼nika warto¶ci± NULL. Program trzyma informacje o tym, co zaalokowa³ i ile to zajmuje, gdzie¶ w osobnej ukrytej tablicy - zale¿nie od kompilatora mo¿e to byæ ró¿nie rozwi±zane. [ale programistê nie powinno to obchodziæ ;-)]

patrz

formatting link

Wska¼niki musisz zerowaæ rêcznie.

free(costam); costam=NULL;

U¿ytkownik "Pawel K" snipped-for-privacy@kpw.qs.pl> napisa³ w wiadomo¶ci news:f2ev4n$n6b$ snipped-for-privacy@inews.gazeta.pl...

Tak, bo je¶li faktycznie ("prewencyjnie") zerujesz wska¼niki przy inicjalizacji, to przy pierwszym przej¶ciu jest jeszcze OK. Dojdziesz do tego pierwszego NULL-a. Ale zauwa¿, ¿e przy zwalnianiu free() nie zeruje wska¼nika, wiêc za drugim razem znów bêdziesz ³azi³ w tej pêtli do zwolnionego ju¿ wêz³a. To raz.

Wywo³anie free() zostawia poprzedni± warto¶æ wska¼nika, a jedynie zwalnia pamiêæ przydzielon± wcze¶niej. Co to znaczy zwalnia pamiêæ? Otó¿ tylko i wy³±cznie to, ¿e odbiera Ci prawo do korzystania z tej pamiêci (w procesorach z ochron± pamiêci i MMU byæ mo¿e usunie odpowiednie adresy z tablicy stron danego procesu, prowokuj±c b³êdy ochrony pamiêci przy próbie odwo³ania siê pod zwolniony adres...). Funkcja free() ani nie zeruje pamiêci zwolnionej, ani nie zeruje wska¼nika zwalnianej pamiêci. Musisz to (to drugie) zrobiæ sam.

Podejrzewam, ¿e pi±tej, tylko za drugim razem.

Listy jednokierunkowe, bez wska¼ników na czo³o listy albo poprzedni element w ka¿dym elemencie, wbrew pozorom naj³atwiej zwalnia siê funkcj± rekurencyjn±. To eleganckie i przejrzyste rozwi±zanie, a przy piêciu elementach listy mo¿na za³o¿yæ, ¿e nawet na mikrokontrolerze stos wytrzyma :-).

Przy rozwi±zaniu iteracyjnym pamiêtaj, ¿e zastosowanie wyra¿enia:

tmp = NULL;

po zwolnieniu tmp zupe³nie nic Ci nie da -- wyzerujesz sobie wska¼nik tymczasowy, a nie wska¼nik z listy. ¯eby skutecznie zwolniæ listê powiniene¶ dochodziæ do przedostatniego elementu, nastêpnie zwalniaæ element ostatni ( free(tmp->next) ), a w przedostatnim ustawiaæ tmp->next na NULL. Wtedy mo¿esz w nastêpnym przebiegu skutecznie znów doj¶æ do przedostatniego elementu. W³a¶nie fakt, ¿e potrzebujesz przedostatniego wêz³a sprawia, ¿e tak wygodnie zrobiæ to rekurencyjnie :-).

Jak dojdziesz do ostatniego elementu zamiast przedostatniego, nie masz gdzie wpisaæ NULL-a po zwolnieniu elementu i w nastêpnym przebiegu pójdziesz w maliny.

Pozdrawiam, Przemys³aw Szeremiota

U¿ytkownik "Pawel K" snipped-for-privacy@kpw.qs.pl> napisa³ w wiadomo¶ci news:f2ev4n$n6b$ snipped-for-privacy@inews.gazeta.pl...

Jak ju¿ siê rozpisa³em: funkcja free() nie zeruje wska¼ników choæby dlatego, ¿e to by³oby bez sensu -- we¼my choæby Twój przyk³ad: wyzerowa³aby tylko jeden z istniej±cych wska¼ników danego wêz³a (i to wska¼nik tymczasowy, tmp), a ten w³a¶ciwy (first->next->next->...) i tak zachowa³by swoj± poprzedni± warto¶æ, bo on w wywo³aniu nie uczestniczy wcale.

S³owem, free() zajmuje siê obszarem zwalnianym, a wska¼nikami tego obszaru musi siê zaj±æ programista -- free() nie ma przecie¿ ¿adnego pojêcia o tym, ile takich wska¼ników jest, ani nie ma ¿adnego do nich dostêpu.

Pozdrawiam, Przemys³aw Szeremiota

Przemysław Szeremiota pisze:

NIe ma az takiej potrzeby, najwazniejszego sie dowiedzialem ze free() nie zeruje wskaznika ... i tu tkwil moj blad.

U¿ytkownik "Pawel K" snipped-for-privacy@kpw.qs.pl> napisa³ w wiadomo¶ci news:f2f24p$73k$ snipped-for-privacy@inews.gazeta.pl...

OK, tylko pamiêtaj, ¿e zwolnienie tmp i wyzerowanie tmp nie rozwi±¿± problemu :-).

Pozdrawiam, Przemys³aw Szeremiota

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required