10 Podprogramy - funkcje
Stosowanie procedur i funkcji (podprogramów) umożliwia rozbicie złożonego ciągu operacji na mniejsze struktury. Zwiększa to czytelność programu, poprawia kontrolę nad rozbudowanym programem i umożliwia wielokrotne wykorzystanie bloków instrukcji ze zmienionymi danymi wejściowymi. Podprogramy mogą mieć strukturę hierarchiczną, a zatem kolejna procedura może być definiowana we "wnętrzu" innej.
Zadaniem funkcji jest obliczenie pojedynczej wartości zaś procedura wykonuje sekwencję działań i może wyprowadzać wiele obliczonych wartości.
Definicja procedury lub/i funkcji umieszczana jest w części deklaracyjnej programu głównego (także innej procedury lub funkcji):
function nazwa (lista parametrów formalnych): typ prosty;
definicje, deklaracje
begin
....
nazwa := wyrażenie;
....
end;
W nagłówku definicji muszą się znaleźć parametry przekazywane do wnętrza funkcji z określeniem ich typów (elementy listy oddzielane są średnikami) oraz typ funkcji (prosty).
Funkcja zapewnia w zasadzie zwrot pojedynczej wartości poprzez jej nazwę (obiekt określonego typu prostego), chociaż można również stosować przekazanie przez zmienną (jak w procedurze, patrz następne ćwiczenie). W bloku wykonawczym funkcji musi zatem znaleźć się instrukcja wykonująca nadanie wartości funkcji (np. instrukcja przypisania dla nazwy funkcji).
Przykładowe nagłówki definicji funkcji:
function suma (x1, x2: real):real;
function sprawdzaj(x1, x2: real; y1, y2: integer ):boolean;
Wykonanie (wywołanie) funkcji odbyć się może:
w wyrażeniu odpowiedniego typu (funkcje typów liczbowych w wyrażeniach arytmetycznych, funkcje logiczne w wyrażeniach logicznych),
w procedurze wyprowadzenia write(ln),
jako parametr innej funkcji lub procedury (w tym standardowej) z zachowaniem zgodności typu.
Parametry wywołania (wykonania) funkcji, zwane parametrami aktualnymi, mogą być stałymi, zmiennymi lub wyrażeniami, oddzielane są przecinkami. Liczba i typ parametrów aktualnych musi być zgodna z deklaracją funkcji.
Przykładowy program ilustruje możliwe sposoby wywołania funkcji:
program p10_1;
var a, b,c :real;
function iloczyn (x1, x2: real): real; {definicja funkcji}
begin
iloczyn := x1*x2; {nadanie wartości funkcji}
end; {koniec definicji funkcji}
begin {program główny}
a := 3.4;
b := 5.6;
writeln (iloczyn( a, b ) ); {użycie funkcji jako parametru instrukcji writeln}
c := 3 iloczyn (a, b);
writeln (c:10:5);
c := 2 iloczyn (b, 1- a)/iloczyn (a, 2*b +1); {użycie funkcji w wyrażeniu}
writeln( c:10:5);
c := 1/iloczyn (c-1, a);
writeln( c:10:5);
if iloczyn(a*a, b-3)>0 then writeln(' dodatni')
end.
Wywołanie (wykonanie) funkcji w programie dokonywane jest zatem tak jak użycie zmiennej (podobnie jak funkcje standardowe). Wartości parametrów aktualnych (lub obliczonych wyrażeń) przekazywane są do funkcji (kopiowane na parametry formalne), następnie wykonywane są instrukcje w „ciele” funkcji i wartość obliczona zwracana jest pod identyfikatorem (nazwą) funkcji do miejsca wywołania.
Poniższy program tabelaryzuje wartości funkcji opisanej przedziałami, w 21 punktach zakresu (0.0, 2.0):
program p10_2;
uses crt;
var i: 0..20;
function fun(x: real): real; {definicja funkcji}
var xkw: real;
begin
xkw := xx;
if x := 0.5 then fun := 0.2xkw-x+0.1
else fun := xkw/(xkw-0.1)
end; {koniec definicji funkcji}
begin {początek programu głównego}
clrscr;
writeln;
writeln ('Tabela wartości funkcji':45);
writeln;
writeln ('x':30, 'f(x)':20);
for i := 0 to 20 do
begin
writeln(i:12, i0.1:20:3, fun(i0.1):20:5)
end;
repeat until keypressed
end .
Ćwiczenie
Wykonać programy przykładowe p10_1, p10_2. Przeanalizować postać deklaracji funkcji, cel jej stosowania, postaci instrukcji wykorzystującej funkcje.
Wykonywać program krokowo (Trace into) obserwując przejście do bloku funkcji w momencie napotkania wywołania funkcji. W oknie Watch obserwować wartości zmiennych i moment nadania wartości zmiennej reprezentującej funkcję.
Napisać program zawierający deklarację funkcji określonej jako:
f(x) = -x +2 dla x<0,
f(x) = x - 2 dla x>=0.
Program główny wyznacza i wyprowadza na ekran wartości funkcji dla:
x = -5, -2, 1, 4.5⋅105 i 6.34.
Zmodyfikować poprzedni program tak, aby funkcja była wykorzystywana w iteracji wyprowadzającej wartości w 20 punktach z przedziału (-5.0; 5.0).
Sporządzić program, którego zadaniem będzie wykorzystanie funkcji typu logicznego sprawdzającej czy dwie wprowadzone wartości typu całkowitego są sobie równe.
Opracować program, w którym wykorzystywana jest funkcja konwersji liczby w układzie pozycyjnym binarnym zapisaną w wektorze:
[cn, cn-1, .... c1, c0]
na liczbę w układzie dziesiętnym.
Zastosować metodę sumowania: L=
11 Podprogramy - procedury
Procedury mogą wykonać sekwencję działań na wartościach wprowadzonych do jej wnętrza i wyprowadzać wiele obliczonych wartości.
Definicja procedury, podobnie jak definicja funkcji. umieszczana jest w części deklaracyjnej programu głównego (także innej procedury lub funkcji):
procedure nazwa (parametry formalne);
definicje, deklaracje
begin
....
instrukcje
....
end;
Parametry formalne służą do przekazywania danych pomiędzy blokiem, w którym wykonywana jest procedura, a samą procedurą. Niektóre z nich przekazują dane wejściowe do funkcji lub procedury, inne mogą zwrócić wyliczone w podprogramie wartości do programu głównego lub nadrzędnego podprogramu. Deklaracje parametrów formalnych są oddzielane średnikami, każda deklaracja składa się z listy zmiennych i nazwy typu.
Przykładowe nagłówki deklaracji procedury :
procedure drukuj (x1, x2: real);
procedure suma (liczba1, liczba2: real; var wynik: real);
Poprzedzające zmienną (lub listę zmiennych) słowo kluczowe var określa przekazanie danych przez zmienną, jego brak przekazanie danych przez wartość. Przekazanie przez wartość stosuje się w celu wniesienia danych wejściowych do podprogramu, natomiast przekazanie przez zmienną ma na celu zwrot wyników działania procedury lub funkcji do miejsca wywołania.
Przekazanie przez wartość traktowane jest jako nadanie wartości początkowej zmiennej lokalnej, w momencie zakończenia podprogramu parametr formalny przestaje istnieć, wartość argumentu nie zostaje zmieniona.
Przekazanie przez zmienną może przenieść wartość do procedury (wejście), po jej zakończeniu powoduje zwrot nowej wartości do programu wywołującego procedurę.
Wykonanie procedury jest odrębną instrukcją. Parametry aktualne odpowiadające pozycji wywołania przez wartość mogą być stałymi, zmiennymi lub wyrażeniami, natomiast parametry aktualne odpowiadające przekazaniu przez zmienną muszą być identyfikatorami (nazwami) zmiennych.
Prosty przykład procedury sumującej dwie liczby:
program p11_1;
var a, b, c :real;
{definicja procedury}
procedure suma (liczba1, liczba2: real; var wynik: real);
begin
wynik := liczba1 + liczba2;
end; {koniec definicji procedury}
begin {początek programu głównego}
a := 2;
b := 2;
{przykładowe wykonania procedury}
suma (6.7, 2*a, c); {trzeci parametr aktualny musi być zmienną}
writeln(c:10:3); {c jest równe10.7}
suma (a , b , c);
writeln(c:10:3); {c jest równe 4}
suma (c , c , c);
writeln(c:10:3); {c jest równe 8}
suma (c, b , a)
writeln(a:10:3); {a jest równe10.7}
end.
Zasięg deklaracji zmiennych
Deklaracje obiektów w programie głównym zwane są globalnymi, "widoczne" są w całym programie, także i w podprogramach (czasami mogą być tam "przesłonięte" czyli ponownie deklarowane. Deklaracje obiektów w definicji podprogramu to deklaracje lokalne dla podprogramu, nie będą "widoczne" w programie wywołującym. Jeśli w ciele definicji podprogramu jest deklaracja zagnieżdżonego podprogramu to obiekty lokalne stają się dla niego zewnętrznymi.
Zasięg deklaracji ilustruje poniższy rysunek:
deklaracje globalne widoczne w całym programie (chyba że przesłonięte w B, C lub D)
deklaracje lokalne w B (zewnętrzne dla C)
deklaracje lokalne w C (deklaracje A i B można przesłaniać)
tu można wykorzystać
procedurę C
deklaracje lokalne w D (deklaracje A można przesłaniać, procedura C niewidoczna)
blok główny programu, tu można wywołać procedury B i D lecz nie procedurę C
Rys 11.1 Zasięg deklaracji w Turbo Pascalu.
Ćwiczenie
W przykładzie p11_1 zastanowić się nad działaniem poszczególnych instrukcji wywołujących procedurę. Przewidzieć rezultaty kolejnych wykonań procedury, w razie potrzeby wzbogacić program w wydruki kontrolne, sprawdzające przewidywane wartości parametrów wyprowadzonych przez zmienną.
Napisać program zawierający deklarację procedury obliczającej iloczyn dwóch zmiennych zespolonych z1 i z2, określonych jako:
z1=a + jb
z2=c + jd
gdzie j jest jednostką urojoną: j=
Iloczyn obu liczb można określić jako:
z=z1⋅z2 = (a + jb)(c+jd) = ac - bd + j (ad + bd)
Zastosować zmienną typu rekordowego o strukturze:
var zesp= record
re, im :real;
end;
W programie głównym wykonać obliczenia iloczynu dowolnych dwóch liczb zespolonych.
Napisać program, którego zadaniem będzie utworzenie niewielkiej tablicy jednowymiarowej zawierającej liczby rzeczywiste oraz zdefiniowanie i wykorzystanie procedury znajdującej w tablicy elementy o maksymalnej i minimalnej wartości.
Zadanie domowe:
Przygotować na dyskietce kod programów przykładowych następnego ćwiczenia
12 Pliki
12.1 Typ plikowy
Plik w pojęciu Turbo Pascala jest ciągiem elementów tego samego typu, odwzorowującym fizyczny zbiór danych gromadzonych w pliku umieszczonym w pamięci zewnętrznej. Dostęp do pliku jest sekwencyjny, tzn. po otwarciu pliku dostępny jest pierwszy element, zaś inne elementy mogą być udostępniane tylko po wykonaniu pewnych operacji (czytanie kolejnych elementów, przesunięcie pozycji czytania itp.).
Aby uzyskać dostęp do pliku fizycznego należy zadeklarować w programie zmienną lub zmienne typu plikowego, które trzeba skojarzyć z plikami dyskowymi. Zmienne te można kojarzyć kolejno z różnymi plikami.
Plik może mieć dowolny typ składowych (oprócz typu plikowego).
Definicja typu plikowego ma postać:
type nazwa = file of typ; plik elementowy (zdefiniowany)
type nazwa = file; plik blokowy (niezdefiniowany)
type nazwa = text; plik tekstowy (predefiniowany)
Przykład użycia pliku elementowego:
type
osoba = record
nazw: string[30];
imie: string[30]
end;
grupa = file of osoba; {typ plikowy}
var
student: osoba;
gr1, gr2, gr3: grupa; {zmienne typu plikowego}
begin
...operacje na pliku...
end.
Dla całościowych zmiennych plikowych możliwe są jedynie niektóre operacje systemu plików, natomiast na składowych możemy wykonywać operacje w zależności od typu składowych.
W pliku elementowym zapis dokonuje się w postaci binarnej, a w tekstowym nawet elementy liczbowe zapisywane są jako tekst.
Obsługa plików wymaga:
opisu zmiennej plikowej w części deklaracyjnej,
skojarzenia zmiennej plikowej z plikiem fizycznym,
otwarcia pliku (do zapisu lub do odczytu),
wykonania niezbędnych operacji (czytanie, zapis i inne),
zamknięcia pliku.
12.2 Operacje plikowe
W poniższej tabeli przedstawiono podstawowe operacje plikowe z użyciem standardowych procedur i funkcji plikowych, w których użyto określeń:
f - nazwa zmiennej typu plikowego,
Wt - wyrażenie tekstowe,
W - wyrażenie odpowiedniego typu,
Z - nazwa zmiennej.
TABELA 12.1. Podstawowe operacje plikowe
Operacja |
Typ |
Zapis |
Przykłady |
Skojarzenie zmiennej plikowej z plikiem fizycznym |
Procedura |
Assign (f , Wt) |
assign(p1,'C:\DANE\gr1.dan'); assign(p2,'C:\DANE\gr2.dan'); |
Otwarcie do odczytu i zapisu (istniejący plik) |
Procedura |
Reset (f); |
reset (p1); |
Otwarcie do zapisu (nowy plik) |
Procedura |
Rewrite (f); |
rewrite (p2); |
Otwarcie do dopisania (na końcu pliku tekstowego ) |
Procedura |
Append (f); |
append (p2); |
Zamknięcie pliku |
Procedura |
Close (f); |
close (p3); |
Detekcja końca pliku |
Funkcja logiczna |
Eof (f) |
if eof (p1) then ... while not eof(gr1) do... |
Odczyt |
Procedura |
Read (f, Z1,..,Zn); |
read (gr1, student.nazw); |
Zapis |
Procedura |
Write(f, W); |
write (gr2, nazwisko); |
UWAGI:
Po otwarciu do odczytu wskaźnik czytania ustawia się na początku pliku,
Po przeczytaniu elementu następuje przesunięcie wskaźnika odczytu do następnego elementu, aby przeczytać dowolny element wewnątrz pliku należy uprzednio przeczytać elementy poprzedzające,
Otwarcie nowego pliku procedurą rewrite powoduje utworzenie pustego pliku,
Gdy eof(f) = true - wskaźnik odczytu (zapisu) znajduje się na końcu pliku,
Gdy po wykonaniu procedury reset okaże się że eof(file) = true to plik jest pusty,
Instrukcja writeln istnieje tylko dla pliku typu tekstowego,
Zapis dopuszczalny tylko na końcu pliku (niemożliwy zapis "w środku" pliku),
Każdy zapis przesuwa wskaźnik o jedną pozycję,
Dopisanie "w środku" pliku wykonuje się przez etapowe przepisywanie do innego pliku.
Poniższy program zawiera modyfikację wcześniejszego przykładu z użyciem procedury oraz zapisu tabeli funkcji do pliku tekstowego:
program p12_1;
uses crt;
var i: 0..20;
y: real;
w: char;
plik: text;
procedure oblicz(x:real; var f:real; var wsk:char); {definicja procedury}
var xkw: real;
begin
xkw := xx;
if x = 0.5 then f := 0.2xkw-x+0.1
else f := xkw/(xkw-0.1);
if f < 0 then wsk := '' else wsk := '+'
end;
begin { początek akcji programu }
assign(plik, 'c:\tp\moje\fun.txt'); { skojarzenie pliku }
rewrite(plik); { otwarcie pliku do zapisu }
clrscr;
writeln;
writeln('Tabela wartosci funkcji':45);
writeln;
writeln('x':30, 'f(x)': 20);
for i := 0 to 20 do
begin
oblicz(i0.1, y, w); {wywołanie procedury}
writeln(i:12, i0.1:20:3, y:20:5, w:3);
writeln(plik, i:12, i0.1:20:3, y:20:5); {zapis do pliku}
end;
close(plik); {zamknięcie pliku}
repeat until keypressed
end .
Poniższy przykład ilustruje wykorzystanie bardziej złożonych struktur i algorytmów:
program p12_2;
{Ilustracja użycia typu rekordowego wraz z zapisem/odczytem danych}
{Program wczytuje dane podawane z klawiatury i zapisuje do tablicy rekordów, a następnie wyświetla listę danych posortowaną według zadanego pola}
uses crt;
type
TOsoba = record { rekord zawierający dane osobowe }
Imie :string[ 25 ];
Nazwisko :string[ 25 ];
Adres :string[ 25 ];
wiek :integer;
Plec :(K,M);
end;
const
MaxOsob = 30; { maksymalny rozmiar tablicy z danymi osobowymi }
var
ListaOsob : array [ 1..MaxOsob ] of TOsoba;
IloscOsob : integer;
NastepnaOsoba : boolean;
Znak :char;
i,n : integer;
Zamienic : boolean;
pom :TOsoba; {zmienna pomocnicza do sortowania tablicy }
f : file of TOsoba;
Nazwa : string;
begin {początek programu}
clrscr;
repeat
writeln('0 - wprowadzanie danych z klawiatury');
writeln('1 - odczyt danych z dysku');
write('Twoj wybór [ 0/1 ]:');readln(znak);
until (znak = '0') or (znak = '1');
if znak = '0' then
begin { wczytanie danych z klawiatury }
NastepnaOsoba := true;
Iloscosob := 0;
while NastepnaOsoba and (IloscOsob <= MaxOsob) do
begin
inc(IloscOsob); {zwiększ N o 1}
with ListaOsob[ IloscOsob ] do
begin
write('Imie: '); readln(Imie);
write('Nazwisko: '); readln(Nazwisko);
write('Adres: '); readln(Adres);
write('Wiek: '); readln(Wiek);
write('Plec [ K/M ]:');
repeat
readln(Znak);
Znak := UpCase(Znak);
until (Znak = 'K') or (Znak = 'M');
case znak of
'K': Plec := K
else Plec := M
end;
end; {koniec with}
if IloscOsob < MaxOsob then
begin
writeln;
writeln('Wprowadziles do tej pory ',IloscOsob,' osob');
write('Chcesz podac nastepna osobe? [ T/N ]');
repeat
readln(Znak);
Znak := UpCase(Znak);
until (Znak = 'T') or (Znak = 'N');
NastepnaOsoba := Znak='T';
end;
end;
writeln;
write('Zapisać wprowadzone osoby na dysku [ T/N ]? ');
repeat
readln(Znak);
Znak := UpCase(Znak);
until (Znak = 'T') or (Znak = 'N');
if znak = 'T' then
begin{ zapis listy na dysk }
write( 'Podaj nazwe pliku:' ); readln(nazwa);
if nazwa <> '' then
begin
assign(f , nazwa);
rewrite(f);
for i := 1 to IloscOsob do write(f, ListaOsob[ i ]);
Close(f);
end;
end;
end { koniec wprowadzania z klawiatury }
else { odczyt z dysku }
begin
repeat
write('Podaj nazwe pliku:');
readln(Nazwa);
until Nazwa < > '';
assign(f,Nazwa); {przypisanie zmiennej plikowej pliku dyskowego}
reset(f); {otwarcie pliku do odczytu}
while not eof(f) and (IloscOsob < MaxOsob) do
begin
inc(IloscOsob);
read(f,ListaOsob [Iloscosob ]);
end;
Close(f); {zamknięcie pliku}
end; { koniec odczytu z dysku }
{sortowanie i wyswietlanie listy }
repeat {wybor sposobu sortowania }
writeln('Wybierz porzadek sortowania:');
writeln(' I - imie');
writeln(' N - nazwisko');
writeln(' W - wiek');
writeln(' P - Plec');
readln(znak);
znak := UpCase(znak);
case znak of
'I' :writeln('Lista posortowana według imion');
'N' :writeln('Lista posortowana według nazwisk');
W' :writeln('Lista posortowana według wieku');
'P' :writeln('Lista posortowana według plci');
else writeln('Lista nieposortowana');
end;
{sortowanie }
for i := 2 to IloscOsob do
begin
n := i;
repeat
case znak of
'I' : Zamienic := ListaOsob[ n ].Imie< ListaOsob[ n -1 ].Imie;
'N' :Zamienic := ListaOsob[ n ].Nazwisko<
ListaOsob[n -1]. Nazwisko;
'W' : Zamienic := ListaOsob[ n ].Wiek < ListaOsob[ n-1 ].Wiek;
'P' : Zamienic := ListaOsob[ n ].Plec < ListaOsob[ n -1 ].Plec;
end;
if Zamienic then
begin
pom := Listaosob[ n ];
Listaosob[ n ] := ListaOsob[ n -1 ];
Listaosob[ n -1 ] := pom;
end;
Dec(n); {zmniejsz N o 1}
until (n = 1) or (not Zamienic);
end; {koniec sortowania}
{ wyswietlenie listy }
for i := 1 to IloscOsob do
begin
write(i:2,' ',ListaOsob[ i ].Imie,' ',ListaOsob[ i ].Nazwisko,' lat ',ListaOsob[ i ].Wiek,' ');
if ListaOsob[ i ].Plec=K then write('K')
else write('M');
writeln( ' ',Listaosob[ i ].Adres);
end;
writeln;
write('Wyświetlić powtórnie [ T/N ]:');readln(znak);
until Upcase(znak) = 'N';
end.
Ćwiczenie
Zainstalować przygotowane w domu kody programów p12_1 i p12_2. Zastanowić się nad ich strukturą i realizacją algorytmów. Znaleźć w kodzie instrukcje wykorzystujące procedury obsługi plików.
Prześledzić krokowo program p12_1. Sprawdzić w DOS-Shell powstanie na dysku pliku tekstowego - obejrzeć jego zawartość dowolnym edytorem ASCII.
Przy pomocy programu p12_2 założyć niewielki plik elementowy. Sprawdzić poprawność wykonania programu przez jego ponowne wykonanie z odczytem i sortowaniem danych
Sporządzić program do zakładania pliku elementowego składającego się z kilku rekordów o strukturze AUTO (marka, rocznik, cena). Następnie napisać program odczytujący ten plik, wypisujący na ekranie:
wszystkie rekordy,
tylko auta o wybranej marce,
auta o cenie wyższej niż 10000 zł.
13 Algorytmy rekurencyjne
Wiele problemów obliczeniowych można zdefiniować rekurencyjnie. Rekurencja oznacza takie zdefiniowanie zagadnienia, gdzie w trakcie formułowania definicji odwołujemy się do niej samej. Przykładem definicji rekurencyjnej może być zapis całkowitej nieujemnej potęgi rzędu N liczby rzeczywistej x:
xn-1*x dla N > 0
xn =
1 dla N = 0
Rekurencja w językach programowania jest realizowana przy pomocy podprogramów wywołujących kolejno same siebie ze zmienianymi parametrami wywołania. Podprogramy rekurencyjne aby poprawnie działały muszą zawierać warunek zakończenia rekurencji aby wywołanie wykonywane było skończoną liczbę razy.
Rekurencja daje proste programy - niestety ma także poważną wadę: każde wywołanie podprogramu wymaga wykonania przez procesor pewnych czynności administracyjnych, co spowalnia działanie programu oraz powoduje odłożenie na stos systemowy dużej liczby danych.
Przykłady:
program p13_1;
{wyznaczanie całkowitej nieujemnej N-tej potęgi liczby x metodą rekurencyjną}
function PotegaN(x:real;N:integer):real;
{ funkcja wyznacza potege N z liczby X }
begin
if N=0 then PotegaN := 1
else PotegaN := PotegaN(x, N - 1)*x; { w definicji funkcji wykorzystanie tejże funkcji}
end;
begin {program główny}
writeln('2^10=', PotegaN(2,10):0:0);
end.
Kolejny przykład to wyznaczanie metodą rekurencyjną silni liczby X:
program p13_2;
function SilniaX(x:integer):longint; {zastosowano typ longint ze względu na duże wartości funkcji silnia}
begin
if x = 1 then SilniaX := 1
else SilniaX := SilniaX(x-1)*x;
end;
begin
writeln ('Silnia z liczby 6= ',SilniaX(6));
end.
Ćwiczenie
Sporządzić kody programów przykładowych z rozdziału.
Wykonywać programy krokowo (Trace into) obserwując wielokrotne wykonywanie funkcji z odkładaniem wartości na stos, a po osiągnięciu warunku końcowego przeliczenie odłożonych watości (potęgowanie, obliczanie silni jako iloczynu). Obserwować wartość parametru funkcji w oknie Watch.
Wykonać samodzielnie program z wykorzystaniem rekurencji dla wyznaczania sumy kolejnych liczb naturalnych parzystych. Parametrem funkcji jest zakres obliczeń - np. 200.
Wykonać program rekurencyjnego wyznaczania 50 składowych ciągu Fibonacciego o definicji:
Fk+2 = Fk+1+Fk
F0 = F1 = 1.
14 Moduły
Moduły są podstawą programowania modularnego i służą do grupowania funkcji i procedur w biblioteki. Moduł nie stanowi samodzielnego programu. Użycie procedur, funkcji, zmiennych definiowanych w module wymaga deklaracji modułu (uses moduł) w programie użytkowym. Moduł powinien być wcześniej skompilowany i umieszczony jako plik w dostępnym folderze (standardowo UNITS).
14.1 Opis struktury modułu
unit nazwa_modułu;
interface {część opisowa }
deklaracja modułów {zawsze pierwsza}
definicja stałych
definicja typów
definicja zmiennych
lista nagłówków procedur i funkcji
implementation {część implementacyjna}
deklaracje i definicje stałych, typów i zmiennych elementów dostępnych tylko w module
definicje procedur i funkcji
initialization {wystepuje rzadko}
działania inicjacyjne
finalization {wystepuje rzadko}
działania finalizacyjne
end .
Przykład modułu:
unit cmplx;
interface
type complex = record
im,re:real
end;
procedure dodaj (a,b:complex; var c:complex);
procedure odejmij (a,b:complex; var c:complex);
............ {i inne}
implementation
procedure dodaj(a,b:complex; var c:complex);
begin
c.re := a.re + b.re;
c.im := a.im + b.im
end;
procedure odejmij (a,b:complex; var c:complex);
begin
c.re := a.re - b.re;
c.im := a.im - b.im
end;
end .
Tak utworzony moduł powinien być poprawnie skompilowany na dysk (opcja Destination - disk w menu Compile). Jego skompilowany plik z rozszerzeniem *.tpu powstanie w katalogu określonym w menu Options - Directories... jako katalog EXE & TPU. Następnie należy go przenieść (lub skopiować) do katalogu określonego w menu Options - Directories... jako Units directory, wówczas można z niego korzystać w dowolnym programie.
Przykład wykorzystania powyżej zdefiniowanego modułu:
program m12;
uses cmplx;
var x,y,z : complex; {można korzystać z typów definiowanych w module}
begin
readln(x.re, x.im); {wczytanie x}
readln(y.re, y.im}; {wczytanie y}
dodaj (x, y, z); {wywołanie procedury modułu cmplx}
writeln ( ' Suma= ' , z.re:12:5 , z.im:12:5);
odejmij (x , y , z);
writeln ( ' Różnica=', z.re:12:5 , z.im:12:5)
end .
Jeśli jeden moduł wykorzystuje wewnątrz funkcje lub procedury innego modułu, deklaracja powinna wyglądać następująco:
unit A;
interface
.............
implementation
uses B;
..............
jeżeli zaś będzie
unit B;
interface
.............
implementation
uses A;
..............
to moduły A i B są wzajemnie zależne.
14.2 Moduły standardowe TurboPascala
Moduł System
(Uwaga: modułu System nie trzeba deklarować w bloku uses)
Moduł ten zawiera:
Predefiniowane stałe i zmienne dla identyfikacji błędów, obsługi wejścia i wyjścia.
Procedury przerwania iteracji (pętli for, while, repeat) i programu:
Break - przerwanie pętli,
Exit - wyjście z bieżącego bloku,
Halt - przerwanie programu.
Funkcje i procedury dynamicznego przydziału pamięci: New, Dispose i inne, adresowe i wskaźnikowe.
Funkcje konwersji: Chr, Ord, Round, Trunc.
Arytmetyczne funkcje standardowe,
Procedury porządkowe: Inc, Dec, Odd, Pred, Succ,
Funkcje i procedury operacji na tekstach:
Concat (lista_elementów_tekstowych) - połączenie tekstów,
Copy (element_tekstowy, pozycja, długość) - wycięcie z tekstu,
Length (element_tekstowy) - długość tekstu,
Str (argument_numeryczny, zmienna tekstowa) - zamiana wartości numerycznej na tekst,
Val(element_tekstowy, zmienna numeryczna, kod) - zamiana łańcucha na wartość (kod - pozycja pierwszego błędnego znaku),
Procedury i funkcje obsługi zbiorów: Assign, Reset, Rewrite, Close, Eof, Eoln i inne,
Inne procedury i funkcje, np.:
Randomize - inicjacja generatora liczb losowych,
Random(zakres) - wartość losowa z zakresu.
Moduł Printer
Moduł zawiera deklarację pliku tekstowego Lst, dzięki któremu możemy drukować tekstowo na drukarce:
program drukuj;
uses Printer;
begin
writeln(Lst, 'Tekst wyprowadzany')
end.
Moduł Crt
Moduł zawiera:
Predefiniowane identyfikatory: trybu ekranu, kolorów,
Podprogramy sterowania trybami ekranu:
ClrScr, Window, Gotoxy (x,y), TextColor, TextBackground i inne,
Funkcję Readkey - wczytanie jednego znaku,
Procedury dźwiękowe:
Delay(opóźnienie w milisekundach);
Sound (częstotliwość),
NoSound; - przerwanie dźwięku.
Moduł Graph - funkcje i procedury graficzne.
Moduł ten zawiera funkcje i procedury użyteczne przy tworzeniu grafiki ekranowej:
procedury udostępniające tryb i sterowniki graficzne, inicjujące i zamykające tryb graficzny.
procedury ustalające kolor, styl dla tła, linii itp.,
procedury rysowania figur prymitywnych (prostokąt, elipsa i inne),
Szczegółową postać podprogramów dostępnych w module Graph oraz opis ich parametrów znaleźć można literaturze lub w pomocy ekranowej.
Inne moduły to:
Moduł Strings - Funkcje i procedury operacji na tekstach
Moduł Dos i WinDos- Funkcje i procedury do bezpośredniego kontaktu z systemem operacyjnym.
Ćwiczenie
Sporządzić moduł gromadzący podprogramy działań na liczbach zespolonych:
unit cmplx;
.... {treść modułu jak powyżej}
end.
Skompilować moduł na dysk (menu Compile - opcja Destination - disk). Jego skompilowany plik z rozszerzeniem tpu powstanie w katalogu określonym w menu Options - Directories... jako katalog EXE & TPU. Następnie należy go przenieść (lub skopiować) do katalogu określonego w menu Options - Directories... jako Units directory.
Napisać program wykorzystujący utworzony moduł:
program p14_1;
uses cmplx; {deklaracja modułu}
var a,b,c:complex; { z typu opisanego w module też można korzystać}
begin
a.re:=1;
a.im:=1;
b.re:=1;
b.im:=1;
dodaj(a,b, c);
writeln(c.re,c.im)
end.
Przetestować program.
Uzupełnić moduł o definicje procedury mnożenia i dzielenia liczb zespolonych i wykorzystać je w programie głównym.
Napisać program zawierający dowolną iterację. Zastosować procedurę biblioteczną break powodującą przerwanie iteracji. Wypróbować jej działanie. Deklaracja modułu System zawierającego procedurę break nie jest potrzebna.
W dowolnym, krótkim programie wypróbować działanie procedury halt.
Napisać program inicjujący dźwięk o określonym czasie trwania i częstotliwości a następnie dźwięk niknie. Zastosować iterację for..do.. do sterowania częstotliwością dźwięku.
15 Typ zbiorowy
Typ zbiorowy to zbiór potęgowy danego typu porządkowego, czyli zbiór wszystkich podzbiorów tego typu.
Definicja typu:
type nazwa_typu = set of typ_porządkowy;
Liczba elementów nie może przekraczać 256 - czyli typ bazowy może być tylko typem Byte, okrojonym całkowitym, znakowym (w tym okrojonym) wyliczeniowym i logicznym.
Przykłady definicji typu zbiorowego:
type
dni = set of (pon,wto,sro,czw,pia,sob,nie);
znaki = set of 'a'..'z';
miesiac = (sty,lut,mar,kwi,maj,cze,lip,się,wrz,paz,lis,gru);
zbior_miesiecy = set of miesiac;
var nazwa_miesiaca : miesiac;
zbior_nazw : zbior_miesiecy;
UWAGA: nazwa_miesiaca może przyjąć wartość tylko jednej z nazw;
zbior_nazw może przyjąć wartość dowolnego podzbioru z nazw bazowych.
Zmiennych typu zbiorowego nie wolno używać w instrukcjach czytania i wyprowadzania wyników, używa się ich jedynie w operacjach wykonawczych, testujących itp.
Operacje logiczne na zbiorach - relacje (porównania) teoriomnogościowe:
a = b równość zbiorów, te same elementy w obu zbiorach,
a <> b różność zbiorów, różne elementy w obu zbiorach (chociaż niektóre mogą się powtarzać)
a <= b zawieranie zbioru a w zbiorze b (prawda jeśli każdy element zbioru a jest w zbiorze b)
a >= b zawieranie zbioru b w zbiorze a (prawda jeśli każdy element zbioru b jest w zbiorze a)
c in a czy element c jest w zbiorze a.
Wartości stałych typu zbiorowego zapisujemy w nawiasach kwadratowych w postaci:
[lista wartości podzbioru]
[okrojenie ze zbioru]
jak na przykład w programie:
program p15_0;
type x=(a,b,c,d); {typ wyliczeniowy}
var z:set of x;
begin
z:=[a,b]; {lista - wybór podzbioru a, b}
z:=[a..c]; {okrojenie - wybór podzbioru a,b,c}
end.
Przykład:
program p15_1;
uses crt;
type miesiace = set of 1..12;
var v, x, y, z: miesiace;
lit :char;
begin
clrscr ;
y:=[1..8];
x:=[1..12];
z:=[1,3,5 ,7 ,8, 10, 12]; {miesiące posiadające 31 dni}
lit:='a' ;
if x<>y then writeln('tak') else writeln( 'nie' ); {tak}
if x<=y then writeln('tak') else writeln( 'nie' ); {nie}
if x>=y then writeln('tak') else writeln( 'nie' ); {tak}
if x=y then writeln('tak') else writeln( 'nie' ); {nie}
if 1 in x then writeln('tak') else writeln( 'nie' ); {tak}
if 9 in y then writeln('tak') else writeln( 'nie' ); {nie}
if lit in ['a'..'z'] then writeln('tak') else writeln( 'nie' ); {tak}
end.
Operacje zbiorowe:
+ suma zbiorów
- różnica zbiorów
∗ iloczyn zbiorów
Przykład:
program p15_2;
type zbiorowy = set of 1..6;
var x , y, v: zbiorowy;
begin
x :=[2,3,4] + [4,5,6] ; {wynik [2,3,4,5,6]}
y := [2,3,4] - [4,5,6] ; {wynik [2,3]}
v := [2,3,4] * [4,5,6] ; {wynik [4] (część wspólna)}
y := v * x ; { przeanalizować wynik}
end.
Ćwiczenie
Sporządzić kod programu p15_1 i wykonać go. Przeanalizować poszczególne instrukcje.
Sporządzić kod programu p15_2 i wykonać go. Przeanalizować poszczególne operacje zbiorowe.
Uzupełnić program o różnicę zbioru wszystkich miesięcy i zbioru miesięcy posiadających 31 dni. Wynik odejmowania przechować w nowej zmiennej p. Sprawdzić przy pomocy instrukcji:
if 2 in p then writeln('luty nie ma 31 dni');
zawieranie się lutego w zbiorze wynikowym.
Napisać program definiujący trzy zmienne typu zbiorowego bazujące na typie znakowym char. Dokonać przypisań dla dwóch z tych zmiennych wartości dowolnych podzbiorów. Wyniki działań (dodawania, odejmowania, mnożenia) obu zmiennych przechować w trzeciej. Sprawdzić przy pomocy menu Debug-Watch że wynik operacji mnożenia stanowi część wspólną obu podzbiorów.
DODATEK
Dodatek zawiera materiały i informacje dla samodzielnego poszerzenia wiedzy w zakresie programowania w języku TurboPascal.
D1 Typ proceduralny
Procedury i funkcje mogą być traktowane nie tylko jako części programu do wykonania lecz także jako elementy przypisane zmiennym i przekazywane do innych funkcji lub procedur jako parametry.
type nazwa = procedure ;
type nazwa = procedure (lista parametrów);
type nazwa = function :typ;
type nazwa = function (lista parametrów):typ;
Przykłady:
type proc : procedure;
proc1 = procedure (x : Real; k : Integer ; var y : Real);
fun = function (x : Real) : Real;
obl = procedure (x : Real; f : fun ; var y : Real) ;
var p : proc;
f : fun;
Przykład programu:
program typ_proceduralny;
uses crt;
type f=function(x:real):real;
var fun:f;
{definicje funkcji}
function sinus(x:real):real;
begin
sinus:=sin(x*pi/180)
end;
{----------------------------}
function cosinus(x:real):real;
begin
cosinus:=cos(x*pi/180)
end;
{----------------------------}
procedure wartosc(x:real;wej:f);
begin
writeln(wej(x):0:10);
end;
{----------------------------}
begin {program główny}
clrscr;
wartosc(0,sinus);
fun := cosinus;
wartosc(0,fun)
end.
UWAGA: nie wolno używać funkcji modułu System (standardowych).
D2 Zmienne wskaźnikowe
Do tej pory używaliśmy zmiennych statycznych. Zmienna statyczna, zadeklarowana deklaracją var jest tworzona w chwili uruchomienia programu. Jej rozmiar definiujemy w trakcie pisania programu - tak więc w przypadku tablic pisząc program musimy przyjąć jakąś maksymalną liczbę elementów tablicy. Dodatkowym ograniczeniem w języku TurboPascal jest to, że zmienne zadeklarowane w jednym module nie mogą mięć więcej niż 64kB. Ominąć ten problem pozwalają tzw. zmienne dynamiczne nazywane popularnie wskaźnikami.
Zmienna statyczna z punktu widzenia procesora jest fragmentem pamięci o rozmiarze pozwalającym pomieścić dane określonego typu. W trakcie wykonywania programu procesor nic nie wie o nazwach zmiennych - posługuje się jedynie adresem, który mówi gdzie zmienna znajduje się w pamięci. W trakcie kompilacji na podstawie zadeklarowanego typu zmiennej kompilator przyporządkowuje odwołaniom do zmiennych konkretne procedury działające na zmiennych zadeklarowanego typu. Następnie przydzielane są zmiennym adresy, tak, aby nie nakładały się na siebie.
Zmienna wskaźnikowa pozwala w trakcie programu przydzielać pamięć zmiennym specjalnymi procedurami i zwalniać tę pamięć, co stanowi o szczególnej przydatności zmiennych tego typu.
Zmienna wskaźnikowa jest więc adresem wskazującym na miejsce w pamięci, gdzie ma być przechowywana wartość zmiennej. Koncepcja wskaźników w Pascalu pozwala nam nie martwić się o długość zmiennej wskazywanej przez zmienną wskaźnikową.
D2.1 Deklaracja zmiennej wskaźnikowej
Zmienną wskaźnikową (czyli adres do zmiennej jakiegoś konkretnego typu) deklaruje się jako zmienną statyczną. Zmienna wskaźnikowa zajmuje w pamięci 4 bajty.
Zmienna wskaźnikowa „wskazuje” na typ bazowy lub typ wskaźnikowy wskazuje na typ bazzowy. Wskazanie określone jest w deklaracji przez użycie znaku ^ przed nazwą typu bazowego.
var
nazwa_zmiennej_wskaznikowej : ^typ_zmiennej;
lub
type
nazwa_typu = ^typ_zmiennej;
var
nazwa_zmiennej_wskaznikowej :nazwa_typu;
"nazwa_zmiennej_wskaznikowej" oraz "nazwa_typu" są dowolnymi akceptowanymi przez Pascal nazwami identyfikatorów.
"typ_zmiennej" określa typ zmiennej wskazywanej przez zadeklarowany wskaźnik. Na tej podstawie kompilator rozpoznaje jaką wielkość pamięci zajmuje zmienna wskazywana przez wskaźnik i jakich procedur użyć do wykonywania operacji na niej. Typ ten musi być określony jednym identyfikatorem.
Zmienna wskaźnikowa dopuszcza jeden wyjątek w podstawowej regule składni języka Pascal, że można używać tylko identyfikatorów wcześniej zadeklarowanych. Deklaracja zmiennej (lub typu) wskaźnikowej może odwoływać się do typu, który zostanie zadeklarowany po deklaracji zmiennej (lub typu) wskaźnikowej.
Przykład:
type
pOsoba =^TOsoba;
TOsoba =record
imie,nazwisko :string;
nastepny :pOsoba;
end;
var
pzmienna:pOsoba;
Zwykle przy deklaracji typów wskaźnikowych (podobnie jak i zmiennych) nazwę identyfikatora typu lub zmiennej zaczyna się od małej litery "p" (od "point" - wskazywać).
D2.2 Odwołanie do zmiennej wskaźnikowej
W naszym programie, aby nadać lub sprawdzić wartość, na którą wskazuje zmienna wskaźnikowa (inaczej mówiąc wartość zmiennej umieszczonej w pamięci pod adresem zawartym w zmiennej wskaźnikowej) musimy do nazwy zmiennej dodać znak "^":
var
px:^integer;
z :integer;
begin
{...}
z := 2;
writeln(z);
px^ := z+2; {nadanie wartości zmiennej wskaźnikowej}
writeln(px^);
px^ := px^*3; {zmiana wartości zmiennej wskaźnikowej}
writeln(px^);
z := 2*px^; {użycie wartości zmiennej wskaźnikowej}
writeln(z);
{...}
end.
^typ - nazwa typu wskazywanego przez zmienną wskaźnikową
x - zawiera adres w pamięci pod którym przechowywana jest wartość zmiennej
x^ - zawiera wartość zmiennej
D2.3 Operacje na wskaźnikach
Na zmiennych wskaźnikowych można wykonać niewiele operacji. Zmienne wskaźnikowe jak i zmienne przez nie wskazywane można przypisywać - należy wtedy pamiętać aby typy były zgodne. Istnieje możliwość wyłączenia kontroli typów zmiennych wskazywanych przez wskaźniki - pozwala to na różne interpretacje wartości zmiennej. W podanym poniżej przykładzie zastosowano operator "@" - zmienna poprzedzona tym operatorem zwraca adres (czyli wskaźnik) do danej zmiennej. W przykładzie do zmiennej p (wskaźnika do tablicy 6-cio bajtowej) wstawiamy adres do zmiennej x typu REAL (też 6-cio bajtowej). Umożliwia nam to dostęp do poszczególnych bajtów zmiennej x:
Przykład:
type
TByteArray=array[1..6] of byte;
var
x : real;
p : ^TByteArray;
i : integer;
begin
x := 2.5;
p := @x; {przypisanie wskazania na 6-bajtową zmienną typu real do wskazania na równiwż 6-bajtową tablicę)
writeln('Liczba typu real o wartosci:',x:0,' składa się z następujacych bajtów:');
for i := 1 to 6 do
writeln('Bajt ',i,' = ',p^[i]); {wydruk poszczególnych bajtów liczby 2.5}
end.
Oprócz przypisania wskaźniki można porównywać. Aby stwierdzić czy zmiennej wskaźnikowej nadano wartość wprowadzono definicję specjalnego adresu, który oznacza umowny "brak adresu" - nil. Tak więc, aby sprawdzić czy zmienna wskaźnikowa wskazuje na jakąś zmienną można użyć konstrukcji:
if zmienna < > nil then ...
D2.4 Tworzenie i likwidowanie zmiennych dynamicznych
Najważniejszą rzeczą przy zmiennych dynamicznych jest ich tworzenie (inaczej alokacja) w pamięci, a następnie ich likwidowanie. Do utworzenia zmiennej (czyli rezerwacji miejsca w pamięci na zmienną wskazywana przez zmienną wskaźnikową) służy procedura new:
procedure new(var x:pointer);
Procedura NEW rezerwuje w pamięci RAM obszar pamięci, który pozwala przechować zmienną typu wskazywanego przez zmienną wskaźnikową x. Adres początku tego obszaru pamięci wpisywany jest do zmiennej x.
Operację odwrotną wykonuje procedura dispose:
procedure dispose(var x:pointer);
Należy pamiętać, że likwidowanie zmiennej procedurą DISPOSE nie nadaje zmiennej wskaźnikowej wartości nil. Operację tę należy przeprowadzić samodzielnie.
D2.5 Lista
Jedną ze struktur danych oferowanych przez zmienne dynamiczne jest lista. Lista składa się z rekordów, w których co najmniej jedno z pól wskazuje na kolejny rekord tego samego typu. Powstaje w ten sposób ciąg kolejno powiązanych ze sobą rekordów.
Istnieją różne rodzaje list - jednokierunkowa, dwukierunkowa, drzewo itp.
W listach należy pamiętać o właściwym dołączeniu kolejnego elementu do łańcuszka elementów aby nie "zgubić" jego adresu.
Przykład
program wskazniki;
uses crt;
const n=3;
type
Wsk = ^ Osoba;
Osoba = record
Kod: 1..100;
Nazw: string[15];
Nast: Wsk;
end;
var osob_1,osob,pom1,pom2:wsk;
k:integer;
p:text;
{-----------------------------------------------)
procedure czytaj(var osob:wsk;N:integer);
var pom1,pom2:wsk;
begin
osob := nil; {puste wskazanie}
writeln ('podaj nr i nazwisko ',n, ' osob');
for k:=1 to n do
begin
new(pom1);
readln (pom1^.kod);
readln (pom1^.nazw);
pom1^.nast. := nil;
if osob = nil then
osob:=pom1
else
begin
pom2 := osob; { Przepisanie wskazania do pomocniczej zmiennej}
{Przewijanie listy do końca NIL }
while pom2^.nast <> nil do
pom2 := pom2^.nast;
pom2^.nast:=pom1
end;
end;
end;
{-----------------------------------------------)
procedure dopisz(var osob:wsk);
var pom1,pom2,pom3:wsk;
begin
writeln('podaj nr nazwisko jednej osoby');
new(pom1);
readln(pom1^.kod);
readln(pom1^.nazw);
pom1^.nast:=nil;
pom2:=osob;
if pom1^.nazw <= pom2^.nazw then
osob:=pom1 {jeśli na początku listy}
else
begin {szukanie miejsca w szeregu}
while pom1^.nazw > pom2^.nazw do
begin
pom3:=pom2; {zapamiętanie miejsca}
pom2:=pom2^.nast; {miejsce następne}
end;
pom3^.nast:=pom1; {wskazanie na wczytane dane}
end;
pom1^.nast:=pom2; {wskazanie następnych danych}
end;
{-----------------------------------------------)
procedure pisz(var osob:wsk);
begin
clrscr;
writeln('zawartosc listy');
osob_1 := osob; {przepisanie wskazania do pomocniczej zmiennej}
while osob_1<> nil do
begin
writeln(osob_1^.kod:4,' ':4,osob_1^.nazw);
osob_1:=osob_1^.nast {przesuwanie wskazań}
end;
repeat until keypressed
end;
{-----------------------------------------------)
begin {program główny}
clrscr;
czytaj(osob,N);
pisz(osob);
dopisz(osob);
pisz(osob);
repeat until keypressed;
end.Poniżej przedstawiono schemat logiczny tworzenia listy jednokierunkowej:
Wstawianie nowego elementu do listy (z sortowaniem):
Lista dwukierunkowa, w której dwa pola wskaźnikowe każdej zmiennej zawierają wskazanie na element następny i poprzedni.
Na podobnej zasadzie działa struktura drzewa, w którym zmienna wskaźnikowa oprócz pól statycznych zawiera wiele pól zawierających bądź wskazanie puste (NIL) bądź na inne zmienne wskaźnikowe tego samego typu.
D3 Zadania
Podaj postać poniższego wyrażenia w składni języka Pascal:
B. Podaj postać poniższego wyrażenia w składni języka Pascal:
E. Podaj postać poniższego wyrażenia w składni języka Pascal:
Opracuj kod programu w którym tablica 5x5 wypełniana jest w pętli kolumnami, a jej elementy są wartościami średnimi obydwu indeksów. Tablica wyprowadzana jest na ekran.
0,5 |
1,5 |
2 |
.. |
|
1,5 |
2 |
2,5 |
.. |
|
2 |
2,5 |
3 |
.. |
|
.. |
.. |
.. |
.. |
|
|
|
|
|
|
Opracuj kod programu w którym tablica 5x5 wypełniana jest w pętli kolumnami, a jej elementy są sumami obydwu indeksów. Tablica wyprowadzana jest na ekran.
2 |
3 |
4 |
.. |
|
3 |
4 |
5 |
.. |
|
4 |
5 |
6 |
.. |
|
.. |
.. |
.. |
.. |
|
|
|
|
|
|
Opracuj kod programu w którym tablica 5x5 wypełniana jest w pętli kolumnami, a jej elementy są różnicami indeksu wiersza i kolumny. Tablica wyprowadzana jest na ekran.
0 |
-1 |
-2 |
.. |
|
1 |
0 |
-1 |
.. |
|
2 |
1 |
0 |
.. |
|
.. |
.. |
.. |
.. |
|
|
|
|
|
|
Opracuj kod programu, w którym podawane są dwie liczby, a następnie wyświetlana jest reszta z dzielenia pierwszej z nich przez drugą.
Opracuj kod programu, w którym wektor o rozmiarze 100 wypełniany jest kwadratami kolejnych liczb parzystych aż do przekroczenia wartości 20000. Tablica wyprowadzana jest na ekran.
Opracuj kod programu, w którym tablica 20x20 wypełniana jest w pętli zerami oprócz przekątnej głównej, która jest wypełniona jedynkami. Tablica wyprowadzana jest na ekran.
Opracuj kod programu, w którym tabelaryzowana jest funkcja y= ln x + x2 w przedziale od 1 do 2 z krokiem 0.1.
Opracuj kod programu, w którym wektor o rozmiarze 30 wypełniany jest kolejnymi liczbami naturalnymi, Lecz jeśli liczba jest podzielna przez 3 to wstawiane jest 0. Tablica wyprowadzana jest na ekran.
Opracuj kod programu, w którym podajemy dwie liczby, następnie na ekranie drukowany jest ich iloczyn i iloraz. Operacja powtarza się w pętli aż do podania wartości zero dla pierwszej z liczb zadawanych.
Opracuj kod programu w którym tablica 50x50 wypełniana jest w pętli znakiem '+' lecz tylko tyle wierszy i kolumn ile zadamy z klawiatury przed wypełnianiem. Wypełniony fragment tablicy wyprowadzany jest na ekran.
Opracuj kod programu w którym cała tablica 50x50 wypełniana jest znakiem '+' a następnie zadana z klawiatury kolumna wypełniana jest znakiem '-'.Tablica wyprowadzana jest na ekran.
Opracuj kod programu w którym tablica 3x20 wypełniana jest w pętli w pierwszej kolumnie kolejnymi liczbami naturalnymi zaś w dwóch pozostałych kolumnach kwadratami sześcianami tych liczb. Tablica wyprowadzana jest na ekran.
Opracuj kod programu w którym tablica 3-elementowa wypełniana jest w pętli rekordami o organizacji Student(nazwisko, ocena). Tablica wyprowadzana jest na ekran.
Opracuj kod programu w którym tablica 10x10 wypełniana jest w pętli dowolnymi liczbami np. kolejnymi całkowitymi parzystymi kolumnowo. Wyprowadź utworzoną tablicę oraz jej tablicę transponowaną (zamienione wiersze z kolumnami) na ekran.
Opracuj kod programu w którym tablica 10x10 wypełniana jest w pętli zerami, zaś jej przekątna główna jedynkami. Tablica wyprowadzana jest na ekran.
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
Opracuj kod programu w którym tablica 10x10 wypełniana jest w pętli zerami, jej przekątna główna jedynkami zaś przeciwprzekątna dwójkami. Tablica wyprowadzana jest na ekran.
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
2 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
2 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
2 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
2 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
2 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
2 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
2 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
2 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
2 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
2 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
Opracuj kod programu z tablicą 11x2 jako tabelą funkcji dla x [0 do 1] z krokiem 0.1 w pierwszej kolumnie oraz wartościami funkcji y=ex w drugiej kolumnie. Tablica jest wyprowadzana na ekran.
Opracuj kod programu w którym tablica o rozmiarze 10x10 zostanie wypełniona zerami oprócz elementów dla których obydwa indeksy są parzyste - te element będą jedynkami. Tablica jest wyprowadzana na ekran.
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
Opracuj kod programu w którym tablica 10x10 wypełniana jest jedynkami dla elementów, których suma podzielna jest przez 3, w przeciwnym razie element jest zerem. Tablica wyprowadzana jest na ekran.
Opracuj kod programu w którym tablica 10x10 wypełniana jest zerami oprócz przeciwprzekątnej wypełnionej jedynkami. Tablica wyprowadzana jest na ekran.
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
Opracuj kod programu w którym tablica 10x10 wypełniona jest zerami oprócz centralnego kwadratu tej macierzy o rozmiarze 4x4, który zawierał będzie jedynki. Tablica wyprowadzana jest na ekran.
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
Zbadaj funkcję sin(x) dl3a x od zera do 2 radianów z krokiem 0.1 radiana. W jednowymiarowej, 21-elementowej tablicy umieść znak '+' dla dodatniej, a znak '-' dla ujemnej wartości tej funkcji. Tablica wyprowadzana jest na ekran.
Opracuj kod programu, w którym wektor o rozmiarze 20 wypełniany jest w pętli kolejnymi liczbami naturalnymi lecz jeśli liczba jest podzielna przez 0 to wstawiane jest zero. Wyprowadź tablicę na ekran.
1 |
2 |
0 |
4 |
5 |
0 |
7 |
.. |
|
Opracuj kod programu w którym w pętli wprowadzane są dowolne liczby. Po wprowadzeniu każdej liczby ukazuje się komunikat czy liczba jest dodatnia czy ujemna. Pętla i program kończy się gdy wprowadzana liczba jest równa zeru.
Opracuj kod programu w którym w pętli wprowadzane są dowolne liczby. Po wprowadzeniu każdej liczby ukazuje się komunikat która z nich jest większa. Pętla i program kończy się gdy wprowadzana liczba jest równa zeru.
Opracuj kod programu, w którym zdefiniowana jest zmienna rekordowa o postaci (Pracownik, pensja, liczba lat pracy). Program umieszcza wczytywane dane w małej tablicy (np. 3-elementowej), a następnie wyświetla sumę pensji wszystkich pracowników.
Opracuj kod programu, w którym w tablicy o rozmiarze 10x10 pierwsza kolumna wypełniona jest samymi jedynkami zaś reszta zerami. Program drukuje tablicę na ekranie.
Opracuj kod programu, w którym zdefiniowana jest zmienna rekordowa o postaci (Marka samochodu, przebieg). Program umieszcza wczytywane dane w małej tablicy (np. 5-elementowej), a następnie wyświetla średni przebieg wszystkich aut.
Opracuj kod programu, w którym zadawane są trzy liczby, a następnie drukowane są w porządku rosnącym i malejącym.
Opracuj kod programu, w którym zadawanych jest 10 liczb umieszczanych w wektorze. Następnie obliczana i wyświetlana jest średnia tych liczb.
Opracuj kod programu, w którym w tablicy 5x5 umieszczone są znaki. Wypełnić tablicę znakiem gwiazdki '*' dla elementów, których suma indeksów jest parzysta, pozostałe wypełnić znakiem spacji. Wyświetlić tablicę na ekranie.
Napisać blok definicji funkcji o Napisać blok definicji funkcji o działaniu:
dla x < 0 : f(x)=0
dla x >= 0 : f(x)=1
Napisać blok definicji funkcji dwóch liczb rzeczywistych, której celem jest znalezienie i wyprowadzenie mniejszej z nich.
Napisać blok definicji funkcji logicznej , której argumentem jest liczba całkowita, a celem wyprowadzenie wartości prawda gdy liczba ta jest nieujemna i wartości fałsz w przeciwnym przypadku.
Napisać blok definicji funkcji, której argumentami są dwie liczby całkowite, funkcja wyprowadza wartość 1 gdy iloczyn tych liczb jest nieujemny zaś 0 gdy jest ujemny (sprawdzenie przeciwnych znaków liczb).
Napisać blok definicji funkcji, której argumentem jest zmienna rekordowa o strukturze (nazwisko, imie); funkcja wyprowadza liczbę znaków w nazwisku (długość łańcucha).
Opracuj kod programu, w którym dla dwóch rekordów o organizacji Czas(minuty, sekundy) zdefiniowana funkcja oblicza różnicę czasu i wyświetla wynik na ekran.
Opracuj kod programu, w którym 3-elementowa tablica rekordów o organizacji Auto(marka, rocznik) zapisywana jest do dyskowego pliku elementowego.
Opracuj kod programu, w którym podawane z klawiatury rekordy o organizacji Auto(marka, rocznik, Silnik(pojemność, moc)), gdzie Silnik jest polem typu rekordowego, zapisywane są do dyskowego pliku elementowego. Ograniczeniem wprowadzania danych jest podanie pustego łańcucha w polu marka.
Napisać program, w którym podawane z klawiatury liczby rzeczywiste aż do podania liczby 0 umieszczane są w tablicy. Następnie zdefiniowana procedura oblicza średnią arytmetyczną elementów tablicy. Program główny wykorzystuje tę procedurę i drukuje wartość średniej.
Opracuj kod programu, w którym wykorzystywana jest procedura służąca do dzielenia dwóch liczb zespolonych o organizacji rekordowej Zesp(re , im).
Utworzyć na dysku sieciowym przy pomocy dowolnego edytora ASCII plik tekstowy zawierający 3 do 4 wierszy tekstu. Napisać program wykorzystujący procedurę odczytu utworzonego pliku i umieszczającego wiersze tekstu w tablicy, a następnie drukującego wiersze tekstu w porządku odwrotnym.
Utworzyć na dysku sieciowym przy pomocy dowolnego edytora ASCII plik tekstowy zawierający dane kilku osób o organizacji Student(nazwisko, ocena1, ocena2, ocena3). Napisać program wykorzystujący procedurę odczytu utworzonego pliku, obliczającą i drukującą średnią ocen każdego studenta i średnią grupy.
Zdefiniować procedurę wyprowadzającą na ekran kolejnymi wartościami wyrażenia y = |2x − 5|. Parametrami wywołania są: wartości krańcowe przedziału p1 i p2 oraz krok dp. Wykorzystać procedurę w programie.
Zdefiniować procedurę obliczającą pole prostokąta. Do procedury przekazywać przez wartość wymiary boków, a przez zmienną wyprowadzać pole powierzchni i drukować na ekranie. Zadawanie danych, wykorzystanie procedury i wydruk wyniku umieścić w pętli kończącej się w przypadku podania wartości ujemnej jako wymiaru pierwszego boku.
Napisać program wczytujący dwie daty o typie rekordowym o organizacji Data (dzień, miesiąc, rok), a następnie przekazać te daty do własnej procedury drukującej na ekranie obie daty w kolejności czasowej.
Utworzyć na dysku przy pomocy dowolnego edytora ASCII plik tekstowy zawierający 20 dowolnych liczb, każda w nowym wierszu.. Napisać program wykorzystujący procedurę odczytu utworzonego pliku, obliczającą i drukującą maksymalną z liczb w pliku.
Napisać program drukujący sumę N liczb naturalnych wykorzystując funkcję sumowania rekurencyjnego n+ (n-1) .... aż do 1.
Utworzyć na dysku przy pomocy dowolnego edytora ASCII plik tekstowy zawierający dane kilku osób o organizacji Student(nazwisko, ocena). Napisać program wykorzystujący procedurę odczytu utworzonego pliku, drukującą jedynie studentów z oceną nie mniejszą niż 4.0.
Utworzyć na dysku przy pomocy dowolnego edytora ASCII plik tekstowy zawierający 10 par dowolnych liczb całkowitych, każda para w nowym wierszu.. Napisać program wykorzystujący procedurę odczytu liczb pliku, umieszczającą je w tablicy [10,2] i drukującą sumy par i sumy kolumn.
Napisać program tworzący na dysku sieciowym F elementowy plik trzech wektorów o rozmiarze 5 zawierających dowolne, wczytywane z klawiatury liczby naturalne. Następnie otworzyć plik do odczytu i wydrukować na ekranie drugą z trzech tablic.
Zdefiniować procedurę drukującą tabelę wartości wyrażenia y = x2 + x −5 z przekazywanymi do procedury przez wartość końcami przedziału i krokiem wydruku. Wykorzystać procedurę w programie głównym w dwóch wywołaniach.
Zdefiniować procedurę obliczającą objętość prostopadłościanu. Do procedury przekazywać przez wartość wymiary boków, a przez zmienną wyprowadzać objętość i drukować na ekranie. Zadawanie danych, wykorzystanie procedury i wydruk wyniku umieścić w pętli kończącej się w przypadku podania wartości ujemnej jako wymiaru pierwszego boku.
D4 Przykład testu egzaminacyjnego z rozwiązaniami
[4 p] Podać "pascalową" postać następującego wyrażenia:
Przykładowe rozwiązanie: (sin(x)*sin(x)+2.5)/(sqrt(ln(x)/ln(10)+2) -1)
albo: (sqr(sin(x))+2.5)/(sqrt(ln(x)/ln(10)+2) -1)
[4 p] Dla tablicy zadeklarowanej jako:
var w : array [ 0..5 ] of char ; k: 0..5;
wypisz jakie wartości przyjmują elementy tablicy po wykonaniu instrukcji:
for k := 0 to 5 do w [k] := chr(ord( 'k' ) + k);
Rozwiązanie:
k |
l |
m |
n |
o |
p |
[10 p] Przy założeniu następujących deklaracji:
type wek = array [ 1 .. 10, 1 .. 10 ] of real ;
rek = record
nazwisko : string [15] ;
wiek : 0 .. 120 ;
end;
var i : integer ;
liczba : real ;
zn : char ;
czy : boolean ;
osoba : rek ;
tab : wek ;
zestaw : set of 1 .. 20 ;
x : file of rek;
procedure pisz (y:rek);
begin
writeln(y.nazwisko);
writeln(y.wiek)
end;
opisz błędy w następujących instrukcjach lub zaproponuj zbliżoną, poprawną ich postać:
a) wek [ 1, 1 ] := 5 ;
wek jest identyfikatorem typu a nie zmiennej
b) assign (x , c:\dane.bin) ;
brak apostrofów 'c:\dane.bin'
c) writeln ( ' Wiek =' , wiek ) ;
powinno być writeln ( ' Wiek =' , osoba.wiek);
d) for i := 1 to 10 do tab[ 1, i ] = i ;
brak dwukropka (instrukcja przypisania)
e) zestaw := 1;
zestaw jest typu zbiorowego, przypisanie zestaw:=[1]
f) writeln (x, osoba.nazwisko, osoba.wiek) ;
do pliku zapisujemy rekord w całości - writeln (x, osoba) ;
g) osoba.nazwisko := Kowalski;
brak apostrofów w stałej łańcuchowej 'Kowalski'
h) if osoba.wiek > 100 then pisz ;
brak parametru if osoba.wiek > 100 then pisz(osoba) ;
i) czy := nazwisko>'K' ;
powinno być np. czy := osoba.nazwisko>'K' ;
j) read (zn:1) ;
czytanie nie może być formatowane
[5 p] Zbadać jak zmieniają się wartości zmiennych a, b, c w trakcie wykonywania poniższego programu, wypełnić tabelkę dla każdej zmiany i określić ostateczne wartości wydrukowane na ekranie:
program p11;
var a,b,c:integer;
begin
a:=1;
b:=1;
while not (a>=20) do begin
for c:=2 downto 1 do b:=b+c;
a:=2*b;
end;
end.
krok |
a |
b |
c |
|
krok |
a |
b |
c |
1 |
1 |
1 |
2 |
|
9 |
|
7 |
|
2 |
|
3 |
|
|
10 |
14 |
|
|
3 |
|
|
1 |
|
11 |
|
|
2 |
4 |
|
4 |
|
|
12 |
|
9 |
|
5 |
8 |
|
|
|
13 |
|
|
1 |
6 |
|
|
2 |
|
14 |
|
10 |
|
7 |
|
6 |
|
|
15 |
20 |
|
|
8 |
|
|
1 |
|
16 |
|
|
|
[7 p] Napisać tekst programu którego zadaniem będzie znalezienie najwcześniejszego w alfabecie napisu w 5-elementowym wektorze z dowolnymi łańcuchami tekstowymi.
program egzamin;
uses crt;
var w : array [1..3] of string;
pierwszy: string;
begin
clrscr;
readln(w[ 1] );
readln(w[ 2] );
readln(w[ 3] );
pierwszy :=w[ 1];
for k:=2 to 5 do
if w[k]<pierwszy then pierwszy := w[k];
writeln(pierwszy);
repeat until keypressed
end.
68 10. Podprogramy - funkcje
10. Podprogramy - funkcje 67
72 11. Podprogramy - procedury
11. Podprogramy - procedury 71
80 12. Pliki
12. Pliki 79
82 13. Algorytmy rekurencyjne
13. Algorytmy rekurencyjne 81
86 14. Moduły
14. Moduły 87
90 15. Typ zbiorowy
15. Typ zbiorowy 89
112 DODATEK
DODATEK 111
Output:
0.0000000000
1.0000000000
Typ wskaźnikowy
WYJĄTEK:
Użycie typu, który jest definiowany później
Zmienne tego typu wskazują na adres w pamięci
Pom1^.kod to zawartość pola rekordu wskazywanego przez zmienną pom1
Dopisanie na końcu
procedure D
deklaracje D
begin
end
procedure C
deklaracje C
begin
end
procedure B
deklaracje B
begin
end
program A
deklaracje A
begin
end.