Podstawy Programowania Wyk ad czwarty: ł Funkcje i procedury.

Transkrypt

Podstawy Programowania Wyk ad czwarty: ł Funkcje i procedury.
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
fragment zawierał 10 błędów, to teraz mamy 20 błędów, które trzeba usunąć1.
Najlepszym rozwiązaniem jest zatem zamknięcie tego kod w podprogramie.
Powtórne użycie tego kodu będzie więc polegało na wywołaniu podprogramu za
pomocą jego nazwy. Drugim powodem stosowania podprogramów jest to, że
pozwalają 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”. Rzeczywiście, mając zapisany w języku programowania
algorytm liczenia silni, można go zamknąć w podprogramie o nazwie „silnia”
lub „licz_silnia”. Jeśli w programie napotkamy teraz instrukcję „licz_silnia(n)”,
to łatwiej 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
wewnątrz tej procedury, tzn. jeśli zadeklarujemy jakąś stałą wewnątrz
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
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ę znaleźć 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
instrukcji przypisania znak:='a'; inne instrukcje, to również zostaną one
4 Funkcje z języka Pascal pod pewnymi względami przypominają funkcje w matematyce.
5 Pod względem konstrukcji, a nie działania.
3
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.
3. Wywołanie i wykonywanie procedur i funkcji
Aby skorzystać w programie (lub innej procedurze lub funkcji) z procedury
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
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
6 Taki sposób wywołania funkcji nazywa się w literaturze „wywołaniem funkcji ze względu na
efekt uboczny jej działania”.
7 Jest to uproszczony opis problemu, rzeczywistość jest trochę bardziej skomplikowana.
4
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ą na wyświetlaniu
komunikatów na ekranie, podprogramy muszą mieć możliwość wpływania na
stan zmiennych globalnych. Funkcje i procedury mogą bezpośrednio się do
nich odwoływać. Załóżmy, że mamy zadeklarowane w programie dwie zmienne
globalne 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ć:
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
8 W niektórych opracowaniach zwaną także rekordem aktywacyjnym podprogramu.
9 Dokładniej – mogą zawierać przypadkową wartość.
5
i w niektóry (bardzo 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
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
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
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. Deklarując parametry należy
pamiętać, że jeśli chcemy przekazać do procedury lub funkcji parametr
faktyczny o dużej objętości, jak np.: zmienną typu string, to należy przekazać
go przez stałą lub zmienną. Nie powinniśmy przekazywać takich zmiennych
przez wartość, ponieważ wartość tych zmiennych jest kopiowana na stos, który
zajmuje stosunkowo mało pamięci i możemy go przepełnić powodując awaryjne
zakończenie programu. Jeśli deklarujemy parametry formalne, typów single,
double, extended oraz comp i przekazujemy je przez stałą lub zmienną, to
możemy takich parametrów zadeklarować maksymalnie osiem. 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.
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 oczywiście w procedurze równocześnie
przekazywane przez stałą, zmienną i przez wartość.
zadeklarować
parametry
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 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 średnikiem15. 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.
15 W literaturze taka deklaracja procedury lub funkcji jest czasem nazywana deklaracją
wyprzedzającą.
8
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ć
na raz 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żą ich 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 programisty16, ale ważnym jest, aby te podprogramy były dobrze
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.
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
16 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
rozwiązanie zaimplementować w postaci podprogramu. Następnie ze
zdefiniowanych podprogramów, możemy „złożyć” cały program17. Prześledźmy
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:
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('Wprowadź 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!');
17 Postępowanie to wywodzi się od sposobu rozwiązywania problemów z innych dziedzin (głownie
matematyki), który podał Kartezjusz.
10
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;
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óźnienie 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).
11
9. Przerwanie wykonania funkcji lub procedury
Język Pascal umożliwia przerwanie wykonania funkcji lub procedury za pomocą wywołania procedury exit. Po jej wykonaniu sterowanie wraca do następnego 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 podprogramie18. 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).
18 Nawet jeśli jest to zagnieżdżona procedura lub funkcja.
12