logo

.
Thursday 09th of September 2010    

Ankety

Co tu není dobré ?
 

Přihlášení



Provoz stránek

návštěv dnes: 29
návštěv včera: 59
návštěv za měsíc: 515
návštěv celkem: 17819

Home Škola PASCAL 16 procedury a funkce
16 procedury a funkce Tisk Email
Hodnocení uživatelů: / 1
NejhoršíNejlepší 
Napsal uživatel Administrator   
Čtvrtek, 29 Říjen 2009 13:58

Procedury a funkce, aneb jak si usnadnit práci

1) Procedury
2) Funkce
3) Unity

Pokud bychom nerozčlenili příklad z minulé lekce pomocí procedur, nevyznali bychom se v něm. Dnes se tedy podíváme mimo jiné i na to, jak zvýšit přehlednost a srozumitelnost programu.

Nejprve několik přehledných zásad

1) Používejte prázdné řádky (oddělujte jimi logicky nezávislé celky)
2) Používejte komentáře na začátku programu (jak se program ovládá, co zbývá dodělat)
3) Používejte komentáře (Proč je tady tohle, jak funguje tohle, co dělá tamto...)
4) Promyslete si alespoň zhruba, jak program bude vypadat, dříve než si vůbec sednete k počítači.
5) Využívejte procedury a funkce
6) Zopakujte si rozdíl mezi procedurou a funkcí.

Procedury

Procedura se definuje takto:

  procedure NázevProcedury(Parametry);
  Definice a deklarace;
  begin
   Příkazy;
  end;

Definice a deklarace jsou stejné jako u programu, s jedinou výjimkou - nesmíme použít uses. (A neměli bychom definovat ani další procedury a funkce - sice to jde, ale je docela umění se v tom pak vyznat.) Potřebuje-li určitý datový typ pouze určitá procedura, je lepší nadefinovat ho přímo v ní. Proměnné, které se vyskytují pouze v těle (mezi beginem a endem) procedury, se takto definují téměř vždy. Tedy např. takto:

  procedure Něco;
  type TohleJindeNenajdete = ^Seznam; {Seznam jsme definovali už v samotném programu}
  var Nic : TohleJindeNenajdete;
  Pomocna : string;
     I, J : integer;
  begin
    ...
  end;

Je ovšem zbytečné takto definovat proměnnou, která se v proceduře nevyskytuje.
Proměnné nadefinované v dané proceduře jsou přístupné pouze v ní samotné.
V proceduře lze nadefinovat dokonce i proměnnou se stejným názvem jako má jiná proměnná někde v hlavním programu. V proceduře pak pracujeme s proměnnou procedury a mimo ní s proměnnou programu. Chceme-li přesto použít proměnnou programu i v těle procedury, kde již máme jinou stejnojmenou proměnnou, můžeme to udělat takto: NázevProgramu.NázevProměnné;

  program StejnyNazev;
  var A:Integer;

  procedure Tudle;
  var A:Integer; {Pochopitelně může mít takováto proměnná i jiný typ}
  begin
   A:=100;
   writeln(StejnyNazev.A);
   writeln(A);
  end;

  begin
   A:=15;
   Tudle;
   writeln(A);
   readln;
  end.

Podívejme se blíže na parametry procedur. Pascal rozlišuje čtyři typy parametrů:

1) Parametry volané hodnotou
Parametry volané odkazem
2) Parametry konstantní
3) Parametry bez udaného typu
4) Parametry volané hodnotou se definují takto Název:Typ Typ musí být již předem znám. (Místo Pole : array [1..2] of Integer musíme tedy psát Pole : TPole, a předem mít nadefinováno TPole = array[1..2] of Integer;)

Voláme-li daný parametr hodnotou, zajímá nás pouze hodnota a je nám jedno, jak je zadána.

Máme-li tedy procedure Naskoc(A:integer); je jedno, použijeme-li Naskoc(2), nebo třeba Naskoc(D), kde D je libovolná proměnná typu Integer. Protože nás zajímá jen hodnota, je jasné, že změníme-li obsah parametru uvnitř procedury, navenek se to neprojeví.

