Procedurą nazywamy wyodrębnioną część programu


Procedurą nazywamy wyodrębnioną część programu, która posiada swoją nazwę, realizuje określone zadania i w ustalony sposób komunikuje się z pozostałymi częściami programu. Procedury stosuje się do wykonywania czynności wielokrotnie powtarzanych w programie lub takich, które mogą być wykorzystane w innych programach. Stosowanie procedur przyczynia się do bardziej efektywnego wykorzystania pamięci, większej przejrzystości programu i pozwala podzielić duże problemy na mniejsze, rozwiązywane przez różne procedury.

Procedury definiuje się w części opisowej programu a definicja procedury ma postać:

Procedure nazwa_procedury[(lista_argumentów)];

[część opisowa procedury]

blok zakończony średnikiem

Lista argumentów ma charakter opcjonalny - procedurę bez argumentów nazywa się bezparametrową. Wszystkie argumenty procedury muszą mieć określone typy, przy czym mogą to być typy standardowe lub zdefiniowane przez programistę.
Część opisowa procedury może zawierać takie same elementy jak część opisowa programu z wyjątkiem deklaracji modułów. Wszystkie zmienne zadeklarowane w części opisowej procedury mają zasięg lokalny - są dostępne tylko w definiowanej procedurze.

Jeżeli program wyprowadza większą ilość wyników i konieczne jest jego częste zatrzymywanie, to w tym celu można zdefiniować procedurę o nazwie np. Stop:

Procedure Stop;

Begin

WriteLn;

WriteLn('Naciśnij klawisz ENTER ...');

ReadLn;

End;

Zdefiniowana procedura jest bezargumentowa i wywołuje się ją tak jak każdą inną bezargumentową procedurę języka (np. ClrScr) wpisując jako instrukcję jej nazwę:

If (x Mod 24)=0 Then Stop;

Standardowa procedura języka Pascal

Sound(częstotliwość : Word);

powoduje wygenerowanie dźwięku o podanej częstotliwości. Dźwięk wydobywa się się głośnika do czasu aż zostanie wyłączony bezparametrową procedurą

NoSound;

Połączenie obu tych procedur

Sound(440);

NoSound;

nie przynosi jednak oczekiwanego efektu - czas pomiędzy włączaniem a wyłączeniem głośnika jest zbyt krótki, aby dźwięk mógł byc słyszalny, ale jeśli obie procedury rozdzielimy trzecią o nazwie

Delay(milisekundy : Word);

która zatrzymuje wykonywanie programu na podaną ilość milisekund (1000ms = 1s), to z pewnością coś usłyszymy.
Wygenerowanie półsekundowego dźwięku o częstotliwości
640Hz uzyskuje się poprzez trzy polecenia:

Sound(640);

Delay(500);

NoSound;

Jeżeli zamierzamy w programie często generować różne dźwięki, to można do tego celu zdefiniować procedurę, np.:

Procedure MySound(Czest, Czas : Word);

Begin

Sound(Czest);

Delay(Czas);

NoSound;

End;

Procedura MySound ma dwa argumenty oznaczające odpowiednio częstotliwość i czas generowanego dźwięku. Wywołując procedurę można jako jej argumenty podawać zarówno wartości stałe, np. MySound(380, 200), jak również zmienne lub wyrażenia typu zgodnego z typem argumentów procedury, czyli Word, np. MySound(2*i, 600-x*x).

Mając zdefiniowaną taką procedurę można na przykład uzyskać płynny dźwięk o coraz wyższej częstotliwości instrukcją:

For x:=1 To 100 Do MySound(200+10*x, 30);

Pisząc program, który np. często wypisuje w różnych miejscach ekranu napisy bez procedur trudno wręcz się obejść. Wypisanie dowolnego napisu w dowolnym miejscu na ekranie wymaga wykonania dwóch czynności - ustawienia kursora tekstowego w wybranym miejscu ekranu oraz samego wypisania napisu.

Procedure Pisz(s : String; kol, Wwer : Byte);

Begin

GotoXY(kol, wier);

Write(s);

End;

Procedura GotoXY jest standardową procedurą modułu Crt i ustawia kursor testowy we wskazanym miejscu ekranu monitora.

Powyższą procedurę można łatwo zmodyfikować w taki sposób, aby wypisywała napis s określonym kolorem i na określonym tłe. Można również zdefiniować inną procedurę wykonującą tą czynność w taki sposób, aby korzystała ona z proceedury Pisz:

