1 / 34

Typy wskaźnikowe, dynamiczne struktury danych

Typy wskaźnikowe, dynamiczne struktury danych. Sterta. przeznaczenie stosu (przypomnienie) sterta. Typ wskaźnikowy. type typ_wskaznikowy = ^typ_wskazywany; np.: type tpr = ^real; { zmienne typu pr będą } { wskaźnikami na zmienne real } var

dugan
Download Presentation

Typy wskaźnikowe, dynamiczne struktury danych

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Typy wskaźnikowe, dynamiczne struktury danych

  2. Sterta • przeznaczenie stosu (przypomnienie) • sterta

  3. Typ wskaźnikowy type typ_wskaznikowy = ^typ_wskazywany; • np.: type tpr = ^real;{ zmienne typu pr będą} { wskaźnikami na zmienne real } var pr : tpr;{ można było też od razu napisać pr: ^real }

  4. Wskaźnik • wskaźnik jak każda zmienna jest określony przez: • typ • rozmiar – niezależny od typu zmiennejwskazywanej • adres • zbiór operacji – silnie ograniczony • zmienna wskazywana to również zmienna • własności wynikają z jej typu

  5. Wskaźnik • Rozmiar zmiennej wskaźnikowej: 4 bajty • kompilator 32-bitowy: 4B adres • kompilator 16-bitowy: 2B segment + 2B offset • kompilator 16-bitowy, „mały” model pamięci: 2B offset, segment domyślny • Adres bezwzględny w pamięci fizycznej a przestrzeń adresowalna wskaźnikiem

  6. Najważniejsze, oczywiste • Wskaźniki należy inicjalizować przed odwołaniem do zmiennych wskazywanych! • alokacja nowej zmiennej (nie zapomnij o dealokacji) • przypisanie adresu istniejącej zmiennej

  7. Inicjalizacja wskaźnika • Procedury new i dispose var pr : ^real; begin new(pr); { rezerwacja obszaru pamięci (6 bajtów - tyle ma real) } { Teraz można używać zarezerwowanego obszaru } pr^ := 2.718; { tak się odwołujemy do zarezerwowanego obszaru } pr^ := 2*pr^; { identycznie jak wyżej, pr^ jest typu real } writeln(pr^); { identycznie jak wyżej, pr^ jest typu real } { Po zakończeniu używania zarezerwowanego obszaru pamięci} {należy go koniecznie zwolnić!!! } dispose(pr); { Od tej chwili nie należy używać pr^ } end.

  8. Zwolnienie wskaźnika • Nie należy zwalniać niezarezerwowanego obszaru pamięci ani zwalniać ponownie tego samego (już zwolnionego) obszaru pamięci! • Jeśli programista nie zwolni zarezerwowanego przez siebie obszaru pamięci, to nie będzie on dostępny dla następnych wywołań procedury new. Jednak po zakończeniu wykonywania programu wszystkie zarezerwowane obszary zostaną automatycznie zwolnione. • Podobny efekt, ale przed zakończeniem programu, można uzyskać wykorzystując parę procedur mark i release.

  9. nil • wyróżnina, specjalna wartość zmiennej wskaźnikowej każdego typu wskaźnikowego • nil w innych językach

  10. Operator @(TP) type tpr = ^real; var pr : tpr; x : double; t : array [0..5] of byte; begin pr = @x; pr^ := 2.718; {Nie wykonujemy dispose!!! } end. • Operator @ zwraca typ wskaźnikowy nie związany z konkretnym typem bazowym (pointer). Dlatego możliwe jest „mieszanie typów” i odwoływanie się do tego samego obszaru pamięci traktując go jak zmienne różnych typów.

  11. Wskaźniki do funkcji i procedur • Po co nam wskaźniki do funkcji i procedur?

  12. To się przydaje: wskaźniki do struktur zawierających wskaźniki • czy na każdą zmienną alokowaną dynamicznie musi przypadać jeden wskaźnik? type tr2 = ^telem; telem = record{ taki typ będzie czytelniejszy } { po narysowaniu } dana: real; { ew. inne pola } nast: tr2 end;

  13. type tr2 = ^telem; telem = record dana: real; { ew. inne pola } nast: tr2 end; var glowa, p1 : tr2; procedure wypisz(el: tr2); begin while el<>nil do begin writeln(el^.dana); el:=el^.nast end end; Lista dynamiczna

  14. begin new(p1); glowa := p1; { utwórz pierwszy element} p1^.dana := 10.0; p1^.nast := nil; {kolejny element} new(p1); { nowa zmienna dynamiczna! } p1^.nast := glowa; { wstawimy na początek listy } glowa := p1; { czyli to jest nowy początek listy } p1^.dana := 8.0; wypisz(glowa); { usun(glowa); } {wypada posprzątać } end.

  15. Usuwanie listy procedure usun(el: tr2); var p: tr2; begin while el<>nil do begin p:=el; el:=el^.nast; dispose(p); { UWAGA: po tym nie można byłoby } { wykonać el:=el^.nast ! } end end;

  16. Struktury dynamiczne • Lista jednokierunkowa • Lista dwukierunkowa • Listy cykliczne • Drzewo binarne • Inne drzewa • Lista a tablica – kiedy wybrać listę?

  17. Wskaźniki (16-bit TurboPascal) • Funkcja Addr(X):pointer. X może być zmienną lub identyfikatorem programu. • Funkcja Ofs(X):word zwraca offset zmiennej (podprogramu) X. • Funkcja Seg(X):word zwraca segment zmiennej (podprogramu) X. • Funkcja Ptr(Seg, Ofs: Word): Pointer tworzy wskaźnik na podstawie podanych wartości segmentu i offsetu. • Adresy wirtualne (kod 16-bit, maszyna 32-bit).

  18. Wskaźniki (16-bit TurboPascal) • Przypisania dozwolone pomiędzy różnymi typami wskaźników (nie sprawdzane)! • funkcja memavail • funkcja maxavail • typ pointer

  19. Wskaźniki (16-bit TurboPascal) • Tablice predefiniowane mem* i port*(mem, memw, meml) mem[$1234:$5678]:=85 • Słowo kluczowe absolute var a: real; { nowa zmienna } b: integer absolute $b000:0000; { określenie konkretnego } {miejsca w pamięci } c: integer absolute a; { zmienna c w tym samym miejscu} { pamięci co zmienna a }

  20. type tekran = array[0..24,0..79] ofrecord znak, atrybut: byte end; tel = record k: integer; { klucz } wyst: integer; { liczba wystąpień } lewy,prawy: pel end; var ekran: tekran absolute $b800:0 { mode co80; dla mode mono: $b000:0 } e2: tekran; { np. do zapamiętywania zawartości ekranu } begin ekran[0,10].znak:=65; { litera A na 11 pozycji górnego wiersza ekranu } e2:=ekran; { zapamiętanie zawartości całego ekranu } {.....} ekran:=e2; { odtworzenie zawartości całego ekranu } end.

  21. Wskaźniki • UWAGA: struktura s zmniejszy dostępny obszar sterty o nie mniej niż sizeof (s) • Fragmentacja pamięci – to jest problem: użyj maxavail

  22. Przykłady • Wstawianie elementu na koniec listy • Lista dwukierunkowa. • Wyszukiwanie elementu w liście. • Lista cykliczna. • Testowanie cykliczności listy. • Drzewo binarne. • Stos, kolejka. • Uporządkowane drzewo binarne

  23. Listy dynamiczne • Uwaga na przypadki szczególne: • lista jest pusta • lista ma tylko jeden element • jesteśmy na początku/końcu listy • Uwaga na przypadek typowy: • nie początek i nie koniec nie pustej listy

  24. Przykład • Uporządkowane drzewo binarne type pel = ^tel; tel = record k: integer; { klucz } wyst: integer; { liczba wystąpień } lewy,prawy: pel end; var korzen: pel;

  25. procedure wstaw(var p:pel; dana: integer); begin if p=nil then begin new(p); with p^ do{ problematyczne to with! } begin k:=dana; wyst:=1; lewy:=nil; prawy:=nil end end else if dana=p^.k then inc(p^.wyst) else if dana<p^.k then wstaw(p^.lewy,dana) else wstaw(p^.prawy,dana) end;

  26. procedure wypisz(p:pel); begin if p<>nil then begin wypisz(p^.lewy); writeln(p^.k:5,' (',p^.wyst,')'); wypisz(p^.prawy); end end; begin wstaw(korzen,3); wstaw(korzen,1); wstaw(korzen,4); { ....... } wstaw(korzen,5); wypisz(korzen); end.

  27. Przykład • Uporządkowane drzewo binarne – zalety tej struktury dynamicznej type pel = ^tel; tel = record k: integer; { klucz } wyst: integer; { liczba wystąpień } lewy,prawy: pel end; var korzen: pel;

  28. Przykład • Sortowanie listy przez proste wstawianie type tw = ^tel; tel = record dana: real; nast: tw end; const glowa: tw = nil; • Mniej przypadków szczególnych: pomocniczy element na początku listy

  29. type tw = ^tel; tel = record dana: real; nast: tw end; const glowa: tw = nil; procedure wstaw(co: tw); { wyszukuje miejsce i wstawia } procedure wypisz(p: tw); { wypisuje całą listę } procedure usun(var p: tw); { usuwa całą listę } function nowy(x:real):tw; { alokuje element i zwraca jego adres }

  30. procedure wstaw(co: tw); { wyszukuje miejsce i wstawia } var p,p1:tw; begin { Zakładamy, że mamy na początku wartownika!!! } p1:=glowa; p:=glowa; while (p<>nil) and (p^.dana<co^.dana) do begin p1:=p; p:=p^.nast; end; { tutaj p=nil albo p^.dana>=co^.dana, czyli musimy wstawić PRZED p^, czyli ZA p1^ } wstaw_za(co,p1) end;

  31. Jak wstawić za danym elementem? procedure wstaw_za(co, za_czym: tw); { wstawia co^ za za_czym^ } var p:tw; begin if za_czym = nil then begin writeln('Za nilem nie wstawiam'); halt end; co^.nast:=za_czym^.nast; za_czym^.nast:=co end;

  32. procedure wypisz(p: tw); begin writeln('-----------'); while p<>nil do begin writeln(p^.dana:10:5); p:=p^.nast end end; procedure usun(var p: tw); var p1: tw; begin while p<>nil do begin p1:=p^.nast; dispose(p); p:=p1 end end;

  33. function nowy(x:real):tw; var p: tw; begin if maxavail<sizeof(p^) then begin writeln('Zabrakło pamięci'); halt end; new(p); p^.dana:=x; p^.nast:=nil; nowy := p end;

  34. begin writeln('Początek: ',memavail); new(glowa); { to będzie element pusty} glowa^.dana:=-9999;{ zakładamy, że nikt nie wstawi -10000 } glowa^.nast:=nil; wstaw(nowy(2)); { wstawianie w odpowiednie miejsce listy } wstaw(nowy(-333)); wstaw(nowy(4)); wypisz(glowa); usun(glowa); writeln('Koniec: ',memavail); end.

More Related