Parametry volané odkazem se definují takto var Název : Typ Pochopitelně, že typ je znám dopředu. Na místo parametrů volaných odkazem lze dosadit pouze proměnnou. Navíc změna hodnoty uvnitř procedury bude patrná i vně, v samotném programu.

Parametry konstantní se definují takto const Název : Typ Překladač se k nim chová jako ke skutečným konstantám. (Místo nich můžeme použít obou předchozích typů. Pokud nikde nebudeme měnit hodnotu parametru, je výsledek stejný. Jsou-li ale použity konstantní parametry, je výsledná procedura o něco málo rychlejší.)

Parametry bez udaného typu lze volat pouze odkazem či jako konstantní. My se jim zatím vyhneme. Více o nich až v lekci o typových změnách a kouzlech s proměnnými.

Můžeme mít tedy třeba takovouto proceduru:
Ehm(a,b:integer;c:byte;var d,e:real;const f,g:char);
V samotném těle programu pak lze napsat například toto:
Ehm(1,5,6,nic,vic,'a','3'); Pokud jsme ovšem definovali proměnné nic a vic jako reálné (na místo parametrů volaných odkazem lze dosadit jen proměnnou !!!)

Existuje několik typů proměnných, které jdou používat pouze jako parametry - jedná se o OpenString (Řetězec bez udané délky) a array (pole bez udané délky). Použití je takovéto:
procedure NevimCo(Retezec : OpenString, Pole : array of NejakyTyp);
U takovýchto parametrů si musíme pomocí funkcí Lenght, High, Low... zjistit jejich skutečnou délku...
Lze definovat i procedury, které využívají jiných procedura a funkcí. Můžeme dokonce definovat procedury, které využívají sami sebe. Jenom si musíme dát pozor, že tento cyklus (tzv. rekurze) někdy skončí.

Problém ovšem nastává, máme-li dvě procedury, z nichž první využívá druhou a obráceně. V Pascalu se totiž smí používat jen to, co jsme již předem nadefinovali. Jak z toho ven? Sdělíme o existenci dané procedury pomocí  procedure NázevA(parametry);forward; Poté dodefinujeme proceduru NázevB (ve které používáme NázevA). A nakonec uvedeme samotné tělo procesdury s názvem NázevA (procedure NázevA; {už nemusíme vypisovat parametry...})
Jednoduchý příklad:

  procedure NicNedela(A:integer);forward;
  procedure NecoDela(A:integer);
  begin
   If A > 0 then NicNedela(A-1);
   writeln(A);
  end;
  procedure NicNedela;
  begin
   If A < 0 then NecoDela(A);
   writeln(A);
  end;

Doufám, že teď je to již jasné.

Funkce

Funkce se definují takto function Název(Parametry):VýslednýTyp; ... Výsledný typ nesmí být vytvořen uživatelem, lze použít pouze standardní pascalovské typy. Následují deklarace a definice a nakonec samotné tělo.

O funkcích platí vše, co bylo řečeno o procedurách (typy parametrů ... direktiva forward). V těle samotné funkce se musí použít přiřazovací příkaz NázevFunkce:=NějakáHodnota; Poslední přiřazení dá výsledek funkce (Je ovšem krajně neetické použít více jak jedno takové přiřazení). Před i po mohou probíhat další příkazy, ty by měly přímo souviset s danou funkcí. Platí však, že funkce by měla skončit, jakmile známe výsledek. Velice často se používá rekurze.

  function Factorial(N:byte):longint;
  begin
   if N >0 then Factorial:= N * Factorial(N-1) else Factorial:=1;
  end;

(Skutečně se při každém průběhu funkce přiřazuje jen jednou. Je-li N>1 používá se rekurze.)

Napište program, který vypočte s využitím známých vzorců pomocí rekurze kombinační číslo ( (n nad k) = (n-1 nad k) + (n-1 nad k-1)...). Příslušné vzorce si vyhledejte (programátor si musí umět sám najít potřebné informace) a  nezapomeňte, že rekurze musí někdy skončit.

Unity

