Procedure Zanesenie; begin write('Vvedite tabelnii nomer rabotyschego: '); readln(s); write('Vvedite fameliu, imia, otchestvo rabochego: '); readln(d); write('Vvedite mesto raboti, spetsialnost: '); readln(f); write('Vvedite domashnii adres rabotauschego: '); readln(g); end;
Procedure SozdanieTree(var a: Adrzv; s: word; d, f, g: string); var z: Adrzv; j: AdrText; begin if a=Nil then begin New(j); j^.Fio:= d; j^.Work:= f; j^.Adres:= g;
New (z); z^.Key:= s; z^.Lev:= Nil; z^.Prav:= Nil; z^.Adr:=j; a:=z; end else begin if a^.Key>s then SozdanieTree(a^.Lev, s, d, f, g) else SozdanieTree(a^.Prav, s, d, f, g); end; end;
Procedure DelVedomost(var a:Adrzv); begin if a=Nil then exit; DelVedomost(a^.Lev); DelVedomost(a^.Prav); dispose(Adr); Adr:=Nil; dispose(a); a:=Nil; end;
Вопрос: правильно ли проведена очистка памяти (память должна возвращаться в кучу перед завершением работы программы)? Возникает ошибка при выполнении удаления адреса a^.Adr.
volvo
17.04.2008 15:19
Цитата
Вопрос: правильно ли проведена очистка памяти (память должна возвращаться в кучу перед завершением работы программы)?
Ответ - да... Во всяком случае FPC утечек в "куче" не показывает, возвращается вся выделенная память.
Но все-таки:
Procedure DelVedomost(var a:Adrzv); begin if a=Nil then exit; DelVedomost(a^.Lev); DelVedomost(a^.Prav); dispose(a^.Adr); { <--- } a^.Adr:=Nil; { <--- } dispose(a); a:=Nil; end;
Цитата
Возникает ошибка при выполнении удаления адреса a^.Adr.
Какая ошибка? Мне ничего не выдало... Показывай, как создаешь дерево (в смысле, вызов SozdanieTree из основной программы...)
Трисемёрки
17.04.2008 17:17
Цитата(volvo @ 17.04.2008 11:19)
Ответ - да... Во всяком случае FPC утечек в "куче" не показывает, возвращается вся выделенная память.
Но все-таки:
Procedure DelVedomost(var a:Adrzv); begin if a=Nil then exit; DelVedomost(a^.Lev); DelVedomost(a^.Prav); dispose(a^.Adr); { <--- } a^.Adr:=Nil; { <--- } dispose(a); a:=Nil; end;
Какая ошибка? Мне ничего не выдало... Показывай, как создаешь дерево (в смысле, вызов SozdanieTree из основной программы...)
Возможно ошибка есть при записи или чтения из файла, поэтому вся программа:
var i, m, q: byte; s, x: word; d, g, f: string[70]; a, Tree: Adrzv; j: AdrText;
W: File of Tabl; Wzveno: Tabl;
Procedure Pravila; begin write('--------------------------------------------------------------------------------'); writeln('Dlia povtornogo oznakomlenia s pravilami nazmite 11: '); writeln('Dlia formirovania dereva nazmite 1: '); writeln('Dlia priamogo vivoda spiska na ekran nazmite 2: '); writeln('Dlia obratnogo vivoda spiska na ekran nazmite 3: '); writeln('Dlia simmetrichnogo vivoda spiska na ekran nazmite 4: '); writeln('Dlia dobavlenia elementa v spisok nazmite 5: '); writeln('Dlia ydalenia elementa iz spiska nazmite 6: '); writeln('Dlia poisca elementa nazmite 7: '); writeln('Dlia zapis v fail nazmite 8: '); writeln('Dlia vivoda iz faila nazmite 9: '); writeln('Dlia vixoda iz programmi nazmite 0: '); write('--------------------------------------------------------------------------------'); end;
Procedure Zanesenie; begin write('Vvedite tabelnii nomer rabotyschego: '); readln(s); write('Vvedite fameliu, imia, otchestvo rabochego: '); readln(d); write('Vvedite mesto raboti, spetsialnost: '); readln(f); write('Vvedite domashnii adres rabotauschego: '); readln(g); end;
Procedure SozdanieTree(var a: Adrzv; s: word; d, f, g: string); var z: Adrzv; j: AdrText; begin if a=Nil then begin New(j); j^.Fio:= d; j^.Work:= f; j^.Adres:= g;
New (z); z^.Key:= s; z^.Lev:= Nil; z^.Prav:= Nil; z^.Adr:=j; a:=z; end else begin if a^.Key>s then SozdanieTree(a^.Lev, s, d, f, g) else SozdanieTree(a^.Prav, s, d, f, g); end; end;
Function Proverka(a: Adrzv): boolean; begin if a=Nil then Proverka:=false else Proverka:=true; end;
Procedure PrintPriam(a: Adrzv); var Adr: AdrText; begin if a<>Nil then begin write('--------------------------------------------------------------------------------'); Writeln('Tabelnii nomer:',a^.Key,' FIO: ', a^.Adr^.Fio); {Writeln('FIO: ', a^.Adr^.Fio); } writeln('Work: ', a^.Adr^.Work,' Adres: ', a^.Adr^.Adres); {writeln('Adres: ', a^.Adr^.Adres);} PrintPriam(a^.Lev); PrintPriam(a^.Prav); end; end;
Procedure PrintObratn(a: Adrzv); var Adr: AdrText; begin if a<>Nil then begin PrintObratn(a^.Lev); PrintObratn(a^.Prav); write('--------------------------------------------------------------------------------'); Writeln('Tabelnii nomer:',a^.Key); Writeln('FIO: ', a^.Adr^.Fio); writeln('Work: ', a^.Adr^.Work); writeln('Adres: ', a^.Adr^.Adres); end; end;
Procedure PrintSimmetr(a: Adrzv); var Adr: AdrText; begin if a<>Nil then begin PrintSimmetr(a^.Lev); write('--------------------------------------------------------------------------------'); Writeln('Tabelnii nomer:',a^.Key); Writeln('FIO: ', a^.Adr^.Fio); writeln('Work: ', a^.Adr^.Work); writeln('Adres: ', a^.Adr^.Adres); PrintSimmetr(a^.Prav); end; end;
Function FindElement(var a: Adrzv; s: word):Adrzv; begin if a=Nil then FindElement:=Nil else begin if s=a^.Key then FindElement:=a else if s<a^.Key then FindElement:=FindElement(a^.Lev, s) else FindElement:=FindElement(a^.Prav, s); end; end;
Procedure PrintElement(FindElement: Adrzv); begin
if FindElement=Nil then writeln('Rabotauschego c takim tabelnim nomerom net.') else begin write('--------------------------------------------------------------------------------'); Writeln('Tabelnii nomer: ',FindElement^.Key); Writeln('FIO: ', FindElement^.Adr^.Fio); writeln('Work: ', FindElement^.Adr^.Work); writeln('Adres: ', FindElement^.Adr^.Adres); write('--------------------------------------------------------------------------------'); end; end;
Procedure DelElement1(var a: Adrzv; S: word); var Q:Adrzv;
Procedure Ud(var E: Adrzv); begin if E^.Prav=Nil then begin Q^.Key:=E^.Key; Q^.Adr:=E^.Adr; Q:=E; E:=Q^.Lev; dispose(Q); End else Ud(E^.Prav); end;
begin if a=Nil then writeln('Rabotauschego c takim tabelnim nomerom net.') else begin if s<a^.Key then DelElement1(a^.Lev, s) else if s>a^.Key then DelElement1(a^.Prav, s) else begin if (a^.Lev=Nil) and (a^.Prav<>Nil) then begin Q:=a; a:=a^.Prav;
dispose(Q); end else
if (a^.Lev<>Nil) and (a^.Prav=Nil) then begin Q:=a; a:=a^.Lev;
dispose(Q); end else
if (a^.Lev=Nil) and (a^.Prav=Nil) then begin
dispose(a); a:=Nil;
end else
if (a^.Lev<>Nil) and (a^.Prav<>Nil) then begin Q:=a; Ud(Q^.Lev); end; END; end; end;
Procedure Prisvoenie(var a:Adrzv); var Adr: AdrText; begin if a<>Nil then begin Wzveno.Key:=a^.Key; Wzveno.FIO:=a^.Adr^.Fio; Wzveno.Work:=a^.Adr^.Work; Wzveno.Adres:=a^.Adr^.Adres; Write(W, Wzveno); Prisvoenie(a^.Lev); Prisvoenie(a^.Prav); end; end;
Procedure Infail(var a:Adrzv); var Adr: AdrText; begin assign(W,'Tree.Pas'); rewrite(W); Prisvoenie(a); close(W); writeln('Cpisok yspeshno soxranen'); end;
Procedure Izfail(var a: Adrzv); begin Assign(W,'Tree.PAS'); {$I-} Reset(W); {$I+} if ioresult<>0 then writeln('Fail ne naiden') else begin if eof(W) then writeln('Fail pust') else begin a:=Nil; repeat read(W,Wzveno); SozdanieTree(a, Wzveno.Key, Wzveno.FIO, Wzveno.Work, Wzveno.Adres); until eof(W); end; close(W); end; end;
Procedure DelVedomost(var a:Adrzv); begin if a=Nil then exit; DelVedomost(a^.Lev); DelVedomost(a^.Prav); dispose(a^.Adr); a^.Adr:=Nil; dispose(a); a:=Nil; end;
begin ClrScr; writeln('Vnimatelno izychite i zapomnite dannyy informatiy'); Pravila; repeat write('Vvedite nomer komandi: '); readln(m);
case m of 11: Pravila; 1: begin DelVedomost(Tree);
Tree:=Nil; writeln('Vvedite kollichestvo chelovek: '); readln(q); for i:=1 to q do begin Zanesenie; SozdanieTree (Tree, s, d, f, g); end; end; 2: begin if Proverka(Tree) then begin PrintPriam(Tree); write('--------------------------------------------------------------------------------'); end else writeln('Oshibka! Spiska ne suschestvuet.'); end; 3: begin if Proverka(Tree) then begin PrintObratn(Tree); write('--------------------------------------------------------------------------------'); end else writeln('Oshibka! Spiska ne suschestvuet.'); end; 4: begin if Proverka(Tree) then begin PrintSimmetr(Tree); write('--------------------------------------------------------------------------------'); end else writeln('Oshibka! Spiska ne suschestvuet.'); end; 5: begin if Proverka(Tree) then begin write('Vvedite dobavliaemoe kollichestvo chelovek: '); readln(q); for i:=1 to q do begin Zanesenie; SozdanieTree (Tree, s, d, f, g); end; end else writeln('Oshibka! Spiska ne suschestvuet.'); end; 6: begin if Proverka(Tree) then begin write('Vvedite tabelnii nomer rabochego: ' ); read(s); PrintElement(FindElement(Tree, s)); end else writeln('Oshibka! Spiska ne suschestvuet.'); end; 7: begin if Proverka(Tree) then begin write('Vvedite tabelnii nomer rabochego: ' ); read(s);
DelElement1(Tree, S);
if Proverka(Tree) then begin writeln('Izmenennii spisok:'); PrintPriam(Tree); write('--------------------------------------------------------------------------------'); end else writeln('Oshibka! Spiska ne suschestvuet.');
END; end; 8: begin if Proverka(Tree) then Infail(Tree) else writeln('Oshibka! Spiska ne suschestvuet.'); end; 9: begin DelVedomost(Tree); Izfail(Tree); PrintPriam(Tree); write('--------------------------------------------------------------------------------'); end;
0: begin DelVedomost(Tree); exit; end;
end; until m=11; readln end.
volvo
17.04.2008 17:29
Опять-таки никаких ошибок не обнаружено... В какой последовательности и что ты делаешь, когда у тебя выскакивает ошибка (я больше про то, КАКАЯ ошибка спрашивать не буду: не хочешь отвечать - дело твое, программа нужна ТЕБЕ в конце концов, мне по барабану, сколько времени ты будешь ошибку искать, если не хочешь чтоб тебе помогли...)
У меня вот что было:
Цитата(console)
Vnimatelno izychite i zapomnite dannyy informatiy Dlia povtornogo oznakomlenia s pravilami nazmite 11: --------------------------- Dlia formirovania dereva nazmite 1: Dlia priamogo vivoda spiska na ekran nazmite 2: Dlia obratnogo vivoda spiska na ekran nazmite 3: Dlia simmetrichnogo vivoda spiska na ekran nazmite 4: Dlia dobavlenia elementa v spisok nazmite 5: Dlia ydalenia elementa iz spiska nazmite 6: Dlia poisca elementa nazmite 7: Dlia zapis v fail nazmite 8: Dlia vivoda iz faila nazmite 9: Dlia vixoda iz programmi nazmite 0: Vvedite nomer komandi: 1-------------------------------------------------------- Vvedite kollichestvo chelovek: 2 Vvedite tabelnii nomer rabotyschego: 23 Vvedite fameliu, imia, otchestvo rabochego: Vvedite mesto raboti, spetsialnost: dsfgdsfg Vvedite domashnii adres rabotauschego: dfgg Vvedite tabelnii nomer rabotyschego: 45 Vvedite fameliu, imia, otchestvo rabochego: dfgsdfg Vvedite mesto raboti, spetsialnost: sdfgdfgg Vvedite domashnii adres rabotauschego: ffggg Vvedite nomer komandi: 2 Tabelnii nomer:23 FIO: ------------------------------------------------------ Work: dsfgdsfg Adres: dfgg Tabelnii nomer:45 FIO: dfgsdfg----------------------------------------------- Work: sdfgdfgg Adres: ffggg Vvedite nomer komandi: 8-------------------------------------------------------- Cpisok yspeshno soxranen Vvedite nomer komandi: 9 Tabelnii nomer:23 FIO: ------------------------------------------------------ Work: dsfgdsfg Adres: dfgg Tabelnii nomer:45 FIO: dfgsdfg----------------------------------------------- Work: sdfgdfgg Adres: ffggg Vvedite nomer komandi: 0-------------------------------------------------------- Heap dump by heaptrc unit 18 memory blocks allocated : 1070/1120 18 memory blocks freed : 1070/1120 0 unfreed memory blocks : 0 True heap size : 163840 (144 used in System startup) True free heap : 163696
Трисемёрки
18.04.2008 12:59
Возможно, я плохо разбираюсь в теории динамических данных, но у меня в окне Watch при выходе из программы "не обнуляются" Tree^. Adr; Tree^.Prav; Tree^.Lev.
volvo
18.04.2008 14:42
А должны? То, что ты видишь - это уже "левые" значения, мусор, совершенно не то, что там было во время работы программы, если поставишь точку останова в DelVedomost - можешь в этом убедиться... У тебя ж сам Tree об-NIL-ен, а ты хочешь увидеть Tree^.{что-то}? Это называется разыменование нулевого указателя, что категорически запрещено.
Более новые компиляторы просто не показывают Tree^.Adr после выполнения Dispose(a), говорят "Cannot access memory at address $0"
Кстати, еще один способ проверить, вся ли память высвобождается - это после вызова Pravila напечатать
Writeln(MemAvail);
, и то же самое сделать после освобождения памяти перед выходом из программы. Значения должны быть одинаковы... Только что проверил - и там и там 528032, все в порядке...
Трисемёрки
18.04.2008 16:28
Большое спасибо volvo
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.