Procedure Pisz(S : String; kol, wier : Byte);

Begin

GotoXY(kol, wier);

Write(s);

End;

Procedure PiszKolor(s : String; kol, wier, kolor, tlo : Byte);

Begin

TextColor(kolor);

TextBackGround(tlo);

Pisz(s, kol, wier);

End;

Var

a : LongInt;

Begin

...

PiszKolor('Podaj wartość zmiennaj A = ', 20, 12, Yellow, Blue);

ReadLn(A);

If a<0 Then

Begin

Pisz('Liczba A nie może być ujemna !!!', 32, 25, White, Red);

Halt;

End;

...

End.

Procedura PiszKolor wykonuje czynności, których nie wykona procedura Pisz: zmienia aktualnie obowiązujący kolor znaków (TextColor) oraz aktualnie obowiązujący kolor tła znaków (TextBackGround). Następnie wywołuje procedurę Pisz, która wykona pozostałe czynności, zgodnie ze swoją definicją: ustawi kursor we wskazanym miejscu ekranu i wypisze podany napis s.
W powyższym fragmencie programu dwuktornie wywoływana jest procedura
PiszKolor, z różnymi argumentami. Wykonanie tych czyności bez użycia procedur wymagałoby dwukrotnego wykonania czterech poleceń (łącznie osiem). To mniej więcej tyle ile zajęły definicje procedur, więc zysk może tutaj wydawać się znikomy, jeśli jednak założymy że program musi wypisać dwadzieścia tego typu napisów, to korzystając z procedur będziemy musieli po pierwsze zdefiniować procedury (10 linijek), a po drugie wywołać procedurę PiszKolor dwudziestokrotnie (20 linijek), łącznie da to tylko 30 linii programu. Dwudziestokrotne wykonywanie tej czynności bez użycia procedury zajmie 80(!) linii programu.

Funkcja stanowi rozszerzenie procedury o możliwość przekazywania jednej wartości ustalonego typu, zgodnego z typem zadeklarowanym w nagłówku funkcji. Funkcje podobnie jak procedury definiuje się w części opisowej programu:

Function nazwa_funkcji[(lista argumentów)] : typ_wyniku;

[część opisowa]

blok zakończony średnikiem

Wewnątrz bloku definiującego funkcję musi wystąpić instrukcja przypisania nadająca wartość definiowanej funkcji w postaci:

nazwa_funkcji:=wartość

przy czym wartość nadawana funkcji musi być zgodna z zadeklarowanym typem wyniku funkcji. Przykładem dotychczas poznanych funkcji bezparametrowych są ReadKey, KeyPressed, natomiast funkcje jednoargumentowe to Sqr i Sqrt.

Definicja funkcji, wartością której będzie pierwiastek stopnia czwartego z liczby rzeczywistej mogłaby mieć postać:

Function Sqrt4(x : Real) : Real;

Begin

Sqrt4:=Sqrt(Sqrt(x));

End;

Tak zdefiniowanej funkcji używa się w taki sam sposób w jaki używamy funkcji standardowych - wywołanie funkcji polega na podaniu jej nazwy oraz argumentu typu rzeczywistego, np.

WriteLn('Suma pierwiastków stopnia czwartego = ', Sqrt4(x)+Sqrt4(x+1));

Wywołanie funkcji Sqrt z ujemnym argumentem powoduje zazwyczaj przerwanie wykonywania programu. Taka sama sytuacja wystąpi w przypadku funkcji Sqrt4, jej obliczenie bowiem polega na obliczeniu pierwiastka stopnia drugiego.
Gdyby definicja funkcji Sqrt4 miała postać

Function Sqrt4(x : Real) : Real;

Begin

If x<0 Then Sqrt4:=0

Else Sqrt4:=Sqrt(Sqrt(x));

End;

to bez względu na wartość argumentu funkcja zostanie poprawnie wykonana, aczkolwiek wynik który zwróci, dla atgumentu ujemnego będzie co najmniej dyskusyjny.

Niemal podręcznikowy przykład nosi nazwę funkcja Min, której wartością jest mniejsza z dwóch liczb a i b:

Function Min(a, b : LongInt) : LongInt;

Begin

If a<a Then Min:=a

Else Min:=b;

End;

W podobny sposób można zdefiniować funkcję Min3, która będzie zwracać najmniejszą z trzech liczb. Można też do tego celu wykorzystać zdefiniowaną już funkcję Min:

