Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Typy wskaźnikowe, dynamiczne struktury danych. Sterta przeznaczenie stosu (przypomnienie) przeznaczenie stosu (przypomnienie) sterta sterta.

Podobne prezentacje


Prezentacja na temat: "Typy wskaźnikowe, dynamiczne struktury danych. Sterta przeznaczenie stosu (przypomnienie) przeznaczenie stosu (przypomnienie) sterta sterta."— Zapis prezentacji:

1 Typy wskaźnikowe, dynamiczne struktury danych

2 Sterta przeznaczenie stosu (przypomnienie) przeznaczenie stosu (przypomnienie) sterta sterta

3 Typ wskaźnikowy type typ_wskaznikowy = ^typ_wskazywany; typ_wskaznikowy = ^typ_wskazywany; np.: np.:type tpr = ^real;{ zmienne typu pr będą} tpr = ^real;{ zmienne typu pr będą} { wskaźnikami na zmienne real } { wskaźnikami na zmienne real } var var pr : tpr;{ można było też od razu napisać pr: ^real } 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: wskaźnik jak każda zmienna jest określony przez: 1. typ 2. rozmiar – niezależny od typu zmiennej wskazywanej 3. adres 4. zbiór operacji – silnie ograniczony zmienna wskazywana to również zmienna zmienna wskazywana to również zmienna własności wynikają z jej typu własności wynikają z jej typu

5 Wskaźnik Rozmiar zmiennej wskaźnikowej: 4 bajty Rozmiar zmiennej wskaźnikowej: 4 bajty kompilator 32-bitowy: 4B adres kompilator 32-bitowy: 4B adres kompilator 16-bitowy: 2B segment + 2B offset kompilator 16-bitowy: 2B segment + 2B offset kompilator 16-bitowy, mały model pamięci: 2B offset, segment domyślny 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 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! Wskaźniki należy inicjalizować przed odwołaniem do zmiennych wskazywanych! alokacja nowej zmiennej (nie zapomnij o dealokacji) alokacja nowej zmiennej (nie zapomnij o dealokacji) przypisanie adresu istniejącej zmiennej przypisanie adresu istniejącej zmiennej

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

8 Zwolnienie wskaźnika Nie należy zwalniać niezarezerwowanego obszaru pamięci ani zwalniać ponownie tego samego (już zwolnionego) obszaru pamięci! 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. 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. 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 wyróżnina, specjalna wartość zmiennej wskaźnikowej każdego typu wskaźnikowego nil w innych językach nil w innych językach

10 (TP) type type tpr = ^real; tpr = ^real; var var pr : tpr; pr : tpr; x : double; x : double; t : array [0..5] of byte; t : array [0..5] of byte; begin begin pr pr pr^ := 2.718; { Nie wykonujemy dispose!!! } pr^ := 2.718; { Nie wykonujemy dispose!!! } end. end. 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. 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? 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? czy na każdą zmienną alokowaną dynamicznie musi przypadać jeden wskaźnik? type type tr2 = ^telem; tr2 = ^telem; telem = record{ taki typ będzie czytelniejszy } telem = record{ taki typ będzie czytelniejszy } { po narysowaniu } dana: real; dana: real; { ew. inne pola } { ew. inne pola } nast: tr2 nast: tr2 end; end;

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

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

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

16 Struktury dynamiczne Lista jednokierunkowa Lista jednokierunkowa Lista dwukierunkowa Lista dwukierunkowa Listy cykliczne Listy cykliczne Drzewo binarne Drzewo binarne Inne drzewa Inne drzewa Lista a tablica – kiedy wybrać listę? 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 Addr(X):pointer. X może być zmienną lub identyfikatorem programu. Funkcja Ofs(X):word zwraca offset zmiennej (podprogramu) X. Funkcja Ofs(X):word zwraca offset zmiennej (podprogramu) X. Funkcja Seg(X):word zwraca segment 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. 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). 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)! Przypisania dozwolone pomiędzy różnymi typami wskaźników (nie sprawdzane)! funkcja memavail funkcja memavail funkcja maxavail funkcja maxavail typ pointer typ pointer

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

20 type tekran = array[0..24,0..79] of record znak, atrybut: byte znak, atrybut: byte end; end; tel = record tel = record k: integer; { klucz } k: integer; { klucz } wyst: integer; { liczba wystąpień } wyst: integer; { liczba wystąpień } lewy,prawy: pel lewy,prawy: pel end; end;var ekran: tekran absolute $b800:0 { mode co80; dla mode mono: $b000:0 } ekran: tekran absolute $b800:0 { mode co80; dla mode mono: $b000:0 } e2: tekran; { np. do zapamiętywania zawartości ekranu } e2: tekran; { np. do zapamiętywania zawartości ekranu }begin ekran[0,10].znak:=65; { litera A na 11 pozycji górnego wiersza ekranu } ekran[0,10].znak:=65; { litera A na 11 pozycji górnego wiersza ekranu } e2:=ekran; { zapamiętanie zawartości całego ekranu } e2:=ekran; { zapamiętanie zawartości całego ekranu } {.....} {.....} ekran:=e2; { odtworzenie 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) UWAGA: struktura s zmniejszy dostępny obszar sterty o nie mniej niż sizeof (s) Fragmentacja pamięci – to jest problem: użyj maxavail Fragmentacja pamięci – to jest problem: użyj maxavail

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

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

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

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

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

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

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

29 type tw = ^tel; tel = record tel = record dana: real; dana: real; nast: tw nast: tw end; end;const glowa: tw = nil; glowa: tw = nil; procedure wstaw(co: tw); { wyszukuje miejsce i wstawia } { wyszukuje miejsce i wstawia } procedure wypisz(p: tw); { wypisuje całą listę } { wypisuje całą listę } procedure usun(var p: tw); { usuwa całą listę } { usuwa całą listę } function nowy(x:real):tw; { alokuje element i zwraca jego adres } { 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!!! } { Zakładamy, że mamy na początku wartownika!!! } p1:=glowa; p1:=glowa; p:=glowa; p:=glowa; while (p<>nil) and (p^.dana nil) and (p^.dana=co^.dana, czyli musimy { tutaj p=nil albo p^.dana>=co^.dana, czyli musimy wstawić PRZED p^, czyli ZA p1^ } wstawić PRZED p^, czyli ZA p1^ } wstaw_za(co,p1) wstaw_za(co,p1) end;

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

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

33 function nowy(x:real):tw; var p: tw; begin if maxavail

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


Pobierz ppt "Typy wskaźnikowe, dynamiczne struktury danych. Sterta przeznaczenie stosu (przypomnienie) przeznaczenie stosu (przypomnienie) sterta sterta."

Podobne prezentacje


Reklamy Google