RTV forum PL | NewsGroups PL

Jak poprawnie zwolnić pamięć w buforze UART z listą jednokierunkową w AVR-GCC?

[AVR-GCC] Lista jednokierunkowa problem...

NOWY TEMAT

elektroda NewsGroups Forum Index - Elektronika Polska - Jak poprawnie zwolnić pamięć w buforze UART z listą jednokierunkową w AVR-GCC?

Pawel K
Guest

Wed May 16, 2007 11:36 am   



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.


--
--
Pozrdawiam
Pawel K from 3miasto
groups(at)kpw.qs.pl
GG: 1263183
---------------- end ----------------

Przemysław Szeremiota
Guest

Wed May 16, 2007 1:13 pm   



Użytkownik "Pawel K" <groups@kpw.qs.pl> napisał w wiadomości
news:f2ems0$fdp$1@inews.gazeta.pl...
Quote:
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.


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

Pawel K
Guest

Wed May 16, 2007 1:57 pm   



Przemysław Szeremiota pisze:
Quote:
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...).
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.


Quote:
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ą.
To zauwazylem, ale bufor ma 5 ramek a wywala sie przy zwalnianiu

jakiejs srodkowej.

Quote:

Dalej, po co te konwersje w wywołaniu free? Przecież tmp jest typu
TxFrame_t*.
to pozostalosc po zdefiniowaniu tmp jako volatile, kompilator wywalal

niezgodnosc typow ...

--
--
Pozrdawiam
Pawel K from 3miasto
groups(at)kpw.qs.pl
GG: 1263183
---------------- end ----------------

Wiktor S.
Guest

Wed May 16, 2007 2:17 pm   



Quote:
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...).

to co dokladnie robi free()? Myslalem ze zeruje wskaznik,
nie myle z obszarem wskazywanym.

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ć Wink]

patrz http://en.wikipedia.org/wiki/Memory_manager


Quote:
wydaje mi sie ze zle wywoluje free() bo
wskazniki mi sie nie zeruja tylko bzduty sie tam wpisuja.

Wskaźniki musisz zerować ręcznie.

free(costam);
costam=NULL;


--
Azarien

Przemysław Szeremiota
Guest

Wed May 16, 2007 2:31 pm   



Użytkownik "Pawel K" <groups@kpw.qs.pl> napisał w wiadomości
news:f2ev4n$n6b$1@inews.gazeta.pl...
Quote:
Przemysław Szeremiota pisze:
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...).
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.

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.


Quote:
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ą.
To zauwazylem, ale bufor ma 5 ramek a wywala sie przy zwalnianiu
jakiejs srodkowej.

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 Smile.


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
Smile.

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

Przemysław Szeremiota
Guest

Wed May 16, 2007 2:37 pm   



Użytkownik "Pawel K" <groups@kpw.qs.pl> napisał w wiadomości
news:f2ev4n$n6b$1@inews.gazeta.pl...
Quote:
Przemysław Szeremiota pisze:
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...).
to co dokladnie robi free()? Myslalem ze zeruje wskaznik,
nie myle z obszarem wskazywanym.

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

Pawel K
Guest

Wed May 16, 2007 2:49 pm   



Przemysław Szeremiota pisze:
Quote:
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 Smile.

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

--
--
Pozrdawiam
Pawel K from 3miasto
groups(at)kpw.qs.pl
GG: 1263183
---------------- end ----------------

Przemysław Szeremiota
Guest

Wed May 16, 2007 2:55 pm   



Użytkownik "Pawel K" <groups@kpw.qs.pl> napisał w wiadomości
news:f2f24p$73k$1@inews.gazeta.pl...
Quote:
Przemysław Szeremiota pisze:
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 Smile.

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

OK, tylko pamiętaj, że zwolnienie tmp i wyzerowanie tmp nie rozwiążą
problemu Smile.

Pozdrawiam,
Przemysław Szeremiota

elektroda NewsGroups Forum Index - Elektronika Polska - Jak poprawnie zwolnić pamięć w buforze UART z listą jednokierunkową w AVR-GCC?

NOWY TEMAT

Regulamin - Zasady uzytkowania Polityka prywatnosci Kontakt RTV map News map