Programowanie/Procedury i funkcje/Struktura jako jedyny ratunek
Podprogram, jako jedyny ratunek
edytujProcedura jako jedyny ratunek. Dlaczego? Otóż, jeżeli znamy podstawowe konstrukcje algorytmiczne i potrafimy je zagnieżdżać, wówczas teoretycznie jesteśmy w stanie napisać każdy algorytm. Jednakże, długość kodu tegoż programu na ekranie komputera staje się coraz większa i po pewnym czasie nie jesteśmy w stanie objąć wszystkiego wzrokiem i umysłem. Z tego powodu powstało pojęcie podprogramu. Podprogram jest fragmentem kodu, który komunikuje się z programem głównym poprzez specjalne zmienne i może być wywoływany wielokrotnie przez program główny bądź inne podprogramy.
Zastosowanie podprogramu pozwala podzielić algorytm na zbiór mniejszych, wydzielonych części. Dzięki temu program jest czytelniejszy i łatwiejszy w utrzymaniu. Jeżeli podprogram jest wykorzystany wielokrotnie, wówczas program staje się mniejszy, bo jest mniej duplikacji kodu. Jedyną poważniejszą wadą podprogramów jest to, że ich uruchomienie wymaga czasem krótkotrwałego zatrzymania pracy programu w celu przełączenia się komputera na wykonanie nowego zadania. Opóźnienie jest zazwyczaj niezauważalne i staje się istotne przy intensywnym wykorzystaniu procesora. Jest to zagadnienie bardziej zaawansowane, poruszające kwestie wydajnościowe.
W językach imperatywnych podprogramy są zazwyczaj nazywane procedurami i funkcjami. Funkcja zwraca pewną wartość (i może komunikować się poprzez parametry), natomiast procedura nie zwraca wartości i komunikuje się z kodem nadrzędnym wyłącznie poprzez parametry.
Przykładową analogią jest sztuka teatralna. Scenariusz jest pisany dla postaci literackiej (np. Klara, Wacław), natomiast w rzeczywistej sztuce występują żywi aktorzy o innych imionach i nazwiskach (np. Danuta Szaflarska, Bogusław Linda). Podprogram jest pisany dla pewnych zmiennych zadeklarowanych w obrębie danego podprogramu. Część z nich (tak, jak owe postacie literackie) służy do komunikowania się z kodem nadrzędnym (który uruchomił ten podprogram). W przypadku sztuki teatralnej wystarczy wystawić sztukę, pamiętając o przekazaniu jej rzeczywistych aktorów dla określonych postaci literackich. W ten sposób algorytm sztuki teatralnej zostanie wykonany, a instrukcje zostaną wykonane przez rzeczywistych aktorów. Sztukę można też wystawić po raz kolejny z inną obsadą. I też będzie działało (algorytm jest ten sam, ale rezultat może być już inny, bo zmienili są aktorzy (konkretnie ich wartości)).
Podobnie w programie mamy początkowo zadeklarowanie zmienne o wybranych przez programistę nazwach. Ale załóżmy, że udało się nam wydzielić zadania, które będą wielokrotnie wykonywane. Przykładem jest rozwiązanie równania kwadratowego. Jest to zadanie dość uniwersalne. Może się przydać w przyszłości, także w innym programie. Zatem rzeczą przydatną jest wydzielenie takiego zadania w formie podprogramu. Matematyka uczy rozwiązywać takie równianie zapisanie w postaci:
a*x*x + b*x + c = 0
Natomiast w rzeczywistym programie problem może być opisany przez inne zmienne. Przykładem może być ruch jednostajnie zmienny w fizyce albo inny problem z zależnością kwadratową. Zamiast zmiennej x
będziemy chcieli podstawić np. zmienną t
określającą czas.
Do podstawiania zmiennych służy interfejs podprogramu. Jest on zawarty w nagłówku funkcji. Deklaruje on zmienne widoczne wewnątrz podprogramu, pod które będzie można podstawić zmienne (lub wartości zmiennych) z kodu nadrzędnego. Zmienne te są nazywane parametrami podprogramu.
Przykładowy interfejs podprogramu rozwiązującego równanie kwadratowe a*x*x + b*x + c = 0
można zapisać (w pseudokodzie) w postaci:
/*
// uwaga: współczynnik a musi być niezerowy, bo będzie dzielenie przez zero!
PROCEDURA OBLICZ_ROWNANIE_KWADRATOWE (RZECZYWISTA, WEJSCIOWA a;
RZECZYWISTA, WEJSCIOWA b;
RZECZYWISTA, WEJSCIOWA c;
BOOL, WYJSCIOWA jestRozwRzecz;
RZECZYWISTA, WYJSCIOWA x1;
RZECZYWISTA, WYJSCIOWA x2)
{
// tutaj odbywa się obliczanie rozwiązania równania kwadratowego
// widoczne są zmienne: a, b, c, jestRozwRzecz, x1, x2
// można także deklarować inne zmienne, potrzebne do wykonania zadań, jednak nie będzie można
// ich przekazać do kodu nadrzędnego.
RZECZYWISTA Delta; // to jest zmienne lokalna (wyróżnik równania kwadratowego)
// oblicz wyróżnik równania kwadratowego
Delta = b*b - 4*a*c
// podejmij decyzję o liczbie rozwiązań równania kwadratowego
// przypadki trudne, potencjalne błędy i inne nieciekawe rzeczy można zrobić na początku
// zostawiając na deser to, co prostsze
IF(Delta < 0)
{// Delta < 0, brak rozwiązań
// Wyróżnik równania ujemny, brak rozwiązań rzeczywistych takiego równania
// przekażemy informację o tym do programu głównego poprzez zmianę wartości parametru wyjściowego
jestRozwRzecz = FALSE
}// Delta < 0, brak rozwiążań
ELSE
{// Delta >= 0, jest 1 lub 2 rozwiązanie rzeczywiste
// równanie posiada jedno rozwiązanie rzeczywiste
jestRozwRzecz = TRUE
// może być jedno lub dwa rozwiązania
IF(Delta == 0)
{// Delta == 0, jest jedno rozwiązanie rzeczywiste
// możemy obliczyć pierwiastki rzeczywiste równania
x1 = -b/(2*a)
x2 = x1
}// Delta == 0, jest jedno rozwiązanie rzeczywiste
ELSE
{// Delta > 0, są 2 rozwiązanie rzeczywiste
// możemy obliczyć pierwiastki rzeczywiste równania
// pamiętajmy o tym, że odjęcie numeryczne dwóch bliskich sobie wartości prowadzi
// do dramatycznego spadku dokładności, w tym przypadku starałem się,
// aby od dodatniego -b nie odejmować dodatniego pierwiastka z delty.
// drugi pierwiastek jest obliczany ze wzoru Viete'a,
// współczynnik a musi być niezerowy
IF(b<0)
{// b ujemne
x1 = -b+sqrt(Delta)/(2*a)
x2 = -b/a - x1
}// b ujemne
ELSE
{// b nieujemne
x1 = -b-sqrt(Delta)/(2*a)
x2 = -b/a - x1
}// b nieujemne
}// Delta > 0, są 2 rozwiązanie rzeczywiste
}// Delta >= 0, jest 1 lub 2 rozwiązanie rzeczywiste
}//PROCEDURA OBLICZ_ROWNANIE_KWADRATOWE
*/
W programie głównym można wywołać powyższy podprogram:
/*
PROGRAM DROGA
{
// program oblicza czas, w którym ciało znajdowało się na zadanej wysokości.
// deklaracje zmiennych programu
RZECZYWISTA a, b, c, s1, s2
BOOL SA_ROZW_RZECZ
// deklaracja zmiennych wejściowych dla procedury
a = 1
b = 2
c = 3
// uruchomienie procedury
WYKONAJ_PODPROGRAM OBLICZ_ROWNANIE_KWADRATOWE (a, b, c, SA_ROZW_RZECZ, s1, s2)
// analiza wyniku
IF(SA_ROZW_RZECZ == FALSE)
{//brak rozwiązań
WRITE ("ciało nie osiągnęło danej wysokości")
}//brak rozwiązań
ELSE
{//są rozwiązania
IF(x1 == x2)
{//jedno rozwiązanie
WRITE("Ciało osiągnęło punkt szczytowy w czasie: ", x1)
}//jedno rozwiązanie
ELSE
{//dwa rozwiązania
WRITE("Ciało osiągnęło zadaną wysokość w czasie: ", x1, " oraz ", x2)
}//dwa roziwązania
}//są rozwiązania
}// PROGRAM DROGA
*/
W programie zadeklarowano zmienne, które zostały następnie przypisane podczas wywołania procedury. W procedurze zadeklarowano zmienną x1 i x2. Podczas wykonania procedury została jej podstawiona zmienna s1 i s2. Po wyjściu z procedury wartości wyjściowe (m.in. s1 i s2 ) mają wartości podstawione w ciele procedury. Oznacza to, że po wywołanie procedury nastąpiło zwrócenie wyników obliczeń. Jest to nazywane efektem ubocznym wywołania podprogramu.
Uwaga: w języku C do opisanego zwrócenia wartości z wnętrze podprogramu (poprzez parametry) konieczne jest użycie wskaźników.