Delphi od podstaw - rozdział 02
Rozdział 2 - podstawy języka Object Pascal
Spis treści:
...podstawy Object Pascal'a
Trochę o modułach
Komentarze
Zmienne
Stałe
Instrukcje if, then, else
Operatory
Instrukcja case
Typy
Rzutowanie
Konwersja
Tablice
Procedury i funkcje
Moduły
Rekordy
Instrukcja wiążąca with
Operacje matematyczne
Pętle
Pętla for
Pętla repeat
Pętla while
Słowo o algorytmach
Polecenia Continue i Break
Etykiety
Funkcje Pred i Succ
Podsumowanie
Cóż to jest ten Object Pascal? Delphi wykorzystuje język
Pascal. Język ten unowocześniono nadając mu nową nazwę - Object Pascal.
Jedni mówią, że programują w Pascalu, drudzy, że w Object Pascalu, a
jeszcze inni mówią, że w Delphi. Ja na tym etapie będę używał nazwy
Object Pascal...
W poprzednim rozdziale napisałeś swój pierwszy program w
Delphi. Cóż pisać nic nie musiałeś, ale program stworzyłeś prawda? Na
samym początku, aby łatwiej Ci było przyswoić ten właśnie język nie będziemy
używać formularzy ani komponentów. Jeżeli masz otwarte Delphi to zamknij
okno formularza oraz edytor kodu. Delphi powinno Cię spytać przy zamykaniu,
czy chcesz zachować zmiany w formularzu ( Save changes to Unit1.pas? ). Naciśnij
No. Ok, formularz jest już zamknięty, edytora kodu także nie widać. Teraz z
menu Project wybierz View Source ( w Delphi 2 jest to View -> Project Source
). Na ekranie pojawił się znów edytor kodu, a w nim zawartość pliku DPR:
program Project1;
uses
Forms;
{$R *.RES}
begin
Application.Initialize;
Application.Run;
end.
Napiszemy teraz program bez wykorzystania formularza ani
komponentów. Na początek...
...podstawy Object Pascal'a
Przyswajaj się z informacją, że prawie każda linia komend
zakończona jest znakiem średnika. Są oczywiście pewne wyjątki. Ogólnie możesz
przyjąć, że wszystkie wyrazy, które Delphi wytłuszcza nie kończą się
znakiem średnika ( wyjątek - słowo end ). Właściwy kod programu wpisywany
jest pomiędzy słowa begin oraz end. Ilość beginów musi się równać ilości
endów inaczej Delphi zasygnalizuje błąd, że brak słowa end. Pierwsza linia
kodu źródłowego musi zaczynać się słowem kluczowym program po którym następuje
wpisanie nazwy programu. Idziemy dalej. Słowo kluczowe uses. Po tym słowie
wpisywane są moduły.
Moduł - jest to plik tekstowy, który może być kompilowany do postaci
wykonywalnej. Programujący wcześniej w Turbo Pacalu albo w C++ wiedzą o co
chodzi. Czytaj dalej, a dowiesz się czegoś więcej.
Już niebawem więcej o modułach. Przeanalizujmy dalszy ciąg
programu. Następuje tam taka linia: {$R *.RES}. Jest
to tzw. dyrektywa. Na razie się tym nie przejmuj - umówię to później. Na
razie tę dyrektywę możesz usunąć. Idziemy dalej, słowo kluczowe begin. Sygnalizuje
ono początek programu - od tego miejsca program będzie wykonywał polecenia.
Następne dwie linijki też możesz usunąć - nie będą nam teraz potrzebne.
No i na końcu słowo end ( z kropką na końcu ) "mówi", że w tym
miejscu program się zakończył. Możesz swój projekt zapisać gdzieś na
dysku. Zauważ, że podczas zapisywania program nie będzie Cię prosił o zapis
formularza, bo go przecież zamknąłeś, nie? No i w katalogu z programem jest
mniej plików.
Trochę o modułach
Doprowadź program do takiej postaci:
program drugi;
uses
Forms;
begin
MessageBox(0, 'Cześć, jestem oknem!', 'Hiehie', MB_OK);
end.
Teraz spróbuj skompilować program ( Ctrl + F9 ). Nie można!
Występuje błąd: [Error] drugi.dpr(7): Undeclared identifier: 'MessageBox'
Program nie wie, co to za polecenie - MessageBox. Wszystko za sprawą modułów.
Tak jak powiedziałem wcześniej w modułach znajdują się deklaracje różnych
poleceń. Akurat deklaracja polecenia MessageBox znajduje się w module Windows.
Tak więc zamiast słowa Forms wpisz Windows.
uses
Windows;
Teraz możesz uruchomić program ( klawisz F9 ). Po
skompilowaniu wyświetli się okienko z tekstem. Dobrze. Zacznijmy omawiać komendę
MessageBox. Jest to pierwsze polecenie, które poznałeś! Jak widzisz po nazwie
komendy w nawiasach trzeba wpisać potrzebne jej informacje. Informacje te
wpisuje się po przecinkach. Pierwszy parametr to tzw. uchwyt. Na razie nie
zawracaj sobie tym głowy - nie mamy formularza to na to miejsce wpisujemy 0.
Kolejny parametr to tekst, który ma pojawić się w okienku - wpisujemy go w
apostrofach. Następny parametr to tekst, który pojawi się na belce tytułowej
okna. Ostatni parametr to przycisk, który pojawi się w oknie. Na razie warto
wiedzieć, że MB_OK to znaczy, że będzie wyświetlany jedynie przycisk
OK.
Spójrz teraz do katalogu, w którym masz zapisany projekt.
Powinien być w nim plik EXE, który zajmuje jedynie... 16 kB! Niesamowite co?
Pierwszy nasz program zajmował aż ~300, a ten tylko 16. Wszystko dlatego, że
nie zastosowaliśmy formularzy, ani modułu Forms, który drastycznie zwiększa
rozmiar EXEka.
Komentarze
Komentarze są najprostszym elementem języka ( każdego języka
). Właściwie nie ma nic do wyjaśnienia. Jak sama nazwa wskazuje służą do
komentowania kodu. Nie są one brane przez kompilator przy kompilacji i możesz
wpisywać w nich co chcesz. Jest kilka stylów komentarzy:
// To jest komentarz jednej linii
{
To może być komentarz wielu linii
}
(*
To jest jeszcze jeden komentarz jednej linii { może zawierać nawiasy klamrowe }
*)
Zmienne
Zmienne są bardzo ważnym elementem programowania. Praktycznie nie ma
programu bez wykorzystania zmiennych. Otóż zmienne umożliwiają
przechowywanie w pamięci komputera jakiś wartości jak tekst, liczby itp.
Zmienne deklaruje się za pomocą słowa var. Oto przykład zmiennej:
var
MojaZmienna : String;
Po słowie var może znaleźć się bardzo wiele ( nieskończenie wiele )
zmiennych. Budowa przedstawia się następująco: najpierw unikalna nazwa
zmiennej, która nie może się powtarzać. Następnie po znaku dwukropka typ
zmiennej oczywiście zakończony średnikiem. Różne typy zmiennych omówię później.
Na razie najważniejsze jest to, że typ String umożliwia przechowywanie wartości
tekstowych. Przy deklarowaniu zmiennych można od razu przypisać im wartość
domyślną:
var
MojaZmienna : String = 'To jest moja pierwsza zmienna';
Zauważ, że przypisanie domyślnej wartości odbywa się po znaku równości.
Oto podstawowe typy zmiennych:
Nazwa Zakres
Byte 0..255
Integer -2 147 483 648..2 147 483 647
Int64 -9 223 372 036 854 775 808..9 223 372 036 854 775 807
Double zmiennoprzecinkowy
Currency zmiennoprzecinkowy
Word 0..65 000
Char znak
Pewnie wcześniej się zastanawiałeś "Skąd komputer wie ile pamięci
ma zarezerwować dla mojej zmiennej?". Otóż nie wie. Wynika to z typu
zmiennej. Np. typ Integer zajmuje w pamięci 4 bajty, a typ Int64 ( nie występuje
w Delphi 2 ) już 8 bajtów. Typ Char, który może przechować tylko pojedynczy
znak zajmuje 1 bajt. Najczęściej używanym typem do przechowywania wartości
liczbowych jest typ Integer. Zastosujmy zmienne w praktyce. Dokonaj zmiany w
poprzednim tworzonym przez nas programie:
{
Copyright (c) 2001 - Adam Boduch
}
program zmiene;
uses
Windows;
var Imie : PChar; // zmienna tekstowa
begin
Imie := 'Adam'; // przypisanie wartości zmiennej
MessageBox(0, 'Cześć, to moje imię', Imie, MB_OK);
end.
Zauważ, że zmienne deklarowane są poza blokiem begin..end. Zauważ, że
nowy typ deklarowany w programie to PChar. PChar jest również typem, który
umożliwia przechowywanie tekstu, ale o tym później. No więc w bloku begin
nastąpiło przypisanie wartości do zmiennej. Przypisanie wartości następuje
za pomocą znaku :=. Tekst, który ma być przypisany oczywiście musi być
wpisany w apostrofach. Jeżeli deklarujesz typ, który przechowuje liczby to
oczywiście liczby nie wpisuj w apostrofach. Przy wypisywaniu zmiennych nie
ma znaczenia w jaki sposób to zapisujesz. Możesz więc napisać tak:
var
MojPiesek, MojKotek : String;
Albo tak:
var
MojPiesek : String;
MojKotek : String;
Stałe
Stałe także służą do przechowywania wartości tyle, że w odróżnieniu
od zmiennych tych wartości, które zostały przypisane podczas pisania programu
nie można później zmieniać. Stałe deklaruje się po słowie kluczowym const.
const
MojaStala = 1;
Imie = 'Adam';
Przy deklaracji stałych nie musisz podawać typu zmiennych aczkolwiek możesz.
Dla wartości liczbowych Delphi automatycznie przypisuje jej typ Integer. Dla
tekstu jest to String. Nie musisz się na to godzić. Jeżeli deklarujesz
stałą tekstową to Delphi jak już powiedziałem przypisuje jej typ String. Jeżeli
chcesz, aby to był typ PChar to piszesz tak:
const
Imie : PChar = 'Adam';
No i teraz stała Imie jest stałą typu PChar.
Instrukcje if, then, else
Instrukcje if, then można przetłumaczyć na polski tak: "Jeżeli coś
tam, coś tam będzie tak to wtedy zrób coś tam coś tam.". Ta
instrukcja służy do porównywania wartości. Przy okazji poznasz nowe polecenia... Do
programu dodaj zmienną "Wylosowanaliczba" typu Integer. Cały kod
programu powinien wyglądać tak:
{
Copyright (c) 2001 - Adam Boduch
}
program ifthen;
uses
Windows;
var WylosowanaLiczba: Integer;
begin
Randomize; // uruchamiamy bęben losujący :)
WylosowanaLiczba := Random(20); // losuj z zakresu 19
if WylosowanaLiczba < 10 then
MessageBox(0, 'Wylosowana liczba jest mniejsza niż 10', '{none}', MB_OK);
if WylosowanaLiczba > 10 then
MessageBox(0, 'Wylosowana liczba jest większa niż 10', '{none}', MB_OK);
end.
Ufff, to już jest trudniejsze, prawda? Najpierw opiszę procedurę losowania
liczby. Na samym początku należy użyć polecenia Randomize. Polecenie
Random(20) losuje liczbę od 0 do 19. Tak się składa, że Delphi nie losuje od
1 do 20 tylko właśnie od 0 do 19. Tak już jest. No więc losuje i wylosowaną
wartość przypisuje do zmiennej WylosowanaLiczba. Następnie następuje
sprawdzenie jaka liczba została wylosowana. Jeżeli jest mniejsza od 10 to
zostaje wyświetlony odpowiedni komunikat. Jeżeli jest większa od 10 to także
wyświetlany jest komunikat. Dosłownie instrukcje if można przetłumaczyć
tak: "Jeżeli zmienna <<WylosowanaLiczba>> jest mniejsza od 10
to...". Porównanie następuje za pomocą znaku < oraz >, które
oczywiście tak jak w matematyce oznaczają większe i mniejsze.
W tym miejscu chciałbym wspomnieć o nowym typie, z którego w przyszłości
korzystać będziesz często. Ten typu to Boolean. Nie przybiera on wartości
liczbowych ani tekstowych. Może przyjmować wartość TRUE ( prawda ), albo
FALSE ( fałsz ).
if ProgramUruchomiony = true then
{ coś }
Jeżeli napiszesz tak:
if ProgramUrhcomiony then
{ coś }
Delphi będzie wiedział, że jak nie napisałeś true, ani false to chodzi
Ci o TRUE.
Operatory
Operatory bardzo często są wykorzystane właśnie wraz z instrukcją if.
Oto podstawowe operatory:
Symbol
Opis
:=
Operator przypisania;
=
Operator równości
>
Większe od...
<
Mniejsze od...
>=
Większe, równe od..
<=
Mniejsze, równe od
<>
Różne od...
+
Operator dodawania
-
Odejmowanie
/
Dzielenie.
*
Mnożenie
div
Dzielenie z odcinaniem reszty z dzielenia.
mod
Dzielenie z pozostawianiem jedynie reszty z
tego dzielenia
and
Operator and ( ang: lub ). Porównywanie
wielu warunków.
or
Operator or ( ang. lub ).
not
Operator not (ang. nie ).
A oto przykład połączenia operatorów z instrukcją if, then:
if (Liczba > 100) and (Liczba < 150) then { jeżeli liczba jest większa od 100, ale mniejsza od 150 }
if (Liczba <> 100) and not (Liczba = 120) then { jeżeli liczba jest rożna od 100 i nie jest to 120 }
if (Liczba < 100) or (Liczba < 150) then { jeżeli liczba jest mniejsza od 100 oraz mniejsza od 150 }
Zauważ, że jeżeli masz więcej warunków do spełnienia to musisz je wsiąść
w nawias.
Do czego w takim razie służy else? Można to przetłumaczyć jako: "w
przeciwnym wypadku". Tzn., co program ma robić jeżeli warunek nie
zostanie spełniony:
if Liczba = 100 then { jezeli liczba jest rowna 100 to rób cos tam }
MessageBox(0, 'Jest to liczba 100', '', MB_OK)
{ w przeciwnym wypadku }
else MessageBox(0, 'Cholera, nie wiem co to za liczba', '', MB_OK);
Jeżeli wylosowana liczba to 100 wyświetl okienko. Zauważ, że po poleceniu
MessageBox nie ma średnika! Wynika to dlatego, że następnym poleceniem będzie
else. Ale uważaj! Jeżeli po instrukcji if, then będzie więcej niż jedna
komenda to musisz wszystko wsiąść dodatkowo w słowa begin i end:
if Liczba = 100 then
begin { <-- trzeba begin bo beda po tym dwa polecenia! }
MessageBox(0, 'Jest to liczba 100', '', MB_OK); { <-- jest średnik!!! }
MessageBox(0, 'Zgadłeś! Brawo!', '', MB_OK); { <-- tu także jest średnik! }
end else MessageBox(0, 'Cholera, nie wiem co to za liczba', '', MB_OK);
Niestety na początku może to być mylące, ale niestety trzeba to zapamiętać.
Jeżeli nie ma else na końcu to cały listing przedstawiał będzie się tak:
if Liczba = 100 then
begin { <-- trzeba begin bo beda po tym dwa polecenia! }
MessageBox(0, 'Jest to liczba 100', '', MB_OK); { <-- jest średnik!!! }
MessageBox(0, 'Zgadłeś! Brawo!', '', MB_OK); { <-- tu także jest średnik! }
end;
Instrukcja case
Instrukcja case jest w działaniu podobna do instrukcji if. Wymyślił ją
pewnie ktoś komu nie chciało się pisać tyle razy if. Stosujemy ją bowiem
wtedy kiedy mamy dużo warunków if.
var Liczba: Integer;
sText : String;
begin
Randomize; // uruchamiamy bęben losujący :)
Liczba := Random(20); // losuj z zakresu 20
case Liczba of
1: sText := 'Kurde, wylosowałeś 1!';
10: sText := 'Sam środek!';
19: sText := 'Sam koniec';
end;
end.
Budowa instrukcji case jest także specyficzna. Najpierw słowo kluczowe case,
później zmienna, która będzie porównywana, a na końcu słowo of. Później
wartości zmiennej "Liczba". Np. jeżeli wylosowana zostanie 1 to
potem średnik. Następnie chcemy, aby do zmiennej sText przypisać jakiś
tekst. Itd. W instrukcji case możesz także wykorzystać instrukcję else:
case Liczba of
1: sText := 'Kurde, wylosowałeś 1!';
10: sText := 'Sam środek!';
19: sText := 'Sam koniec';
else sText := 'Eeee, już nic.';
end;
Tak jak w przypadku instrukcji if jeżeli masz dwie linie komend musisz
wszystko wziąć pomiędzy blok begin i end:
case Liczba of
1: begin { będą dwie linie - trzeba użyć słowa begin }
sText := 'Kurde, wylosowałeś 1!';
Liczba := 2;
end; { koniec całego bloku }
{ ... }
end;
Instrukcja case ma jeszcze jedną zaletę. Można w niej określić wartość
od do - spójrz:
case Liczba of
1..10: sText := 'Kurde, wylosowałeś 1.. albo 10!';
11..20: sText := 'Sam środek!';
21..40: sText := 'Sam koniec';
end;
Rozumiesz? Tekst "Sam koniec" zostanie wyświetlony wtedy, gdy
zmienna Liczba będzie wartości od 21 do 40.
Typy
Nowe typy danych można w programie rejestrować stosując słowo kluczowe type.
Np.:
type
TPartie = (ppSLD, ppSamoobrona, ppPO, ppPiS);
Można również deklarować typy liczbowe:
type
NowyTyp = 0..20;
W tym wypadku zmienna korzystająca z tego typu może mieć wartość od 0 do
20. Tak, teraz możemy normalnie korzystać z tego typu:
var NT : NowyTyp;
No, i wszystko jasne..
Napiszmy teraz przykładowy program korzystający z typów. Oto cała treść
programu - przyjrzyj mu się, a ja zaraz go opiszę:
{
Copyright (c) 2001 - Adam Boduch
}
program typy;
uses
Windows;
type
TPartie = (ppSLD, ppSamoobrona, ppPO, ppPiS);
var
sText : PChar;
Wybory : TPartie;
begin
Randomize; // uruchamiamy bęben losujący :)
Wybory := TPartie(Random(4));
case Wybory of
ppSLD: sText := 'Sebastian Florek pomógł! Miler się cieszy';
ppSamoobrona: sText := 'Idziemy blokować drogi! Lepper na prezydenta!';
PPPO : sText := 'Nie finansować partii z budżetu państwa!';
ppPiS : sText := 'Przywrócić karę śmierci!';
end;
MessageBox(0, sText, 'Wybory 2001', MB_OK);
end.
Co my tu mamy... Zadeklarowałem nowy typ TPartie ( reguła nakazuje, aby
nowy typ nazywać od litery T ). Później utworzyłem zmienną do tego typu i
nazwałem ją Wybory. Następnie do zmiennej Wybory przypisana zostaje losowa
wartość ( albo ppSLD, albo ppSamoobrona, ppPo lub ppPiS ). Zwróć uwagę na
specyficzny zapis procedury losowania:
Wybory := TPartie(Random(4));
Losujemy spośród czterech bo tyle mamy partii. To co tutaj użyłem nazywa
się rzutowaniem. O rzutowaniu będzie mowa później. Na razie powiem, że jest
to sposób na oszukanie kompilatora.
Idziemy dalej: następnie w zależności od wylosowanej partii do zmiennej
sText zostaje przypisany odpowiedni tekst. Następnie ten tekst zostaje wyświetlony
w oknie.
Rzutowanie
W poleceniu MessageBox trzeba podawać kilka parametrów. W przypadku
drugiego i trzeciego parametru ma być to tekst, który zostanie wyświetlony w
okienku. Ten tekst musi być typu PChar. Możesz więc napisać tak i będzie
dobrze:
var
Tekst, Tytul : PChar;
begin
Tekst := 'Delphi jest fajne!';
Tytul := 'Nie wiem?';
MessageBox(0, Tekst, Tytul, MB_OK);
Tak, będzie dobrze. Dlaczego? Bo zmienne Tekst oraz Tytul są typu PChar.
Teraz zamiast typu PChar napisz String:
var
Tekst, Tytul : String;
begin
Tekst := 'Delphi jest fajne!';
Tytul := 'Nie wiem?';
MessageBox(0, Tekst, Tytul, MB_OK);
Takie coś już nie przejdzie. Kompilator wyświetli błąd: [Error]
Project1.dpr(21): Incompatible types: 'String' and 'PChar'. Kompilator próbuje
Ci powiedzieć: "Co Ty wyprawiasz! Przecież typy PChar i typ String to
dwie różne rzeczy!". Częściowo ma racje, ale to tylko głupia maszyna i
da się ją oszukać. Do tego właśnie służy rzutowanie. Polega to na
oszukaniu kompilatora. On "myśli", że jest to typ PChar, a ty
stosujesz typ String:
var
Tekst, Tytul : String;
begin
Tekst := 'Delphi jest fajne!';
Tytul := 'Nie wiem?';
MessageBox(0, PChar(Tekst), PChar(Tytul), MB_OK);
Jest to rzutowanie typu String na typ PChar. Kompilacja się powiedzie i
wszystko będzie dobrze. Fajnie, nie? Ale takie coś przejdzie tylko do czasu.
Bo takie coś już nie wyjdzie:
var
Licznik : Integer;
begin
Licznik := 1;
MessageBox(0, PChar(Licznik), '', MB_OK);
end.
Fachowca by powiedział: "To oczywiste. Przecież typy Integer i PChar
zapisane są w odrębnych komórkach pamięci i bleblelble". Ktoś jednak
pomyślał i stworzył:
Konwersja
Konwersja polega na wykorzystaniu gotowych poleceń do zmiany typów. Jeżeli
np. typ Integer chcesz przedstawić w postaci tekstu ( String ) stosujesz
polecenie IntToStr. Zaraz przetestujemy to w praktyce. Żeby użyć tego
polecenia do listu modułów uses musisz dodać moduł SysUtils. Gotowe? A,
wiesz co? Dodaj jeszcze moduł Dialogs. Powinno to wyglądać tak:
uses
Windows,
SysUtils, { <-- ten moduł jest konieczny, aby zastosować konwersje }
Dialogs; { <-- ten zawiera jedno polecenie - ShowMessage }
Moduł Dialogs zawiera polecenie ShowMessage, którego będziemy używali.
Jak łatwo się domyśleć polecenie to wyświetla w oknie tekst ( to taka
odmiana polecenia MessageBox ). Wpisz taki tekst do programu ( komentarze możesz
oczywiście pominąć ):
var
Data : TDateTime; { nowy typ - przechowuje datę }
Rozdzial : Integer; { znany już typ Integer }
Imie : String; { również znany typ String }
begin
Data := Now; { przypisuje zmiennej aktualną datę }
Rozdzial := 2;
Imie := 'Komputer';
ShowMessage('Cześć, mam na imię ' + Imie + ', a Ty właśnie czytasz ' + IntToStr(Rozdzial) +
' rozdział książki o Delphi! Dzisiaj jest: ' + DateToStr(Data));
end.
Hohhoho. To coś trudniejszego, ale jakże przydatne w programowaniu.
Zacznijmy od początku. Polecenie ShowMessage ma tylko jeden parametr - jest nim
tekst, który ma być wyświetlony w okienku. Tekst ten ma być typu String.
Operator + służy do połączenia odpowiednich części ( zmiennych ). Po
prostu gdy chcesz w dane miejsce wstawić wartość zmiennej to kończysz tekst
stawiając apostrof, następnie znak + mówiący o podłączeniu zmiennej. Później
wpisujesz zmienną, która ma być w to miejsce wstawiona. W powyższym wypadku jeżeli
będziesz chciał wstawić zmienną, która nie jest typu String trzeba będzie
zastosować konwersje. Program możesz uruchomić i sprawdzić jak działa.
Oto
inne polecenia konwertujące typy:
IntToStr - konwertuje zmienna "Integer" na "String"
StrToInt - "String" na "Integer"
StrPas - "PChar" na "String"
StrPCopy - "String" na "PChar"
TimeToStr - zmienna "Time" na "String"
DateToStr - zmienna "Date" na "String"
StrToDate - "String" na "Date"
StrToTime - "String" na "Time"
CurrToStr - "Currency" ( zmiennoprzecinkowy ) na "String"
StrToCurr - "String" na "Currency"
FloatToStr - zmiennoprzecinkowy na "String"
Tablice
Tablice to zbiór zmiennych tego samego typu. Popatrz zamiast deklarować
kilka zmiennych tego samego typu:
var
Zmienna1, Zmienna2, Zmienna3, Zmienna4 : String;
Możesz zapisać to w formie tablicy:
var
Zmienna : array[0..3] of String;
Tablice deklaruje się za pomocą słowa kluczowego array. Następnie w
nawiasach klamrowych wpisujesz z ilu elementów ma się składać tablica. W tym
wypadku z czterech ( 0 to także element tablicy ). Na końcu jakiego typu
mają być elementy tablicy. Teraz jeżeli chcesz poszczególnym elementom
przypisać jakieś wartości robisz tak:
Zmienna[0] := 'Adam';
Zmienna[1] := 'Marta';
Zmienna[2] := 'Zuzia';
Zmienna[3] := 'Bronia';
Nic nadzwyczajnego. Elementy tablicy mogą być wykorzystane jak zwykłe
zmienne:
ShowMessage(Zmienna[0] + ' ' + Zmienna[1]);
Począwszy od Delphi 4 można deklarować w programie tablice dynamiczne.
Tzn., podczas pisania programu nie określasz z ilu elementów będzie się składać
tablica - robisz to później.
var Dynamiczna : array of String;
Z ilu elementów składa się tablica? Nie wiadomo. Deklarujesz to później.
W tym celu musisz zastosować polecenie SetLength. Oto przykładowy program:
{
Copyright (c) 2001 - Adam Boduch
}
program tablica;
uses
Windows,
Dialogs;
var Tab : array of String; // tablica dynamiczna
begin
SetLength(Tab, 4); // deklarujesz, z ilu elementów będzie się składać tablica
{ wpisujesz elementy }
Tab[0] := 'Adam';
Tab[1] := 'Marta';
Tab[2] := 'Zuzia';
Tab[3] := 'Bronia';
Randomize;
ShowMessage(Tab[Random(4)]);
end.
W tym wypadku w okienku pojawi się losowo wybrany element tablicy. Pytanie:
W jakich wypadkach stosować tablice dynamiczne? W takich wypadkach, w których
programista sam nie wie podczas pisania programu z ilu elementów będzie się
składać tablica. Może to być np. określane podczas trwania programu przez użytkownika.
Z tablicami wiążą się jeszcze dwa bardzo przydatne polecenia - Low i High.
Podają one kolejno najmniejszy element tablicy jak i największy. Jeżeli więc
tablica wygląda tak:
var Tab : array[10..100] of String;
To zastosowanie polecenia Low(Tab) zwróci liczbę 10 - pierwszy element
tablicy. Polecenie High natomiast zwraca liczbę 100 - ostatni element
tablicy.
Pozostało jeszcze omówienie tablic dwuwymiarowych. Oczywiście tablice można
deklarować także jako stałe.
const
Tab : array[0..1, 0..2] of String =
(('Fiat', 'Uno', '45 KM'),
('Fiat', 'Punto', '80 KM'));
W tym wypadku elementów będzie dwa, ale każdy z elementów będzie zawierał
po 3 pozycje. Może z początku nie będzie to dla Ciebie jasne. Teraz trzeba
odwołać się do poszczególnych elementów. Np. element 'Fiat' znajduje się
pod indeksem [0][0].
const
Tab : array[0..1, 0..2] of String =
(('Fiat', 'Uno', '45 KM'),
('Fiat', 'Punto', '80 KM'));
begin
ShowMessage(Tab[0][0] + Tab[0][1] + Tab[0][2]);
end.
Element 'Uno' jest pod indeksem [0][1]. Np. element 'Punto' jest pod indeksem
[1][1]. Rozumiesz?
Procedury i funkcje
Procedury i funkcje obecne są w każdym języku programowania ( w C++ są
tylko funkcje ). Są to wydzielone bloki kodu, które wykonują jakąś czynność.
Np. potrzebujesz wiele razy użyć jakiegoś kodu. Żeby nie zapisywać tego
tyle razy możesz użyć procedury. Piszesz kod tylko raz a jeżeli będziesz go
potrzebował w dalszej części programu to po prostu piszesz nazwę tej
procedury.
Procedury deklaruje się tak:
procedure MojaPierwszProcedura;
begin
{ tutaj wpisujesz kod procedury }
end;
Funkcje deklaruje się tak:
function MojaPierwszaFunkcja : Integer;
begin
{ kod funkcji }
end;
Zauważ specyficzną budowę funkcji. Funkcja ZAWSZE musi zwrócić rezultat
wykonanej operacji, a procedura nie. Napiszemy program, który będzie
podnosił liczbę do potęgi. Ale od początku. Funkcje mogą zawierać
parametry. Nie muszą, ale mogą. Parametry funkcji to dane potrzebne do jej
wykonania. Oto przykład deklaracji funkcji z parametrem:
function DoPotegi(Liczba : Integer) : Integer;
W takim wypadku jeżeli będziesz chciał wykonać funkcję DoPotegi będziesz
musiał podać jeden parametr, którym jest liczba typu Integer. Oczywiście
parametrów może być o wiele więcej:
function DoPotegi(Liczba1 : Integer; Liczba2 : Integer) : Integer;
Żeby ułatwić sobie zadanie możesz to napisać w ten posób:
function DoPotegi(Liczba1, Liczba2 : Integer) : Integer;
To co? Piszemy ten program? Cały kod wygląda tak:
{
Copyright (c) 2001 - Adam Boduch
}
program potega;
uses
Windows, SysUtils, Dialogs;
function DoPotegi(Liczba: Integer) : Integer;
begin
Result := Liczba * Liczba;
end;
begin
ShowMessage(IntToStr(DoPotegi(2)));
end.
Zwróć uwagę na naszą funkcje. Po słowie kluczowym Result deklarujemy
rezultat wykonanej funkcji. Rezultatem jest mnożenie dwóch parametrów dzięki
czemu mamy funkcję, która podnosi liczbę do potęgi. W programie rezultat
wykonania procedury zostaje wyświetlony w okienku. Teraz rozumiesz czym się różni
procedura od funkcji? Gdybyśmy zamiast funkcji użyli procedury to program by
się nie skompilował ( procedura nie może zwrócić rezultatu wykonanej
operacji ).
Bodajże także od Delphi 4 wprowadzono możliwość tzw. przeciążania
procedur i funkcji. Polega to na tym, że w programie mogą istnieć dwie
procedury/funkcje o tej samej nazwie pod warunkiem, że ich parametry będą różne.
W takim wypadku funkcję/procedurę trzeba opatrzyć dodatkowo klauzurą
overload.
function DoPotegi(Liczba: Integer) : Integer; overload;
begin
Result := Liczba * Liczba;
end;
function DoPotegi(Liczba: Currency) : Currency; overload;
begin
Result := Liczba * Liczba;
end;
W pierwszym przypadku Liczba jest typu Integer, a w drugim typu Currency. Przypomnę,
że typ Currency to typ zmiennoprzecinkowy. Teraz możemy wykorzystać jedną bąć
drugą funkcje:
DoPotegi(2.2);
Pytanie: "Skąd program ma wiedzieć, która funkcję wykorzystać?".
Po parametrze. Jeżeli parametr jest zmiennoprzecinkowy to znaczy, że chcesz
wywołać funkcję drugą, jeżeli jest to liczba cała - pierwszą procedurę.
Istnieje możliwość deklaracji "procedury w procedurze". Np:
procedure Glowna;
procedure Child;
begin
{ kod procedury }
end;
begin
end;
Teraz możesz procedurę Child używać wiele razy w procedurze Glowna jeżeli
nie chcesz wiele razu przepisywać treści procedury Child.
Deklarując procedurę lub funkcję można przypisać im wartości domyślne
tak jak w wypadku zmiennych. Oto przykład:
procedure NowaGra(ImieGracza : String; NumerGracza : Integer = 1);
Teraz jeżeli chcesz daną procedurę wywołać możesz, ale nie musisz
podawać drugiego parametru:
procedure NowaGra('Bleblelele');
Albo:
procedure NowaGra('Bleblgble', 2);
Tak i tak będzie dobrze.
Moduły
Dotąd wykorzystywaliśmy moduły gotowe, dostarczone wraz z Delphi. Teraz
stworzymy swój moduł. Możemy w nim zamieszczać procedury i funkcje, które później
będą wykorzystywane w programie. Nowy moduł możesz utworzyć z menu File wybierając
New. W oknie, które się pojawi kliknij na ikonę Unit. W edytorze kody pojawi
się nowa zakładka. Jej zawartość wygląda tak:
unit Unit1;
interface
implementation
end.
Otóż KAŻDY moduł musi się składać ze słów kluczowych interface oraz
implementation. W sekcji Interface wpisuje się tylko nagłówek procedury lub
funkcji, czyli jej nazwę. Fachowo nazywa się to deklaracją. W sekcji
Implementation natomiast treść procedury/funkcji. Zapisz moduł wybierając z
menu File -> Save All. Podaje nazwę modułu - ja podałem nazwę Tools -
Delphi stworzył plik Tools.pas. Zauważysz, ze w programie, w miejscu gdzie
wypisane są moduły dodany został nowy - nasz:
uses
Windows,
SysUtils,
Dialogs,
Tools in 'Tools.pas';
Dobrze. Zajmijmy się naszym modułem. Doprowadź go do takiej postaci:
unit Tools;
interface
uses Windows;
{ deklaracje }
procedure About;
function DoPotegi(Liczba: Integer) : Integer;
implementation
{ definicje }
function DoPotegi(Liczba: Integer) : Integer;
begin
Result := Liczba * Liczba;
end;
procedure About;
begin
MessageBox(0, '© by A.B.', 'O programie...', MB_OK);
end;
end.
Zapisz swój moduł. Teraz w programie do listy uses możesz dodać
nazwę swojego modułu - Tools. W programie możesz wykorzystać procedury, które
zadeklarowałeś w swoim module pisząc po prostu nazwę tej procedury.
Musisz wiedzieć, że to co jest zawarte w sekcji implementation modułu nie
będzie widoczne dla innych modułów. Znaczy to, że program będzie ciągle wyświetlał
błąd, że nie wie co to za procedura, której chcesz użyć. Możesz więc
pisać w module procedury bez deklarowania ich w sekcji interface pod warunkiem,
że nie chcesz, aby były wykorzystywane w innych modułach.
Dodatkowo masz możliwość umieszczenia w module dwóch słów kluczowych,
które są opcjonalne. Są to initialization oraz finalization. Umieszczasz je
przed słowem kluczowym end. ( z kropką! ). Po słowie initialization możesz
zapisać instrukcje, które będą wykonywane na samym początku, a po
finalization są zapisywane instrukcje, które mają być wykonane przed zakończeniem
programu.
{ instrukcje modułu... }
initialization
ShowMessage('Rozpoczącie pracy z modułem.');
finalization
ShowMessage('Koniec pracy z modułem.');
end.
Rekordy
Rekordy to taka paczuszka. Jest to jeden typ ( lub zmienna ), która może
zawierać w sobie inne zmienne.
type
TDane = record { <-- brak średnika na końcu! }
Imie: String;
Nazwisko: String;
end;
Właśnie zadeklarowałeś nowy typ. Jest to rekord. Zawiera on w sobie inne
zmienne. Rekordy mają specyficzną budowę. Deklaruje się je poprzez słowo
kluczowe record. Na początku zapewne trudno Ci będzie zrozumieć istotę
stosowania rekordów. Sprawdźmy to w praktyce. Na początek trzeba stworzyć
zmienną, która będzie wskazywać na rekord:
var Dane : TDane; // zmienna wskazuje na rekord
Następnie należy wypełnić pola rekordu. Cały kod programu wygląda teraz
tak:
{
Copyright (c) 2001 - Adam Boduch
}
program rekord;
uses
Windows;
type
TDane = record { <-- brak średnika! }
Imie: String;
Nazwisko: String;
end;
var Dane : TDane; // zmienna wskazuje na rekord
begin
Dane.Imie := 'Adam';
Dane.Nazwisko := 'Boduch';
MessageBox(0, PChar('Nazywam się: ' + Dane.Imie + ' ' + Dane.Nazwisko), 'Hiehie', MB_OK);
end.
Użyliśmy tutaj operatora, który nie został omówiony wcześniej. Operator
ten to . Tak kropka... Jest to operator odwołania. W przyszłych rozdziałach
operatora tego będziemy używali całkiem często. Za jego pomocą możemy odwołać
się do poszczególnych elementów obiektu. W tym wypadku elementem obiektu są
zmienne zawarte w rekordzie, a samym obiektem rekord. Tak więc do zmiennych
zawartych w rekordzie przypisujemy wartości. Następnie w okienku wartości te
są wyświetlone.
W Delphi 5 ( w Delphi 4 także ) zastosowano pewne ułatwienie. Mamy możliwość
"podglądu" jakie elementy znajdują się w rekordzie. Wystarczy, że
po nazwie obiektu ( tzn., zmiennej, która wskazuje na rekord ) postawimy kropkę
i odczekamy parę sekund. Pojawi się takie okienko:
Żeby stworzyć rekord niekoniecznie trzeba deklarować nowy typ. Można to
zrobić od razu w zmiennej:
var
Dane : record { <-- brak średnika! }
Imie: String;
Nazwisko: String;
end;
Trzeba jednak uważać, aby nie postawić znaku równości ( = ). Jeżeli
deklarujesz rekord jako zmienną to stawiasz znak dwukropka tak jak to zostało
pokazane na powyższym kodzie.
Podczas zapisywania rekordów możesz przed słowem record dodać jeszcze
jedno - packed. Powoduje ono zmniejszenie rozmiaru jaki zajmuje rekord w pamięci
komputera. Różne zmienne zajmuje w pamięci określoną ilość bajtów. W
rekordzie dodaje się wszystkie zmienne ( ilość bajtów zajmowanych przez
zmienne ) i wiemy ile zajmuje w pamięci rekord. Jeżeli nie użyjesz słowa
packed to ta ilość zaokrąglana jest dodatkowo do 8 bajtów. Tak więc uzycie
słowa kluczowego packed powoduje pakowanie rekordu.
Instrukcja wiążąca with
Instrukcja ta nie robi nic specjalnego. Po prostu ułatwia programiście
pracę. Zamiast pisać:
Dane.Imie := 'Adam';
Dane.Nazwisko := 'Boduch';
Można zastosować instrukcję wiążącą i zmniejszyć ilość wypisanych słów:
with Dane do
begin
Imie := 'Adam';
Nazwisko := 'Boduch';
end;
Wszystkie elementy
Operacje matematyczne
W Object Pascal'u wykonywanie operacji matematycznych to nic trudnego.
Wykorzystuje się podstawowe operatory jak = + - / *. Wszystko jasne.
Chciałbym jednak omówić jeszcze dwie komendy - div, mod. Pierwsza z nich
oddziela resztę z dzielenia, a druga pozostawia tylko resztę z dzielenia. Spójrz
na poniższy przykład:
var
X, Y, Z : Integer;
begin
X := 13;
Y := 4;
Z := X / Y;
end.
W przykładzie tym próbujemy podzielić dwie liczby - 13 na 4. Przy próbie
skompilowania pojawia się błąd: [Error] rekord.dpr(17): Incompatible types: 'Integer' and
'Extended'. Skąd on się bierze? Próbujemy podzielić dwie całkowite liczby,
a następnie wynik przypisać do zmiennej, która także może przechowywać
tylko liczby całkowite. Kompilator próbuje nam powiedzieć, że nie wie jaki będzie
rezultat wykonanego działania i czy wynik nie będzie zmiennoprzecinkowy. Jeżeli
byłby zmiennoprzecinkowy to nie może przypisać go do typu całkowitego. Jeżeli
zamiast znaku / zastosujesz div:
Z := X div Y;
To wszystko będzie dobrze. Ewentualna reszta z dzielenia będzie obcięta.
Możesz używać operatora / ale tylko wtedy jeżeli zmienne będą typu
zmiennoprzecinkowego - np. Currency:
var
X, Y, Z : Currency;
begin
X := 13;
Y := 4;
Z := X / Y;
end.
Jeżeli wynik będzie z resztą to program ją wyświetli - jeżeli nie - wyświetli
bez reszty. Istnieją w Object Pascal'u procedury, które zaokrąglają
wartość zmiennoprzecinkową do góry lub na dół. Round zaokrągla do góry,
a Trund na dół.
Round(2.55566); // w rezultacie da 3
Trund(2.55566); // w rezultacie da 2
Pętle
Czas przejść do elementu programowania, który występuje we wszystkich językach
programowania czyli pętli...
Pętla -
instrukcja, która jest wykonywana tak długo aż nie zostanie spełniony
warunek jej zakończenia. Pętle można zastosować do ciągłego wykonywania
tej samej czynności.
Załóżmy, ze chcesz wykonać kilka razy tę samą czynność, czyli np.
kilka razy wyświetlić to samo okienko. Zamiast pisać to tak:
ShowMessage('okienko');
ShowMessage('okienko');
ShowMessage('okienko');
można zastosować pętle.
Pętla for
Jest to najprostsza ze wszystkich pętli. Stosuj ją wtedy gdy wiesz
konkretnie podczas pisania programu ile razy ta pętla ma być używana. Budowa
pętli for przedstawia się następująco:
var
I : Integer;
begin
for I := 0 to 3 do
{ polecenia }
end.
W tym wypadku instrukcje zawarte po słowie "do" będą wykonywane
czterokrotnie. Zmienna I przechowuje wartości. Może to zabrzmieć
niezrozumiale więc wyjaśniam. Po pierwszym wykonaniu danej czynności zmienna
I ma wartość 0, po drugim wykonaniu wartość 1, itd., itd. Jeżeli stosujesz
pętle for to zawsze musisz używać zmiennej. Regułą jest nadawanie zmiennej
nazwy "I". Wiadomo wtedy, że dana zmienna wykorzystywana jest do pętli
for.
Ok, budowa pętli przedstawia się następująco: na samym początku słowo
kluczowe for, następnie wartość od której pętla ma się rozpoczynać - w
naszym wypadku jest to 0. Po słowie "to" wartość na której pętla
ma się zakończyć. Na samym końcu słowo "do" i operacje do
wykonania. Jeżeli po słowie "do" jest więcej niż jedna instrukcja
to należy wszystko wsiąść dodatkowo w blok begin i end. Oto treść
pierwszego programu z pętlami:
{
Copyright (c) 2001 - Adam Boduch
}
program petlafor;
uses
Windows, Dialogs, SysUtils;
var
I : Integer;
begin
for I := 1 to 3 do
ShowMessage('To jest okienko nr: ' + IntToStr(i));
end.
Dodatkowo w oknie jest wyświetlony nr. okienka!
Jak dotąd wykonywaliśmy pętle od dołu do góry. Można odwrotnie - od góry
do dołu. Wtedy zamiast słowa kluczowego "to" stosujemy słowo "downto".
for I := 3 downto 1 do
ShowMessage('To jest okienko nr: ' + IntToStr(i));
Pętla repeat
Przy okazji omawiania tej pętli poznasz nowe właściwości funkcji
MessageBox. Otóż oprócz standardowego przycisku OK w okienku mogą być wyświetlone
również inne. Np. Tak i Nie. Funkcja MessageBox zwraca również jaki przycisk
został naciśnięty. W naszym przykładzie wyświetlane będzie okienko dopóki
użytkownik nie naciśnie przycisku Tak.
{
Copyright (c) 2001 - Adam Boduch
}
program petlaepeat;
uses
Windows;
var
Results : Integer;
begin
{ wyświetlaj okienko dopóki użytkownik kliknie na przycisk Tak }
repeat
Results := MessageBox(0, 'Cześć! Lubisz Delphi?', 'Pytanie', MB_YESNO);
until Results = ID_YES;
end.
Zmienna Results przechowuje dane jaki przycisk został naciśnięty. Jeżeli
użytkownik nacisnął przycisk Tak to zmienna Results zawiera wartość ID_YES.
Jeżeli kliknął na Nie to zawiera ID_NO. Skąd to wiem? Poczytaj pomoc do
Delphi. Naciśnij F1 i wpisz Messagebox, a zobaczysz informację na temat tej
funkcji.
Budowa pętli jest następująca: najpierw słowo kluczowe repeat po którym
następują czynności, które będą powtarzane. Na końcu słowo unitl po którym
następuje sprawdzenie, czy użytkownik rzeczywiście nacisnął przycisk
"Tak".
Pętla repeat BĘDZIE wykonywana przynajmniej raz w przeciwieństwie do...
Pętla while
Która to może nie zostać wykonana wcale jeżeli warunek jej wykonania
został spełniony. Pętla repeat jest rzadziej używana od pętli while, ale są
one do siebie podobne. Oto przykład:
var
I : Integer;
begin
I := 3; // przypisanie początekowej wartości zmiennej I
while I > 0 do // wykonuj dopóki wartość zmiennej będzie większa od 0
begin
ShowMessage('Okienko nr: ' + IntToStr(i)); // wyświetl okienko
Dec(i); // zmniejsz o jeden wartość zmiennej I
end;
end.
Zacznijmy od końca, czyli objaśnienie polecenia Dec. Otóż zmniejsza ono o
jeden wartość zmiennej I. Znaczy to samo co:
I := I -1;
Istnieje także polecenie Inc, które zwiększa wartość zmiennej o jeden.
Oba polecenia mogą zawierać jeden dodatkowy parametr, który "mówi"
o ile wartość ma być zwiększona lub zmniejszona. Domyślnie jest to 1, ale
możesz zapisać:
Inc(i, 2);
I będzie zwiększona o 2.
Wróćmy do pętli. Na samym początku zmiennej I należy przypisać wartość
domyślną. W naszym przypadku będzie to 3. Sprawdź, co będzie jeżeli nie
zadeklarujesz tej wartości. Program się wogule nie wykona. Tzn. nie program, a
pętla. Otóż w przeciwieństwie do pętli repeat pętla while może się nie
wykonać jeżeli będzie spełniony warunek jej wykonania. A jeżeli nie
przypiszesz zmiennej I wartości domyślnej to Delphi zrobi to za Ciebie i będzie
to cyfra 0. W pętli jest dokładnie napisane, że ma się wykonać TYLKO wtedy,
gdy zmienne I będzie większa od 0. Po wykonaniu czynności, czyli wyświetleniu
okienka wartość zmiennej I zostaje zmniejszona.
Słowo o algorytmach
Algorytm
- skończona sekwencja komend, która ma na celu rozwiązanie jakiegoś
problemu. Innymi słowy jest to rozwiązanie jakiegoś problemu.
Napiszmy jakiś algorytm. Zadanie będzie wyglądało następująco:
przeszukać w tablicy interesującego elementu, a następnie zwrócić indeks
pod którym się znajduje. Najpierw deklarujmy tablice:
const
{ deklarujemy tablice imion wśród których będziemy szukać }
Tablica : array[0..4] of String =
('Zenowefa', 'Anita', 'Aga', 'Magda', 'Sylwia');
Teraz najważniejsza część zadania - napisanie algorytmu, który realizował
będzie proces przeszukiwania.
function Szukaj(Element: String) : Integer;
var
I : Integer;
begin
{
Funkcja poszukuje w tablicy elementu określonego w parametreze "Element".
Jeżeli znajdzie to zwraca numer pod którym element się znajduje.
}
I := 0; // wartość początkowa
{ Kontynuj dopóki nie przeszukasz całej tablicy i dopóki nie znajdziesz elemntu }
while (I < High(Tablica)) and (Tablica[i] <> Element) do
Inc(i); // zmień obszar poszukiwać o jeden
{ jeżeli nie znajdziesz to zwróć -1 }
if Tablica[i] <> Element then Result := -1 else
Result := i; { jeżeli znajdziesz to zwróć numer pod którym się znajduje }
end;
Tylko się nie przestrasz! Większą część stanowią komentarze.
Wykorzystałem do tego pętle while. Na samym początku deklaruje wartość
zmiennej I - od tego elementu zaczynamy poszukiwania. Następnie następuje
sprawdzenie, czy przeszukano już całą tablicę i czy "przeglądany"
element jest różny od szukanego. Jeżeli tak to zwiększ obszar poszukiwań o
jeden i sprawdź, czy "przeglądany" aktualnie element nie jest tym którego
szukamy. Jeżeli nie znaleziono to zwróć -1, a w przeciwnym wypadku zwróć
indeks poszukiwanego elementu.
{
Copyright (c) 2001 - Adam Boduch
}
program algo1;
uses
Windows, Dialogs, SysUtils;
const
{ deklarujemy tablice imion wśród których będziemy szukać }
Tablica : array[0..4] of String =
('Zenowefa', 'Anita', 'Aga', 'Magda', 'Sylwia');
function Szukaj(Element: String) : Integer;
var
I : Integer;
begin
{
Funkcja poszukuje w tablicy elementu określonego w parametrze "Element".
Jeżeli znajdzie to zwraca numer pod którym element się znajduje.
}
I := 0; // wartość początkowa
{ Kontynuuj dopóki nie przeszukasz całej tablicy lub dopóki nie znajdziesz elementu }
while (I < High(Tablica)) and (Tablica[i] <> Element) do
Inc(i); // zmień obszar poszukiwać o jeden
{ jeżeli nie znajdziesz to zwróć -1 }
if Tablica[i] <> Element then Result := -1 else
Result := i; { jeżeli znajdziesz to zwróć numer pod którym się znajduje }
end;
begin
if Szukaj('Anita') <> -1 then // sprawdź, czy znaleziono
ShowMessage('Znalazłem szukany element pod indeksem: ' + IntToStr(Szukaj('Anita'))) else
ShowMessage('Nie znalazłem');
end.
Czasem zamiast poszukiwać tej, czy innej komendy do wykonania jakiegoś
zadanie wystarczy, że trochę pomyślimy i być może uda nam się dane zadanie
zrealizować. Nie jest to łatwe, przyznaje. Ale kto powiedział, że
programowanie jest łatwe?
Polecenia Continue i Break
Polecenia te wykorzystywane są wyłącznie w połączeniu z pętlami.
Pierwsze z nich powoduje przejście do samego początku pętli. Program nie
wykonuje dalszego członu pętli, a powraca na jej początek ( sprawdza warunek
jej zakończenia ). Drugie natomiast powoduje natychmiastowe przerwanie działania
pętli - wyjście z niej. Oto przykład użycia polecenia Continue:
const
{ deklarujemy tablice imion wśród których będziemy szukać }
Tablica : array[0..4] of String =
('Zenowefa', 'Anita', 'Aga', 'Magda', 'Sylwia');
procedure Szukaj(Element: String);
var
I : Integer;
begin
for I := Low(Tablica) to High(Tablica) do // punkt A
begin
if Tablica[i] = Element then // jeżeli element zostanie znaleziony...
begin
ShowMessage('Znalazłem - kontynuuje'); //... wyświetl informacje
Continue; // do punktu A
ShowMessage('Ten tekst się nie wyświetli...');
end;
end;
end;
Drugie polecenie Continue nigdy się nie wyświetli. Spowodowało to
polecenia Continue. Dzięki niemu nastąpił skok do początku pętli. Teraz
kolejny bardzo podobny przykład tyle, że z poleceniem Break:
const
{ deklarujemy tablice imion wśród których będziemy szukać }
Tablica : array[0..4] of String =
('Zenowefa', 'Anita', 'Aga', 'Magda', 'Anita'); { dwa razy Anita! }
procedure Szukaj(Element: String);
var
I : Integer;
begin
for I := Low(Tablica) to High(Tablica) do
begin
if Tablica[i] = Element then // jeżeli element zostanie znaleziony...
begin
ShowMessage('Znalazłem - przerywam'); //... wyświetl informacje
Break; // koniec programu
ShowMessage('Ten tekst się nie wyświetli...');
end;
end;
end;
Zwróć uwagę na to, że przy deklaracji tablicy dwa razy wystąpiło imię
"Anita". Lecz program jeżeli znajdzie je raz nie będzie tego robił
powtórnie. Dlaczego? Bo zastosowaliśmy komendę Break, która spowodowała właśnie
zakończenie pętli.
Etykiety
Większość programistów uważa, że stosowanie etykiet jest
"nieetyczne" i nie ma takiej konieczności. Ja jednak opiszę tutaj o
co chodzi w tych etykietach. Najprościej mówiąc powodują one
"skok" do wybranego punktu.
procedure Szukaj(Element: String);
var
I : Integer;
label
Info;
begin
for I := Low(Tablica) to High(Tablica) do
begin
if Tablica[i] = Element then // jeżeli element zostanie znaleziony...
begin
ShowMessage('Znalazłem'); //... wyświetl informacje
goto Info;
end;
end;
Info:
ShowMessage('już znalazłem');
end;
Na początek etykietę należy zadeklarować. Robi się to za pomocą słowa
kluczowego Label. Następnie nazwa etykiety. Jeżeli chcesz do niej natychmiast
przeskoczyć stosujesz słowo kluczowe goto, a następnie nazwę etykiety. To
nie wszystko bo co ma etykieta robić? Gdzieś w programie musisz napisać jej
kod. Najpierw piszesz nazwę etykiety, dwukropek, a później już kod.
Być może podałem nie jasny przykład, ale chyba rozumiesz o co
chodzi?
Funkcje Pred i Succ
Funkcje te mają prawie takie same działanie jak polecenia Inc oraz Dec.
Jedyna ważna różnica to taka, że Inc i Dec to procedury, a Pred i Succ to
funkcje.
Tak więc funkcja Pred zmniejsza o jeden - tzn:
Pred(100);
daje rezultat 99. Użycie funkcji Succ powoduje zwiększenie o jeden. Także
napisanie Succ(99) daje liczbę 100.
Operowanie na łańcuchach
Wiesz już, że tekst możesz połączyć za pomocą operatora +. To nie
wszystko. Przede wszystkim do łańcuchów możesz dodawać znaki ASCII. Zakładam,
że wiesz co to są te znaki ASCII. Wstawia się je poprzedzając kod znakiem #.
Np. znak ENTER ma kod 13 i jeżeli chcesz zrobić linię odstępu piszesz tak:
MessageBox(0, 'Pierwsza linia' + #13 + 'Druga linia', '', MB_OK);
Pewnie teraz powiesz: "Dobrze, ale skąd mam wiedzieć jaki numer
posiada konkretny znak?". Skorzystaj z programu mojego autorstwa, który
znajdziesz na dyskietce dołączonej do książki.
Możesz także mieć dostęp do poszczególnych znaków danego ciągu znaków.
Wszystko za sprawą nawiasów klamrowych []:
var
Imie : String;
Znak : Char;
begin
Imie := 'Delphi';
Znak := Imie[1];
ShowMessage('Pierwsza linia mojego imienia to: ' + Znak);
end.
Zgadnij co zostanie wyświetlone w okienku? Tak, litera D.
Również deformacji z łańcuchami możesz dokonać stosując typ PChar. Oto
przykład:
var
S : PChar;
begin
S := 'Delphi';
S := S + 1;
ShowMessage(S);
end.
Z wyglądu może to wydać się niezrozumiałe. Do zmiennej tekstowej dodałem
cyfrę 1? W rzeczywistości zmniejszyłem długość tej zmiennej obcinając
pierwszą literę. To możliwe jest tylko w typie PChar - String już tego nie
umożliwia.
Deklarując zmienną typu String możesz określić z ilu znaków będzie się
mogła max. składać. Robi sięto tak:
var
S : String[20];
W takim wypadku zmienna S będzie ciągiem znaków o max. długości 20.
Bardziej skomplikowane zagadnienia związane z operacją na łańcuchach
poznasz czytając dalsze rozdziały książki.
Wskaźniki
Nie zawaham się powiedzieć, że wskaźniki to najbardziej skomplikowany
element programowania dla początkujących programistów. Otóż wskaźnik
wskazuje na adres zmiennej w pamięci. Ale zacznijmy od początku. Normalnie
pamięć w Delphi przydzielana jest statycznie. Tzn., że w trakcie uruchamiania
programu Windows "wie" ile dla niego przeznaczyć pamięci. Takie coś
nosi nazwę Stosu.
Sterta jest to cała dostępna pamięć komputera.
Dzięki wskaźnikom możemy przydzielać pamięć dynamicznie w trakcie działania
programu. Oto przykład:
type
TRec = record
Imie : String[20];
Nazwisko : String[20];
Kod : Word;
end;
PRec = ^TRec;
var
Rec : PRec;
begin
New(Rec); // przydzielamy pamięć dla rekordu
Rec^.Imie := 'Jan';
Rec^.Nazwisko := 'Kowalski';
Rec^.Kod := 00000;
Dispose(Rec); // zwalniamy pamięć
end.
Wskaźnik do danego obiektu można utworzyć za pomocą znaku ^. W tym
wypadku stworzyliśmy rekord, a następnie stworzyliśmy wskaźnik do rekordu. Późnie
deklarujemy zmienną, która jest typu PRec, czyli wskaźnikowego. Zanim
rozpoczniemy przydzielanie danych do rekordu musimy przydzielić pamięć do
rekordu. Później trzeba na końcu pamięć zwolnić za pomocą polecenia
Dispose. Są jeszcze inne sposoby na przydzielanie pamięci, ale na razie nie
zawracaj sobie tym głowy.
Tak jak napisałem wcześniej wskaźniki wskazują na adres pamięci, w której
zapisana jest wartość danej zmiennej. Mając adres komórki pamięci możemy tę
wartość zmienić.
var
I : Integer;
P : ^Integer;
begin
I := 1; // przypisujemy wartość zmiennej
P := @I; // uzyskujemy komórkę pamięci, w której zapisana jest wartość zmiennej I
P^ := 2; // nadajemy nową wartość w komórce
{ teraz następuje wyświetlenie }
ShowMessage('Zmienna I po modifikacji ma wartość: ' + IntToStr(i));
end.
Jeżeli chcemy odczytać wartość danej zmiennej to kompilator odczytuje
wartość komórki, w której dana zmienna jest zapisana. Przy pomocy
takiego zapisu:
P := @I;
Otrzymujemy adres komórki pamięci, w której zapisana jest zmienna I. Adres
ten zapisany jest do wskaźnika P. Teraz w tej komórce chcesz wpisać nową
wartość - robisz tak:
P^ := 2; // znak ^ jest potrzebny gdyż jest to wskaźnik!
Podsumowanie
W tym rozdziale nauczyłeś się bardzo dużo. Możesz powiedzieć, że
podstawy Object Pascal'a masz opanowane. Jeżeli czegoś nie rozumiesz to
przeczytaj jeszcze raz ten rozdział.. Jeżeli nadal nie będziesz rozumiał
to przejdź do następnego rozdziału. Później powróć do tego i wszystko się
wyjaśni. W następnym rozdziale zajmiemy się programowaniem obiektowym bo w końcu
do tego służy Delphi. Powodzenia!
Wyszukiwarka
Podobne podstrony:
ROZ02haasPl roz02roz02więcej podobnych podstron