PP1 wyklad 4


Podstawy Programowania
Wykład czwarty:
Funkcje i procedury.
1.Podprogramy
Podprogramy są wyodrębnionymi fragmentami programu komputerowego.
Istnieją dwa główne powody dla których je stosujemy. Tworząc duży program
komputerowy stwierdzamy dosyć często, że wygodnie by było użyć fragmentu
kodu, który już wcześniej napisaliśmy. Najprostsze rozwiązanie tego problemu,
polegające na skopiowaniu go nie jest rozwiązaniem najlepszym. Jeśli ów frag-
ment zawierał 10 błędów, to teraz mamy 20 błędów, które trzeba usunąć1. Naj-
lepszym rozwiązaniem jest zatem zamknięcie tego kod w podprogramie. Powtór-
ne użycie tego kodu będzie więc polegało na wywołaniu podprogramu za po-
mocą jego nazwy. Drugim powodem stosowania podprogramów jest to, że po-
zwalają one podzielić kod na niezależne jednostki zwiększając jego czytelność.
Specjaliści od teorii programowania mówią o  budowaniu abstrakcji wyższego
rzędu (abstrakcja w tym przypadku rozumiana jest jako uogólnienie i uprosz-
czenie). Rzeczywiście, mając zapisany w języku programowania algorytm li-
czenia silni, można go zamknąć w podprogramie o nazwie  silnia lub
 licz_silnia . Jeśli w programie napotkamy teraz instrukcję  licz_silnia(n) , to ła-
