dyn.pdf
(
341 KB
)
Pobierz
Zmienne dynamiczne
Informatyka
EP AGH Kr
-
1
-
Zmienne
dynamiczne -
podstawowe pojęcia
Każdy skompilowany program, napisany w Turbo/Borland Pascalu zajmuje cześć pamięci operacyjnej
komputera
, w sposób
przedstawiony na rysunku poniżej.
HeapEnd
wolny obszar stosu
HeapPtr
stos dla zmiennych dynamicznych
bufor nakładkowy
HeapOrg
OvrHeapEnd
OvrHeapOrg
segment stosowy dla zmiennych lokalnych
SSeg:SPtr
wolny obszar segmentu stosowego
SSeg:0000
zmienne globalne
segment danych
literały zmienne
DSeg:0000
blok kodu modułu System
blok kodu pierwszego modułu
zawartość obrazu
bloki kodu kolejnych modułów
zbioru .EXE
blok kodu ostatniego modułu
blok kodu programu
blok wstępny programu (PSP)
PrefixSeg
Blok wstępny
Þ
Kod programu
Þ
Kody modułów
Þ
4
Podczas wczytywania zbioru .EXE do pamięci, system operacyjny DOS tworzy
blok wstępny programu
(blok
PSP
). Ten obszar
pamięci służy do komunikacji pomiędzy systemem operacyjnym i programem. Blok PSP (Program Segment Prefix) zajmuje 256 bajtów.
Adres segmentu pamięci, od którego rozpoczyna się ten blok jest pamiętany w predefiniowanej zmiennej PrefixSeg.
4
Kod programu głównego zajmuje pierwszy
blok kodowy
.
4
W kolejnych blokach pamiętane są kody zadeklarowanych w programie modułów (w odwrotnej kolejności niż zadeklarowane). W
ostatnim bloku kodowym pamiętany jest kod standardowego modułu
System
.
4
Żaden z bloków kodowych nie może zając więcej niż 64 kB pamięci, natomiast rozmiar wszystkich bloków łącznie jest
ograniczony jedynie wielkością pamięci komputera.
Segment danych
Þ
Segment stosowy
Þ
Bufor nakładkowy
Þ
♦
W segmencie danych
pamiętane są wszystkie literały zmienne zdefiniowane w programie i modułach oraz zmienne globalne
zadeklarowane w programie i modułach. Początek adresu tego segmentu jest wartością standardowej funkcji DSeg. Rozmiar segmentu
danych (podobnie jak poszczególnych segmentów kodowych) nie może przekraczać 64 kB.
♦
W segmencie stosowym
pamiętane są zmienne lokalne. Kolejne zmienne zapamiętywane są w kierunku malejących adresów
pamięci. Rozmiar segmentu stosowego (max 64 kB) ustala się za pomocą dyrektywy kompilatora M lub w menu systemu Turbo/Borland
Pascal.
♦
Do przechowywania segmentów nakładkowych programu jest wykorzystywany
bufor nakładkowy.
Jeśli program nie posiada
segmentów nakładkowych, rozmiar tego bufora jest równy zeru. Adresy początku i końca bufora nakładkowego pamiętane są
w predefiniowanych zmiennych OvrHeapOrg i OvrHeapEnd.
Zmienne statyczne a dynamiczne
Þ
Sterta
Þ
♦
Zmienne typu statycznego
(globalne - umieszczane w segmencie danych i lokalne - umieszczane w segmencie stosowym)
istnieją
przez cały czas wykonywania tej części programu, w której są zadeklarowane
. Każdy z tych segmentów ma rozmiar
maksymalny równy 65635 bajtów.
4
W Turbo/Borland Pascalu, obok zmiennych statycznych występują zmienne dynamiczne reprezentujące obiekty dla
których pamięć jest przydzielana na określone żądanie. Zmienne te nie posiadają identyfikatorów, a odwołanie do nich
następuje za pomocą wskaźnika. Wartościami zmiennych dynamicznych są elementy typu wskaźnikowego, które
określają adresy pamięci zmiennych dynamicznych.
♦
Zmienne dynamiczne przechowywane są na
stosie dla zmiennych dynamicznych (na stercie)
. Pamięć dla tych zmiennych jest
przydzielana za pomocą standardowych procedur New i GetMem. Zmienne dynamiczne mogą zajmować całą resztę pamięci dostępną
podczas wykonywania programu. Adres początku stosu pamiętany jest w zmiennej HeapOrg, a adres wierzchołka stosu w zmiennej
HeapPtr.
Informatyka
EP AGH Kr
-
2
-
Definicja typu wskaźnikowego
Þ
Definicja typu wskaźnikowego ma postać:
type
identyfikator_typu_wskaźnikowego
=
^identyfikator_typu_bazowego;
Zmienne typu wskaźnikowego wskazują na dane typu bazowego.
Identyfikator typu bazowego może być określony wcześniej lub w tym samym
zdaniu type, w którym występuje definicja danego typu wskaźnikowego.
Przykłady:
a)
type
Macierz = Array[1..10, 1..10] of Byte;
Macierz_dynamiczna = ^Macierz;
b)
type
Lista_dynamiczna = ^Lista;
Lista = record
Lp : Byte
X,Y : Real;
end;
c)
type
Liczba = ^LongInt;
Zmienne wskaźnikowe
Þ
Po wprowadzeniu deklaracji:
var
M : Macierz_dynamiczna;
L : Lista_dynamiczna;
zmiennej wskaźnikowej M można będzie w programie przypisywać adresy pamięci danych (zmiennych dynamicznych) typu Macierz,
natomiast zmiennej wskaźnikowej L - adresy pamięci danych (zmiennych dynamicznych) typu Lista.
Deklaracja zmiennej wskaźnikowej
var
x : Liczba
umożliwi przypisanie zmiennej x adresów pamięci danych (zmiennych dynamicznych) typu LongInt.
Zmienne wskaźnikowe można również zadeklarować następująco:
var
M1 : ^Macierz; L1 : ^Lista; X1 : ^LongInt;
Zmienne dynamiczne pamiętane są segmencie pamięci o strukturze stosowej.
Zmienne wskazywane
Þ
Aby odwołać się do zmiennej typu wskaźnikowego stosuje się zmienne wskazywane postaci:
zmienna_wskaźnikowa^
Przykład:
type
Lista = record
Lp : Byte; X,Y : Real;
end;
Lista_dynamiczna = ^Lista;
var
L : Lista_dynamiczna;
Zmienna wskaźnikowa L jest związana z typem wskaźnikowym Lista_dynamiczna. Wartościami zmiennej wskaźnikowej L będą adresy
pamięci danych (zmiennych dynamicznych) typu Lista. Zmienna wskazywana L^ będzie natomiast rekordem typu Lista o adresie
określonym przez zmienną wskaźnikową L.
Odwołania za pomocą zmiennych wskazywanych:
Þ
Odwołania typu
L.Lp:=1;
L.X:=10.0;
L.Y:=20.0;
są błędne, ponieważ L jest zmienną wskaźnikową.
Poprawne odwołanie powinno być zapisane za pomocą zmiennych wskazywanych:
L^.Lp:=1; L^.X:=10.0;
(wcześniej jednak należy w odpowiedni sposób utworzyć zmienną dynamiczną).
Zmienne wskazywane stosuje się przede wszystkim do dynamicznego zarządzania pamięcią operacyjną. Do tworzenia i zwalniania
zmiennych dynamicznych oraz do zarządzania obszarem pamięci przeznaczonym na zmienne dynamiczne służą procedury i funkcje
standardowe:
4
New, GetMem
- do utworzenia zmiennej dynamicznej i podstawienia pod zmienną wskaźnikową
odpowiedniego adresu pamięci.
4
Dispose, FreeMem, Release
- do zwolnienia obszaru pamięci dynamicznej (usunięcia odpowiedniej
zmiennej dynamicznej z pamięci).
4
Mark, MaxAvail, MemAvail.
L^.Y:=20.0;
Informatyka
EP AGH Kr
-
3
-
4
Procedura
New
New
(zmienna_wskaźnikowa)
lub
New
(zmienna_wskaźnikowa, konstruktor)
- do utworzenia zmiennej dynamicznej typu obiektowego
.
Przykład:
New(L);
Do utworzonej zmiennej dynamicznej można odwołać się za pomocą zmiennej wskazywanej postaci zmienna_wskaźnikowa^, np:
L^.Lp:=1; L^.X:=10.0; L^.Y:=20.0;
Zmiennej dynamicznej tworzonej za pomocą procedury New jest przydzielany blok pamięci równy rozmiarowi typu, z którym związana
jest wyspecyfikowana zmienna wskaźnikowa. W przykładzie powyżej, zmiennej dynamicznej będzie przydzielony blok pamięci równy 13
bajtów (Lp - 1 bajt, X,Y - po 6 bajtów).
4
Procedura
GetMem
GetMem
(zmienna_wskaźnikowa, rozmiar_pamięci)
Rozmiar_pamieci jest wyrażeniem typu Word określającym rozmiar pamięci rezerwowany na zmienną dynamiczną.
Przykład:
GetMem(L,13);
jest równoważne
New(L);
4
Procedura
Dispose
Dispose
(zmienna_wskaźnikowa)
lub
Dispose
(zmienna_wskaźnikowa, destruktor) -
do zwolnienia pamięci zajmowanej przez obiekt dynamiczny.
Procedura Dispose zwalnia obszar pamięci zajmowany przez zmienną wskazywaną.
Na przykład:
Dispose
(L);
(Uwaga, wymagane jest, aby zwalniana zmienna dynamiczna była uprzednio utworzona za pomocą procedury New).
4
Procedura
FreeMem
FreeMem
(zmienna_wskaźnikowa, rozmiar_pamięci)
Procedura ta zwraca do stosu przeznaczonego na zmienne dynamiczne obszar pamięci wskazywany zmienną_wskaźnikową i zajmujący
liczbę bajtów określoną argumentem rozmiar_pamięci, Np.
FreeMem
(L,13);
(Uwaga, wymagane jest, aby rozmiar_pamięci był taki sam jak w wywołaniu procedury GetMem tworzącej tę zmienną dynamiczną.
4
Procedura
Release
Release
(zmienna_wskaźnikowa)
Procedura ta usuwa ze stosu zmienną dynamiczną wskazywaną zmienną_wskaźnikową oraz wszystkie zmienne następujące po niej.
Przykład:
{
$M
30000,0,655008}
type
Wektor_statyczny =
Array
[1..50]
of
Byte
;
Wektor_dynamiczny = ^Wektor_statyczny;
Macierz_dynamiczna =
Array
[1..100]
of
Wektor_dynamiczny;
var
M : Macierz_dynamiczna; i, j :
Integer
; rozmiar:
LongInt
;
begin
rozmiar:=
SizeOf
(M); { wyznaczenie rozmiaru zmiennej wskaźnikowej M }
Writeln
('Maksymalny blok pamieci : ',
MaxAvail
);
Writeln
('Rozmiar zmiennej wskaznikowej M : ',rozmiar);
for
i:=1
to
100
do
New
(M[i]);
{ przydzielenie pamięci zmiennej dynamicznej wskazywanej przez M[i] }
for
i:=1
to
100
do
for
j:=1
to
50
do
M[i]^[j]:=i+j;
{ wartość i+j jest przypisywana zmiennej wskazywanej o adresie określonym przez M[i] }
for
i:=1
to
100
do
for
j:=1
to
50
do
Writeln
(M[i]^[j]);
for
i:=100
downto
1
do
Dispose
(M[i]);
{ zwolnienie obszaru pamięci zajmowanego przez zmienną dynamiczną wskazywaną przez M[i]}
end
.
Informatyka
EP AGH Kr
-
4
-
Przykład programu umożliwiającego analizę wykorzystania pamięci operacyjnej
program
analiza;
{$M 1024,0,30}
type
s60
=
String
[60];
var
a,b,c,d,s :
LongInt
;
g,h,i
:
^Double
;
t
:
Text
;
procedure
pisz(napis:S60; liczba:LongInt);
begin
Writeln(t,napis:60,liczba:30)
end
;
procedure
pisz10 (napis:S60; liczba1,liczba2:LongInt);
begin
Write(t,napis:60,' ',liczba1,':');
case
liczba2
of
0..9 : Write (t, '000',liczba2);
10..99 : Write (t, '00',liczba2);
99..999 : Write (t, '0',liczba2)
else Write (t, liczba2);
end
; {case }
Write (t, (liczba1*16+liczba2):16 );
end
; { pisz10 }
procedure
pisz16(liczba1,liczba2:Word);
const
znak :
Array
[0..$F]
of Char
= '0123456789ABCDEF';
begin
Write(t,' ');
Write(t, znak [
Hi
(liczba1)
shr
4] );
Write(t, znak [
Hi
(liczba1)
and
$F] );
Write(t, znak [
Lo
(liczba1)
shr
4] );
Write(t, znak [
Lo
(liczba1)
and
$F] );
Write(t,':');
Write(t, znak [
Hi
(liczba2)
shr
4] );
Write(t, znak [
Hi
(liczba2)
and
$F] );
Write(t, znak [
Lo
(liczba2)
shr
4] );
Write(t, znak [
Lo
(liczba2)
and
$F] );
Writeln(t);
end
; { pisz16 }
procedure
jeden;
var
d,e,f:
Double
;
begin
pisz10('Adres wolnego segmentu stos. dla zm.lokalnych',
SSeg
,0);
pisz16(
SSeg
,0);
Writeln(t);
pisz('Wolna przestrzen segmentu dla zm. lokalnych *',
SPtr
);
pisz10('Adres ost. zajetego bajtu w seg. stos. *',
SSeg
,
SPtr
);
pisz16(
SSeg
,
SPtr
);
Informatyka
EP AGH Kr
-
5
-
pisz10('Adres 1-ego zajetego bajtu w seg. stos. *',
SSeg
,1023);
pisz16(
SSeg
,1023);
pisz('Rozmiar segmentu stosowego zajetego przez zmienne lokalne *',(s*
OvrHeapOrg
-(s*
SSeg
+
SPtr
)) );
Writeln(t);
pisz('Razem max. rozmiar segmentu stosowego dla zmiennych lokalnych',s*(
OvrHeapOrg
-
SSeg
) );
Writeln(t);
pisz10('Adres zmiennej lokalnej d {rozmiar 8}',
Seg
(d),
Ofs
(d) );
pisz16(
Seg
(d),
Ofs
(d));
pisz10('Adres zmiennej lokalnej e {rozmiar 8}',
Seg
(e),
Ofs
(e) );
pisz16(
Seg
(e),
Ofs
(e));
pisz10('Adres zmiennej lokalnej f {rozmiar8 }',
Seg
(f),
Ofs
(f) );
pisz16(
Seg
(f),
Ofs
(f));
Writeln(t);
end
; { jeden }
procedure
dwa;
begin
pisz10('Adres zmiennej dynamicznej wskazywanej przez g^ {rozmiar 8}',
Seg
(g^),
Ofs
(g^));
pisz16(
Seg
(g^),
Ofs
(g^));
pisz10('Adres zmiennej dynamicznej wskazywanej przez h^ {rozmiar 8}',
Seg
(h^),
Ofs
(h^));
pisz16(
Seg
(h^),
Ofs
(h^));
pisz10('Adres zmiennej dynamicznej wskazywanej przez i^ {rozmiar 8}',
Seg
(i^),
Ofs
(i^));
pisz16(
Seg
(i^),
Ofs
(i^));
end
; { dwa }
begin
{ analiza }
Assign
(t,'8.res');
Rewrite
(t);
s:=16;
for a:=1 to 66 do Write(t,' ');
Writeln(t,'Seg:Ofs Seg*16+Ofs $$$$:FFFF');
Writeln(t);
pisz10('Adres poczatku bloku PSP',
PrefixSeg
,0);
pisz16(
PrefixSeg
,0);
pisz('Rozmiar bloku PSP',256);
Writeln(t);
pisz10('Adres bloku kodu programu od',
CSeg
,0);
pisz16(
CSeg
,0);
for a:=1 to 42 do Write(t,' ');
Writeln(t,'Rozmiar zbioru EXE',s*(
DSeg
-
CSeg
):30);
Writeln(t);
pisz10('Adres poczatku segmentu danych',
DSeg
,0);
pisz16(
DSeg
,0);
pisz('Rozmiar segmentu danych',s*(
SSeg
-
DSeg
));
Writeln(t);
pisz10('Adres zmiennej globalnej a {4 bajty }',
Seg
(a),
Ofs
(a));
pisz16(
Seg
(a),
Ofs
(a));
pisz10('Adres zmiennej globalnej b {4 bajty }',
Seg
(b),
Ofs
(b));
Plik z chomika:
evil_aangel
Inne pliki z tego folderu:
binarne drzewa poszukiwań.pdf
(147 KB)
binarne drzewa poszukiwań1.pdf
(207 KB)
dyn.pdf
(341 KB)
MergeSort.pdf
(58 KB)
Kolejki.pdf
(289 KB)
Inne foldery tego chomika:
PK
Problemy społeczne i zawodowe informatyki
Zgłoś jeśli
naruszono regulamin