to get the file

Transkrypt

to get the file
Instrukcja
Podstawy programowania 2
laboratoryjna
1
Temat: Wprowadzenie do wskaźników
Przygotował: mgr inż. Tomasz Michno
1 Wstęp teoretyczny
Rysunek przedstawia najważniejszą różnicę pomiędzy zmiennymi, a wskaźnikami: zmienna
przechowuje dane (bezpośrednio wskazuje na komórkę w pamięci z danymi), natomiast wskaźnik
przechowuje adres w pamięci, za pomocą którego można uzyskać dostęp do danych. To, jak
zostaną rozpoznane dane znajdujące się pod tym adresem, zależy od zadeklarowanego typu
wskaźnika (istnieje możliwość zmiany rozpoznawanego typu za pomocą rzutowania, jednak nie
będziemy się tym na razie zajmowali).
1.1 Deklarowanie wskaźników
Wskaźniki deklaruje się bardzo podobnie jak zwykłe zmienne - w celu utworzenia wskaźnika
wystarczy poprzedzić typ znakiem „^”:
nazwaWskaźnika : ^typ;
W celu uzyskania dostępu do wartości, która znajduje się pod wskazywanym przez wskaźnik
adresem, należy użyć znaku „^” za wskaźnikiem. Dostęp taki pozwala zarówno na odczyt, jak
i modyfikację.
Przykładowo, wskaźnik typu integer można zadeklarować następująco:
wskaznik : ^integer;
Natomiast odczytanie wartości i wyświetlenie jej na ekranie może zostać napisane następująco:
writeln( 'Wartosc odczytana przez wskaznik: ', wskaznik^ );
1.2 Wskaźniki i zmienne
Wskaźniki mogą wskazywać na zmienne deklarowane standardowo (w sekcji var) oraz
na zmienne dynamiczne (tworzone w trakcie działania programu), z którymi najczęściej
są wykorzystywane.
Aby powiązać wskaźnik ze „zwykłą” zmienną, wystarczy przypisać do niego adres
tej zmiennej. Adres zmiennej można uzyskać poprzedzając zmienną znakiem @.
przykład:
var
liczba
: integer;
wskaznik : ^integer;
BEGIN
{...}
wskaznik := @liczba;
writeln('Liczba odczytana przez wskaznik: ', wskaznik^ );
{...}
END.
Początkowo taki sposób dostępu do danych może wydawać się niepotrzebnym
utrudnieniem, jednak jak się zaraz okaże może być przydatny.
Przykład 1.
Wskaźnik może być przydatny, gdy chcemy zdecydować podczas działania programu, którą
zmienną przetwarzać bez niepotrzebnego kopiowania tego samego kodu dla każdej zmiennej.
Alternatywnym rozwiązaniem jest użycie dodatkowej zmiennej (która przechowa wartość
do przetworzenia), jednak nie jest zalecane ze względu na większe zużycie pamięci i konieczność
ponownego przypisania wartości do właściwej zmiennej.
Kod z użyciem wskaźnika
program przyklad1;
uses CRT;
var
a,b,c : integer;
wybor : char;
wskaznik : ^integer;
BEGIN
write('Podaj wybor (a, b lub c): ');
readln(wybor);
a:=1; b:=2; c:=3;
wskaznik:=@a;
case wybor of
'a': wskaznik:=@a;
'b': wskaznik:=@b;
'c': wskaznik:=@c;
end;
Kod bez użycia wskaźników
program przyklad1;
uses CRT;
var
a,b,c : integer;
wybor : char;
BEGIN
write('Podaj wybor (a, b lub c): ');
readln(wybor);
a:=1; b:=2; c:=3;
case wybor of
'a':
begin
writeln('wybrano liczbe: ', a);
a:=2-a;
a:=sqr(a);
writeln('liczba po przeksztalceniach: ', a);
end;
'b':
begin
writeln('wybrano liczbe: ', b);
b:=2-b;
b:=sqr(b);
writeln('liczba po przeksztalceniach: ', b);
end;
'c':
begin
writeln('wybrano liczbe: ', c);
c:=2-c;
c:=sqr(c);
writeln('liczba po przeksztalceniach: ', c);
end;
end;
writeln('wybrano liczbe: ', wskaznik^);
wskaznik^:=2-wskaznik^;
wskaznik^:=sqr(wskaznik^);
writeln('liczba po przeksztalceniach: ',
wskaznik^);
readln;
END.
readln;
END.
Przykład 2.
Przekazywanie przez parametr w procedurach i funkcjach – odpowiednik słowa kluczowego var
(w większości języków jest to jedyny sposób na stworzenie odpowiednika słowa var).
program przyklad2;
uses CRT;
type
Pinteger = ^integer;
var
liczba : integer;
procedure dodajDziesiec( wskLiczba : Pinteger );
begin
wskLiczba^:= wskLiczba^ + 10;
end;
BEGIN
liczba:=2;
writeln('Liczba = ', liczba);
dodajDziesiec(@liczba);
writeln('Liczba = ', liczba);
readkey;
END.
1.3 Wskaźniki i zmienne dynamiczne.
Zmienne
dynamiczne
są
zmiennymi
tworzonymi
w trakcie
działania
programu,
w dowolnym momencie jego działania. Ich utworzenie zazwyczaj jest związane z akcją
użytkownika lub określonym stanem programu, co powoduje że trudno jest użyć zwykłych
zmiennych. Często są związane również z dużymi danymi, które nie mogą zostać utworzone
w Pascalu w zwykły sposób (właśnie z powodu rozmiaru) lub gdy niezbędna jest większa kontrola
nad zużyciem pamięci.
Utworzenie zmiennej dynamicznej odbywa się za pomocą procedury New(wskaźnik), która
przydziela aplikacji odpowiedni fragment pamięci, a następnie zapisuje jej adres w podanym jako
parametr wskaźniku. Wielkość przydzielonej pamięci zależy od typu wskaźnika. Bardzo ważne jest,
aby później taki fragment pamięci zwolnić za pomocą procedury Dispose(wskaźnik), ponieważ
w przeciwnym wypadku może dojść do tzw. wycieku pamięci1. Wycieki pamięci polegają
na niezwalnianiu całej przydzielonej pamięci, co przy dużej liczbie alokacji może spowodować
całkowite zapełnienie pamięci dostępnej dla programu. W celu wykrywania takich błędów
przydatna jest zdefiniowana w Pascalu stała o nazwie MemAvail, wyświetlająca ilość wolnej
pamięci.
Przykład:
Program przyklad3;
uses
CRT;
var
wskaznik : ^integer;
BEGIN
clrscr;
writeln('Wolna pamiec: ', MemAvail, ' bajtow.');
New(wskaznik);
writeln('Wolna pamiec: ', MemAvail, ' bajtow.');
Dispose(wskaznik);
writeln('Wolna pamiec: ', MemAvail, ' bajtow.');
readkey;
END.
{wyczyszczenie ekranu}
{wolna pamięć przed alokacją}
{alokacja pamięci}
{wolna pamięć po alokacji}
{zwolnienie przydzielonej pamięci}
{wolna pamięć pod koniec programu}
Wynik działania:
Jak widać powyżej, ilość wolnej pamięci zmniejszyła się po utworzeniu zmiennej dynamicznej,
natomiast po jej usunięciu wróciła do poprzedniej wartości.
2 Zadania
Zadanie 1.
Wypisz liczbę wolnej pamięci (w bajtach).
Zadanie 2.
Napisz program, w którym za pomocą wskaźnika zmienisz wartość zmiennej (tego samego typu).
Wyświetl wyniki na każdym etapie działania programu.
1 Więcej pod adresem: http://pl.wikipedia.org/wiki/Wyciek_pami%C4%99ci
Zadanie 3.
Napisz program, w którym:
a)
•
utworzysz zmienną typu Real (nazwijmy ją zmiennaReal) i przypiszesz jej dowolną wartość
rzeczywistą, np.: zmiennaReal:=1.5;
•
utworzysz wskaźnik typu integer (wsk), który wskazuje na zmiennaReal
•
wyświetlisz zawartość zmiennaReal
•
wyświetlisz zawartość wsk^
•
do wsk przypiszesz dowolną liczbę integer, np.: wsk^:=10;
•
wyświetlisz zawartość zmiennaReal
•
wyświetlisz zawartość wsk^
•
co można było zauważyć?
•
utworzysz zmienną o nazwie znak typu char i przypiszesz do niej dowolną literę (lub inny
b)
znak drukowalny)
•
utworzysz wskaźnik o nazwie wskZnak typu byte, który wskazuje na znak
•
wyświetlisz zawartość znak oraz zawartość wskZnak
•
do wskZnak przypiszesz dowolną liczbę z przedziału od 33 do 126
•
wyświetlisz zawartość znak oraz zawartość wskZnak
•
co można było zauważyć?
Zadanie 4.
Napisz program, który utworzy dwie tablice, każda typu integer indeksowana od 1 do 30000
(rozmiar 60000 bajtów). Spróbuj najpierw utworzyć je jako zwykłe zmienne, a następnie jako
zmienne dynamiczne. Wskazówka: zadeklaruj typ tablicowy.
Zadanie 5.
Napisz procedurę, która będzie dynamicznie tworzyła rekord wizytówki (imię, nazwisko, telefon, email) z wartości podanych jako parametry. Równocześnie procedura ma zwracać poprzez parametr
wskaźnik na nowo utworzony rekord (bez wykorzystania słowa var w parametrze).

Podobne dokumenty