Function Min3(a, b, c : LongInt) : LongInt;

Begin

Min3:=Min(a, Min(b, c));

End;

Obliczając często potęgi o całkowitych wykładnikach wygodnie jest zdefiniować sobie funkcję obliczającą taką potęgę:

Function Pot(podst : Integer; wykl : Byte) : LongInt;

Var

i : Byte;

wynik : LongInt;

Begin

wynik:=1;

For i:=1 To wykl Do wynik:=wynik*podst;

Pot:=wynik;

End;

Zmiennej wynik przypisujemy wartość 1, a następnie przemnażamy tą zmienną przez podstawę potęgi dokładnie wykl razy. Warto zwrócić uwagę, że dla wykładnika wykl=0 pętla For nie zostanie wykonana ani razu i funkcja zwróci wartość 1.

Mając tak zdefiniowaną funkcję Pot obliczenie wartości np. takiego dziwoląga 12+23+34+45+56+67 wymaga wykonania jednej prostej pętli sumującej:

wynik:=0;

For i:=1 To 6 Do wynik:=wynik+Pot(i, i+1);


Uwagi do funkcji o procedur
Używając w programach funkcji lub procedur należy pamiętać, że:


Przekazywanie argumentów funkcji i procedur
Sposób przekazania argumentu do funkcji lub procedurze zależy od sposobu w jaki zdefiniowana została funkcja lub procedura, mówiąc bardziej szczegółowo, od sposobu deklacji jej argumentów. Istnieją dwie zasadnicze metody:
przekazanie przez wartość oraz przekazanie przez zmienną.

Procedure P(a : Integer);

Begin

a:=a*a+1;

WriteLn(a);

End;

Tak zdefiniowaną procedurę program móże wywołać z argumentem w postaci zmiennej P(x), P(dlugosc), w postaci stałej P(1), P(1024) oraz w postaci dowolnego wyrażenia P(Sqr(12)+x-12) - wszystkie chwyty są tu dozwolone - jedyny warunek jaki musi spełnić argument podany w wywołaniu nazywa się typ, który musi być zgodny z typem argumentu wskazanym w deklaracji procedury.

Wewnątrz definicji procedury P dostępna jest zmienna a : Integer, występująca na liście argumentów. Zmienna ta jest zmienną lokalną, dostępną tylko wewnątrz bloku definiującego procedurę i nie można się do niej odwołać z żadnego innego miejsca programu, bo w żadnym innym miejscu, czy to w innej procedurze, czy też w bloku programu, zmiennej tej po prostu nie ma. Jak w znanym przeboju: "pojawia się", gdy program rozpoczyna wykonywanie procedury, "i znika", gdy sterowanie opuszcza procedurę.

Aby zrozumieć ten machanizm należy uświadomić sobie kilka szczegółów związanych z pamięcią programu. Każdy uruchamiany przez system operacyjny program otrzymuje od systemu operacyjnego fragment pamięci (ciągły obszar) o określonym rozmiarze. System operacyjny nie ingeruje w sposób wykorzystania przez program tej pamięci, jego zadanie polega jedynie na przydziale programowi pamięci i wczytaniu do niej samego programu, który podczas wykonywania wykorzystuje tą pamięć na swoje potrzeby.
W pamięci tej można wyróżnić kilka szczególnych obszarów: tzw.
segment danych, czyli obszar przewidziany na zmienne statyczne programu, tj. wszystkie zmienne zadeklarowane w części opisowej programu, obszar sterty, czyli pamięć zarezerwoną dla tzw. zmiennych dynamicznych (tworzonych podczas wykonywania programu), a także obszar stosu, tj. pamięć przeznaczoną m. in. na argumenty funkcji i procedur oraz zmienne lokalne funkcji i procedur.
To co nas szczególnie tu interesuje to
stos (and. stack). Standardowy rozmiar stosu zależy wyłącznie od ustawień domyślnyh kompilatora i najczęściej wynosi 16 lub 32 KB. Kompilatory za ogół pozwalają zmienić rozmiar stosu, albo za pomocą ustawienie opcji gdzieś w menu środowiska zintegrowanego, albo poprzez umieszczenie w kompilowanym programie odpowiednią derektywę.

W momencie wywołania procedury program na stosie tworzy wszystkie zmienne wskazane na liście argumentów procedury i nadaje im początkowe wartości, zgodnie z tym, co podano w wywołaniu procedury. Wykonanie polecenia:

P(Sqr(12)-12);

