background image

Rozdział 2.

Pascal bardziej zaawansowany

W tym rozdziale będziesz poznawać w dalszym ciągu tajniki języka Object Pascal. Za-

poznasz się z następującymi zagadnieniami:

υ 

Instrukcja warunkowa 

if

 … 

then

 … 

else

υ 

Pętle: 

for

while

 i 

repeat

υ 

Instrukcja wyboru: 

case

υ 

Zakresy widzialności

υ 

Rekordy

υ 

Funkcje i procedury

if, then, else

Istnieją pewne słowa kluczowe, które występują we wszystkich językach programowania.
Jednym z nich jest instrukcja warunkowa if. Instrukcja ta służy do sprawdzania okre-

ślonego warunku w programie i w zależności od tego, czy warunek ten jest spełniony,

wykonywania różnych fragmentów kodu. Oto przykład:

var
  X : Integer;
begin
  X := StrToInt(Edit1.Text);
  if X > 10 then
    Label1.Caption := 'Podałeś liczbę większą od 10.';
end;

W przykładzie tym zawartość pola edycyjnego zapamiętywana jest w zmiennej typu
Integer. Jeżeli liczba ta jest większa od 10, wyrażenie x > 10 otrzymuje wartość

True i wyświetlany jest odpowiedni komunikat. W przeciwnym przypadku nic nie jest

wyświetlane. Innymi słowy – jeżeli wyrażenie warunkowe (zawarte między słowami
if i then) osiąga wartość True (prawda), wykonywana jest instrukcja znajdująca się

bezpośrednio za słowem then.

background image

64

Część I

64

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Instrukcja warunkowa if służy do sprawdzania określonego warunku, i w zależno-
ści od jego spełnienia wykonywania jednej lub więcej linii kodu.

Wykonywanie wielu instrukcji

Załóżmy, że chcesz, aby w przypadku spełnienia warunku wykonywany był blok kodu

składający się z wielu linii. W tym celu musisz te linie objąć słowami kluczowymi 

begin

end

:

if X > 10 then begin
  Label1.Caption := 'Podałeś liczbę większą od 10.';
  ZrobCosZLiczba(X);
end;

Kiedy wyrażenie warunkowe jest fałszywe, cały ten blok jest ignorowany i wykonywa-

na jest pierwsza instrukcja następująca po tym bloku.

Object Pascal posiada wiele zapisów skrótowych ułatwiających pisanie ko-

du i zwiększających jego czytelność. Jeden z nich pozwala sprawdzać, czy

jakaś zmienna typu 

Boolean

 ma wartość 

True

, podając tylko  jej nazwę,

np.:

if OtwartoPlik then CzytajDane;

Powyższa instrukcja ma takie samo znaczenie, co

if OtwartoPlik = True then CzytajDane;

Metoda ta ma zastosowanie tylko w przypadku zmiennych typu Boolean. Z

kolei sprawdzić fałszywość takiej zmiennej można dodając słowo 

not

przed jej nazwą, np.:

var
  OtwartoPlik : Boolean;
begin
  OtwartoPlik := OtworzJakisPlik;
  if not OtwartoPlik then WyswietlKomunikatOBledzie;
end;

Kod z takimi skrótami wygląda po prostu „elegancko”. Poza tym poznawa-

nie ich ułatwi Ci czytanie kodu w programach przykładowych.

1

                                                          

1

 Dla dociekliwych: może to zaskakujące, ale warunek if X nie jest dokładnie tym samym, co wa-

runek if X = TRUE – pierwszy z nich jest prawdziwy, jeżeli reprezentacja zmiennej X zawiera

przynajmniej jeden bit niezerowy, drugi natomiast prawdziwy jest tylko wtedy, jeśli reprezentacja
ta równa jest d o kła dn ie   wartości TRUE (w Delphi 4 Ord(TRUE) równe jest 1) (przyp. red.)

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

65

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

65

Dodajemy else

W niektórych przypadkach istnieje potrzeba wykonania pewnej sekwencji instrukcji,
gdy wyrażenie warunkowe będzie prawdą, i wykonania innej sekwencji instrukcji, gdy
wyrażenie warunkowe będzie fałszem. Do instrukcji warunkowej należy wtedy dodać
słowo 

else

:

if X = 20 then
  ZrobCos(X)
else
  ZrobCosInnego(X);

Słowo kluczowe else używane jest w połączeniu z if i oznacza początek
instrukcji, które wykonywane są, gdy wyrażenie warunkowe osiąga wartość
False.

W powyższym przykładzie w zależności od wartości X wywołana będzie jedna albo
druga funkcja (ale nie obie).

Zwracam też uwagę na to, że instrukcja następująca po słowie 

then

 nie jest zakończona

średnikiem. Dzieje się tak dlatego, że cała sekwencja 

if … then … else

 traktowana jest

jako jedna instrukcja. Przy tym średnika tego nie stosuje się tylko wtedy, gdy między

then

 i 

else

 jest tylko jedna instrukcja (tzn. nie ma ich kilku między słowami 

begin

 i 

end

).

Oto kilka przykładów prawidłowej składni instrukcji warunkowej:

if X = 20 then
  ZrobCos(X) {brak średnika, ponieważ jest to pojedyncza linia}

else
  ZrobCosInnego(X);

if X = 20 then begin
  ZrobCos(X);
  end

   {brak średnika, ponieważ blok begin/end traktowany}

else

begin

   {jest jak pojedyncza linia}

  ZrobCosInnego(X);
  end;