Některé funkce a procedury jsou natolik obecné, že se vyskytují ve více programech. Aby nás jejich neustále vypisování neobtěžovalo, je lepší umístit je do zvláštního souboru. (Tento způsob se také využívá tehdy, jestliže máme funkcí moc a výsledný program by byl velice dlouhý a nepřehledný). Takovéto procedury a funkce se umisťují do tzv. jednotek (units), které vypadají takto:

  unit Název;
  interface
   Definice a Deklarace;
  implementation
   Definice a Deklarace;
  begin
   Inicializační Část;
  end.

Unit musíme uložit do stejnojmenného souboru (Název.pas), jinak nepůjde využít.

V části interface definujeme to, co by mělo být zjevné i mimo naší unitu (procedury, funkce, konstanty, typy...). U procedur a funkcí uvádíme pouze hlavičky (úplné)

V části implementation pak definujeme to, co potřebujeme pouze pro potřeby dané unity (pomocné funkce, typy, konstanty, proměnné,...) Dále zde pak dodefinujeme těla funkcí z interface(zde stačí psát zkrácenou hlavičku - bez parametrů a výsledného typu). Je ovšem lepší psát hlavičku úplnou (implementation je pak přehlednější), musíme ale dát pozor, abychom uvedli hlavičky přesně ve stejném tvaru jako v sekci interface.
Do Inicializační části napíšeme příkazy, které se provedou, když jednotku načítáme do paměti (máme-li jednotku pro práci s grafikou, bylo by dobré smazat obrazovku a nastavit grafický režim....). Neobsahuje-li náš program žádnou inicializační část, můžeme begin vynechat (ale end. zůstává)

Příklad - jednotka pro práci s komplexními čísly (pro ilustraci zkrácené hlavičky)

  unit CPLX;
  {Obsahuje příkazy pro práci s komplexními čísly}
  interface
  type Komplex = record
                  R:Real;
                  I:Real;
                 end;
  procedure Secti(A,B:Komplex;var Vysledek:Komplex);  {A+B}
  procedure Odecti(A,B:Komplex;var Vysledek:Komplex); {A-B}
  procedure Znasob(A,B:Komplex;var Vysledek:Komplex); {A*B}
  procedure Del(A,B:Komplex;var Vysledek:Komplex);    {A/B}

  implementation
  procedure Secti;
  begin
   Vysledek.R:=A.R+B.R;
   Vysledek.I:=A.I+B.I;
  end;
  procedure Odecti;
  begin
   Vysledek.R:=A.R-B.R;
   Vysledek.I:=A.I-B.I;
  end;

  procedure Znasob;
  begin
   Vysledek.R:=A.R*B.R-A.I*B.I;
   Vysledek.I:=A.R*B.I+A.I*B.R;
  end;

  procedure Del;
  var C:Real;
  begin
   Vysledek.R:=B.R;
   Vysledek.I:=-B.I;
   Vysledek:=Znasob(A,Vysledek);
   C:=Sqr(B.R)+Sqr(B.I);
   Vysledek.R:=Vysledek.R/C;
   Vysledek.I:=Vysledek.I/C;
  end;

  end.

Napíšeme-li nyní ve svém programu uses CPLX; (a je-li CPLX.pas uložen ve stejném adresáři), můžeme využívat nových příkazů Secti, Odecti, Znasob a Del; Rovněž můžeme použít typ Komplex (ten ovšem nejde vypsat pomocí Writeln...)

Jednotky mohou obsahovat v sekci uses další jednotky. Pokud by dvě jednotky odkazovaly na sebe navzájem, přesuneme v jedné z nich sekci uses až do oddílu implementation.

To pro dnešek stačí. Zkuste si napsat vlastní jednotku (libovolnou) a využít ji v některém ze svých programů. Pro ty otrlejší - napište jednotku pro práci s dynamickým seznamem pracovníků.

Zdroj: http://programar.webpark.cz

Aktualizováno Čtvrtek, 29 Říjen 2009 14:07
 
bottom

top

kolik vás je ?

Právě připojeni - hostů: 6 

bottom

Založeno na Joomla!. Designed by: Free Joomla 1.5 Template, dns. Valid XHTML and CSS.