polega po pierwsze, na obliczeniu wartości wyrażenia będącego argumentem procedury P, po drugie na utworzeniu na stosie zmiennej a typu Integer, tak jak wskazano w deklaracji, po trzecie przypisaniu tej zmiennej obliczonej wartości wywołania i wreszcie po czwarte na przeniesieniu sterowania do pierwszej instrukcji procedury.

Pamięć po kompilacji programu

obszar danych | obszar sterty | obszar stosu

XXXX---------------------- ---------------------- ---------------------

Znakiem '-' zaznaczono niewykorzystywany obszar pamięci, znakiem X pamięć zajmowaną przez zmienne statyczne programu. W momencie wywołanie procedury P w obszarze stosu zostanie utworzona zmienna a będąca argumentem wywołania procedury i przed rozpoczęciem wykonywania kodu procedury zmienna ta otrzyma taką wartość z jaką została wywołana procedura P, czyli wartość 132 (szesnastkowo 84). Wówczas będzie to wyglądać następująco:

Pamięć programu w momencie wywołania procedury P

obszar danych | obszar sterty | obszar stosu

XXXX---------------------- ---------------------- 0084-----------------

Zmienna na stosie będzie istnieć do momentu zakończenia wykonywania procedury P i to na niej właśnie będą wykonywane wszystkie operacje zawarte w definicji procedury. W szczególności wskutek wykonania przypisania a:=a*a+1 ulegnie zmianie wartość zmiennej a na 4411(16):

Pamięć programu po wykonaniu przypisania a:=a*a+1

obszar danych | obszar sterty | obszar stosu

XXXX---------------------- ---------------------- 4411-----------------

Po zakończeniu wykonywania procedury wszystko wraca do normy:

Pamięć programu po wykonaniu procedury P

obszar danych | obszar sterty | obszar stosu

XXXX---------------------- ---------------------- ---------------------

O przekazaniu argumentu procedurze przez zmienną mówimy wówczas, gdy na liście argumentów identyfikator zmiennej poprzedzono słowem kluczowym Var:

Procedure Czytaj(Var a : Word);

Begin

Repeat

Write('Podaj dodatnią liczbę naturalną A = ');

ReadLn(a);

Until a>0;

End;

Wywołanie tak zadeklarowanej procedury jest możliwe tylko wówczas, gdy jako agrument podana zostanie zmienna typu Word (nie może to być zmienna żadnego typu zgodnego). Przy przekazaniu argumentu przez zmienną na stosie nie tworzy się żadnych zmiennych tymczasowych - procedura pracuje bezpośrednio na przekazanej jej zmienej.
Jeśli tak zdefiniowaną procedurę wywołamy w programie ze zmienną
ilosc:

...

Var

ilosc : Word;

Begin

Czytaj(ilosc);

WriteLn('Wczytano liczbę = ', ilosc);

End.

to występująca w definicji zmienna a podczas wykonania procedury będzie tożsama ze zmienną globalną programu ilosc.

Przez zmienną przekazuje się do funkcji i procedur takie argumenty, których zmiany wykonane przez procedurę powinny być trwałe, jak np. odczyt wartości z klawiatury.
Również duże struktury danych jak tablice należy w miarę możliwości przekazywać przez zmienną, gdyż w przeciwnym wypadku na stosie tworzone są ich kopie i znaczne zagłębienie wykonywania procedur może doprowadzić do wyczerpania miejsca na stosie, a tym samym do błędu wykonania programu.



Wyszukiwarka

Podobne podstrony:
Bulimia rozdział 5; część 2 program
Bulimia rozdział 19; część 2 program
Bulimia rozdział 13; część 2 program
Bulimia rozdział 9; część 2 program
Bulimia rozdział 6; część 2 program
Bulimia rozdział 8; część 2 program
Bulimia rozdział 12; część 2 program
STRING - Procedury i funkcje, Szkoła, Klasa 1, Programowanie struktularne i obiektowe
Bulimia rozdział 2 4; część 2 program
Bulimia rozdział 7; część 2 program
Bulimia rozdział 11; część 2 program
Bulimia rozdział 10; część 2 program
Bulimia rozdział 5; część 2 program
Bulimia rozdział 6; część 2 program
Bulimia rozdział 13; część 2 program
Bulimia rozdział 9; część 2 program
Bulimia rozdział 10; część 2 program
Bulimia rozdział 8; część 2 program
Bulimia rozdział 12; część 2 program

więcej podobnych podstron