if X = 20 then begin
  ZrobCos(X);    {wiele instrukcji w bloku begin/end, po każdej
  X := 200;

   {jest średnik}

  Y := 30;
  end

else begin
  ZrobCosInnego(X);
  X := 100;
  Y := 15;
  end;

background image

66

Część I

66

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Dla kompilatora nie ma znaczenia, czy słowa 

then,  begin 

else

  są

w jednej, czy też w wielu liniach. Poniższe dwa fragmenty kody są sobie
równoważne:

{Pierwsza wersja}
if X = 20 then begin
  ZrobCos(X);
  X := 200;
  Y := 30;
end else begin
  ZrobCosInnego(X);
  X := 100;
  Y := 15;

end;

{Druga wersja}
if X = 20
then
begin
  ZrobCos(X);
  X := 200;
  Y := 30;
end
else
begin
  ZrobCosInnego(X);

  X := 100;
  Y := 15;
end;

Najlepiej sam obierz sobie jakiś styl i stosuj go konsekwentnie. Najważ-
niejszym kryterium jest przy tym czytelność kodu.

Pamiętaj o tym, że znak „=” oznacza operator równości, natomiast „:=” jest
operatorem przypisania. Częstym błędem jest zamiana tych dwóch operato-
rów. Jednak w tym przypadku kompilator wyświetli odpowiedni komuni-
kat.

Zagnieżdżone instrukcje if

W razie potrzeby istnieje możliwość zagnieżdżania instrukcji 

if

. Zagnieżdżanie jest niczym

innym, jak umieszczaniem instrukcji 

if

 wewnątrz innej instrukcji 

if

.

if X > 10 then
  if X < 20 then
    Label1.Caption := 'Wartość X jest między 10 a 20.';

Jest to jednak bardzo uproszczona sytuacja. W rzeczywistości kod najczęściej jest

znacznie bardziej skomplikowany. Można się czasami naprawdę pogubić w gąszczu

słów 

if

then

begin

 i 

end

. Spójrz na poniższy przykład:

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

67

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

67

if X > 100 then begin
  Y := 20;
  if X > 200 then begin
    Y := 40;
    if X > 400 then begin
      Y := 60;
      ZrobCos(Y);
    end;
  end;
end else if X < -100 then begin
  Y := -20;
  if X < -200 then begin
    Y := -40;
    if X < -400 then begin
      Y := -60;
      ZrobCos(Y);
    end;
  end;
end;

To jeszcze nie był najbardziej skomplikowany przykład, ale wiesz zapewne, o co mi
chodzi.

Jeżeli sytuacja wymaga zastosowania dwóch lub trzech zagnieżdżonych in-
strukcji if, może to być dobra okazja do użycia instrukcji case.

W przykładach przytoczonych do tej pory używałem tylko jednego wyrażenia warun-
kowego w instrukcji 

if

. Kiedy stosowane jest tylko jedno wyrażenie warunkowe, można

je ująć w nawiasy lub nie. Jednakże, jeżeli tych wyrażeń warunkowych jest więcej niż
jedno, musisz ująć każde z nich w nawiasy. Na przykład:

if (X = 20) and (Y=50) then
  ZrobCos;

Gdybyś zapomniał wstawić nawiasów, kompilator poinformowałby Cię o tym wyświe-
tlając odpowiedni komunikat.

Instrukcja warunkowa jest bardzo często spotykana w programach pisanych w Object
Pascalu. Nie jest ona wcale skomplikowana, więc nie będziesz miał z jej stosowaniem
prawdopodobnie żadnych kłopotów. Jedyne, o czym musisz pamiętać, to odpowiednia
liczba słów 

begin

 i 

end

.

Wyrażenie if ... then ... else, wariant 1

Składnia

if wyrazenie_warunkowe then
  instrukcja_wykonywana_gdy_true
else

  instrukcja_wykonywana_gdy_false;

background image

68

Część I

68

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Wyrażenie warunkowe if ... then ... else, wariant 2

Składnia

if wyrazenie_warunkowe_1 then
  begin
  instrukcje_wykonywane_gdy_true;
  end
else
  begin
  instrukcje_wykonywane_gdy_false;
  end;

Pętle

Pętle (instrukcje iteracyjne) są drugim elementem istniejącym chyba we wszystkich ję-
zykach programowania. Mogą być one używane do działań na kolejnych elementach
tablicy, do wykonywania pewnych instrukcji określoną liczbę razy, do sekwencyjnego
odczytywania pliku dyskowego, itd. Liczba zastosowań pętli jest chyba nieograniczona.
Omówię tutaj pętle typu 

for

while

 i 

repeat

. Wszystkie te typy mają pewne wspólne

elementy, a mianowicie:

υ 

Punkt startu

υ 

Blok instrukcji wykonywanych przy każdej iteracji („ciało pętli”)

υ 

Punkt stopu

υ 

Sprawdzenie warunku zakończenia działania pętli

υ 

Możliwość użycia procedur 

Break

 i 

Continue

Pętla jest elementem języka programowania służącym do iteracyjnego wy-
konywania określonych instrukcji aż do spełnienia warunku zakończenia
działania.

Punktem startu pętli jest słowo kluczowe 

for

while

 albo 

repeat

. Ciało pętli stanowi

jedna lub wiele dowolnych instrukcji Object Pascala. Jeżeli instrukcji jest więcej niż
jedna, muszą one być (z wyjątkiem pętli 

repeat

) objęte słowami 

begin

 i 

end

. Punktem

stopu jest w przypadku pętli 

for

 i 

while

 zamykające ciało słowo 

end

, natomiast

w przypadku pętli 

repeat

 punktem stopu jest słowo kluczowe 

until

.

Pętle z reguły działają następująco: Następuje wejście do pętli, następnie sprawdzany
jest warunek zakończenia działania. Jeżeli warunek ten jest fałszywy, wykonywane są
instrukcje stanowiące ciało pętli. Po osiągnięciu punktu stopu następuje skok na począ-
tek i ponowne sprawdzenie warunku zakończenia działania. Jeżeli będzie miał wartość

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

69

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

69

False

, cały cykl się powtarza. W przeciwnym przypadku następuje skok do instrukcji

następnej za punktem stopu, czyli wyjście z pętli. Wyjątkiem jest pętla 

repeat

, w której

sprawdzanie warunku zakończenia działania następuje dopiero po wykonaniu ciała pętli.

Znaczenie warunku zakończenia działania pętli można wyrazić na przykład następująco:
„Wykonuj to i to, dopóki X jest różne od 10” albo „Czytaj kolejne bajty z pliku dopóki
nie osiągniesz jego końca”.

Częstym błędem jest takie skonstruowanie warunku zakończenia działania
pętli, że nie może on nigdy osiągnąć wartości 

True

. W rezultacie tego pro-

gram wpada w nieskończoną pętlę. Jedynym wyjściem jest wtedy zastoso-
wanie kombinacji klawiszy 

Ctrl+Alt+Del

 i „zabicie” tego programu (w

oknie „Zamknij program” lub w Menedżerze Zadań Windows NT zapętlo-
ny program oznaczony jest jako „nie odpowiada”).

W Delphi IDE zwykle uruchamia się programy klikając ikonę „Run” albo
naciskając klawisz F9. Sposobem na „zabicie” tak uruchomionego progra-
mu jest wybranie z menu opcji Run | Program Reset albo naciśnię-
cie kombinacji klawiszy Ctrl+F2. Jednak Windows 95 może zawiesić się
całkowicie po kilkukrotnym użyciu tej opcji (Windows NT jest w tym
przypadku o wiele bardziej odporne). Staraj się więc jej nie nadużywać.

Uzbrojeni w dopiero co zdobytą wiedzę możemy teraz przystąpić do dokładniejszego
zapoznawania się z poszczególnymi typami pętli.

Pętla for

Jest to najpopularniejszy typ pętli. Parametrami tej pętli są wartość początkowa i war-
tość końcowa zmiennej sterującej. Jeżeli wartość początkowa jest mniejsza od wartości
końcowej, używane jest słówko 

to

. Jeżeli natomiast wartość początkowa jest większa

od końcowej, stosowane jest słówko 

downto

.

Składnia

Pętla for, odliczanie do góry
for wartosc_poczatkowa to wartosc_koncowa do begin
  instrukcje;
end;

W tej wersji blok instrukcji oznaczonych jako 

instrukcje

 wykonywany jest dopóty,

dopóki zmienna sterująca zainicjowana wartością 

wartosc_poczatkowa

 nie osiągnie

wartości 

wartosc_koncowa

. Zmienna sterująca jest inkrementowana (jej wartość zwiększa

się o 1) w trakcie każdej iteracji.

background image

70

Część I

70

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Składnia

Pętla for, odliczanie do dołu
for wartosc_poczatkowa downto wartosc_koncowa do begin
  instrukcje;
end;

Ta wersja pętli działa tak samo jak poprzednia z tą różnicą, że zmienna sterująca jest

dekrementowana.

Formalne zapisy zawsze są dość niejasne i trudne z początku do zrozumienia, w prze-

ciwieństwie do przykładów, których kilka przedstawiam poniżej.

Pierwszy z nich ilustruje użycie pętli 

for

 z odliczaniem do góry:

var
  I : Integer;
begin
  for I := 0 to 9 do begin
    Memo1.Lines.Add('Iteracja nr ' + IntToStr(I));
  end;
end;

Instrukcja dodająca linię tekstu do komponentu 

Memo1

 wykona się tutaj 10 razy. Zmienna

sterująca 

I

 przyjmuje kolejno wartości od 0 do 9.

Nazywanie zmiennej sterującej pętli for literą I jest tradycją wywodzącą
się jeszcze z Fortranu i jest często spotykane.

Oto następny przykład, który jest zmodyfikowaną wersją pierwszego:

var
  I : Integer;
begin
  for I := 9 downto 0 do begin
    Memo1.Lines.Add('Iteracja nr ' + IntToStr(I));
  end;
end;

W tym przypadku 

I

 osiąga kolejno wartości od 9 do 0. Słowo 

downto

 wskazuje na to, że

wartość zmiennej sterującej ma być zmniejszana o 1 przy każdym przebiegu pętli.

Stosowanie słów kluczowych begin i end obejmujących jedną instrukcję
(stanowiącą ciało pętli) nie jest wymagane.

Przykładowy program z pętlą for

Nic tak dobrze nie utrwala teorii jak praktyka. Napiszmy więc program, w którym za-
stosujemy pętlę 

for

 i komponent 

Memo

 (wspomniany już wcześniej w tym rozdziale).

Wykonaj następujące czynności:

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

71

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

71

 

1. 

Utwórz nową aplikację (

File | New Application

).

 

2. 

Umieść przycisk na formularzu.

 

3. 

Znajdź komponent 

Memo

 na karcie „Standard” Palety Komponentów (powinien

znajdować się po lewej stronie komponentu 

Button

) i umieść go na formularzu.

 

4. 

Powiększ rozmiar umieszczonego na formularzu komponentu 

Memo1

 poprzez

przeciągnięcie czarnego prostokąta w jego prawym dolnym rogu.

 

5. 

Kliknij podwójnie na przycisku. Otworzy się procedura obsługi 

OnClick

 tego

przycisku. Wpisz do niej:

procedure TForm1.Button1Click(Sender: TObject);
var
  I : Integer;
begin

  Memo1.Lines.Clear;

  for I := 0 to 5 do
    Memo1.Lines.Add('Iteracja nr: ' + IntToStr(I));

  Memo1.Lines.Add('');

  for I := 5 downto 0 do
    Memo1.Lines.Add('Iteracja nr: ' + IntToStr(I));

end;

Uruchom teraz program. Po naciśnięciu przycisku zawartość komponentu 

Memo1

 po-

winna wyglądać jak na rysunku 2.1.

Rysunek 2.1.
Wynik działania
pętli for

Tak jak powiedziałem wcześniej, wartość zmiennej sterującej pętli 

for

  jest  przy  każ-

dym przebiegu zwiększana o 1. Nie ma niestety w Object Pascalu możliwości zmiany
tego kroku. Nie można na przykład odliczać od 0 do 100 z krokiem co 10. Aby uzyskać
taki efekt, należy użyć dodatkowej zmiennej:

background image

72

Część I

72

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

var
  I : Integer;
  X : Integer;
begin
  X := 0;
  Memo1.Lines.Clear;

  for I := 0 to 9 do begin
    Memo1.Lines.Add('Wartość zmiennej w bieżącej iteracji: ' + IntToStr(X));
    Inc(X, 10);
    end;
end;

Po uruchomieniu tak zmodyfikowanego programu na komponencie 

Memo1

 pokazałyby

się linie:

Wartość zmiennej w bieżącej iteracji: 0
Wartość zmiennej w bieżącej iteracji: 10
Wartość zmiennej w bieżącej iteracji: 20
Wartość zmiennej w bieżącej iteracji: 30
Wartość zmiennej w bieżącej iteracji: 40
Wartość zmiennej w bieżącej iteracji: 50
Wartość zmiennej w bieżącej iteracji: 60
Wartość zmiennej w bieżącej iteracji: 70
Wartość zmiennej w bieżącej iteracji: 80
Wartość zmiennej w bieżącej iteracji: 90

Zwróć uwagę na wywołanie procedury Inc. Funkcja ta dodaje do zmiennej
będącej jej parametrem określoną wartość – w tym przypadku 10. Gdy nie po-
da się wartości, następuje zwiększenie o 1, tak jak w poniższym przykła-
dzie:

Inc(X);

{znaczy to samo, co X := X + 1}

Analogicznie do procedury Inc (zwiększanie) działa jej bliźniaczka – Dec
(zmniejszanie):

Dec(X);

{X := X - 1}

Dec(X, 10);

{X := X – 10}

Funkcje Pred i Succ

Funkcja 

Pred

 (od ang. predecessor) zwraca poprzednik swojego argumentu. Na przykład,

Pred(10)

 daje 9, 

Pred(100)

 daje 99 itd. Poniższe 3 pętle 

for

 są więc równoważne (celem

jest 10-krotne wywołanie procedury 

JakasProcedura

):

var
  X : Integer;
begin
  X := 10;

  for I := 0 to 9 do
    JakasProcedura;

  for I := 0 to X – 1 do

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

73

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

73

    JakasProcedura;

  for I := 0 to Pred(X) do
    JakasProcedura;
end;

Funkcja 

Succ

 (od ang. successor) – analogicznie - zwraca następnik argumentu. Przydaje

się ona często przy odliczaniu wstecz:

for I := 100 downto Succ(X) do
  JakasProcedura;

Pętla while

Pętla 

while

 tym różni się od pętli 

for

,  że posiada warunek zakończenia działania

sprawdzany na początku każdej iteracji. Pętla wykonuje się tak długo, dopóki warunek
ten pozostaje prawdziwy.

var
  X : Integer;
begin
  X := 0;
  while X < 1000 do begin
    X := JakiesObliczenia;
    JakasInnaProcedura;
  end;
  ...
end;

W tym przykładzie w pętli wywoływana jest funkcja 

JakiesObliczenia

, która zwraca

pewną wartość przypisywaną zmiennej X. Dopóty, dopóki wartość ta jest mniejsza od
1000, pętla jest wykonywana. Jeżeli natomiast zmienna X będzie równa lub większa niż
1000, nastąpi opuszczenie pętli (skok do pierwszej instrukcji po niej następującej). Czę-
sto w pętli 

while

 do sprawdzania warunku zakończenia działania używa się zmiennej

typu 

Boolean

, którą można ustawiać w ciele pętli:

var
  Zakonczone: Boolean;
begin
  Zakonczone := False;
  while not Zakonczone do begin
    JakasProcedura;
    Zakonczone := JakasFunkcjaZwracajacaWartoscBoolean;
    JakasInnaProcedura;
  end;
end;

Zmienna 

Zakonczone

 musi kiedyś przyjąć wartość 

True

, aby pętla mogła się zakończyć.

Stwórzmy teraz inną przykładową aplikację z użyciem pętli 

while

. Otwórz nowy pro-

jekt i umieść na formularzu 

Button

 oraz 

Memo

. Kliknij podwójnie przycisk i jego proce-

durę obsługi zdarzenia 

OnClick

 zmodyfikuj następująco:

procedure TForm1.Button1Click(Sender: TObject);
var

background image

74

Część I

74

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

  I : Integer;
begin
  I := 5;
  Memo1.Lines.Clear;
  while I > -1 do begin
    Memo1.Lines.Add('Dzisiaj mam ' + IntToStr(I) + ' spraw do
załatwienia.');
    Dec(I);
  end;
  Memo1.Lines.Add('Uff!');
end;

Po uruchomieniu programu i kliknięciu przycisku 

Button1

 w komponencie 

Memo1

 pojawi

się tekst:

Dzisiaj mam 5 spraw do załatwienia.
Dzisiaj mam 4 spraw do załatwienia.
Dzisiaj mam 3 spraw do załatwienia.
Dzisiaj mam 2 spraw do załatwienia.
Dzisiaj mam 1 spraw do załatwienia.
Dzisiaj mam 0 spraw do załatwienia.
Uff!

W programie tym zadeklarowałeś zmienną 

I

 i przypisałeś jej początkową wartość 5.

Następnym krokiem było wejście do pętli. Przy każdym przebiegu pętli następowało
dodanie jednej linii tekstu do komponentu 

Memo1

 i zmniejszenie o 1 wartości zmiennej 

I

.

Gdy 

I

 osiągnęła wartość –1, nastąpiło wyjście z pętli i dodanie do 

Memo1

 ostatniej linii

tekstu.

Składnia

while wyrazenie_warunkowe do begin
  Instrukcje;
end;

W pętli 

while

 blok instrukcji 

Instrukcje

 wykonywany jest tak długo, dopóki wyrażenie

warunkowe 

wyrazenie_warunkowe

 ma wartość 

True

. Wartość wyrażenia warunkowego

musi być zainicjalizowana przed wejściem do pętli oraz określana w ciele pętli. Wyjście
z pętli następuje, gdy wyrażenie warunkowe sprawdzane na jej początku jest fałszywe.
Gdy w ciele pętli jest tylko jedna instrukcja, słowa kluczowe 

begin

 i 

end

 nie są wymagane.

Pętla repeat

Pętla 

repeat

 jest bardzo podobna do pętli 

while

. Różnica między nimi jest niewielka,

ale jednak bardzo istotna. W pętli 

while

 warunek zakończenia działania sprawdzany

jest na początku (przed pierwszym wykonaniem ciała pętli), natomiast w pętli 

repeat

warunek zakończenia działania sprawdzany jest na jej końcu. Oto poprzedni przykład,
w którym pętlę 

while

 zastąpiono pętlą 

repeat

:

procedure TForm1.Button1Click(Sender: TObject);
var
  I : Integer;

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

75

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

75

begin
  I := 5;
  Memo1.Clear;
  repeat
    Memo1.Lines.Add('Dzisiaj mam ' + IntToStr(I) + ' spraw do
    ∑ załatwienia.');
    Dec(I);
  until I = -1;
  Memo1.Lines.Add('Uff!');
end;

Rezultat działania tego programu będzie taki sam, jak poprzednio. Zwróć uwagę, że nie
trzeba tu używać słów 

begin

 i 

end

, ponieważ ich rolę spełniają w tej pętli słowa 

repeat

until

.

Składnia

repeat
  Instrukcje;
until wyrazenie_warunkowe;

W pętli tej blok kodu oznaczony jako Instrukcje wykonywany jest tak długo, dopóki
wyrażenie warunkowe jest fałszywe. Wartość wyrażenia warunkowego musi być zaini-
cjalizowana przed wejściem do pętli oraz określana w ciele pętli. Wyjście z pętli następuje,
gdy wyrażenie warunkowe sprawdzane na jej końcu jest prawdziwe.

W pętli 

repeat

 instrukcje stanowiące ciało pętli będą wykonane co naj-

mniej raz, niezależnie od wartości wyrażenia warunkowego. W pętli 

while

wyrażenie warunkowe obliczane jest na początku, więc ciało pętli może
nigdy nie być wykonane.

Instrukcja goto

Instrukcja 

goto

 umożliwia skok wprost do umieszczonej w kodzie programu etykiety

zadeklarowanej uprzednio dyrektywą 

Label 

(nie mylić z komponentem 

TLabel

 – przyp.

red.)  , a tym samym wykonanie pierwszej następującej po niej instrukcji. Ilustruje to
poniższy przykład:

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
label
  Petelka;
begin
  Memo1.Clear;
  I := 0;
Petelka:
  Inc(I);
  Memo1.Lines.Add(IntToStr(I));
  if I < 5 then
    goto Petelka;
end;

background image

76

Część I

76

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Nie jest tutaj konieczne użycie pary 

begin

 i 

end

, ponieważ wykonywane będą po prostu

wszystkie linie kodu pomiędzy etykietą a instrukcją 

goto

.

Stosowanie instrukcji 

goto

 w Object Pascalu jest uważane za zły zwyczaj.

Poza tym nie jest konieczne. Wszystko to, co można zrobić za pomocą in-
strukcji 

goto

, można równie dobrze osiągnąć stosując pętle 

while

 albo 

re-

peat

.

2

Składnia

label
  nazwa_etykiety;

  goto nazwa_etykiety;
  ...
nazwa_etykiety;

Po napotkaniu instrukcji 

goto

 następuje skok do miejsca programu oznaczonego etykietą.

                                                          

2

 Redakcja wydania polskiego nie podziela w pełni tego kategorycznego stwierdzenia. Fakt, iż użycie

instrukcji goto stwarza znakomitą okazję do zagmatwania programu nie oznacza jeszcze, iż każde

jej użycie czyni program zagmatwanym – ba, niekiedy program (paradoksalnie) zyskuje na czytelno-
ści. Tak się bowiem składa, że Object Pascal posiada np. znakomite mechanizmy natychmiastowego
„wyskoczenia” z pętli (break) lub procedury (exit), nie ma natomiast równoważnego mecha-
nizmu umożliwiającego wyskok z bloku begin…end – i wtedy użycie goto jest niezbędne, na

przykład:

   X := 1; Y := 2;
   BlokKompletny := FALSE;
   Begin
     ...
     if LiczbaBledow > 0
     Then
       Goto PozaBlok;
     ...
     if BladFatalny
     Then
       Goto PozaBlok;
     ...
   End;

   BlokKompletny := TRUE;

PozaBlok:
   If BlokKompletny Then
   begin
     X := X / 3; Y := Y + 1;
   End
   Else
   Begin
     X := 0; Y := 0;
   End;

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

77

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

77

Procedury Continue i Break

Zanim zakończymy temat pętli, powinieneś jeszcze poznać dwie procedury, które czę-
sto stosowane są w połączeniu z nimi. Procedura 

Continue

 umieszczona gdziekolwiek

w ciele pętli powoduje natychmiastowy skok do punktu stopu. Przykład:

var
  Zrobione : Boolean;
  Wstrzymaj : Boolean;
begin
  Zrobione := False;
  while not Zrobione do begin
    ...
    Wstrzymaj := SprawdzStan;
    if Wstrzymaj then Continue;

{skok do punktu stopu petli}

    {tutaj kod wykonywany, gdy Wstrzymaj = False}
  end;
end;

Procedura 

Break

 jest używana do natychmiastowego i całkowitego zatrzymania pętli

(wyjścia z niej). Na przykład, szukasz jakiejś określonej liczby w tablicy liczb przeszukując
ją w pętli. W przypadku znalezienia tej liczby, można przerwać poszukiwania zapa-
miętując jednocześnie indeks tej liczby w tablicy:

var
  Tablica

: array[0.99] of Integer;

  Indeks

: Integer;

  PoszukiwanaLiczba : Integer;
  I

: Integer;

begin
  WypelnijTablice;

{wypełnienie tablicy wartościami}

  Indeks := -1;
  PoszukiwanaLiczba := 50;
  for I := to High(Tablica) do begin
    if Tablica[I] = PoszukiwanaLiczba then begin
      Indeks := I;
      Break;
    end;
  end;
  if Indeks <> -1 then
    Label1.Caption := 'Poszukiwaną liczbę znaleziono pod indeksem '
    ∑+ IntToStr(Indeks)
  else
    Label1.Caption := 'Poszukiwanej liczby nie ma w tablicy.';
end;

Procedur 

Continue

 i 

Break

 używa się tylko wewnątrz pętli 

for

repeat

 albo 

while

. Jeżeli

spróbujesz użyć tych procedur gdziekolwiek indziej, kompilator wypisze komunikat

BREAK or CONTINUE outside of loop

”.

background image

78

Część I

78

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Instrukcja case

Instrukcję 

case

 można traktować jak rozbudowaną instrukcję 

if

. Pozwala ona na wy-

konanie jednego z wielu bloków kodu bazując na wyniku określonego wyrażenia, funkcji
czy zmiennej. Wynik ten musi być typu porządkowego (

Integer

Word

Byte

 itd.), nie

może to być  łańcuch ani liczba zmiennoprzecinkowa. Oto przykład:

case PrzekroczeniePredkosci of
  0 : Mandat := 0;
  5 : Mandat := 50
  10 : Mandat := 75;
  15 : Mandat := 100;
  20,
  25,
  30 : Mandat := PrzekroczeniePredkosci * 20;
  else begin
   Mandat := MaksymalnyMandat;
  end;
end;

Wyrażeniem, na podstawie którego następuje wykonanie określonego fragmentu kodu,
jest w tym przypadku zmienna 

PrzekroczeniePredkosci

. Jeżeli przyjmie ona wartość 0,

wykonana zostanie instrukcja 

Mandat := 0

, gdy przyjmie wartość 5, wykonana zostanie

instrukcja 

Mandat := 50

 itd. Instrukcja ostatnia przed 

else

 wykona się, gdy 

Przekrocze-

niePredkosci

 będzie równe 20 albo 25 albo 30. Jeżeli natomiast zmienna ta będzie miała

wartość, której nie ma na liście, wykona się instrukcja 

Mandat := MaksymalnyMandat

.

Część 

else

 instrukcji 

case

 jest opcjonalna. Oto przykład instrukcji 

case

, w której nie

ma słowa 

else

:

case X of
  10 : PierwszaProcedura;
  20 : DrugaProcedura;
  30 : TrzeciaProcedura;
end;

Składnia

case wyrazenie of
  wartosc1 : instrukcje_1;
  wartosc2 : instrukcje_2;
  ...
  wartoscn : instrukcje_n;
  else
  instrukcje_w_innym_przypadku;
end;

Instrukcja 

case

 pozwala na wykonanie różnych fragmentów kodu w zależności od

wartości wyrażenia 

wyrazenie

. Jeżeli 

wyrazenie

  będzie równe 

wartosc1

, wykonane

będą 

instrukcje_1

, jeżeli 

wyrazenie

  będzie równe 

wartosc2

, wykonane będą 

in-

strukcje_2

, itd. Jeżeli 

wyrazenie

 nie będzie miało  żadnej z wymienionych wartości,

zostaną wykonane 

instrukcje_w_innym_przypadku

. Część 

else

 jest opcjonalna.

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

79

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

79

Zakres widzialności

Termin „zakres widzialności” odnosi się do nazw zmiennych i określa, w jakich czę-
ściach programu można odwoływać się do danej zmiennej. Większość zmiennych są to
tzw. „zmienne lokalne” tzn. takie, do których odwoływać się można tylko w tym bloku
kodu, w którym zostały zadeklarowane. Spójrz na listing 2.1 (jest to kompletny kod
źródłowy modułu wygenerowanego przez Delphi, te elementy, które nie były jeszcze
omawiane, możesz zignorować).

Listing 2.1. SCOPEU.PAS

unit ScopeU;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

var
  X : Integer;

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  X : Integer;

  procedure Test;
  var
    X : Integer;
  begin
    X := 300;
    { This X variable has a value of 300. }
    Memo1.Lines.Add('Local Function X: ' + IntToStr(X));
  end;

begin
  X := 100;
  Memo1.Lines.Clear;
  { Local X has a value of 100. }

background image

80

Część I

80

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

  Memo1.Lines.Add('Local X: ' + IntToStr(X));
  { Unit scope X has a value of 200. }
  Memo1.Lines.Add('Global X: ' + IntToStr(ScopeU.X));
  { Call the Test proecedure. }
  Test;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  { Initialize the unit variable X. }
  X := 200;
end;
end.

Pierwszą rzeczą, która się rzuca w oczy jest to, że zmienna X jest deklarowana w sumie
3 razy: w linii 27. w sekcji 

implementation

, w linii 33. w metodzie 

Button1Click

 oraz

w linii 37. w procedurze lokalnej 

Test

. Normalnie, jeżeli zadeklaruje się omyłkowo ja-

kąś zmienną więcej niż jeden raz, kompilator wyrzuca błąd 

Identifier redeclared:

'X'

 i kompilacja jest przerywana. Ten program jednak kompiluje się i uruchamia bez

żadnych problemów. Dlaczego? Ponieważ każda ze zmiennych X z listingu 2.1 ma inny
zakres widzialności.

Przyjrzyjmy się dokładniej listingowi 2.1. Deklaracja zmiennej X w linii 37. umieszczona
jest wewnątrz procedury 

Test

 i jest to zmienna lokalna tej procedury (wybiegam w tym

momencie trochę w przyszłość, ponieważ funkcje lokalne omówione będą dopiero
w rozdziale „Procedury i funkcje lokalne”). Zmienna X zadeklarowana w linii 37. wła-
ściwie nie istnieje poza procedurą 

Test

. Podobnie, zmienna X zadeklarowana w linii 33. jest

lokalna dla procedury 

Button1Click

 i poza nią nie istnieje.

Spójrzmy teraz na zmienną 

X

 zadeklarowaną w sekcji 

implementation

. Ta zmienna

widzialna jest w każdym miejscu modułu. Nasuwa się w tym momencie pytanie:

W procedurze 

Button1Click

 są w takim razie dwie zmienne 

X

: jedna z linii 27. i druga

z linii 33, która jest używana, skoro obie są widzialne? Odpowiedź brzmi: ta z linii 33.

(zmienna lokalna procedury 

Button1Click

). Druga, zmienna 

X

 widzialna w całym module,

jest w tym momencie przykryta. Można się do niej jednak odwołać podając kwalifikator

zakresu. Przykład takiego odwołania jest w linii 50:

Memo1.Lines.Add('Zmienna X widzialna w całym module: '
∑+ IntToStr(ScopeU.X));

Zapis 

ScopeU.X

 oznacza, że chodzi tu o zmienną 

X

 widzialną w całym module 

ScopeU

, a nie

o zmienną lokalną o tej samej nazwie.

Jak już wcześniej wspominałem, deklarując zmienną w sekcji 

implementation

, czyni

się  ją widzialną w całym module. Jeżeli chcesz, żeby jakaś zmienna była widoczna

również w innych modułach projektu, musisz zadeklarować tę zmienną w sekcji 

interface

(zmienna 

Form1

 na listingu 2.1 zadeklarowana jest w ten sposób). Do zmiennej takiej

można odwoływać się w innych modułach. Nazywane są one zmiennymi globalnymi.

Aby odwołać się do zmiennej zadeklarowanej w sekcji 

interface

 innego modułu

wystarczy jedynie dodać ten moduł do listy 

uses

 bieżącego modułu i można używać

nazwy tej zmiennej, jakby była ona zadeklarowana lokalnie (ewentualnie z użyciem

kwalifikatora zakresu, gdyby oprócz zmiennej globalnej istniałaby zmienna lokalna o tej

samej nazwie).

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

81

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

81

Zmienne deklarowane w sekcji 

interface

 nie są tak do końca zmiennymi

globalnymi. Prawdziwa zmienna globalna powinna być widoczna w całym
projekcie bez konieczności umieszczania deklarującego ją modułu na liście

uses

. W Delphi istnieje kilka prawdziwych zmiennych globalnych inicjali-

zowanych przez kompilator. Użytkownik nie może jednak sam tworzyć ta-
kich zmiennych.

Rekordy

Rekord jest zestawem powiązanych zwykle ze sobą danych „opakowanych” w jedną
całość. Powiedzmy, że chcesz przechowywać dane o nazwiskach i adresach osób. Wygod-
nie byłoby w tym przypadku wyodrębnić jakąś strukturę, w której dałoby się umieścić
wszystkie dane (imię, nazwisko, ulica, miasto). Rekordy są właśnie stworzone do takich
celów. Aby użyć rekordu, należy najpierw stworzyć nowy typ danej (rekord) o potrzeb-
nej strukturze, następnie należy zadeklarować zmienną typu „rekordowego”, do której
można już wpisywać dane. Rekord deklaruje się za pomocą słowa kluczowego 

record

:

type
  TKartaAdresowa = record
    Imie : string;
    Nazwisko : string;
    Ulica : string;
    Miasto : string;
    KodPocztowy : Integer;
  end;

Każdy element rekordu nazywany jest polem. Poszczególne pola muszą być deklarowa-
ne jak zmienne. W powyższym przykładzie w skład rekordu wchodzi 5 pól typu 

string

oraz jedno pole typu 

Integer

 (kod pocztowy powinien być  właściwie także typu

string

, ale dla celów edukacyjnych lepiej zadeklarować rekord o polach różnych typów).

Rekord jest zbiorem powiązanych ze sobą danych zgrupowanych w jednej
strukturze. Po zadeklarowaniu typu rekordowego trzeba zadeklarować
zmienną tego typu, aby móc umieszczać w niej dane. Składniki rekordu na-
zywane są polami.

Rekord z powyższego przykładu nadaje się dobrze do tego, o czym tu pi-
szę, lecz nie jest najlepszy, jeżeli chodzi o zapisywanie rekordów do pliku
dyskowego. Każdy rekord zapisywany w pliku musi mieć stałą długość w
bajtach. Ponieważ używane są tu długie łańcuchy, nie ma żadnej gwarancji,
że każdy rekord tego typu będzie miał taki sam rozmiar. Przy tworzeniu re-
kordów, które mają być zapisywane do pliku, lepiej użyć łańcuchów 

shor-

tstring

 lub nawet tablic znaków. Operacje na plikach omówię szczegóło-

wo w następnym rozdziale.

background image

82

Część I

82

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Teraz, kiedy rekord mamy już zadeklarowany, trzeba zadeklarować zmienną, aby móc
z tego rekordu korzystać:

var
  Karta001 : TKartaAdresowa;

Powyższa deklaracja przydziela pamięć dla zmiennej 

Karta001

 typu 

TKartaAdresowa

.

Przypisanie wartości polom tej zmiennej wygląda następująco:

Karta001.Imie

:= 'Jan';

Karta001.Nazwisko

:= 'Kowalski';

Karta001.Ulica

:= 'Klonowa';

Karta001.Miasto := 

'Białystok';

Karta001.KodPocztowy

:= 15113;

Jak widać, do poszczególnych pól można się odwoływać stosując notację kropkową
(kwalifikowaną) – po nazwie zmiennej następuje kropka i nazwa pola. Umożliwia to za-
równo wpisywanie, jak i odczyt danych:

Label1.Caption := Karta001.Nazwisko;

Składnia

nazwa = record
  pole_1 : typ;
  pole_2 : typ;
  ...
  pole_n : typ;
end;

Słowo kluczowe 

record

 deklaruje zbiór pól (

pole_1

pole_2

, ..., 

pole_n

) i nadaje mu

nazwę (

nazwa

).

Instrukcja with

Instrukcja 

with

, aczkolwiek nie tylko ona, jest często stosowana w połączeniu z rekor-

dami. Przytoczę tutaj poprzedni przykład, w którym następowało wypełnienie rekordu

Karta001

 wartościami:

Karta001.Imie

:= 'Jan';

Karta001.Nazwisko

:= 'Kowalski';

Karta001.Ulica

:= 'Klonowa';

Karta001.Miasto := 

'Białystok';

Karta001.KodPocztowy

:= 15113;

Słowo kluczowe 

with

 może być w tym przypadku użyte w celu uproszczenia zapisu:

with Karta001 do begin
  Imie

:= 'Jan';

  Nazwisko

:= 'Kowalski';

  Ulica

:= 'Klonowa';

  Miasto 

:= 'Białystok';

  KodPocztowy

:= 15113;

end;

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

83

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

83

Słowo 

with

 znaczy „Zrób z tym obiektem (

Karta001

) następującą rzecz…”. Dzięki

niemu nie trzeba stosować zapisu kwalifikowanego. Wszystko pomiędzy słowami 

begin

end

 odnosi się do obiektu 

Karta001

. Oszczędza to sporo pisania, oprócz tego kod staje

się znacznie czytelniejszy.

Tablice rekordów

Podobnie jak zmienne typu 

Integer

Char

 czy 

Word

, rekordy można także grupować

w tablice. Przy tym deklarowanie i używanie tablic rekordów nie jest tak bardzo skom-

plikowane:

var
  TablicaKart : array[0..9] of TKartaAdresowa;
begin
  TablicaKart[0].Imie

:= 'Jan';

  TablicaKart[0].Nazwisko

:= 'Kowalski';

  TablicaKart[0].Ulica

:= 'Klonowa';

  TablicaKart[0].Miasto

:= 'Białystok';

  TablicaKart[0].KodPocztowy

:= 15425;

  TablicaKart[1].Imie

:= 'Roman';

  TablicaKart[1].Nazwisko

:= 'Kaleta';

  TablicaKart[1].Ulica

:= 'Storczykowa';

  TablicaKart[1].Miasto

:= 'Sopot';

  TablicaKart[1].KodPocztowy

:= 81855;

  Label1.Caption 

:= TablicaKart[0].Nazwisko;

  ...
end;

Pliki dołączane

Pliki dołączane są to pliki tekstowe zawierające kod źródłowy, które w czasie kompilacji

traktowane są przez kompilator jak część pliku, do którego zostały dołączone. Zwykle

umieszcza się w plikach dołączanych deklaracje stałych albo dyrektywy kompilatora,

które mają być użyte w wielu plikach projektu lub wielu projektów, i których po prostu nie

opłaca się przepisywać za każdym razem. Pliki dołączane mają zwyczajowo rozszerzenie

.INC

. Na listingu 2.2 przedstawiony jest przykładowy plik dołączany:

Listing 2.2. TEST.INC

const
  DomyslnaSzerokosc = 500;
  DomyslnaWysokosc

= 300;

type
  KartaAdresowa = record
    Imie : string;
    Nazwisko : string;
    Ulica : string;
    Miasto : string;
    KodPocztowy : Integer;
  end;

background image

84

Część I

84

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Aby utworzyć plik dołączany, trzeba po prostu otworzyć nowy plik tekstowy i zapisać
go z rozszerzeniem 

INC

. Najpierw wybierz opcję 

File | New

 z menu. Następnie kliknij

podwójnie ikonę „Text”. W Edytorze Kodu otworzy się nowy, pusty plik tekstowy.
Wpisz kod, który chcesz umieścić w pliku dołączanym i wybierz z menu 

File | Save

As

. Podaj nazwę pliku z rozszerzeniem 

.INC

 (nie zapomnij o tym, gdyż standardowo

pliki tekstowe zapisywane są z rozszerzeniem 

.TXT

).

Dołączanie pliku 

.INC

 do pliku głównego polega na wpisaniu w pliku głównym w miejscu

dołączenia dyrektywy kompilatora 

$I

:

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,
  StdCtrls;

{$I TEST.INC}
...

Rezultat jest taki, jakby plik 

.INC

 wklejono w tym miejscu do pliku głównego. Oczywiście

kod w pliku dołączanym musi być składniowo poprawny, inaczej przy kompilacji wy-
stąpią błędy.

Funkcje, procedury i metody

Funkcje i procedury to wydzielone bloki kodu wykonujące jakieś określone zadania.
Programy pisze się z reguły po to, żeby przy ich pomocy rozwiązać jakiś skomplikowany
i rozbudowany problem (np. wspomaganie sprzedaży w sklepie). Aby ułatwić sobie
rozwiązanie tego problemu, dzieli się go na mniejsze problemy cząstkowe (np. wyko-
nanie dziennego zestawienia sprzedaży). Każdy taki problem cząstkowy rozwiązuje
określona procedura albo funkcja. Problemy mogą być najróżniejsze. Na przykład mogą
być funkcje, które pobierają dwie liczby, wykonują na nich jakieś skomplikowane ope-
racje matematyczne i zwracają wynik – albo funkcje, które przetwarzają  łańcuchy.
Można tych funkcji używać (wywoływać je) w dowolnym miejscu programu.

Funkcje i procedury bardziej ogólnie nazywa się podprogramami. Podprogramy są bardzo
ważną częścią każdego języka programowania – Object Pascal nie jest tu wyjątkiem.
Najprostszy rodzaj podprogramu nie pobiera żadnych danych wejściowych (parametrów)
oraz nie zwraca żadnego wyniku. Inne podprogramy mogą wymagać jednego lub więcej
parametrów i mogą też zwracać jakieś wyniki. Reguły nazewnictwa funkcji i procedur
są takie same jak dla zmiennych.

Funkcja jest to wydzielony blok kodu, który wykonuje określoną czynność i
zwraca wynik.

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

85

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

85

 

Parametr  jest wartością przekazywaną do funkcji albo procedury, który
modyfikuje lub określa zakres jej działania.

Rysunek 2.2.
Budowa funkcji

Procedura jest to wydzielony blok kodu, który wykonuje określoną czyn-
ność, lecz nie zwraca wyniku.

Rysunek 2.3.
Budowa procedury

Metoda jest to procedura lub funkcja, która jest składnikiem klasy.

 Jak widać z powyższych definicji, jedyną różnicą między funkcją a procedurą jest to,
że funkcja zwraca jakiś wynik, a procedura nie.

Napiszmy teraz przykładowy program, który będzie wykorzystywał funkcję:

 

1. 

Utwórz nową aplikację.

 

2. 

Umieść na formularzu po jednym komponencie 

Label

 i 

Button

.

background image

86

Część I

86

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

 

3. 

Kliknij podwójnie na umieszczonym właśnie przycisku, żeby utworzyć dla

niego procedurę obsługi zdarzenia 

OnClick

.

 

4. 

Używając klawisza ze strzałką skierowaną do góry przesuń kursor w Edytorze

Kodu powyżej utworzonej przed momentem procedury.

 

5. 

Wpisz do tekstu programu następującą funkcję:

function Mnozenie(Liczba1, Liczba2 : Integer) : Integer;
begin
  Result := Liczba1 * Liczba2;
end;

Plik źródłowy modułu w Edytorze Kodu powinien teraz wyglądać jak na rysunku 2.4.

Rysunek 2.4.
Edytor Kodu
z wyświetloną
funkcją Mnozenie

 

6. 

Przesuń kursor z powrotem do procedury 

TForm1.Button1Click

 i zmodyfikuj

ją tak, żeby zawierała następujący kod:

procedure TForm1.Button1Click(Sender: TObject);
var
  X : Integer;
begin
  X := Mnozenie(10, 20);
  Label1.Caption := IntToStr(X);
end;

Uruchom teraz program i naciśnij przycisk. Etykieta powinna teraz zawierać liczbę 200.

Program działa w następujący sposób: Po naciśnięciu przycisku wywoływana jest procedura

obsługi zdarzenia 

OnClick

 tego przycisku. Ta procedura z kolei wywołuje funkcję 

Mnozenie

przekazując do niej dwa parametry – liczby 10 i 20. Wynik zwrócony przez funkcję

Mnozenie

 zapamiętywany jest w zmiennej X, która z kolei wyświetlana jest na ekranie.

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

87

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

87

Przykład ten ilustruje stosowanie samodzielnych funkcji w programie Del-
phi. Normalnie, uczyniłbym tę funkcję składnikiem klasy formularza, jed-
nak ponieważ nie omawiałem jeszcze klas, nie chcę teraz za bardzo kom-
plikować przykładu.

Mogłeś analizując ten przykład pomyśleć: „No dobrze, ale skąd funkcja ma wiedzieć,
którą zmienną ma zwrócić jako swój wynik?” Przyjrzyjmy się jeszcze raz funkcji

Mnozenie

:

function Mnozenie(Liczba1, Liczba2 : Integer) : Integer;
begin
  Result := Liczba1 * Liczba2;
end;

Każda funkcja w Object Pascalu ma predefiniowaną zmienną lokalną o nazwie 

Result

.

Używana jest ona właśnie do przechowywania wyniku zwracanego przez tę funkcję.
Wystarczy więc przypisać zmiennej 

Result

 wartość, którą funkcja ma zwrócić jako

wynik.

Jest oprócz tego drugi sposób przypisywania wartości wynikowi funkcji.
Zamiast zmiennej 

Result

 używa się po prostu nazwy funkcji:

function Mnozenie(Liczba1, Liczba2 : Integer) : Integer;

begin

  Mnozenie := Liczba1 * liczba2;

end;

Wersję  tę często spotyka się w starszych wersjach Pascala i w programach
przeniesionych do Delphi z Turbo Pascala (jednego z poprzedników Delphi).

Funkcję 

Mnozenie

 można wywoływać na kilka sposobów. Jako parametry można prze-

kazywać do niej zmienne, wartości podane wprost lub nawet wyniki wywołań innych
funkcji. Na przykład:

X := Mnozenie(2, 5); {przekazywanie wartości podanych wprost}
X := Mnozenie(A, B); {przekazywanie zmiennych}
Label1.Caption := IntToStr(Mnozenie(X, Y));
{wynik funkcji użyty jako parametr innej funkcji}
Mnozenie(X, Y);

{zignorowanie wyniku funkcji}

W ostatniej linii, przy wywołaniu funkcji 

Mnozenie

, wartość przez nią zwracana jest

ignorowana. Nie ma to w tym przypadku większego sensu, jednak pomijanie wyniku
funkcji jest często stosowaną praktyką w programowaniu. Spotyka się wiele funkcji,
które po wykonaniu określonej akcji zwracają jako wynik status tego wywołania (np.
informację, czy akcja się powiodła). Jeżeli ta informacja nie jest Ci do niczego potrzeb-
na, możesz ją po prostu zignorować.

background image

88

Część I

88

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Dodajmy teraz do naszego programu przykładowego procedurę:

 

1. 

Kliknij podwójnie na przycisku umieszczonym na formularzu. W Edytorze
Kodu wyświetlona będzie procedura 

TForm1.Button1Click

.

 

2. 

Przesuń kursor do góry o kilka linii tak, aby znajdował się on między procedurami

Mnozenie

 i 

TForm1.Button1Click

. Wpisz następujący kod:

procedure Powitanie;

begin
  MessageDlg('Witaj!', mtInformation, [mbOk], 0);
end;

 

3. 

Dodaj linię kodu na końcu procedury obsługi zdarzenia 

OnClick

 komponentu

Button

 tak, aby wyglądała ona następująco:

procedure TForm1.Button1Click(Sender: TObject);
var
  X : Integer;
begin
  X := Mnozenie(10, 20);
  Label1.Caption := IntToStr(X);
  Powitanie;
end;

Teraz uruchom program ponownie. Tym razem, oprócz wyniku mnożenia wyświetlone-
go na etykiecie, pokaże się okienko informacyjne. Wyświetlenie okienka jest skutkiem
wywołania procedury 

Powitanie

. Wywołanie to jest bardzo proste, ponieważ procedura

ta nie wymaga żadnych parametrów. Ważne jest tu zrozumienie tego, że kod umieszczony
w procedurze 

Powitanie

 wykonywany jest tylko wtedy, gdy wprost wywoła się tę pro-

cedurę.

Za każdym razem, kiedy zajdzie potrzeba powtórzenia jakiejś partii kodu
kilka lub więcej razy, rozważ umieszczenie jej w podprogramie. Będziesz
mógł wtedy wywoływać po prostu ten podprogram.

Podprogramy mogą (i często to robią) wywoływać inne podprogramy. Mogą one nawet
wywoływać same siebie. Wywoływanie samych siebie przez podprogramy nazywane
jest  rekurencją i stosowane jest raczej w uzasadnionych przypadkach przez doświad-
czonych programistów.

Rekurencją  nazywa się wywoływanie przez procedurę lub funkcję samych
siebie.

Deklaracja i definicja

Funkcje i procedury często posiadają deklarację, zawsze natomiast posiadają definicję.

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

89

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

89

Deklaracja jest pojedynczą instrukcją, która opisuje nazwę i parametry (je-
żeli występują) podprogramu. W przypadku funkcji deklaracja opisuje
również typ zwracanego przez nią wyniku.

Definicja procedury albo funkcji zawiera właściwą treść tej procedury albo
funkcji i umieszczona jest w sekcji 

implementation

 modułu.

Oto trzy główne przypadki, kiedy konieczne jest deklarowanie funkcji albo procedury:

υ 

Gdy funkcja albo procedura ma być używana w innych modułach.

υ 

Gdy definicja tej funkcji albo procedury znajduje się poniżej miejsca w pliku
źródłowym, w którym dana funkcja albo procedura jest wywoływana.

υ 

Gdy funkcja albo procedura jest składnikiem klasy.

Do tej pory w tej książce nie używałem deklaracji funkcji i procedur, jedynie definicje.
Nie wystąpiła dotąd taka potrzeba – definicje te zawsze poprzedzały wywołanie. Deklaracja
funkcji 

Mnozenie

 wyglądałaby następująco:

function Mnozenie(Liczba1, Liczba2 : Integer) : Integer;

Deklaracje funkcji i procedur umieszczane są w sekcji 

interface

. Umożliwia do wy-

woływanie ich także w innych modułach. Są one publiczne. Jeżeli nie chcesz, żeby jakaś
funkcja lub procedura była publiczna, nie umieszczaj jej deklaracji w sekcji 

interface

.

Zamiast tego umieść jej definicję w sekcji 

implementation

 na samym początku tak, żeby

była widoczna w jak największej części modułu. Mimo, że do tej pory nie stosowałem
deklaracji, mógłbym to robić w następujący sposób:

unit Unit1;

interface

...

function Mnozenie(Liczba1, Liczba2 : Integer) : Integer; {deklaracja}

implementation

procedure TForm1.Button1Click(Sender: TObject);
var
  X : Integer;
begin
  X := Mnozenie(10, 20);
end;

function Mnozenie(Liczba1, Liczba2 : Integer) : Integer;
begin
  Result := Liczba1 * Liczba2;
end;

end.

background image

90

Część I

90

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

W tym przypadku deklaracja funkcji 

Mnozenie

 jest konieczna, ponieważ jej definicja

jest poniżej procedury 

Button1Click

, w której następuje jej wywołanie.

Jeżeli zadeklarujesz funkcję i zapomnisz ją potem zdefiniować, kompilator
wypisze komunikat o błędzie 

Unsatisfied forward or external

declaration: 'Mnozenie'

.

Parametry przekazywane przez stałą, przez wartość
i przez referencję

Istnieją trzy sposoby przekazywania parametrów do procedur i funkcji (tak naprawdę więcej
niż trzy, ale tutaj tylko te będę omawiał): przez stałą, przez wartość i przez referencję.

Parametry przekazywane przez wartość

Wszystkie parametry, których używałeś do tej pory pracując z tą książką, były to parametry
przekazywane przez wartość. Parametry takie można porównać do zmiennych lokal-
nych w procedurze lub funkcji – można je modyfikować, lecz zmienna globalna o tej
samej nazwie pozostanie niezmieniona. Tak samo modyfikacja parametru przekazanego
do funkcji przez wartość nie zmienia oryginalnej zmiennej. Stwórzmy nową funkcję,
która będzie ilustrowała to zagadnienie. Nazwiemy ją 

MnozenieKwadratow

. Będzie ona

podnosić do kwadratu dwie przekazane do niej liczby i mnożyć te kwadraty:

function MnozenieKwadratow(Liczba1, Liczba2 : Integer) : Integer;
begin
  Liczba1 := Liczba1 * Liczba1;
  Liczba2 := Liczba2 * Liczba2;
  Result := Liczba1 * Liczba2;
end;

Wywołajmy teraz tę funkcję w następujący sposób:

procedure TForm1.Button1Click(Sender: TObject);
var
  X : Integer;
  Y : Integer;
  Z : Integer;
begin
  X := 2;
  Y := 3;
  Z := MnozenieKwadratow(X, Y);
  Label1.Caption := 'X = ' + IntToStr(X) + 'Y = ' + IntToStr(Y) + 'Z = '
  ∑ + IntToStr(Z);
end;

Do funkcji 

MnozenieKwadratow

 przekazywane są wartości dwóch zmiennych (

X

 i 

Y

). Są

one modyfikowane wewnątrz funkcji (podnoszone do kwadratu). Oryginalne zmienne
jednak pozostają niezmienione, ponieważ do funkcji przekazywane są ich kopie.

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

91

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

91

Parametry przekazywane przez stałą

Innym sposobem na przekazywanie danych wejściowych do funkcji jest ich przekazanie
przez stała. Wartości tych parametrów nie mogą być zmieniane wewnątrz funkcji. Oto
przykład:

procedure PowiedzCos(const S : string);
begin
  S := S + 'Test';
  ShowMessage(S);
end;

To jest jeden z kilku przykładów kodu w tej książce, przy próbie kompilacji którego
wystąpi błąd. Odnosić się on będzie do  pierwszej linii procedury i będzie brzmiał 

Left

side cannot be assigned to

. Błąd ten będzie generowany, ponieważ  słowo 

const

znajdujące się przed parametrem oznacza, że nie może on być modyfikowany w ciele
procedury. Jeżeli chcesz zabezpieczyć jakieś parametry przekazywane do procedury lub
funkcji przed modyfikacją, to jest właśnie sposób na to.

3

Parametry przekazywane przez referencję

Przy przekazywaniu parametrów przez referencję

4

, kompilator nie robi ich kopii ani

w żaden inny sposób nie zabezpiecza tych parametrów przed modyfikacją wewnątrz
procedury. Referencja jest to po prostu odwołanie do jakiejś zmiennej. Znaczy to, że
wszelkie modyfikacje wykonywane na parametrach są de facto modyfikacjami wyko-
nywanymi na oryginalnych zmiennych. Poniżej przedstawiony jest przykład takiego
przekazania:

procedure DoKwadratu(var Liczba: Integer);
begin
  Liczba := Liczba * Liczba;
end;

procedure TForm.Button1Click(Sender: TObject);
var
  X : Integer;
begin
  X := 20;
  DoKwadratu(X);
  Label1.Caption := IntToStr(X);

{X równe jest teraz 400}

end;

                                                          

3

 Dociekliwy Czytelnik mógłby zapytać w tym miejscu, czym właściwie różni się przekazywanie

parametru przez wartość od przekazywania przez stałą? Obydwa te sposoby uniemożliwiają zmianę
wartości przekazanego parametru – co osiągane jest w dwojaki sposób: przy przekazywaniu przez
wartość tworzona jest ad hoc kopia robocza parametru, na której wykonywane są wszelkie modyfi-
kacje tego ostatniego, zaś przy przekazywaniu przez stałą kompilator zabrania dokonywania jakich-
kolwiek modyfikacji parametru, eliminując konieczność tworzenia owej kopii; z tego też względu
przekazanie przez stałą jest efektywniejsze zarówno pamięciowo (oszczędza się pamięć, nie tworząc
kopii) jak i czasowo (wykonanie kopii zajmuje bowiem pewną ilość czasu). (przyp. red.)

4

 Przekazywanie parametru przez referencję nazywane bywa również przekazaniem „przez adres” lub

„przez zmienną” (przyp. red.).

background image

92

Część I

92

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Słówko 

var

 umieszczone przy parametrze oznacza, że jest on przekazywany przez refe-

rencję.

Wiele słów kluczowych w Object Pascalu ma kilka znaczeń. Słowo 

var

 na

przykład oznacza, że dany parametr przekazywany jest przez referencję.
Rozpoczyna też ono sekcję deklaracji zmiennych. Kompilator właściwie
interpretuje je za każdym razem wnioskując z kontekstu, w jakim się dane
słowo znajduje.

W procedurze 

DoKwadratu

 zmieniana jest wartość parametru 

Liczba

. Tym samym wartość

zmiennej 

X

, która jest przekazana do tej procedury, przed wywołaniem 

DoKwadratu

wynosząca 20, po tym wywołaniu jest już inna (400).

Ponieważ parametr procedury 

DoKwadratu

 jest przekazywany przez referencję, musisz

w wywołaniu tej procedury użyć zmiennej takiego samego typu, jak parametr. Nie możesz
na przykład napisać:

DoKwadratu(30);

{Błąd przy kompilacji!}

Nie możesz też przekazać do tej procedury zmiennej innego typu niż typ parametru:

var
  X : Word;
begin
  X := 20;
  DoKwadratu(X);

{Błąd przy kompilacji!}

Komunikat kompilatora wygenerowany przy próbie kompilacji powyższego kodu będzie
brzmiał 

Types of actual and formal var parameters must be identical

.

Formalnie funkcja może zwracać tylko jedną wartość. Parametry przeka-
zywane przez referencję to sposób na obejście tego ograniczenia. Jeżeli
funkcja może je modyfikować (może ich być dowolnie dużo), można
uznać, że może zwracać w ten sposób wiele wartości.

Funkcje i procedury lokalne

Funkcje i procedury lokalne zawierają się w innych funkcjach lub procedurach. Na
przykład:

procedure TForm1.Button1Click(Sender: TObject);
var
  X : Integer;

  {procedura lokalna:}
  procedure Test;
  begin
    Memo1.Lines.Add('Procedura lokalna, X = ' + IntToStr(X));
  end;

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

93

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

93

begin
  X := 100;
  Memo1.Lines.Clear;
  Memo1.Lines.Add('Procedura główna, X = ' + IntToStr(X));
  Test;
end;

Procedura 

Test

 zawarta jest w sekcji 

var

 procedury 

Button1Click

. Procedury takie nazy-

wają się procedurami lokalnymi podprogramu, w którym są zawarte. Mogą być one
wywołane tylko z poziomu zawierającego je podprogramu, nie są widoczne nigdzie indziej.

Ważną cechą charakteryzującą funkcje i procedury lokalne jest to, że widoczne są w niej
zmienne lokalne otaczającego je podprogramu. W powyższym przykładzie, zmienna 

X

zadeklarowana jako zmienna lokalna procedury 

Button1Click

, widoczna jest w procedurze

Button1Click

 oraz w procedurze Test. Po uruchomieniu tego programu w komponen-

cie 

Memo

 widoczny będzie tekst:

Procedura główna, X = 100
Procedura lokalna, X = 100

Przeciążanie funkcji i procedur

Począwszy od wersji czwartej Delphi, Object Pascal pozwala na deklarowanie dwóch
lub więcej funkcji i procedur (metod) o tych samych nazwach, lecz o różnych parametrach
(w tym samym zakresie widzialności).

Przeciążanie metod jest to deklarowanie dwóch lub więcej funkcji albo pro-
cedur o tych samych nazwach, ale o różniących się listach parametrów.

Metody o tych samych nazwach nazywa się metodami przeciążonymi.

Przedstawiałem wcześniej przykładowy program, który zawierał funkcję o nazwie

Mnozenie

. Funkcja ta pobierała dwie liczby typu 

Integer

 i zwracała ich iloczyn. Co

jednak byłoby, gdyby trzeba było mnożyć także liczby typu 

Double

 albo 

Word

? W po-

przednich wersjach Delphi konieczne było napisanie kilku funkcji o odpowiednich pa-

rametrach:

{deklaracje w programie napisanym w Delphi 1, 2 albo 3}
function MnozenieInt(Liczba1, Liczba2 : Integer) : Integer;
function MnozenieDouble(Liczba1, Liczba2 : Double) : Double;
function MnozenieWord(Liczba1, Liczba2 : Word) : Word;

Znacznie prostszym rozwiązaniem byłoby stworzenie jakiejś jednej uniwersalnej funkcji

Mnozenie

, która wiedziałaby, kiedy mnożyć liczby 

Integer

, kiedy 

Double

 a kiedy 

Word

.

W Delphi 4 jest to możliwe – właśnie dzięki przeciążaniu. Oto, jak deklaracje takiej

funkcji wyglądają w Delphi 4:

{deklaracje w programie napisanym w Delphi 4}
function Mnozenie(Liczba1, Liczba2 : Integer) : Integer; overload;
function Mnozenie(Liczba1, Liczba2 : Double) : Double; overload;
function Mnozenie(Liczba1, Liczba2 : Word) : Word; overload;

background image

94

Część I

94

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Nadal trzeba napisać oddzielne definicje dla każdej z wersji, ale używając tych funkcji

można już posługiwać się jedną nazwą. Kompilator troszczy się o wywołanie odpo-

wiedniej wersji w zależności od parametrów wywołania. Na przykład:

var
  X, Y, Z : Double;
begin
  X := 1.5;
  Y := 10.5;
  Z := Mnozenie(X, Y);
end;

Kompilator widząc, że do funkcji przekazywane są liczby typu 

Double

 wywołuje funkcję

Mnozenie

, która mnoży liczby typu 

Double

. Analogicznie, jeżeli parametrami są liczby

typu 

Integer

, kompilator wywołuje funkcję mnożącą liczby typu 

Integer

.

Przeciążane funkcje rozróżniane są między sobą tylko i wyłącznie na pod-
stawie typu lub liczby parametrów, nie na podstawie typu wyniku. Nie
można deklarować dwóch funkcji o tych samych nazwach, takich samych
parametrach, różniących się jedynie typem wyniku:

function Funkcja01 : Integer; overload;
function Funkcja01 : Word; overload;

Przy próbie kompilacji programu z dwiema powyższymi liniami wystąpi błąd

Declaration of 'Funkcja01' differs from previous decla-
ration.

Parametry domyślne procedur i funkcji

Procedura lub funkcja może posiadać parametry domyślne, tzn. takie, które
w przypadku braku odpowiednich parametrów przy wywołaniu zastępują
je, przekazując przy tym określoną wartość.

 Przykład funkcji posiadającej parametr domyślny przedstawiony jest poniżej:

{Deklaracja procedury}
{Parametr 'NajpierwWyczysc' ma domyślną wartość False}
procedure Przerysuj(NajpierwWyczysc : Boolean = False);
[Definicja procedury}
procedure Przerysuj(NajpierwWyczysc : Boolean);
begin
  if NajpierwWyczysc then begin
    {instrukcje czyszczące ekran}
  end;
  {instrukcje rysujące na nowo}
end;

Można tę funkcję wywoływać z parametrem lub bez parametru. Gdy wywołuje się  ją

z parametrem, zachowuje się ona tak, jak zwyczajna funkcja. Gdy natomiast nie poda się

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

95

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

95

parametru podczas wywołania, funkcja przyjmie, że ten parametr podano i że ma on

wartość 

False

. Dwie następujące linie kodu działają więc identycznie:

Przerysuj;
Przerysuj(False);

Deklarując funkcję można łączyć parametry domyślne ze zwykłymi:

{deklaracja}
function GrajPlikWave(Nazwa : string; WPetli : Boolean = False;
LiczbaPowtorzen : Integer = 10) : Integer;

[wywołania funkcji GrajPlikWave}
R := GrajPlikWave('chime.wav');

{pojedyncze odtworzenie}

R := GrajPlikWave('ding.wav', True);

{odtworzenie 10 razy}

R := GrajPlikWave('bell.wave', True, 5);

{odtworzenie 5 razy}

Parametry domyślne mogą zaoszczędzić czasem dużo pisania przy tworzeniu programu.
Jeżeli na przykład napisałeś funkcję, która w 99 % wywołań ma te same parametry,
możesz je uczynić domyślnymi. Jeżeli trzeba podać inne parametry – wystarczy je po
prostu wpisać.

Jeżeli w deklaracji funkcji występują jakieś parametry domyślne, muszą wy-
stąpić na końcu listy parametrów. Poniższa deklaracja nie jest prawidłowa:

procedure MojaProcedura(X : Integer; Y : Integer = 10; Z :
Integer);

Aby ta funkcja mogła się prawidłowo kompilować, należy parametr do-
myślny 

Y

 przesunąć na koniec listy:

procedure MojaProcedura(X : Integer; Z : Integer; Y :
Integer = 10);

Podsumowanie

Poznałeś w tym rozdziale podstawowe zagadnienia Object Pascala. Było to konieczne,
żeby móc w ogóle rozpocząć pisanie programów w Delphi. Na początku rozdziału zaj-
mowaliśmy się różnymi typami pętli, następnie omawiałem instrukcję 

case

 i jej stosowanie.

Następnym zagadnieniem był zakres widzialności zmiennych, potem omawiałem rekordy.
Ukoronowaniem rozdziału były funkcje i procedury.

Warsztat

Warsztat składa się z pytań kontrolnych oraz ćwiczeń utrwalających i pogłębiających
zdobytą wiedzę. W razie trudności lub wątpliwości, odpowiedzi do tych pytań zamiesz-
czone są w Dodatku A, „Quiz – odpowiedzi”.

background image

96

Część I

96

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

Pytania i odpowiedzi

υ 

Jak głęboko można zagnieżdżać instrukcje 

if

?

Formalnego ograniczenia nie ma. Zbyt skomplikowane konstrukcje jednak stają
się praktycznie nieczytelne i niemodyfikowalne.

υ 

Czy pętle będą automatycznie kończyć swoje działanie, jeżeli coś pójdzie
nie tak?

Nie. Jeżeli program wpadnie w nieskończoną  pętlę, jedynym sposobem na jej
przerwanie będzie zakończenie tego programu przez użytkownika z poziomu
Menadżera Zadań Windows lub poprzez wybranie opcji 

Run | Program reset

z poziomu Delphi IDE.

υ 

Czy w każdej instrukcji 

case

 musi być słowo 

else

?

Nie, sekcja 

else

 jest opcjonalna.

υ 

Czy w programie może istnieć więcej niż jedna zmienna o tej samej nazwie?

Tak, jeżeli będą one w różnych zakresach widzialności. Na przykład, można
zadeklarować zmienną globalną 

X

 i zmienną lokalną o tej samej nazwie.

υ 

Jakie są korzyści z przeciążania procedur i funkcji?

Przeciążanie funkcji i procedur umożliwia deklarowanie kilku funkcji lub proce-
dur o tej samej nazwie, które wykonują te same operacje na parametrach różnych
typów. Na przykład można zadeklarować funkcję 

RysujFigure

, której parametrem

raz może być odcinek, raz trójkąt, a raz koło. Unika się w ten sposób deklarowania
dużej liczby funkcji o różnych nazwach, przez co upraszcza się programowanie.

υ 

Czy można używać typu rekordowego bez deklarowania zmiennych tego
typu?

Nie. Konieczne jest zadeklarowanie odpowiednich zmiennych, bez których
korzystanie z typów rekordowych nie jest możliwe.

Quiz

 

1. 

Które instrukcje są wykonywane, jeżeli wyrażenie warunkowe w instrukcji 

if

ma wartość 

True

?

 

2. 

Ile wyników może zwrócić funkcja?

 

3. 

 Jaka (oprócz składniowej) jest różnica między pętlą 

while

 i pętlą 

repeat

?

 

4. 

Jak działają procedury 

Break

 i 

Continue

?

background image

Rozdzia³ 2. 

 Pascal bardziej zaawansowany

97

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc

97

 

5. 

Co to jest zmienna globalna?

 

6. 

Czy rekord może zawierać w sobie dane różnych typów (

Char

Integer

,

Word

 itd.)?

 

7. 

Jak można odwoływać się do pól rekordu?

 

8. 

Ile może być w programie funkcji i procedur?

 

9. 

Czy funkcja może wywołać inną funkcję lub procedurę?

 

10. 

Czy rekordy można umieszczać w tablicach?

Ćwiczenia

 

1. 

Napisz procedurę o nazwie 

Test2

, która zmienia właściwość 

Caption

 kompo-

nentu 

Label

. Umieść na formularzu przycisk, po naciśnięciu którego nastąpi

wywołanie procedury 

Test2

.

 

2. 

Dodaj do programu z ćwiczenia 1 procedurę 

Test1

, która wywołuje procedurę

Test2

. Zmień procedurę obsługi zdarzenia 

OnClick

 komponentu 

Button

 tak,

żeby wywoływała ona procedurę 

Test1

 zamiast 

Test2

.

 

3. 

Napisz program wyświetlający w komponencie 

Memo

 20 razy tekst „Będę od

dzisiaj słuchał się mamy”.

 

4. 

Stwórz rekord zawierający następujące dane o pracownikach: imię, nazwisko,
adres, data zatrudnienia oraz pole zawierające informację, czy dany pracownik
jest ubezpieczony.

background image

98

Część I

98

C:\WINDOWS\Pulpit\Szymon\Delphi 4 dla każdego\02.doc