Kirjautuminen

Haku

Tehtävät

Opasarkisto: Pascal-ohjelmointi: Osa 5 - Funktiot, aliohjelmat ja omat moduulit

  1. Osa 1 - Mistä Pascal alkaa?
  2. Osa 2 - Vakiot, muuttujat ja tietueet
  3. Osa 3 - Silmukat ja ehtolauseet
  4. Osa 4 - Tiedostot
  5. Osa 5 - Funktiot, aliohjelmat ja omat moduulit

Kirjoittaja: Metabolix. Vuosi: 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.

Aliohjelmat ja funktiot

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.

Omat moduulit

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';

Varovaisuus kannattaa

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


Kommentit

polsystem [23.10.2006 15:19:08]

Lainaa #

Melkoisen hyvä opassarja.

uid-11960 [08.11.2012 18:54:54]

Lainaa #

Tosi hyvä opassarja

Koodi123 [03.02.2019 13:10:17]

Lainaa #

Hyvä opassarja, mutta ehkä käytän nyt kuitenkin C:tä.

Kirjoita kommentti

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.

Muista lukea kirjoitusohjeet.
Tietoa sivustosta