Kirjoittaja: Metabolix (2004).
⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠
Kun on kirjoittanut ohjelmaansa hetkisen, alkaa usein huomata, että jotkin usein toistuvat rutiinit tahtovat nielaista koodista varsinaisen asian. Juuri tämän takia on olemassa funktioita (function
) ja aliohjelmia (procedure
). Molempien tarkoitus on sama: usein toistuva koodinpätkä voidaan kirjoittaa yhteen paikkaan ja kutsua sieltä aina tarvittaessa.
Näistäkin apuvälineistä huolimatta voi suuri koodimäärä olla musertava. Tällöin onkin syytä luoda oma moduuli (module), toiselta nimeltään yksikkö (unit), johon voi sijoittaa osan koodista. Tiedosto on hyvä nimetä niin, että nimi kertoo sisällöstä. Mikäli sisältö on sekalainen, on nimi usein vain "Unit" ja numero.
Aliohjelman tai funktion otsikolla tarkoitetaan sen nimeä, syötteitä ja funktion tapauksessa myös palautusarvon tyyppiä. Syötteet määritellään sulkuihin nimen perään, funktion palautusarvon tyyppi taas kaksoispisteen jälkeen määrittelyn lopussa. Normaalisti aliohjelmaan luodaan uudet muuttujat, joita voidaan muokata aliohjelmassa muokkaamatta kuitenkaan alkuperäisiä muuttujia. Haluttaessa voidaan sanalla var
määritellä alkuperäiset muuttujat muokattavaksi, jolloin niihin tehdyt muutokset tehdään alkuperäisiin muuttujiin. Tätä usein käytetäänkin palautusarvon välittämiseen aliohjelmasta. Mikäli halutaan varmistaa ettei syötteitä muokata ollenkaan, ne voidaan sanalla const
määritellä vakioiksi. Otsikko päättyy puolipisteeseen.
Itse aliohjelman tai funktion runko kirjoitetaan otsikon jälkeen normaalin koodin tapaan: ensin vakiot (const
) ja muuttujat (var
), sitten begin
, koodi ja end;
(huomaa puolipiste). Funktion tapauksessa tulee koodin aikana asettaa palautusarvo. Tämä tehdään asettamalla arvo funktion nimelle aivan kuin se olisi muuttuja. Uudemmissa kääntäjissä (nykyään lähes kaikissa) arvon voi antaa muuttujalle Result, joka on automaattisesti palautusarvon tyyppiä. Kun funktio päättyy, muuttujan Result arvo palautetaan kutsujalle. Aiemmin funktiossa sitä voi käyttää muuttujana siinä missä tavallisiakin muuttujia.
Funktioita ja aliohjelmia voidaan liittää myös muuttujiin. Tämä on usein korvaamaton apuväline visuaalisella puolella. Muuttujia, joihin funktioita ja aliohjelmia voidaan liittää, kutsutaan osoittimiksi. Ne eivät sisällä funktion toimintaa, vaan nimensä mukaisesti osoittavat funktioon. Nämä muuttujatyypit tulee määrittää ohjelman alkuun. Määrityksessä kerrotaan, onko kyseessä funktio vai aliohjelma, minkälaisia syötteitä se ottaa ja minkälainen on sen palautusarvo. Käytetyillä syötteiden nimillä ei ole merkitystä, mutta syötteitä tulee olla yhtä monta ja niiden tulee olla samassa järjestyksessä.
program Funktiot; {$APPTYPE CONSOLE} uses SysUtils; const Koko = 31; type TTaulukko = Array [0 .. Koko] of Integer; (* Määritellään muuttujatyyppi TLajittelu, joka siis osoittaa aliohjelmaan, * jonka parametreinä on kaksi kokonaislukua ja muuttuva TTaulukko *) TLajittelu = procedure (const Alku, Loppu: Integer; var Taulu: TTaulukko); (* Vaihtaa lukujen paikkaa *) procedure Vaihda(var A, B: Integer); begin A := A xor B; B := B xor A; A := A xor B; end; (* Bubblesort on melkoisen hidas lajittelualgoritmi *) procedure Bubblesort(const Alku, Loppu: Integer; var Taulu: TTaulukko); var I, J: Integer; begin (* Käydään lista läpi alusta toiseksi viimeiseen asti *) for I := Alku to Loppu - 1 do begin (* Käydään joka kerta lista läpi lopusta I:tä seuraavaan asti *) for J := Loppu downto I + 1 do begin (* Jos nämä kaksi lukua ovat väärässä järjestyksessä *) if Taulu[I] > Taulu[J] then begin (* Vaihdetaan niiden paikkoja *) Vaihda(Taulu[I], Taulu[J]); end; end; end; end; (* Shellsort on melkoisen nopea lajittelualgoritmi *) procedure Shellsort(const Alku, Loppu: Integer; var Taulu: TTaulukko); var Valmis: Boolean; Hyppy, I, J: Integer; begin (* Asetetaan Hyppy listan pituuden mittaiseksi *) Hyppy := Loppu - Alku; while Hyppy > 1 do begin (* Tämä on toinen tapa jakaa kokonaisluku kahdella. * Sen bittejä siirretään yhden bitin verran oikealle. *) Hyppy := Hyppy shr 1; repeat begin Valmis := True; (* Käydään taulukko läpi yhä pienemmällä välillä. I:n ja J:n * ero on sama kuin Hyppy, ja koska Hyppy pienenee ulommassa * while-silmukassa, luvut siirretään yhä tarkemmin paikoilleen. *) J := Alku + Hyppy; I := Alku; while J <= Loppu do begin (* Jos luvut ovat väärin päin, vaihdetaan ja kerrotaan, * että ei olla vielä valmiita *) if Taulu[I] > Taulu[J] then begin Vaihda(Taulu[I], Taulu[J]); Valmis := False; end; (* Suurennetaan molempia *) Inc(I); Inc(J); end; (* Toistetaan, kunnes ollaan tältäosin valmiita *) end until Valmis; (* Viimeisellä toistolla Hyppy on 1, joten toisto päättyy *) end; end; var Taulu1, Taulu2, Taulu3: TTaulukko; X, Y: Integer; Lajittelu: TLajittelu; begin for X := 0 to Koko do begin Taulu1[X] := Random(100000); Taulu2[X] := Taulu1[X]; Taulu3[X] := Taulu1[X]; end; (* Lajitellaan Taulu1 Bubblesortilla ja Taulu2 Shellsortilla *) Lajittelu := Bubblesort; Lajittelu(0, Koko, Taulu1); Lajittelu := Shellsort; Lajittelu(0, Koko, Taulu2); (* Kirjoitetaan tulokset *) for X := 0 to Koko do Writeln(Taulu1[X] : 11, Taulu2[X] : 11, Taulu3[X] : 11); end.
Moduuliin kuuluu neljä välttämätöntä sanaa. Ensimmäinen on unit
, joka kirjoitetaan moduulin alkuun. Sen perään kirjoitetaan moduulin nimi, joka on sama kuin tiedoston nimi. Seuraava on interface
, josta alkaa sisällön määrittely. Kolmantena tulee implementation
, jonka jälkeen kirjoitetaan uudestaan kunkin funktion ja aliohjelman määritelmä ja tällä kertaa myös koodi. Loppuun tulee tietenkin end.
Tyhjä moduuli näyttää siis tältä:
unit TyhjaModuuli; interface implementation end.
Kun moduuliin lisätään koodia, siitä voi tulla vaikkapa tällainen:
unit Luvunheitto; interface type TLuku = record X, Y, Arvo: Single; end; procedure HeitaLukuIlmaan(Korkeus: Single; var Luku: TLuku); implementation procedure HeitaLukuIlmaan(Korkeus: Single; var Luku: TLuku); var Vauhti, MaxKorkeus, Alku: Single; const Aloituskerroin = 0.9; begin Vauhti:= Aloituskerroin * Korkeus; Alku := Luku.Y; MaxKorkeus := Korkeus + Luku.Y; (* Nostetaan Lukua kunnes se on korkeimmillaan *) while Luku.Y < MaxKorkeus do begin Luku.Y := Luku.Y + Vauhti; Vauhti := Vauhti / 2; end; (* Lasketaan Luku takaisin *) while Luku.Y - Vauhti > Alku do begin Luku.Y := Luku.Y - Vauhti; Vauhti := Vauhti * 2; end; Luku.Y := Alku; end; end.
Omat irtomoduulit sisällytetään ohjelman uses
-listaan vaikkapa näin:
uses Esimerkki in 'Esimerkki.pas';
Lopuksi vielä pähkinä purtavaksi: mitä vikaa tässä mahtaa olla?
program Ongelma; procedure Vaihda(var A, B: Longint); var C: Longint; begin C := A; A := B; B := C; end; var X: Longint; begin X := 10; Vaihda(X, 4); end.
Vastaus: Aliohjelma ei voi vaihtaa annetun luvun 4 tilalle muuttujan X arvoa, koska luku 4 ei ole muuttuja. Onneksi Pascal-kääntäjä huomauttaa tästä virheestä.
Lauri Kenttä, 18.9.2004
Melkoisen hyvä opassarja.
Tosi hyvä opassarja
Hyvä opassarja, mutta ehkä käytän nyt kuitenkin C:tä.
Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.