twiej jest nam zrozumieć co ona wykonuje, niż gdybyśmy musieli prześledzić
wykonanie samego kodu. Program podzielony na podprogramy jest zatem
prostszy do analizowania i łatwiej jest w nim usuwać błędy. W języku Pascal
istnieją dwa rodzaje podprogramów  funkcja i procedura.
2.Ogólna struktura procedur i funkcji
Tworzenie funkcji lub procedury nazywa się jej definiowaniem. Definicja
procedury zaczyna się nagłówkiem składającym się ze słowa kluczowego
procedure, po którym występuje nazwa (identyfikator) procedury2. Po nazwie
opcjonalnie może wystąpić lista parametrów formalnych. Całość zakończona
jest średnikiem. Po nagłówku procedury występuje ciało procedury3. Jego
struktura przypomina strukturę programu głównego. Składa się ono z części
opisowej i z bloku instrukcji, które będą w procedurze wykonywane. Część
opisowa procedury może, podobnie jak część opisowa programu zawierać
definicje stałych, typów, deklaracje zmiennych i etykiet, a także definicje
innych procedur i funkcji. Nie może natomiast zawierać sekcji zaczynającej się
słowem kluczowym uses i pozwalającej na włączanie do programu modułów.
Wszystkie elementy występujące w części opisowej procedury są widoczne tylko
1 Programiści wymyślili nawet regułę, która przypomina, żeby czegoś takiego nie robić DRY (Don't
Repeat Yourself).
2 Zaleca się aby nazwa ta była czasownikiem lub zawierała czasownik, ale nie jest to wymóg.
3 Termin ciało procedury (lub ciało funkcji) może oznaczać również instrukcje zawarte
w podprogramie między słowami kluczowymi begin i end.
2
wewnątrz tej procedury, tzn. jeśli zadeklarujemy np. jakąś stałą wewnątrz
procedury i będziemy próbować użyć jej w bloku głównym programu, to taki
program się nie skompiluje. Te elementy nazywamy elementami lokalnymi
procedury. Blok w którym są zawarte instrukcje wykonywane w procedurze
rozpoczyna się słowem kluczowym begin, a kończy słowem end zakończonym
średnikiem. Definicja funkcji4 jest podobna do definicji procedury, ale są
różnice. Funkcje zawsze zwracają wynik swojego działania. Nagłówek funkcji,
w przeciwieństwie do nagłówka procedury zaczyna się słowem kluczowym
function, a po nazwie funkcji i ewentualnej liście parametrów umieszczany jest
dwukropek i nazwa typu wartości przez funkcję zwracanej. W bloku instrukcji
musi się znalezć instrukcja przypisania, gwarantująca, że ta wartość zostanie
rzeczywiście zwrócona. Jest ona tworzona według schematu:
nazwafunkcji := wartość;
Poniżej umieszczone są przykłady prostej procedury i funkcji:
procedure wypisz;
begin
clrscr;
writeln('Prosta procedura.');
readln;
end;
Do najprostszych procedur5 należą procedury bez parametrów. Aby program,
w którym procedura wypisz jest umieszczona skompilował się prawidłowo,
musi być do niego włączony moduł crt, w którym jest zdefiniowana procedura
clrscr (jest ona również procedurą bez parametrów, ale jest to procedura
predefiniowana  dostarczona nam przez twórców kompilatora Pascala).
Zastosowanie procedur bezparametrowych powinno być ograniczone do
prostych czynności, takich jak wypisywanie komunikatów na ekran. Należy
zauważyć, że wszystkie instrukcje, które zostały umieszczone w bloku
instrukcji omawianej procedury są wywołaniami procedur stanowiących
podstawowe elementy języka Turbo Pascal.
function znak:char;
begin
znak:='a';
end;
Funkcja w ramce zwraca ustaloną wartość (znak a). Jeśli umieścilibyśmy po
4 Funkcje z języka Pascal pod pewnymi względami przypominają funkcje w matematyce.
5 Pod względem konstrukcji, a nie działania.
3
instrukcji przypisania znak:='a'; inne instrukcje, to również zostaną one
wykonane. Jeśli zapomnimy o instrukcji przypisania, to funkcja zwróci
przypadkowy znak, a nie znak o kodzie ASCII równym 97 (litera a). Funkcje
mogą zwracać wartości typów podstawowych, nie mogą natomiast zwracać
bezpośrednio wartości typów złożonych.
Uwaga: Środowisko Free Pascal umożliwia funkcjom zwracanie wartości w inny
sposób niż opisany wyżej, tzn. za pomocą zmiennej Result lub wywołania proce-
dury Exit (opisana w podrozdziale 9). Ponieważ te sposoby nie są zgodne ze
standardem języka, ani z środowiskiem Turbo Pascal, oraz wymagają dodat-
kowych zabiegów, żeby je uaktywnić, to nie będą one w ramach przedmiotu
używane.
3. Wywołanie i wykonywanie procedur i funkcji
Aby uruchomić w programie (lub innej procedurze lub funkcji) procedurę, to
należy ją w nim wywołać. W przypadku procedury wypisz, wystarczy umieścić
w programie jej nazwę zakończoną średnikiem. Miejsce w programie, gdzie
procedura lub funkcja jest wywoływana nazywamy po prostu miejscem
wywołania. Po napotkaniu wywołania procedury program wykonuje skok do
miejsca, gdzie w pamięci została ona umieszczona i wykonuje ją. To wykonanie
zaczyna się od miejsca oznaczonego słowem kluczowym begin, które nazywane
jest  punktem wejścia sterowania . Po wykonaniu procedury program skacze
do punktu znajdującego się bezpośrednio za miejscem jej wywołania i wykonuje
następną w kolejności instrukcję. Funkcję możemy wywołać w ten sam sposób,
ignorując wartość przez nią zwracaną6, ale najczęściej wywołuje się ją w sposób
pozwalający zachować tę wartość w jakiejś zmiennej. Załóżmy, że w programie
mamy zadeklarowaną zmienną globalną typu char, o nazwie zm. Wywołanie
funkcji znak może mieć postać: zm:=znak; Funkcję można również wywołać
w wyrażeniu, np.: n*sin(x).
4.Zmienne lokalne
W części opisowej podprogramu możemy definiować i deklarować elementy,
które będą widoczne tylko wewnątrz niego. Są to elementy lokalne, ukryte
przed otoczeniem podprogramu. W przypadku stałych, typów danych i etykiet
mechanizm ukrywania jest prosty  wystarczy, aby kompilator zadbał o to by
ich nazwy nie pojawiały się poza podprogramem. W przypadku zmiennych
sytuacja jest trochę bardziej skomplikowana, bo kompilator musi przydzielić na
nie miejsce w pamięci. Pamięć, która zostaje przydzielona skompilowanemu
6 Taki sposób wywołania funkcji nazywa się w literaturze  wywołaniem funkcji ze względu na
efekt uboczny jej działania .
4
programowi komputerowemu w celu jego uruchomienia dzieli się na trzy
obszary7. W pierwszym obszarze znajdują się rozkazy programu, w drugim dane
dla tych rozkazów, a trzeci jest przeznaczony na tak zwany stos. Informacje na
stosie są przechowywane zgodnie z regułą LIFO (ang. Last In First Out), co
można przetłumaczyć jako:  ostatni nadszedł, pierwszy wyszedł . Załóżmy, że
naszym podprogramem jest procedura. W momencie jej wywołania na stosie
rezerwowana jest pamięć na tak zwaną ramkę stosu8. Ta ramka zawiera
miejsce na zmienne lokalne, parametry procedury i adres powrotu. Wszystkie
wartości zapisywane w zmiennych lokalnych są więc umieszczane na stosie
w opisywanej ramce. Po zakończeniu działania procedury ramka jest usuwana
ze stosu. Załóżmy, że w procedurze jest wywoływana inna procedura lub
funkcja. W takim przypadku, za ramką stosu pierwszej procedury tworzona jest
ramka procedury w niej wywołanej. Po zakończeniu wykonania drugiej
procedury jest niszczona jej ramka, a sterowanie wraca do pierwszej procedury.
Na podstawie tego opisu łatwo zauważyć, że zmienne lokalne istnieją w pamięci
komputera tylko podczas wykonywania procedury, w której zostały
zadeklarowane, dlatego też nazywane są zmiennymi automatycznymi. Pamięć
na te zmienne nie jest zerowana, tak więc nie są one domyślnie inicjalizowane
żadną wartością9. Wewnątrz podprogramu nie możemy zadeklarować dwóch
zmiennych o takich samych nazwach, ale możemy mieć zmienną lokalną,
o takiej samej nazwie, jak zmienna globalna. Wewnątrz podprogramu będzie
widoczna tylko zmienna lokalna, natomiast nie będziemy mieli bezpośredniego
dostępu do zmiennej globalnej o takiej samej nazwie. To zjawisko nazywa się
przykrywaniem i dotyczy nie tylko zmiennych ale również innych elementów
lokalnych. Ponieważ zmienne lokalne pozwalają na lepszą gospodarkę pamięcią
komputera (istnieją tylko wtedy, kiedy są potrzebne), to zaleca się ograniczanie
liczby zmiennych globalnych, na rzecz zmiennych lokalnych.
5.Parametry procedur i funkcji
Aby wykonywać jakąś użyteczną pracę, nie tylko polegającą np. na
wyświetlaniu komunikatów na ekranie, podprogramy muszą mieć możliwość
wymiany informacji z resztą programu. Funkcje i procedury mogą bezpośrednio
odwoływać się do zmiennych globalnych. Załóżmy, że mamy zadeklarowane
w programie dwie takie zmienne o nazwach a i b oraz typie byte. Procedura,
która pobiera od użytkownika pewne wartości i umieszcza je w tych zmiennych
mogłaby mieć następującą postać:
7 Jest to uproszczony opis problemu, rzeczywistość jest trochę bardziej skomplikowana.
8 W niektórych opracowaniach zwaną także rekordem aktywacyjnym podprogramu.
9 Dokładniej  mogą zawierać przypadkową wartość.
5
procedure pobierz;
begin
writeln('Podaj dwie liczby z przedziału [0,255]');
readln(a);
readln(b);
end;
Bezpośrednie korzystanie ze zmiennych globalnych, choć dopuszczalne
i w niektóry (raczej rzadkich) sytuacjach nieuniknione jest uważane za złą
technikę programowania i nie należy tego robić10. Jeśli chcemy wykonać
operacje na wartości znajdującej się w zmiennej, wówczas musimy w nagłówku
procedury lub funkcji umieścić parametry11, przez które te wartości zostaną
przekazane. Parametry są zmiennymi lokalnymi12, które pełnią ważną rolę  ich
zadaniem jest komunikacja z otoczeniem procedury lub funkcji. Są one
umieszczane w nawiasach okrągłych, na liście parametrów, tuż za nazwą
procedury lub funkcji. Deklarując parametr podajemy jego nazwę i typ. Jeśli
chcemy zadeklarować dwa lub większą liczbę parametrów, to rozdzielamy je
średnikami. Jeśli parametry mają być tego samego typu, to wymieniamy ich
nazwy rozdzielając je przecinkami, a potem, po dwukropku podajemy ich typ.
Oto przykładowy nagłówków z parametrami dla funkcji i procedury:
procedure wzor(a,b:real; x:byte);
function wzor(a,b:real; x:byte):char;
Parametry znajdujące się na liście parametrów funkcji lub procedury
nazywamy parametrami formalnymi. W miejscu wywołania procedury lub
funkcji należy za te parametry podstawić parametry faktyczne13. Tymi
parametrami mogą być np.: zmienne globalne programu lub zmienne lokalne
procedury, w której dany podprogram został wywołany, o ile mają one typy
zgodne z typami parametrów. Ponadto parametrów faktycznych musi być tyle
samo ile jest parametrów formalnych. Powyższe objaśnienie nie do końca jest
precyzyjne. Istnieją bowiem trzy sposoby przekazania parametrów faktycznych.
Pierwszy z nich to przekazanie przez wartość. Parametry formalne, które
10 Niektóry informatycy przyjmują bardziej skrajną postawę i zalecają, aby w ogóle nie stosować
zmiennych globalnych. Jest to oczywiście możliwe w językach programowania, o trochę innej
filozofii tworzenie programów niż ma to miejsce w Pascalu, ale dobrą praktyką jest stosowanie
w programach napisanych w języku Pascal jak najmniejszej liczby zmiennych globalnych.
11 Wymiennie możemy używać określenia  argumenty .
12 W związku z tym nie mogą mieć takich samych nazw jak inne zmienne lokalne.
13 Zwane także argumentami wywołania. W literaturze polskiej funkcjonuje pojęcie  parametrów
aktualnych , które wydaje się być niezbyt udanym tłumaczeniem angielskich słów actual
parameters. Bardziej odpowiednim tłumaczeniem byłoby  parametry właściwe .
6
zostały zadeklarowane wyżej pozwalają właśnie na taki typ przekazania.
Parametrem faktycznym, przekazanym przez wartość może być zmienna,
wyrażenie lub wartość, o typie zgodnym z typem parametru. W takim
przypadku wartość parametru faktycznego jest kopiowana do parametru
formalnego. Wewnątrz funkcji lub procedury parametr ten może być
traktowany jak zwykła zmienna, tzn. można go odczytywać lub zmieniać jego
wartość. Po wykonaniu podprogramu ten parametr, tak jak zwykłe zmienne
lokalne jest usuwany z pamięci wraz z zawartością. Jeśli nie chcemy jej stracić,
to musimy ją w jakiś sposób  utrwalić , np.: wypisując na ekran. Drugim
sposobem jest przekazanie przez stałą. Parametr formalny pozwalający na takie
przekazanie jest poprzedzony słowem kluczowym const. Pod ten parametr
możemy również podstawiać wartość, wyrażenie lub zmienną, ale wewnątrz
procedury nie można zmieniać jego wartości, jest on tylko do odczytu. Ostatnim
sposobem przekazania jest przekazanie przez zmienną, zwane również
przekazaniem przez adres. W tym przypadku parametr formalny pozwalający
na takie przekazanie jest poprzedzony słowem kluczowym var. Jako parametr
faktyczny może być za niego podstawiona wyłącznie zmienna. Parametrowi
formalnemu nie jest przypisywana wartość zmiennej, która za niego została
podstawiona w miejscu wywołania podprogramu, ale adres tej zmiennej.
Oznacza, to że wszelkie modyfikacje wartości parametru będą również
modyfikacjami wartości tej zmiennej i te modyfikacje zostaną zachowane po
zakończeniu podprogramu. W przypadku przekazania przez wartość, zmienna
podstawiona pod parametr formalny po zakończeniu podprogramu ma taką
samą wartość jak przed jego rozpoczęciem, niezależnie od tego co działo się
z parametrem formalnym wewnątrz podprogramu. Parametry przekazywane
przez wartość i stałą pełnią więc rolę wyłącznie parametrów wejściowych
podprogramu, natomiast parametry przekazywane przez zmienną są zarówno
parametrami wejściowymi, jak i wyjściowymi. Parametry pozwalają uczynić
podprogramy bardziej uniwersalnymi i elastycznymi. Dobrze sparametryzowany
podprogram14 może być stosowany do rozwiązywania wielu podobnych do siebie
zagadnień. Parametry wraz z nazwą stanowią interfejs podprogramu. Jeśli
programista korzysta z procedur i funkcji napisanych przez innych
programistów, to nie musi znać szczegółów ich działania, wystarczy, żeby
wiedział, co one robią i jak należy je wywołać, tj. jakie przekazać im argumenty
wywołania. Poniżej znajdują się przykłady procedur, które stosują różne
sposoby przekazania parametrów. Te same sposoby przekazywania
parametrów mogą być zastosowane dla funkcji.
14 Nie oznacza, to że taki podprogram musi zawierać dużą liczbę parametrów. Zbyt duża ich liczba
może być równie szkodliwa, co ich brak.
7
Przez wartość:
procedure wyswietl(x,y:byte);
begin
writeln('W procedurze - przed wykonaniem zmian: ',x:3,y:3);
x:=x+3;
y:=y-1;
writeln('W procedurze - po dokonaniu zmian: ',x:3,y:3);
end;
Przez stałą:
procedure wyswietl2(const x,y:byte);
begin
writeln('W procedurze - nie można zmienić wartości parametrów ',x+2:3,y-1:3);
{x:=x+1; to się nie skompiluje}
end;
Przez zmienną:
procedure wyswietl3(var x,y:byte);
begin
writeln('W procedurze - przed dokonaniem zmian: ',x:3,y:3);
x:=x+1;
y:=y-1;
writeln('W procedurze - po wykonaniu zmian: ',x:3,y:3);
end;
Można również w procedurze lub funkcji równocześnie zadeklarować parametry
przekazywane przez stałą, zmienną i przez wartość.
Uwaga: Zalecanymi sposobami przekazywania parametrów faktycznych o dużej
objętości, np. typu string, jest przekazanie przez zmienną lub stałą. Przekazanie
przez wartość powoduje skopiowanie ich zawartości na stos. W przypadku
środowiska Free Pascal, w większości przypadków nie ma to żadnego
znaczenia15, ale w środowisku Turbo Pascal tworzone są programy z bardzo
ograniczoną wielkością stosu. Przekazanie zbyt wielu, zbyt dużych parametrów
może się skończyć jego przepełnieniem i w konsekwencji awaryjnym za-
kończeniem programu. Turbo Pascal ogranicza także liczbę parametrów formal-
nych typu single, double, extended lub comp do ośmiu.
15 Dokumentacja FreePascala zaleca jednak, aby zwrócić na to uwagę.
8
5.Deklaracja procedur i funkcji
W procedurach i funkcjach możemy korzystać z elementów, które zostały
zdefiniowane lub zadeklarowane przed ich definicjami. Co jednak zrobić jeśli
chcemy wywołać w procedurze inną procedurę, ale nie chcemy lub nie możemy
z jakiś powodów na razie jej definiować? Możemy w takim wypadku procedurę
zadeklarować, podając jej nagłówek, a następnie po jej nagłówku umieszczając
słowo kluczowe forward zakończone średnikiem16. Tak zadeklarowaną funkcję
lub procedurę należy oczywiście kiedyś zdefiniować, niemniej jednak możemy ją
wywoływać (na etapie pisania programu, nie zaś wykonania), zanim zostanie
ona zdefiniowana.
6.Zagnieżdżone funkcje i procedury.
Dowiedzieliśmy się, że zmienne lokalne są ukryte dla elementów programu
znajdujących się na zewnątrz podprogramu. Język Pascal pozwala również na
umieszczanie wewnątrz procedur i funkcji definicji innych procedur i funkcji,
które są lokalne, tzn. widoczne wyłącznie w podprogramie, w którym zostały
zdefiniowane. Takie procedury i funkcje nazywamy zagnieżdżonymi. Mają one
dostęp do wszystkich składowych funkcji lub procedury, w której zostały
zdefiniowane, natomiast funkcja lub procedura otaczająca je nie ma dostępu do
ich elementów lokalnych. Stosowanie zagnieżdżonych procedur i funkcji
pozwala na ukrywanie implementacji, a więc ukrywanie szczegółów związanych
z funkcjonowaniem danego podprogramu.
7. Uwagi na temat pisania funkcji i procedur
Definicja funkcji i procedury nazywana inaczej jej treścią powinna być
niewielka. Dobrze napisaną funkcję lub procedurę powinno dać się wyświetlić
w całości na ekranie. Jeśli jej treść się nie mieści na ekranie, to należy
rozważyć podzielenie jej na mniejsze części. Dobrym zwyczajem jest
umieszczanie po nagłówku funkcji lub procedury komentarzy objaśniających,
co robi dany podprogram i do czego służą jego parametry. Należy również
pamiętać o wcięciach ułatwiających czytanie kodu. To czy dany fragment
programu zostanie zaimplementowany jako funkcja, czy jako procedura zależy
wyłącznie od programisty17, ale ważnym jest, aby te podprogramy były dobrze
16 W literaturze taka deklaracja procedury lub funkcji jest czasem nazywana deklaracją
wyprzedzającą.
17 Programiści piszący tak zwane programy obiektowe zalecają, aby stosować głównie funkcje,
a parametry do nich przekazywać wyłącznie przez stałe. Niestety w języku Pascal takie podejście
nie jest możliwe.
9
sparametryzowane. Istnieje pewien ciekawy sposób pisania funkcji, który
wywodzi się z innego języka programowania, języka C. Otóż funkcja może
wykonywać działania, których wyniki są zwracane do parametrów faktycznych
przekazywanych przez zmienne, natomiast wartość funkcji oznacza status
wykonania tych działań. Wartość zero, najczęściej oznacza, że wyniki są
poprawne, wartości różne od zera oznaczają, że wystąpił jakiś błąd. Pojedyncza
wartość sygnalizuje pojedynczy rodzaj błędu. Zaleca się, aby nazwy procedur
i funkcji były czasownikami lub zawierały czasowniki. Najważniejszą cechą jaką
powinny mieć nazwy podprogramów jest jednak ich opisowość, tzn. nazwa
powinna być krótka, ale dobrze wyjaśniać co dany podprogram robi, np.
wypisz_binarnie lub wyznacz_delte.
8.Uwagi dotyczące pisania złożonych programów
Języki pozwalające na definiowanie podprogramów, takie jak Pascal, nazywamy
językami strukturalnymi. Pozwalają one pisać programy na zasadzie:  od ogółu
do szczegółu , tzn. problem, który program ma rozwiązać dzielimy na mniejsze
podproblemy, aż będziemy w stanie rozwiązać każdy z tych podproblemów i to
rozwiązanie zaimplementować w postaci podprogramu. Następnie ze
zdefiniowanych podprogramów, możemy  złożyć cały program18. Prześledzmy
to postępowanie na przykładzie prostego programu. Załóżmy, że chcemy
napisać program obliczający silnię, który będzie sprawdzał poprawność
wprowadzonych przez użytkownika danych wejściowych. Narzucającym się
rozwiązaniem jest umieszczenie obliczeń w funkcji, a komunikacji
z użytkownikiem i walidacji danych wejściowych w procedurze. Po bliższej
analizie problemu możemy dojść do wniosku, że proces walidacji danych
można podzielić na dwa etapy: sprawdzenie czy podana wartość jest liczbą
i sprawdzenie, czy ta liczba mieści się w określonym zakresie. Pierwszą
czynność można zaimplementować w postaci procedury zagnieżdżonej
w procedurze wykonującej czynność drugą (procedura sprawdzająca, czy
podane przez użytkownika dane są poprawne nie będzie wykorzystywana przez
inne elementy programu, dlatego może być przed nimi ukryta). Oto kod
programu, który powstał na bazie powyższego opisu:
18 Postępowanie to wywodzi się od sposobu rozwiązywania problemów z innych dziedzin (głownie
matematyki), który podał Kartezjusz.
10
program licz_silnie;
uses
crt;
var
n:byte;
procedure pobierz_dane(var x:byte);
procedure sprawdz(var x:byte);
var
s:string;
blad:integer;
begin
repeat
writeln('Wprowadz liczbę naturalna z przedziału [0,8]');
readln(s);
clrscr;
val(s,x,blad);
if blad<>0 then writeln('Błąd, to nie jest liczba!');
until blad=0;
end;
begin
repeat
sprawdz(x);
if x>8 then writeln('Liczba nie należy do podanego przedziału');
until x<=8;
end;
function silnia(n:byte):word;
var
i:byte;
s:word;
begin
s:=1;
11
for i:=1 to n do s:=s*i;
silnia:=s;
end;
begin
clrscr;
pobierz_dane(n);
writeln('Wartość silni dla n=',n:1,' wynosi: ',silnia(n),'.');
readln;
end.
Po przeanalizowaniu wszystkich zalet stosowania podprogramów powstaje
pytanie, czy to rozwiązanie ma jakieś wady. Jedyną wadą stosowania funkcji
i procedur jest nieznaczne spowolnienie wykonywania programu. Opóznienie to
spowodowane jest przez takie czynności jak: wywołanie podprogramu,
stworzenie dla niego ramki stosu, usunięcie ramki stosu i powrót do fragmentu
programu, który wywołał podprogram. W większości przypadków ten narzut
czasu nie ma znaczenia i na pewno nie jest argumentem na rzecz zarzucenia
używania podprogramów i powrotu do pisania programów monolitycznych (bez
podziału na funkcje i procedury).
9.Przerwanie wykonania funkcji lub procedury
Język Pascal umożliwia przerwanie wykonania funkcji lub procedury za po-
mocą wywołania procedury exit. Po jej wykonaniu sterowanie wraca do następ-
nego rozkazu, znajdującego się za wywołaniem procedury lub funkcji, której
wykonanie zostało przerwane. Jeśli procedura exit zostanie wywołana
w programie głównym, to nastąpi jego zakończenie. W ten sam sposób działa
procedura halt, z tym że ona przerywa wykonanie programu niezależnie od
tego, czy zostanie wywołana w bloku głównym programu, czy w pod-
programie19. Dodatkowo można ją wywołać z parametrem faktycznym będącym
liczbą naturalną. Ta liczba jest kodem zakończenia programu (0  poprawne
wykonanie, wartość różna od zera  wystąpił błąd).
10. Przeciążanie podprogramów (tylko Free Pascal)
Jednym z dodatków jakie wprowadziło środowisko Fee Pascala jest przeciążanie
podprogramów. Oznacza to, że możemy w programie zdefiniować kilka
19 Nawet jeśli jest to zagnieżdżona procedura lub funkcja.
12
procedur lub funkcji, które mają te same nazwy, ale różnią się listą
parametrów. Różnice te mogą polegać na tym, że co najmniej jeden
z parametrów ma zmieniony typ, lub na tym, że podprogramy mają różną liczbę
parametrów. Kompilator ustala, którą wersję procedury lub funkcji ma
wywołać po liczbie i typie parametrów faktycznych, które są przekazywane
w miejscu jej wywołania. Przeciążanie podprogramów pozwala je bardziej
uogólnić, czyli umożliwia ich lepszą abstrakcję. Załóżmy na potrzeby przykładu,
że chcemy mieć procedurę podobną do inc dla zmiennych typu real. Oby
napisać taką procedurę musimy przyjąć co będzie następnikiem liczby
zmiennopozycyjnej. Niech to będzie liczba 0.01. Oryginalna procedura inc może
przyjmować także drugi parametr, który określa przyrost wartości zmiennej.
Korzystając z możliwości przeciążania podprogramów napiszemy dwie wersje
naszej procedury. Pierwsza będzie przyjmowała tylko jeden parametr
i zwiększała wartość zmiennej podstawionej pod niego o 0.01, a druga będzie
miała dwa parametry i będzie zwiększała wartość zmiennej podstawionej pod
pierwszy parametr o wartość drugiego parametru. Kod programu z tą
procedurą (o nazwie pseudoinc) znajduje się w ramce poniżej.
program przeciazanie_podprogramow;
uses
crt;
procedure pseudoinc(var x:real);
begin
x:=x+0.01;
end;
procedure pseudoinc(var x:real; y:real);
begin
x:=x+y;
end;
var
a:real;
begin
clrscr;
13
a:=1.0;
pseudoinc(a);
writeln(a:6:4);
pseudoinc(a,0.02);
writeln(a:6:4);
readln;
end.
W bloku główny programu wywoływane są obie wersje procedury pseudoinc.
Najpierw wywoływana jest wersja z jednym parametrem, potem z dwoma
parametrem. Proszę zwrócić uwagę, że pierwszy parametr jest w obu wersjach
procedury jest przekazywany przez zmienną. Dzięki temu zmiana wartości
zmiennej podstawionej z ten parametr procedury pseudoinc może być
zachowana po zakończeniu jej wykonywania. Free Pascal wprowadza również
do języka nowy rodzaj podprogramów, które pozwalają na przeciążanie
operatorów (tzn. +, -, *, /, itd.). Ich działanie będzie opisane w kolejnych
materiałach do wykładu.
14


Wyszukiwarka

Podobne podstrony:
PP1 wyklad
PP1 wyklad 8
PP1 wyklad 3
PP1 wyklad 5
PP1 wyklad 1
PP1 wyklad 2
PP1 wyklad
PP1 wyklad 4
PP1 wyklad 5
PP1 wyklad 9
PP1 wyklad
PP1 wyklad
Sieci komputerowe wyklady dr Furtak
Wykład 05 Opadanie i fluidyzacja
WYKŁAD 1 Wprowadzenie do biotechnologii farmaceutycznej

więcej podobnych podstron