Konspekt wykładu „Podstawy programowania”
sem.3 i 4, WSAiZ, kier. Informatyka
opr. Tomasz Bajorek
Wstęp:
Do 1954 roku - język maszynowy (Eniac, Mark I- USA)
Kodowanie instrukcji procesora w postaci ciągu liczb dwójkowych (elementarny rozkaz i dane)
pracochłonność (same liczby, długie algorytmy działań takich jak dodawanie i mnożenie
trudność śledzenia błędów
lata 50-te - zastąpienie kodów operacji nazwami mnemotechnicznymi
np. mnożenie MPY (multiply)
język symboliczny - assembler
ASSEMBLER - także program tłumaczący na kod maszynowy (wewnętrzny) DISSASSEMBLER - tłumaczenie odwrotne, stosowany do dziś - np. oprogramowanie interfejsów pomiarowych, wprowadzanie danych z pomiarów i ich obróbka komputerowa
CECHY:
zmniejszona ale nadal duża pracochłonność
błędy - prawie każda kombinacja znaków mogła być wykonana
ukierunkowanie na konkretny komputer (procesor) dla którego program był pisany
wąski zbiór rozkazów, prymitywna architektura ówczesnych komputerów, brak rejestrów, brak operacji zmiennoprzecinkowych
Etap przejściowy - tzw. systemy automatycznego programowania - „sztuczki” programistyczne pozwalające na prostsze wykonywanie operacji zmiennopozycyjnych, obliczanie funkcji itp., prostsze programowanie lecz spowolnienie ok. 5-krotne programów, zarzucone z uwagi na sprzętowe rozwiązanie problemów operacji zmiennoprzecinkowych
Języki wysokiego poziomu
1954 - FORTRAN - języki tzw. wysokiego poziomu Fortran (Formula Translator)
(kod maszynowy i assembler to niski poziom - bliższy procesorowi)
Zapis operacji w sposób łatwiejszy, zrozumiały i dobrze kontrolowany przez programistę
Po stworzeniu kodu programu w języku następuje proces translacji (tłumaczenia, kompilacji) na język wewnętrzny komputera.
Problemy:
zrozumiałość
jednoznaczność
skuteczność tłumaczenia
Języki wysokiego poziomu po etapie początkowym stały się maszynowo niezależne z powodu wielu wersji translatorów (programów kompilujących) REWOLUCJA - wiele wersji FORTRANU (standard Fortran4, F77 Laheya)
W kolejnych latach - obfitość języków programowania Inne języki wysokiego poziomu
COBOL - dla przedsiębiorstw, język prawie naturalny (ang) MULTIPLY - mnożenie, ADD - dodawanie
Do dziś specjaliści potrzebni (w USA 500 $/godz za zmiany daty w 2000)
BASIC, LOGO - prostota, interpretacja w odróżnieniu od kompilacji, tłumaczenie „na bieżąco” każdej instrukcji a nie programu w całości
PASCAL, C, C+, C++ - języki strukturalne z elementami tzw. programowania obiektowego
OOP (Object Oriented Programming) - języki zorientowane obiektowo (PROLOG, Visual Basic, Turbo Vision dla Pascala, Delphi -Object Pascal, Java)
Klasyfikacja języków programowania:
do przetwarzania danych: COBOL, dBase
do obliczeń naukowych : Fortran, Pascal, MATLAB
do programowania systemowego - tworzenie sytemów operacyjnych: C, BCPL, BLISS
opisu zleceń - DOS, MVS
konwersacyjne: LISP, zmiany z terminala w trakcie konwersacji
symulacyjne - symulacja procesów (najczęściej w czasie rzeczywistym): mechanika, elektronika, termodynamika itp. - SIMULA, CSSL
algorytmiczne (większość): programowanie to zapis sposobu wykonania
niealgorytmiczne: nie jak ale co ma być zrobione - sterowanie nie algorytmem lecz danymi - problematyka sztucznej inteligencji
obiektowe - pewien zbiór danych (obiekty) są aktywne i mają swoje cechy (własności); poprzez zdarzenia (zwykle wymuszone przez użytkownika ale nie tylko) mogą te własności zmieniać lub wywoływać akcje obliczeniowe
specjalizowane - ukierunkowane na pewną klasę problemów, np. obróbkę baz danych, analizę układów elektronicznych itp.
CO TO JEST JĘZYK PROGRAMOWANIA ?
DANE - reprezentują świat rzeczywisty lub abstrakcyjny i opis jego obiektów
OBIEKTY mają przypisany zbiór operacji - działań na tych obiektach
Alfabet języka - skończony zbiór znaków.
Słowo - skończony ciąg znaków alfabetu
Język formalny- zbiór słów nad określonym alfabetem
Język programowania - zbiór konwencji i umów umożliwiających komunikatywność (zrozumiałość) umów (dla kompilatora).
Określa się przy tym:
syntaktykę (składnię) języka - zbiór reguł opisujących poprawne konstrukcje językowe
semantykę - zasady interpretacji tych konstrukcji
np.
Przykład:
CZERWONY JECHAŁEM BYŁEŚ. - zła składnia
KULISTA ŚCIANA PŁUCZE AUTOBUS. - poprawna składnia ale niepoprawna semantycznie (znaczeniowo)
Błędy składniowe - np. zapomnieć słowa kluczowego instrukcji lub je przekręcić
Błędy semantyczne - zły typ danych, licznik pętli nie jest typu całkowitego, j=0; k=1/j (dzielenie przez zero)
Jeżeli ponadto:
- syntaktyka pozwala na analizę poprawności konstrukcji językowych
- opis języka obejmuje pragmatykę (zalecenia do używania poprawnych struktur)
to język formalny może być językiem programowania.
Definicja algorytmu
ALGORYTM - skończony zbiór ściśle określonych zasad rozwiązywania pewnej klasy zadań
ALGORYTM - (przepis) - specyfikacja ciągu operacji, które w wyniku działania na wejściowy zbiór obiektów dają zbiór wynikowy
Opis algorytmu składa się z:
- opisu obiektów podlegających przetwarzaniu
- opisu czynności wykonywanych na tych obiektach
OBIEKTY - dane
dana = (nazwa danej, wartość danej)
deklaracje, definicje - opisy obiektów
instrukcje - czynności na obiektach
program - algorytm zapisany w języku programowania
podprogram - wyodrębniona część programu (ze względu na czytelność lub wielokrotne użycie) posiadająca wyodrębnioną nazwę i sposób wymiany informacji z pozostałymi jego częściami
deklaracja podprogramu - opis podprogramu
instrukcja wywołania podprogramu - wykonanie, zastosowanie podprogramu wewnątrz programu głównego lub innego podprogramu
kod źródłowy - tekst programu w języku programowania (plik tekstowy pas)
kompilacja - tłumaczenie kodu źródłowego na wykonywaną postać binarną, ładowalną (plik exe) - odrębny proces
interpretacja - tłumaczenie kolejnych instrukcji w trakcie procesu wykonywania
Przetwarzanie programu użytkowego
W przypadku przetwarzania programu, wymagającego wykorzystania programów bibliotecznych, uzyskany po procesie kompilacji kod wynikowy należy poddać procesowi łączenia, konsolidacji (linkowanie) z kodami dołączanymi a następnie wykonać kod ładowalny.
Sposoby pisania programu:
- program źródłowy utworzony dowolnym edytorem tekstu - kompilacja - konsolidacja (link - łączenie z podprogramami bibliotecznymi (modułami)
lub
korzystanie z ze zintegrowanych pakietów programistycznych (wewnętrzne narzędzia edycji, kompilacji i konsolidacji, weryfikacji błędów itp.)
Zatarcie granic między programowaniem a użytkowaniem- pakiet też jest programem i programując korzystamy z programu, podobnie EXCEL - programowanie arkusza to korzystane (wykonanie programu) a po części tworzenie pliku wynikowego metodami programistycznymi: (wyrażenia według konwencji EXCELA, makro w konwencji VBA itp.
Co świadczy o przydatności i skuteczności języka programowania
Dobra notacja, przejrzystość, prostota (łatwość przyswojenia zasad)
Jednoznaczność zapisu
Funkcjonalność
- zbyt szeroka to też niedobrze bo niebezpieczeństwo dwuznaczności zapisów (grube dukumentacje)
- stąd dołączanie modułów 9ułatwia kontrolę błędów i wyłączenie wielorakości syntaktyki)
Weryfikacyjność - test błędów, czasem te cechy w sprzeczności bo deklaracje explicite poszerzają strukturę programu ale ułatwiają kontrolę zmiennych, np. błąd literowy w nazwie obiektu bez deklaracji to nowa zmienna a za deklaracjami błąd braku deklaracji
Elastyczna opisywalność obiektów: np. data to liczby, operacje liczbowe dopuszczalne ale dzielenie jest bezsensowne
Czytelność struktury programu
Dostępność
Cena
Efektywność - skuteczność kompilacji, szybkość programu wynikowego
Dokumentacja
PASCAL (autor Nicklaus Wirth, lata 70-te)
Cechy:
Język wysokiego poziomu - stosowanie składni syntaktycznej języka bez znajomości struktury wewnętrznej komputera
Mechanizmy kontroli struktur i reguł gramatycznych - identyfikacja i poprawa błędów
Język algorytmiczny - zapis koncepcji i zadań opracowanych przez programistę
Język strukturalny - fragmenty algorytmu zapisywane w odrębnych strukturach językowych
Język modularny - składanie programu z modułów
Język publikacyjny
2. ŚRODOWISKO zintegrowanego pakietu programowania języka TURBO PASCAL (7.0)
2.1. URUCHAMIANIE
turbo [plik.pas] wersja trybu rzeczywistego DOS
tpx [plik.pas] wersja trybu chronionego DOS
Menu operacji |
ALT+wyróżniona litera nagłówka menu |
Wybór okna edycyjnego |
ALT+nr okna |
Okno OUTPUT⇔ edytor |
ALT+F5 |
Otwarcie pliku |
F3 |
Zapis pliku |
F2 |
Kompilacja |
ALT+ F9 (F9) |
Wykonanie |
CRTL+F9 |
Step over (krokowo) |
F8 |
Trace into |
F7 |
Watch |
śledzenie wartości wyszczególnionych zmiennych |
Breakpoints |
„pułapki” - miejsca chwilowego zatrzymania programu w celu |
Pomoc |
F1 |
2.2 BŁĘDY
Błędy procesu kompilacji
- zatrzymanie kompilacji i krótki opis błędu - ang.
Najczęstsze błędy:
Opis |
Opis angielski |
nieznany identyfikator |
unknown identifier |
zła składnia |
syntax error |
niezgodność typów |
type mismatch |
błąd w wyrażeniu |
error in expression |
nieoczekiwany koniec pliku |
unexpected end of file |
”;” oczekiwany |
”;” expected |
”)” oczekiwany |
”)” expected |
”do” oczekiwany |
”DO” expected |
itd.... |
|
Błędy wykonania polegają zazwyczaj na:
niewłaściwym użyciu poprawnych instrukcji
przekroczeniu zakresów zmiennych (wymagana kontrola)
braku możliwości wykonania operacji systemowych
niewłaściwej operacji matematycznej np. dzielenie przez 0, logarytm z liczby ujemnej itp.
Kombinacja CTRL+Break umożliwia przerwanie „zawieszonego” programu
Błędy kompilacji :syntaktyczne (składniowe)
Błędy wykonania :semantyczne
2.3 EDYTOR TP
Standardowo pliki pisane w języku TP mają rozszerzenie pas.
Operacje edytorskie mogą się odbywać:
- przez menu,
- przez klawisze nawigacyjne,
- CTRL+znak lub CTRL+znak1(Q lub K) a następnie znak2.
Operacja |
Klawisze |
przesunięcie kursora o znak lub wiersz |
strzałki nawigacyjne |
przewinięcie tekstu o stronę |
PgUp, PgDn |
skok kursora na początek, koniec wiersza |
Home, End |
skok na początek, koniec okna |
CTRL+Home, CTRL+End |
skok na początek, koniec tekstu |
CTRL+PgUp, CTRL+PgDn |
zmiana trybu: wstawianiezastępowanie |
Insert |
wstawienie pustego wiersza |
CTRL+N ENTER w trybie wstawiania |
usunięcie znaku |
Delete lub Backspace |
usunięcie słowa |
CTRL+T |
usunięcie wiersza |
CTRL+Y |
usunięcie reszty wiersza |
CTRL+Q,Y |
zaznaczenie początku bloku |
CTRL+K,B |
zaznaczenie końca bloku |
CTRL+K,K |
zaznaczenie słowa jako bloku |
CTRL+K,T |
ukrycie bloku |
CTRL+K,H |
kopiowanie bloku w miejsce kursora |
CTRL+K,C |
przesunięcie bloku w miejsce kursora |
CTRL+K,V |
usuwanie bloku |
CTRL+K,Y |
wcięcie (indent) bloku |
CTRL+K,I |
cofanie wcięcia bloku |
CTRL+K,U |
zapis bloku do pliku |
CTRL+K,W |
wczytanie bloku z pliku |
CTRL+K,R |
szukanie ciągu znaków(find) |
CRTL+Q,F |
szukanie i zastąpienie(replace) |
CTRL+Q,A |
kontynuacja szukania lub zastępowania |
CTRL+L |
2.4 SKŁADOWE JĘZYKA
2.4.1. Struktura blokowa programu i podprogramów
PROGRAM nazwa (parametry);
USES ... deklaracje modułów ;
LABEL ... deklaracje etykiet ;
CONST ... definicje stałych ;
TYPE ... definicje typów ;
VAR ... deklaracje zmiennych ;
definicje funkcji i podprogramów
BEGIN
pierwsza instrukcja ;
druga instrukcja ;
....
....
ostatnia instrukcja ;
END.
Instrukcje wykonywane są kolejno od pierwszej do ostatniej, pod warunkiem, że charakter instrukcji nie stanowi inaczej (np. „pętle”, skoki, przekazanie wykonania do podprogramu itp.)
Nagłówek programu (opcjonalny- czyli nieobowiąkowy):
- słowo kluczowe PROGRAM i identyfikator (nazwa) do 255 znaków
- parametry programu - komunikacja z otoczeniem, nazwy plików wejścia i wyjścia (pliki standardowe INPUT oraz OUTPUT)
Sekcja deklaracji:
- 5 typów, czasami istotna kolejność, np. wcześniej deklaracja typu a potem zmiennej tego typu
BEGIN - początek sekcji instrukcji (wykonywalnej)
END - koniec sekcji instrukcji
kropka kończy program
INSTRUKCJE - oddzielane średnikami.
2.4.2 ALFABET JĘZYKA
- duże i małe litery alfabetu łacińskiego (rozróżnialne tylko dla stałych tekstowych)
- cyfry 0 do 9
- jednoznakowe symbole specjalne:
+ - * / = < > [ ] .
, : ; ( ) { } ^ # $ @
Wieloznakowe symbole specjalne:
dwuznakowe
< > < = > = := . .
- słowa kluczowe (nie wszystkie)
AND |
DOWNTO |
IF |
PROCEDURE |
TYPE |
ARRAY |
ELSE |
IN |
PROGRAM |
UNTIL |
BEGIN |
END |
LABEL |
RECORD |
USES |
CASE |
FILE |
MOD |
REPEAT |
VAR |
CONST |
FOR |
NOT |
SET |
WHILE |
DIV |
FUNCTION |
OF |
THEN |
WITH |
DO |
GOTO |
OR |
TO |
|
2.4.3. IDENTYFIKATORY (NAZWY)
Identyfikatory - nazwy złożone z ciągu znaków
Identyfikatory standardowe:
typów danych - Boolean, Char, Integer, Real, String i inne
stałych - False, True, Maxint
funkcji - Abs, Sin, Cos, Sqr, Sqrt, Exp i inne
procedur - Read, Readln, Reset, Rewrite, Write, Writeln
plików - Input, Output
Identyfikatory własne nadaje użytkownik dla:
programu, obiektów (zmiennych), typów, podprogramów, modułów.
Zasady tworzenia identyfikatorów własnych:
Ciąg znaków (liter, cyfr, znaku podkreślenia _ )
Nie wolno używać spacji wewnątrz nazwy
Pierwszym znakiem musi być litera
Długość w standardzie języka nieograniczona (255)
Nierozróżnialne małe i duże litery
Przykłady:
A, C5, XY20, cyfra, e22, delta, dzienD, IDENT1, ident1
To_jest_dlugi_identyfikator_lecz_poprawny
Uwaga1: IDENT1 i ident1 są traktowane jako ten sam obiekt.
Uwaga2: Można przedefiniować identyfikatory standardowe lecz wtedy tracą one swoje znaczenie i nabierają nowego, nadanego przez użytkownika, np. możemy wprowadzić zmienną o nazwie sin lecz wówczas tracimy możliwość używania funkcji sin.
2.4.4 SEPARATORY
Separator nagłówka programu, deklaracji i instrukcji
; {średnik}
Opcjonalne separatory symboli języka
spacja, ciąg spacji, ENTER, komentarz
Z tym że:
Dwa dowolne słowa kluczowe, identyfikatory lub liczby bez znaku muszą być oddzielone co najmniej jednym separatorem. Ciąg spacji jest równoważny jednej spacji.
2.4.5 KOMENTARZ
W programie komentarz (własne uwagi lub opis działań) ma postać ciągu znaków w nawiasach klamrowych
{ ............................. }
UWAGA: Można dezaktywować niektóre instrukcje na etapie testowania programu zamykając je w nawiasach klamrowych.
Przydatne jest i do dobrego tonu należy umieszczanie komentarzy lecz nadmiar powoduje zmniejszenie przejrzystości.
2.5 STAŁE (literały)
2.5.1 Stałe liczbowe
A. całkowite
ciąg cyfr bez spacji (ew. poprzedzony znakiem + lub -)
Przykłady: -1 23234 012 0 -1234
$F12A - liczba w zapisie szesnastkowym
zakres : -32768 do 32767 dla typu integer
-2.15 mld do 2.15 mld (dla typu Longint)
B. rzeczywiste
Zapis stałopozycyjny
{±}m.n
gdzie m i n całkowite, dodatnie
UWAGA: kropka rodziela część całkowitą i ułamkową
Przykłady : 2.333 - 456.0
NIE WOLNO: .45 brak części całkowitej
WOLNO: 234.
Zapis zmiennopozycyjny (wykładniczy)
[-]m[.n]
[-]k
gdzie m,n,k całkowite dodatnie
Litera E (lub e) interpretuje pomnożenie liczby dziesiętnej m .n przez 10 do potęgi k.
Notacja wykładnicza przydatna dla liczb bardzo dużych i bardzo małych.
Przykłady:
0.1 -4.5 34.678 -1.5e-12 3.4E7 {tzn. 3.4.107=34000000}
UWAFA: Zakresy dla różnych podtypów różne !!!!
2.5.2 Stałe łańcuchowe
ciąg znaków ograniczonych apostrofami
Przykłady: 'Turbo Pascal' 'a'
2.5.3 Stałe logiczne
- wartości logiczna nadawane zmiennym i wyrażeniom typu logicznego Boolean
True - prawda False - fałsz
3. DEKLARACJE I DEFINICJE
3.1. Deklaracja modułów.
Modułu są to biblioteki procedur i funkcji, które po zadeklarowaniu modułu można wykorzystać w programie.
uses lista_nazw_modułów ;
np. uses graph;
uses crt,printer;
3.2. Deklaracja etykiet.
Etykiety służą do zaindeksowania instrukcji programu w celu np. wykonania programowego skoku do instrukcji o danej etykiecie - rzadko stosowane.
label lista_etykiet ;
np. label 12, 45;
label alfa, beta, gamma;
3.3. Definicje stałych (nazw literałów) i ich wartości.
Stałe są obiektami o wartości niezmiennej w trakcie wykonywania programu.
const nazwa1=wartość1; nazwa2=wartość2 ; ....;
np. const e=2.71828;
prawda = true;
nazwisko = 'Kowalski';
3.4. Definicje typów.
Definicja typu jest nazwanym opisem typu (najczęściej niestandardowego), używanym potem w deklaracjach zmiennych.
type nazwa1 = opis_typu1 ; nazwa2 = opis_typu2 ; .....;
np. type
dni_tyg = (po,wt,sr,cz,pi,so,ni); {typ wyliczeniowy}
ck = 1..20; {typ okrojony}
napis = string[30];
........
3.5. Deklaracje zmiennych.
var lista nazw zmiennych: typ1;
lista nazw zmiennych: typ2; ....;
Przykładowe deklaracje:
var
x, suma, v15: integer;
wynik1: real;
znak: char;
nazwisko, imie: napis; {wcześniej opisany typ}
czy_jest: boolean;
var alfa : dni_tyg; {zdefiniowany wyżej}
x , y , z : ck; {jak wyżej}
3.6. Definicje procedur i funkcji.
Procedure nazwa (......);
.....
.....
end;
Function nazwa(....):typ;
........
.......
end;
Funkcje i procedury mają strukturę blokową identyczną jak program główny, ale o tym później.
4.TYP DANYCH
Każda stała, zmienna, wyrażenie lub funkcja jest pewnego typu - pozwala to uniezależnić się w pewnym stopniu od fizycznej reprezentacji obiektów w pamięci komputera.
Typ określa:
Zbiór wartości, do którego należy stała, bądź jakie może przyjmować zmienna czy wyrażenie, lub jakie mogą być generowane przez funkcję
Zbiór operacji jakie mogą być wykonywane przez funkcję
Typy oferowane przez język PASCAL:
standardowe typy proste - Integer, Real, Word, Byte, Boolean, Char i inne
standardowy typ strukturalny - String
niestandardowe typy proste - okrojony, wyliczeniowy
niestandardowe typy strukturalne: tablicowy, zbiorowy, rekordowy, plikowy
niestandardowy typ plikowy.
Typ standardowy - zbiór wartości i operacje określone w języku.
Typy strukturalne (złożone) - wprowadzone w związku z praktycznymi potrzebami reprezentacji danych.
UWAGA:
W sekcji instrukcji wolno używać tylko takich identyfikatorów, których znaczenie określono w sekcji deklaracji
4.1 KLASYFIKACJA TYPÓW
4.2 TYPY PROSTE (porządkowe + rzeczywiste)
4.2.1 Typy porządkowe
A.Typy całkowite
Typ Integer
Używamy w deklaracji zmiennych:
var x,y:Integer;
zakres zależy od implementacji - dla IBM PC
stała Maxint = 215-1 = 32767
Inne typy całkowite:
Shortint |
-128 do 127 |
Word |
0 do 65535 |
Byte |
0 do 255 |
Longint |
-2.15 mld do 2.15 mld |
B. Typ znakowy Char
Zmienne tego typu mogą przyjmować wartości pojedynczego znaku
Przykład:
var znak:char;
begin
znak:='c'; {operacja przypisania - nadania wartosci}
.....
end.
C. Typ logiczny:Boolean
Zmienne tego typu mogą przyjmować wartości stałych logicznych True lub False
D. Typ wyliczeniowy
Typ wyliczeniowy jest typem prostym, porządkowym stanowiącym skończony, uporządkowany zbiór wartości oznaczonych nazwami (identyfikatorami), wybranymi przez użytkownika :
(lista wartości)
np. var
forma: (prostokat, kwadrat, elipsa, okrag);
dzien: (po, wt, sr, cz, pi, so, ni);
Dopuszcza się wykonywania na obiektach typu wyliczeniowego operacji przypisania, np.:
forma := elipsa;
dzien := po;
porównania (porządek według wyliczenia) np.:
po < wt
elipsa > kwadrat
a także użycia funkcji standardowych dla typów porządkowych, np.:
pred(wt) po
ord(wt) 1
Dla obiektów tego typu nie wolno stosować operacji arytmetycznych oraz wykorzystywać zmiennych tego typu w instrukcjach read/write.
E. Typ okrojony
Typ okrojony wyznacza podzbiór dowolnego typu porządkowego (boolean, char, integer, wyliczeniowy) zwanego typem bazowym:
w1 .. w2
gdzie w1 w2
np. var
zakres: 1..10;
cyfra: '0'..'9';
dni_wolne: so .. ni;
Operacje i funkcje obowiązują jak dla typu bazowego.
4.2.2 Typy rzeczywiste
Typy rzeczywiste - używane dla zmiennych przyjmujących wartość liczbową rzeczywistą
Typ Real - podstawowy
Tabela typów rzeczywistych:
Nazwa |
Najmn. wart.dod. |
Najw.wartość |
Real |
2.9e-39 |
1.7e38 |
Single |
1.5e-45 |
3.4e38 |
Double |
5.0e-324 |
1.7e308 |
Extended |
3.4e-4932 |
1.1e4932 |
UWAGA na zakresy: opcje pakietu dopuszczają brak sprawdzania zakresów - Options - Compiler - Runtime errors - Range checking - włączone lub nie.
4.3 TYP ŁAŃCUCHOWY String
Typ łańcuchowy zmiennej umożliwia przechowywanie wartości typu tekstowego (do 255 znaków)
STRING - do 255 znaków
STRING[20] - deklaracja max. długości
Przykład:
....
var nazwisko:String[20];
begin
nazwisko:='Kowalski'; {przypisanie wartości tekstowej do zmiennej}
writeln(nazwisko:15); {wydruk na ekranie w polu o szerokości 15 z wyrównaniem do prawej}
....
4.4 TYPY STRUKTURALNE - zmienne mogące zawierać wiele wartości (tablice, rekordy, obiekty, zbiory) - omówione zastaną później
UWAGA: PAMIĘĆ: Char - 1 bajt, Integer - 2 bajty, Real - 6 bajtów inne więcej.
Przykład:
PROGRAM DEKLARACJE;
TYPE
nasz = (a,b,c,d,e);
napis_krotki: string [5];
VAR
litera: char;
godzina, minuta, sekunda: integer;
ilosc, suma: real;
napis_tytulowy : string;
etykieta: napis_krotki;
litera : nasz;
BEGIN
Jeszcze nie umiemy wykonywać akcji
END.
5. INSTRUKCJE
5.1 Klasyfikacja instrukcji
5.2 Instrukcja przypisania
Zmiennym nadawane są wartości w trakcie wykonywania programu przy pomocy instrukcji przypisania:
identyfikator zmiennej := wyrażenie;
:= dwuznakowy operator przypisania
W instrukcji przypisania zmiennej o identyfikatorze z lewej strony znaku przypisania nadawana jest wartość obliczonego wyrażenia.
UWAGA2: obowiązek zgodności typów zmiennej i wyrażenia (z wyjątkami: np. zmiennej typu real można przypisać wartość wyrażenia typu integer)
Przykład:
Program wartosci;
const
EXP = 2.71828;
PI = 3.1415926;
FRAZA = 'Koniec danych';
SYMBOL = ':=' ;
var
Litera: Char;
Godzina, Minuta, Sekunda: Integer;
Ilosc, Suma: Real;
Napis_Tytulowy: String;
begin
Godzina := 12 ;
Minuta := 23 ;
Litera := 'C' ;
Ilosc := 56.87E4;
Napis_Tytulowy := FRAZA ;
Minuta := 24
end.
W powyższym przykładzie zmiennym nadano wartości stałe, brak operacji matematycznych, brak wprowadzania danych i wyprowadzania wyników. Aby nadać zmiennym wartości obliczane na podstawie innych zmiennych należy użyć po prawej stronie instrukcji przypisania wyrażeń odpowiedniego typu.
5.3 Wyrażenia
Wyrażeniem arytmetycznym może być stała, zmienna lub zapis złożonej operacji na stałych, zmiennych i funkcjach (standardowych, bibliotecznych lub własnych użytkownika) z użyciem operatorów arytmetycznych i nawiasów (okrągłych).
Najprostsza postać wyrażenia to stała lub zmienna
W → stała
W → zmienna
Bardziej skomplikowane wyrażenia zawierają operatory i funkcje.
Definicja rekurencyjna (czyli definiowanie przez samą siebie):
W → W operator W
Ponadto używamy nawiasów w celu zmiany hierarchii działań
5.3.1 Operatory
Operatory arytmetyczne:
- jednoargumentowe
zmiana znaku,
+ powielenie znaku,
- dwuargumentowe
- multiplikatywne
mnożenie,
/ dzielenie (rzeczywiste),
div dzielenie całkowite (oba operatory całkowite)
mod reszta z dzielenia całkowitego
- addytywne
+ dodawanie
- odejmowanie.
Przykłady:
7/2 3.5 |
4/2 2.0 |
6.5/2 3.75 |
7 div 2 3 |
17 mod -5 2 |
3.5*x-6/(4-x)+5 |
Kolejność wykonywania operacji określają następujące reguły:
- nawiasy są najważniejsze (od najbardziej wewnętrznych),
- ważność operatorów:
1. jednoargumentowe,
2. multiplikatywne,
3. addytywne.
- dla operatorów tej samej wagi - kolejność od lewej do prawej,
- jeżeli w wyrażeniu są tylko argumenty całkowite i nie ma dzielenia rzeczywistego to wynik jest typu integer,
- jeżeli występuje chociaż jeden element typu real lub dzielenie rzeczywiste to wynik jest typu real.
Na elementach tekstowych (char, string) możemy dokonywać operacji łączenia tekstów (tzw. konkatenacja) używając znaku +,
Np:
nazwisko := 'Kowalski';
tekst_1 := 'Pan ' + nazwisko ;
w rezultacie zmienna tekst_1 przyjmie wartość tekstową 'Pan Kowalski '.
5.3.2 Funkcje standardowe
Istnieje możliwość użycia w wyrażeniu funkcji standardowych (kontekst identyczny jak zmienne proste) w postaci:
nazwa_funkcji (argument)
Argumentem może być wyrażenie odpowiedniego typu. Zestaw funkcji standardowych przedstawia tabela 9.1.
TABELA Funkcje standardowe
Znaczenie |
Nazwa funkcji |
Typ funkcji |
Typ argumentu |
Przykład |
Wartość bezwzględna |
abs |
całkowity rzeczywisty |
całkowity rzeczywisty |
abs(-2) 2 |
Pierwiastek kwadratowy |
sqrt |
rzeczywisty |
rzeczywisty |
sqrt(5.45) |
Kwadrat |
sqr |
rzeczywisty |
rzeczywisty |
sqr(x-5) |
ex |
exp |
rzeczywisty |
rzeczywisty |
exp(-x/2) |
Logarytm naturalny |
ln |
rzeczywisty |
rzeczywisty |
ln(2x-4) |
Sinus |
sin |
rzeczywisty |
rzecz. (radiany) |
sin(3alfa) |
Cosinus |
cos |
rzeczywisty |
rzecz. (radiany) |
cos(beta/2) |
Arcus tangens |
arctan |
rzeczywisty |
rzeczywisty |
arctan(fi) |
Liczba =3.1415... |
pi |
rzeczywisty |
brak |
sin(30*pi/180) |
Część całkowita |
int |
rzecz. |
Całkowity Rzeczywisty |
int(2.5) 2.0 |
Część ułamkowa |
frac |
rzecz. |
Całkowity Rzeczywisty |
frac(3.6) 3.0 |
Zaokrąglenie |
Round |
całkowity |
Rzeczywisty |
round(3.6) 4 |
Obcięcie |
Trunc |
całkowity |
Rzeczywisty |
trunc(3.6) 3 |
Znak następny |
Succ |
znakowy |
znakowy |
succ ('g') 'h' |
Znak poprzedni |
pred |
znakowy |
znakowy |
pred(' j ') ' i ' |
znak o podanym kodzie ASCII |
chr |
znakowy |
całkowity |
chr(49) '1' |
kod znaku |
ord |
całkowity |
znakowy |
ord('1') 49 |
Długość tekstu |
length |
łańcuchowy |
całkowity |
length(`alfa') 4 |
W wyrażeniach istotne są wszelkie ograniczenia obszaru określoności, np. użycie ln(-3), sqrt(-5.0) spowoduje błędy wykonania.
Brak w języku funkcji standardowej potęgowania, stąd stosuje się :
x4 xxxx lub sqr (x)sqr (x) lub sqr (sqr (x))
xy exp (yln (x))
Należy zwrócić uwagę na możliwość wystąpienia przekroczenia dopuszczalnych zakresów przy obliczeniach.
Przykład prawidłowo zapisanego wyrażenia:
(5xx-2sin (x)+1.5e-5)/(abs (sqrt (x+2)-2)+exp (1.5ln (y)))
W przypadku zastosowania instrukcji:
zmienna := funkcja(zmienna);
obliczana jest wartość funkcji a następnie uaktualniana wartość zmiennej, np.
...
x := 5;
x := 2+sqr(x);
x:=x+5; {
...
w wyniku uzyskuje się x = 27.
Możliwe jest stosowanie także funkcji, które umieszczone są w innych modułach, np. Crt, Graph i in.. Ich użycie wymaga odpowiedniej deklaracji modułu, np.:
uses crt ;
Użyteczne są funkcje biblioteczne modułu crt:
- cls procedura czyszczenia ekranu
- bezparametrowa funkcja readkey, która służy do wczytania z klawiatury jednego znaku,
- funkcja logiczna keypressed, która służy do sprawdzenia naciśnięcia dowolnego klawisza.
UWAGA
operatory arytmetyczne - szczególnie mnożenia
2*x a nie 2x
format wykładniczy 1.34E-8, 1e7 a nie e7
argumenty funkcji trygonometrycznych w RADIANACH,
kolejność działań - nawiasy
brak potęgowania, brak funkcji tangens i cotangens
różnica SQR i SQRT
5.3.3 Wyrażenia logiczne
Wyrażeniem logicznym może być:
1. stała
true prawda 1 - logiczne
false fałsz 0 - logiczne
2. zmienna - typ boolean
3. relacja - porównanie w sensie liczbowym lub tekstowym (wg kolejności alfabetycznej) wg schematu:
wyrażenie1 operator arytmetyczny wyrażenie2
Relacja ma wartość logiczną true lub false. Operatorami relacji są:
(różny)
Przykładowo: x12 2
(4x+1.5) 30.7
nazwisko 'F' nazwiska od F do końca alfabetu
Uwaga: Operatory , , należy używać ostrożnie dla typów rzeczywistych ze względu na przybliżenie wartości.
4. stałe logiczne, zmienne logiczne, relacje (w nawiasie), połączone operatorami logicznymi:
- jednoargumentowym
not (negacja) np. not (i < 5) not obecny
- dwuargumentowymi
and (iloczyn logiczny -„i”) np. (x > 0) and (x < 3)
or (suma logiczna -„lub”) np. (x < 0) or (x > 100)
xor (różnica symetryczna - suma modulo2)
argument 1 |
argument 2 |
and |
or |
xor |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
1 |
1 |
0 |
W operacji przypisania wartości zmienej logicznej musi zachodzić zgodność typów.
Przykład:
var
zwolniony, obecny: boolean;
ocena: real;
begin
...
zwolniony := (ocena >= 4.5) and obecny;
...
end.
5.4 Instrukcje czytania i wyprowadzania danych
Do wprowadzenia (standardowo z klawiatury) wartości zmiennej w trakcie wykonania programu służy procedura:
[(lista zmiennych)];
Uwaga: w nawiasach klamrowych { } -elementy do wyboru, w nawiasach kwadratowych [ ] - elementy opcjonalne
Np. readln (x1, x2, x3, y);
read(x);
Liczby podajemy polami oddzielonymi co najmniej jedną spacją, przecinkiem lub w osobnych wierszach.
Jeżeli wpiszemy za dużo liczb to nadwyżka jest pamiętana dla następnej instrukcji read, natomiast w instrukcji readln czytane jest tyle ile potrzeba a reszta zostaje zignorowana.
Należy uważać na zgodność typów zmiennych i danych (stała całkowita może być wczytana do zmiennej rzeczywistej lecz nie odwrotnie).
Procedurą wyprowadzania danych (standardowo na ekran) jest:
[ (lista elementów) ];
Po wykonaniu instrukcji write kursor pozostaje na końcu wiersza zaś po writeln następuje zmiana wiersza. Elementami listy są stałe, zmienne i wyrażenia wraz z opcjonalnym określeniem formatu wyprowadzenia o postaci:
W:m wyrażenie całkowite określające szerokość pola (liczba znaków), dla liczb typu real m 8,
W:m:n m - jak wyżej, n - liczba cyfr po kropce dziesiętnej (tylko typ real).
Przykłady:
begin
x := -21.546;
y := 'Napis=';
writeln(x); -2.154600000E+01
writeln(x:8); -2.2E+01
writeln(x:10:3); -21.546
writeln(y:10, 'TurboPascal':12); Napis= TurboPascal
end.
5.5 Reguły graficzne tworzenia schematów blokowych
Start i stop
Operacje wejścia i wyjścia
Instrukcja wykonawcza (proces) Blok decyzyjny
Łącznik stronicowy
6. Turbo Pascal instrukcje warunkowe, instrukcje iteracyjne
6.1. Instrukcje warunkowe
6.1.1 Instrukcja if ( jeśli)
Postać skrócona:
if WB then Instrukcja;
„jeśli” „to”
Wykonywane jest badanie warunku logicznego WB a następnie:
- jeśli WB = true to Instrukcja jest wykonywana,
- jeśli WB = false to Instrukcja jest ignorowana.
Postać pełna:
if WB then Instrukcja_1 else Instrukcja_2;
„jeśli” „to” „w przeciwnym przypadku”
postać skrócona postać pełna
Wykonywane jest badanie warunku:
- jeśli WB = true to wykonywana jest Instrukcja_1,
- jeśli WB = false to wykonywana jest Instrukcja_2.
Instrukcja może być tzw. instrukcją złożoną (sekwencji):
begin
ciąg instrukcji
end;
Instrukcje wewnętrzne if mogą także być innymi instrukcjami if.
Przykład:
if (x = 0) then begin
y := y+5;
writeln(y:10:3)
end
else writeln('x jest ujemne');
6.1.2 Instrukcja wyboru - case
Postać instrukcji:
case w of
s1,...,sn : Instrukcja_1;
sn+1,...,sm : Instrukcja_2;
....
[ else Instrukcja_k ]
end;
w - wyrażenie selektor typu porządkowego (całkowitego, znakowego),
s - stałe wyboru (etykiety wyboru) w możliwej postaci:
s; - pojedyncza wartość,
s1,...,sn - lista wartości,
s1 .. s2 - zakres wartości.
Działanie instrukcji polega na obliczeniu wartości wyrażenia w i w zależności od wyniku wykonywana jest instrukcja (także złożona) odpowiadająca wartości (wartościom, zakresowi) stałej wyboru.
Instrukcja w opcjonalym bloku po else wykonywana jest dla wartości niewystępującej wcześniej. W listach wyboru można powtarzać te same wartości.
Przykład:
case miesiac of
2: dni := 28;
4, 6 , 9, 10: dni := 30;
1..12: dni := 31; {lub else dni := 31}
end ;
6.2. Instrukcje iteracyjne
6.2.1 Instrukcja for (dla)
for Z := Wi1
Wi2 do Instrukcja;
Z - zmienna sterująca (prosta lub indeksowana), typu porządkowego (np. całkowitego lub znakowego).
Wi1 i Wi2 - wyrażenia tego samego typu
Wersja z to Wersja z downto
Wartość zmiennej sterującej zmienia się od Wi1 do Wi2 narastająco (to) lub malejąco (downto), z krokiem 1 w przypadku zmiennej całkowitej lub co znak w wypadku zmiennej typu char.
Np. x := 0;
for i := 1 to 3 do x := x+5; {po trzykrotnie wykonanej iteracji
x 15}
Instrukcja for jest stosowana gdy z góry znana jest liczba powtórzeń. Wewnątrz iteracji nie wolno zmieniać wartości zmiennej sterującej.
Instrukcją wewnętrzną może być inna instrukcja for (zagnieżdżanie iteracji), także instrukcja złożona. Poniżej przykład programu wyprowadzającego 10 wierszy po 4 gwiazdki w wierszu.
var i: integer;
j: char;
begin
for i := 1 to 10 do
begin
writeln;
for j := 'a' to 'd' do write('')
end
end .
6.2.2 Instrukcja while (dopóki)
while WB do Instrukcja;
Działanie instrukcji polega na powtarzaniu wykonywania instrukcji dopóki wyrażenie logiczne WB posiada wartość true. Wartość ta jest sprawdzana każdorazowo przed wykonaniem instrukcji.
Istnieje zatem konieczność wykonania w instrukcji (także złożonej) operacji wpływającej na wartość wyrażenia logicznego. Jeśli błędny warunek spowoduje nieskończoną pętlę możemy przerwać program kombinacją klawiszy CTRL+Break.
Rys. Schemat blokowy instrukcji WHILE
Przykładowy fragment programu oblicza sumę liczb parzystych od 2 do 100:
i := 2;
suma := 0;
while i <= 100 do
begin
suma := suma + i;
i := i + 2;
end;
6.2.3 Instrukcja repeat / until (powtarzaj .. aż)
repeat
ciąg instrukcji
until WB ;
Ciąg instrukcji wewnętrznych jest powtarzany dopóty, dopóki wyrażenie logiczne WB posiada wartość false, zmiana na true powoduje zakończenie pętli. Sprawdzanie warunku odbywa się na końcu pętli, stąd jest ona conajmniej raz wykonywana. Podobnie jak w iteracji while jedna z instrukcji powinna mieć wpływ na wartość wyrażenia logicznego.
Rys. Schemat blokowy instrukcji REPEAT / UNTIL
Przykład: x := 3;
repeat
x := x + 5;
until x 100;
Przykład:
program p6a;
uses crt;
var
a, b, c, delta, x1, x2: real;
begin
clrscr;
writeln('Podaj wspolczynniki rownania kwadratowego');
write('a=');
readln(a);
write('b=');
readln(b);
write('c=');
readln(c);
delta := b*b-4*a*c;
if delta < 0 then writeln('Brak pierwiastkow rzeczywistych')
else
if delta = 0 then writeln('Pierwiastek pojedynczy x1=x2=', -b/2/a)
else
begin
delta := sqrt(delta);
x1 := (-b-delta)/2/a;
x2 := (-b+delta)/2/a;
writeln('Pierwiastki rownania kwadratowego');
writeln('x1=':20,x1:10:2);
writeln('x2=':20,x2:10:2)
end;
readln;
end .
program p6b;
var x: 1..7;
begin
writeln('WHILE');
x := 1;
while x = 7 do
begin
write('witaj');
x := x+1;
end;
writeln;
writeln('FOR');
for x := 1 to 7 do write('witaj');
writeln;
writeln ('REPEAT');
x := 1;
repeat
write('witaj');
x := x+1;
until x 7;
readln;
end .
program p6c;{Przydzielenie do grup wiekowych}
uses crt;
var
wiek: integer;
begin
ClrScr;
repeat
write( 'Podaj wiek:' );
readln(wiek);
case wiek of
0..20 : writeln('GRUPA I');
21..40 : writeln('GRUPA II');
41..60 : writeln('GRUPA III')
else writeln('GRUPA IV')
end;
until wiek = 0;
write('Nacisnij ENTER');
readln
end .
7. Typ tablicowy
7.1 Definicja typu
Typy standardowe mają swoje nazwy (boolean, real, integer, char...), istnieje też możliwość wprowadzenia unikalnych nazw dla własnych typów i ich definiowania:
nazwa typu = opis typu
np. type
dni_tyg = (po,wt,sr,cz,pi,so,ni);
ck = integer;
ck1 = 1..20;
nap = string[30];
var
dzien, dn: dni_tyg;
i, j, k: ck;
l, m, n: ck1;
nazw, imie: nap;
Na nazwach typów nie wolno przeprowadzać operacji. Definicja typu musi poprzedzać użycie go w deklaracji zmiennej.
7.2 Typ tablicowy - array
Typ tablicowy jest typem strukturalnym (złożonym) stanowiącym skończony zbiór elementów tego samego typu, o położeniu określanym przez indeksy. Zmienna typu tablicowego odpowiada tablicy (macierzy) w sensie matematycznym.
array[ lista typów indeksów ] of typ składowych
typ porządkowy typ dowolny
np. var
tab1: array [ 0..50 ] of integer;
tab2,tab3: array [1..20, 1..30] of real;
tablica: array [ boolean, zakres, dzien_tyg] of char;
Tablice posiadają wymiar zależny od liczby indeksów (1, 2, 3-wymiarowe) oraz rozmiar zależny od zakresu określoności indeksu w każdym wymiarze (np. rozmiar - 10 kolumn, 15 wierszy).
Zmienne tablicowe całościowe mogą być wykorzystane jedynie w operacji przypisania (przy zgodności typów), np.:
var
tab1, tab2: array [1..10, 1..20] of real;
begin
...
tab1 := tab2;
...
end.
natomiast inne operacje dokonywane być mogą tylko na składowych jeśli są dozwolone dla ich typu.
Przykład 1:
...
tab1[2,3] := 0.1; {nadanie wartości elementowi tablicy}
for i := 1 to 20 do tab2[1, i]:= 0.0; {wypełnianie pierwszego wiersza zerami}
for i := 1 to 20 do tab2[i, i]:= i/2; {wypełnianie przekątnej głównej wartościami 0.5 1 1.5 itd.}
for i := 1 to 20 do
for k:= 1 to 20 do tab2[i, k]:=1 {wypełnianie całej tablicy stałą wartością}
for i := 1 to 20 do
begin
for k:= 1 to 20 do write(tab2[i,k]:4:2);
writeln
end; {wydruk na ekranie całej tablicy}
...
Przykład 2:
type dni_tyg = (po, wt, sr, cz, pi, so, ni);
wek = array[dni_tyg, boolean] of real;
var x: wek;
begin
...
x[po, true] := 10.2;
writeln(x[wt, false]/100:20:5);
if x[sr,false] > 3e2 then writeln(' W srode za duzo ');
...
end .
Przykład 3:
type opis= (nazw, imie);
var grupa: array[1..100, opis] of string[30];
i: integer
begin
...
grupa[1, nazw] := 'Kowalski';
if grupa[i, imie] = 'Stanislaw' then
writeln(grupa[i, nazw]:30, grupa[i, imie]:20);
...
end .
7.3 Typ rekordowy - record
Typ rekordowy jest typem strukturalnym o strukturze jednowymiarowej i o składowych dowolnych typów, które nazywają się polami:
Opis typu:
record
lista_nazw_pól_1: typ1;
lista_nazw_pól_2: typ2;
........
end;
np.
type
data = record
rok: 1900..2100;
mies: 1..12;
dzien: 1..31;
end;
type student = record
nazw: string[20];
imie1, imie2: string[15];
data_ur: data;
mezczyzna: boolean;
rodzenstwo: array[1..5] of string[15]
end;
Do pól rekordu istnieje dostęp bezpośredni, odwołanie do pola zmiennej odbywa się przez nazwę zmiennej rekordowej i nazwę pola, oddzielonych kropką:
nazwa_zmiennej . nazwa_pola [. ew_nazwa_pola_składowego ...]
np.
student . nazw := 'Kowalski';
if student . data_ur . rok < 1975 then ...
UWAGI:
W jednym typie rekordowym wszystkie pola muszą mieć różne nazwy.
Na zmiennych całościowych jedyną dopuszczalną operacją jest przypisanie, na zmiennych składowych można dokonywać operacji dopuszczalnych dla ich typu.
Zmienne rekordowe można zgromadzić w tablicy, np.:
var grupa: array[1..30] of student; {wcześniej zdefiniowany typ}
lub
var grupa: array[1..30] of record
pole1: typ1;
pole2: typ2;
...
end;
begin
...
grupa[1]. nazw := 'Nowak';
if grupa[2]. data_ur. rok < 1975 then writeln(grupa[3]. rodzenstwo[1]:20);
...
end .
7.4. Instrukcja wiążąca - with
Instrukcja with upraszcza zapis dostępu do pól rekordu. Odwołanie w instrukcji (także złożonej) może nastąpić bezpośrednio do nazw pól wymienionych w liście zmiennych, bez wyspecyfikowanej nazwy zmiennej całościowej.
with lista_zmiennych_rekordowych do Istrukcja;
Przykład 1:
var zespolona: record
rzecz, uroj: real
end;
begin
with zespolona do
begin
rzecz := 2.5;
uroj := 1.0
end;
...
end .
Przykład 2:
program p11a;
uses crt;
var k, dzien: 1..31;
miesiac: 1..12;
rok: 1900..2000;
begin
clrscr;
write('Podaj dzien:');
read(dzien);
write('Podaj miesiac:');
read(miesiac);
write('Podaj rok:');
readln(rok);
clrscr;
writeln(dzien:72, ':', miesiac:2, ':',rok:4);
for k := 1 to dzien do writeln(k:4);
end .
Przykład 3:
program p11b;
uses crt;
type osoba= record
nr: integer;
nazw: string[30];
end;
var
j: 1..10;
student: osoba;
grupa: array[1..10] of osoba;
begin
clrscr;
writeln('Wczytanie danych do tablicy');
with student do
for j := 1 to 10 do
begin
write('Podaj numer: ');
readln(nr);
write('Podaj nazwisko: ');
readln(nazw);
grupa[ j ] := student
end
.....
end .
Jeżeli rekordy znajdują się w tablicy, np.
var osoba: record
nazwisko:string;
imie:string:
wiek:0..100
end;
grupa: array [1..30] of osoba;
to dostęp do pola pojedynczego rekordu tej tablicy może się odbyć w postaci przykładowej
writeln (grupa[5].nazwisko );
12. Turbo Pascal - procedury, funkcje, pliki
12.1. Procedury i funkcje
Stosowanie procedur i funkcji (podprogramów) umożliwia rozbicie złożonego ciągu operacji na mniejsze struktury. Zwiększa ono czytelność programu.
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 i funkcji umieszczana jest w części deklaracyjnej programu głównego (także innej procedury lub funkcji):
procedure nazwa (parametry formalne);
definicje, deklaracje
begin
....
akcje
....
end;
function nazwa (parametry formalne): typ;
definicje, deklaracje
begin
....
nazwa := wyrażenie;
....
end;
Zmienne deklarowane wewnątrz procedury lub funkcji maja zasięg lokalny, tzn. obowiązuję jedynie w ich wnętrzu i niedostępne są po zakończeniu ich wykonania.
Parametry formalne służą do przekazywania danych. Deklaracje parametrów są oddzielane średnikami, każda deklaracja składa się z listy zmiennych i nazwy typu. Poprzedzające listę słowo var określa przekazanie danych przez zmienną, jego brak przekazanie danych przez wartość. Przykładowe nagłówki procedury i funkcji:
procedure alfa (nr, liczba1: integer; var log: boolean);
function ff (x1, x2: real): real;
Wywołanie (wykonanie) funkcji w programie dokonywane jest jak użycie zmiennej. Wywołanie procedury jest odrębną instrukcją. W nawiasie wpisujemy argumenty (parametry aktualne), których liczba i typ muszą odpowiadać liczbie parametrów formalnych.
Na przykład:
y := z + ff ( 10.5, zm11); {wywołanie funkcji}
alfa (5, 4, jest); {wywołanie procedury}
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. Argumenty mogą być stałymi, zmiennymi bądź wyrażeniami.
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ę. Parametry aktualne przekazujące przez zmienną muszą być identyfikatorami (nazwami) zmiennych.
Poniższy program tabelaryzuje wartości funkcji opisanej przedziałami, w 21 punktach zakresu (0.0, 2.0):
program tabela1;
uses crt;
var i: 0..20;
function fun(x: real): real; {definicja funkcji}
var xkw: real;
begin
xkw := x*x;
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 wartosci 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) {wywołanie funkcji
w instrukcji wyjścia}
end;
repeat until keypressed
end .
12.2. 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 DOS-u w pamięci zewnętrznej. Dostęp do pliku jest sekwencyjny, tzn. dostępny jest tylko jeden element określony przez aktualne położenie wskaźnika, zaś inne elementy mogą być udostępniane tylko po wykonaniu pewnych operacji na pliku (np. przesuwanie wskaźnika). Rozmiar pliku jest dynamiczny. Zmienną typu plikowego można kojarzyć kolejno z różnymi plikami dyskowymi. Plik może mieć dowolny typ składowych oprócz pliku. 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:
type
osoba = record
nazw: string[30];
imie: string[30]
end;
grupa = file of osoba;
var
student: osoba;
gr1, gr2, gr3: grupa;
begin
...
end.
Dla całościowych zmiennych plikowych możliwe są jedynie niektóre operacje DOS-u, natomiast na składowych możemy wykonywać operacje w zależności od typu składowych.
W pliku zdefiniowanym 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.3. Operacje plikowe
W poniższej tabeli przedstawiono podstawowe operacje plikowe, w których użyto określeń:
f - nazwa zmiennej plikowej,
Wt - wyrażenie tekstowe,
W - wyrażenie odpowiedniego typu,
Z - nazwa zmiennej.
TABELA 12.1. Podstawowe operacje plikowe
Operacja |
Typ |
Zapis |
Przykład |
skojarzenie |
procedura |
assign (f , Wt) |
assign(gr1,'C:\DANE\gr.dt'); |
otwarcie do odczytu |
procedura |
reset (f); |
reset (gr1); |
otwarcie do zapisu |
procedura |
rewrite (f); |
rewrite(gr2); |
dopisanie (na końcu pliku!) |
procedura |
append (f); |
append (gr2); |
zamknięcie pliku |
procedura |
close (f); |
close(gr3); |
detekcja końca pliku |
funkcja logiczna |
eof (f) |
if eof(gr1)= true then ... |
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 ustawia się na początku pliku,
Otwarcie nowego pliku powoduje utworzenie pustego pliku,
Gdy eof(f) = true - wskaźnik znajduje się na końcu pliku,
Gdy po reset okaże się że eof(file) = true to plik jest pusty,
Po przeczytaniu elementu następuje przesunięcie wskaźnika do następnego elementu
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 tabela2;
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ższe przykłady ilustrują wykorzystanie bardziej złożonych struktur i algorytmów:
Przykład programu wyznaczania maksimum i minimum wartości losowych
program maksimum;
uses crt;
var x : array[1..100] of real;
i, k : 1..100;
max, min : real;
begin
clrscr;
randomize;
for i := 1 to 20 do begin
for k := 1 to 100 do
x [k] := random (256*256-1) / (256*256-1);
{wyznaczenie maksimum i minimum}
max := x [1];
min := x [1];
for k := 2 to 100 do
if x [k] > max then max := x [k ];
if x [k] < min then min := x [k ];
writeln( 'max=' , max:12:5, 'min=' : 10 , min:12:5);
end;
repeat until keypressed
end.
SORTOWANIE
Prosty algorytm sortowania
1 przebieg
12 5 11 4 7 2 ZMIANA 1
5 12 11 4 7 2
5 12 11 4 7 2 ZMIANA 2
4 12 11 5 7 2
4 12 11 5 7 2 ZMIANA 3
2 12 11 5 7 4
2 przebieg
2 12 11 5 7 4 ZMIANA 4
2 11 12 5 7 4 ZMIANA 5
2 5 12 11 7 4
2 5 12 11 7 4 ZMIANA 6
2 4 12 11 7 5
3 przebieg
2 4 12 11 7 5 ZMIANA 7
2 4 11 12 7 5 ZMIANA 8
2 4 7 12 11 5 ZMIANA 9
2 4 5 12 11 7
4 przebieg
2 4 5 12 11 7 ZMIANA 10
2 4 5 11 12 7 ZMIANA 11
2 4 5 7 12 11
5 przebieg
2 4 5 7 12 11 ZMIANA 12
2 4 5 7 11 12
liczba analiz
Sortowanie bąbelkowe
1 przebieg
12 5 11 4 7 2 ZMIANA 1
5 12 11 4 7 2 ZMIANA 2
5 11 12 4 7 2 ZMIANA 3
5 11 4 12 7 2 ZMIANA 4
5 11 4 7 12 2 ZMIANA 5
5 11 4 7 2 12
2 przebieg
5 11 4 7 2 12
5 11 4 7 2 12 ZMIANA 6
5 4 11 7 2 12 ZMIANA 7
5 4 7 11 2 12 ZMIANA 8
5 4 7 2 11 12
5 4 7 2 11 12
3 przebieg
5 4 7 2 11 12 ZMIANA 9
4 5 7 2 11 12
4 5 7 2 11 12 ZMIANA 10
4 5 2 7 11 12
4 5 2 7 11 12
4 5 2 7 11 12
4 przebieg
4 5 2 7 11 12
4 5 2 7 11 12 ZMIANA 11
4 2 5 7 11 12
4 2 5 7 11 12
4 2 5 7 11 12
4 2 5 7 11 12
5 przebieg
4 2 5 7 11 12 ZMIANA 12
2 4 5 7 11 12
2 4 5 7 11 12
2 4 5 7 11 12
2 4 5 7 11 12
2 4 5 7 11 12
6 przebieg
2 4 5 7 11 12
2 4 5 7 11 12
2 4 5 7 11 12
2 4 5 7 11 12
2 4 5 7 11 12
2 4 5 7 11 12
Sortowanie bąbelkowe skrócone
1 przebieg
12 5 11 4 7 2 ZMIANA 1
5 12 11 4 7 2 ZMIANA 2
5 11 12 4 7 2 ZMIANA 3
5 11 4 12 7 2 ZMIANA 4
5 11 4 7 12 2 ZMIANA 5
5 11 4 7 2 12
2 przebieg
5 11 4 7 2 12
5 11 4 7 2 12 ZMIANA 6
5 4 11 7 2 12 ZMIANA 7
5 4 7 11 2 12 ZMIANA 8
5 4 7 2 11 12
3 przebieg
5 4 7 2 11 12 ZMIANA 9
4 5 7 2 11 12
4 5 7 2 11 12 ZMIANA 10
4 5 2 7 11 12
4 przebieg
4 5 2 7 11 12
4 5 2 7 11 12 ZMIANA 11
4 2 5 7 11 12
5 przebieg
4 2 5 7 11 12 ZMIANA 12
2 4 5 7 11 12
Prosty algorytm sortowania
Program sortowanie;
type
TOsoba = record { rekord zawierajcy dane osobowe }
Imie :string[ 25 ];
wiek :integer;
end;
const
MaxOsob = 30;
var
ListaOsob : array [ 1..MaxOsob ] of TOsoba;
i,n : integer;
znak : char;
Zamienic : boolean;
pom : TOsoba; {zmienna pomocn. do sortowania tablicy }
begin
..........
..........
{sortowanie}
repeat {wybor sposobu sortowania }
writeln('Wybierz porzadek sortowania:');
writeln(' I - imie');
writeln(' W - wiek');
readln(znak);
znak := UpCase(znak);
case znak of
'I' :writeln('Lista posortowana wedlug imion');
'W' :writeln('Lista posortowana wedlug wieku');
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;
'W' : Zamienic := ListaOsob[ n ].Wiek < ListaOsob[ n-1 ].Wiek;
end;
if Zamienic then
begin
pom := Listaosob[ n ];
Listaosob[ n ] := ListaOsob[ n -1 ];
Listaosob[ n -1 ] := pom;
end;
Dec(n); {zmniejsza n o 1}
until (n = 1) or (not Zamienic);
program Tab_rekordow;
{ Ilustracja uzycia typu rekordowego }
{ program wczytuje liste osob z klawiatury do tablicy rekordow,
a nastepnie wyswietla liste posortowana wedlug zadanego pola }
type
TOsoba = record { rekord zawierajacy dane osobowe }
Imie : string[ 25 ];
Nazwisko : string[ 25 ];
Adres : string[ 25 ];
wiek : integer;
Plec :(K,M);
end;
const
MaxOsob = 30; {maks. 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 pomocn. do sortowania tablicy }
begin
{wczytanie danych z klawiatury }
NastepnaOsoba := true;
Iloscosob := 0;
while NastepnaOsoba and (IloscOsob <= MaxOsob) do
begin
inc(IloscOsob);
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 ]:'); readln(znak);
case znak of
'K','k':Plec := K
else
Plec := M
end;
end;
if IloscOsob < MaxOsob then
begin
writeln;
write('Chcesz podac nastepna osobe? [ T/N ]');
readln(Znak);
NastepnaOsoba := UpCase(Znak)='T';
end;
end;
{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 wedlug imion');
'N' :writeln('Lista posortowana wedlug nazwisk');
'W' :writeln('Lista posortowana wedlug wieku');
'P' :writeln('Lista posortowana wedlug 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(l);
until (n = 1) or (not Zamienic);
end;
{ 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(' Adres', Listaosob[ i ].Adres);
end;
writeln;
write('Wyswietlic powtornie [ T/N ]:');
readln(znak);
until Upcase(znak) = 'N';
end.
program Tab_rek_pliki;
{Ilustracja uzycia typu rekordowego wraz z zapisem/odczytem listy z dysku}
{ program w czytuje liste osob z klawiatury do tablicy rekordow, a nastepnie wyswietla liste posortowana wedlug zadanego pola }
uses crt;
type
TOsoba = record { rekord zawierajcy 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 pomocn. 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 wybor [ 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);
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;
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('Zapisac 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 wedlug imion');
'N' :writeln('Lista posortowana wedlug nazwisk');
'W' :writeln('Lista posortowana wedlug wieku');
'P' :writeln('Lista posortowana wedlug 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);
until (n = 1) or (not Zamienic);
end;
{ 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('Wyswietlic powtornie [ T/N ]:');readln(znak);
until Upcase(znak) = 'N';
end.
13. Rekurencja
Wiele zagadnień w technice i matematyce można zdefiniować rekurencyjnie. Definicja rekurencyjna oznacza takie zdefiniowanie problemu gdzie odwołujemy się do definiowanej właśnie definicji. Przykładem takiej definicji może być potęga całkowita nieujemna rzędu N liczby rzeczywistej x:
xn = jeśli n > 0 to xn-1*x
jeśli n = 0 to 1
Rekurencja w językach programowania realizowana jest przy pomocy podprogramów wywołujących same siebie. Podprogramy rekurencyjne aby poprawnie działały muszą spełniać następujący warunek: podprogram musi zawierać warunek, który powoduje zakończenie rekurencji, czyli nie wywołuje po raz kolejny samego siebie.
Rekurencja daje proste i eleganckie 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ład - wyznaczanie N-tej potęgi liczby X:
Program Potega1;
{wyznaczanie potęgi całkowitej nieujemnej N z 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;
end;
begin
writeln('2^10=',PotegaN(2,10):0:0);
end.
Przykład - wyznaczanie silni z liczby x:
program Silnia; {Wyznaczanie silni liczby X - metoda rekurencyjna}
function SilniaX(x:longint):longint;
begin
if x = 1 then SilniaX := 1
else SilniaX := SilniaX(x-1)*x;
end;
begin
Writeln('Silnia z liczby 6= ',SilniaX(6));
end.
14. 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 TurboPascal-u 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. Linker przydziela zaś zmiennym adresy, tak, aby nie nakładały się na siebie.
Zmienna wskaźnikowa pozwala w trakcie programu przydzielać pamięć zmiennym specjalnymi procedurami.
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ą (TurboPascal posiada mechanizmy pozwalające wyłączyć kontrolę kompilatora nad typem i długością zmiennej - mechanizmy te nie będą przedmiotem tego wykładu).
14.1. Deklaracja zmiennej wskaźnikowej
Zmienną wskaźnikową (czyli adres do zmiennej jakiegoś konkretnego typu) deklaruje się jako zmienną statyczną. Zmienna wskaźnikowa zajmuje 4 bajty.
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ą ilość pamięci zawiera 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.
type
pOsoba =^TOsoba;
TOsoba =record
imie,nazwisko :string;
nastepny :pOsoba;
end;
var
pzmienna:TOsoba;
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ć).
14.2. Odwołanie do zmiennej wskaźnikowej
W naszym programie, aby dostać się do wartości na którą wskazuje zmienna wskaźnikowa (inaczej mówiąc do zmiennej umieszczonej w pamięci pod adresem zawartym w zmiennej wskaźnikowej) musimy do nazwy zmiennej dodać znak "^":
var
x,y :^integer;
z :integer;
begin
{...}
z := 2
x^ := z+2;
y := x^*3
z := x^+y^;
{...}
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
14.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 "@" - nazwa identyfikatora zmiennej (lub podprogramu) poprzedzona tym operatorem daje 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,' sklada się z nastepujacych bajtow:');
for i := 1 to 6 do
writeln('Bajt ',i,' = ',p^[i]); {wydruk posczegó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 ...
Niestety należy pamiętać, że likwidowanie zmiennej procedurą DISPOSE (o tym dalej) nie nadaje zmiennej wskaźnikowej wartości NIL. Operację tę należy przeprowadzić samodzielnie.
14.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 pozwoli 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);
Lista
Najciekawszą strukturą danych oferowaną 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. Istnieją różne rodzaje list - jednokierunkowa, dwukierunkowa, drzewo itp.
W listach należy pamiętać o tym, że każdy utworzony element musimy dołączyć do łańcuszka elementów, w przeciwnym wypadku, jeśli "zgubimy" adres do niego jest on stracony dla naszej aplikacji.
Przykład
program dynamika;
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;
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 {jesli na poczatku listy}
else
begin {szukanie miejsca w szeregu}
while pom1^.nazw > pom2^.nazw do
begin
pom3:=pom2; {zapamietanie miejsca}
pom2:=pom2^.nast; {miejsce nastepne}
end;
pom3^.nast:=pom1; {wskazanie na wczytane dane}
end;
pom1^.nast:=pom2; {wskazanie nastepnych 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 {cialo programu}
clrscr;
czytaj(osob,N);
pisz(osob);
dopisz(osob);
pisz(osob);
repeat until keypressed;
end.
Poniżej przedstawiono schemat logiczny tworzenia listy jednokierunkowej:
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 statycznch zawiera wiele pól, zawierających bądź wskazanie puste (NIL) bądź na inne zmienne
14. Moduły
Moduły są podstawą programowania modularnego i służą do grupowania funkcji i procedur w biblioteki. Moduł nie stanowi samodzielnego programu. Jego użycie wymaga deklaracji. Moduł powinien być wcześniej skompilowany i umieszczony w katalogu 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
end lub instrukcja złożona {część inicjująca}
.
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 menu Compile). Jego skomplilowany 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 modułu:
Program m12;
uses cmplx;
var x,y,z : complex;
begin
........ {zdefiniowane x i y}
dodaj (x,y,z);
writeln (`Suma=', z.re:12:5 , z.im:12:5);
odejmij (x,y,z);
writeln (`Roznica=', 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ł Printer
Zawiera deklarację pliku tekstowego Lst, dzięki któremu:
program drukuj;
uses Printer;
begin
writeln(Lst, `Tekst wyprowadzany')
end;
Moduł System
(Uwaga: nie trzeba go deklarować w bloku Uses)
Zawiera:
Predefiniowane stałe i zmienne dla identyfikacji błędów, obsługi wejścia i wyjścia.
Procedury przerwania pętli 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 łańcuchowe: Concat, Copy, Length,
Concat (lista_łańcuchów) - połączenie łańcuchów
Copy (łańcuch, pozycja, długość) - wycięcie z łańcucha
Length (łańcuch) - długość łańcucha
Str (argument numeryczny, zmienna łańcuchowa)
- zamiana wartości na łańcuch
Val(łańcuch, 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 Randomize
Moduł Crt
Zawiera predefiniowane identyfikatory: trybu ekranu, kolorów
Podprogramy sterowania trybami ekranu:
ClrScr, Window, Gotoxy (x,y), TextColor, TextBackground i inne
Funkcje:
Readkey - wczytanie jednego znaku
Procedury dźwiękowe:
Delay(opóźnienie w milisekundach);
Sound (częstotliwość);
NoSound; - przerwanie dźwieku
Moduł Strings - Funkcje i procedury operacji na tekstach
Moduł Dos i WinDos- Funkcje i procedury do bezpośredniego kontaktu z systemem operacyjnym.
Moduł Graph - funkcje i procedury graficzne.
14.2. Podstawy programowania obiektowego
Elementy opisane uprzednio dotyczą tzw. programowania strukturalnego - koncepcja tradycyjna. Główną jego składową są instrukcje działające na danych. Złożone programy korzystają z funkcji, procedur i modułów w celu uproszczenia zarządzania i kontroli nad programem, lecz nie zmienia to podstawowej koncepcji.
Programowanie zorientowane obiektowo (OOP - Object Oriented Programming) umożliwia przedstawienie problemu w postaci logicznie powiązanych ze sobą struktur danych zwanych obiektami, wymieniających informacje między sobą.
Znając pojęcie modułu można tworzyć quasi-obiekty, przykładowo:
unit kolo;
interface
var sx, sy, pr, wzorzec, kolor :Word;
procedure inicjuj (x, y, r : Word);
procedure styl (k, w: Word);
procedure rysuj;
implementation
uses Graph;
procedure inicjuj;
begin
sx:=x;
sy:=y;
pr:=r;
kolor:= GetMaxColor; {na wypadek pominięcia wyboru koloru}
wzorzec:= SolidFill {i wzorca procedurą styl}
end;
procedure styl;
begin
kolor:=k;
wzorzec:=w;
end;
procedure rysuj;
begin
SetColor(kolor);
SetFillStyle (wzorzec, kolor);
FillEllipse(sx, sy, pr, pr);
end;
end .
unit ramka;
interface
var lgx, lgy, pdx, pdy, wzorzec, kolor :Word;
procedure inicjuj (x1, y1, x2, y2 : Word);
procedure styl (k, w: Word);
procedure rysuj;
implementation
uses Graph;
procedure inicjuj;
begin
lgx:=x1;
lgy:=y1;
pdx:=x2;
pdy:=y2;
kolor:= GetMaxColor;
wzorzec:= SolidFill
end;
procedure styl;
begin
kolor:=k;
wzorze:=w;
end;
procedure rysuj;
begin
SetColor(kolor);
SetFillStyle (wzorzec, kolor);
Bar3D(lgx, lgy, pdx, pdy, 0, TopOff);
end;
end .
Widoczne jest podobieństwo obu modułów, powtarzalność pewnych parametrów.
Zapisujemy obydwa moduły na dysku pod nazwami plikowymi takimi jak w nagłówkach modułów i kompilujemy na dysk (powstają dwa pliki z rozszerzeniem tpu). Umieszczamy je w katalogu UNITS. Wykorzystanie obu modułów mogłoby przykładowo wyglądać następująco:
program grafika;
uses crt, graph, kolo, ramka;
var st,tryb :integer;
znak:Char;
begin
repeat
writeln('1 - kolo, 2 - ramka. Wybieraj ');
znak:=Readkey
until (znak='1') or (znak='2')
st:=Detect; {detekcja sterownika graficznego}
InitGraph(st,tryb, 'C:\TP\BGI'); {zainicjowanie trybu graficznego}
case znak of
'1': begin
kolo.inicjuj( 10, 20, 50);
kolo.styl ( LightRed, SolidFill);
kolo.rysuj
end;
'2' : begin
ramka.inicjuj( 10, 10, 50, 50);
ramka.styl ( LightBlue, SlashFill);
ramka.rysuj
end
end;
repeat until keypressed;
CloseGraph
end.
Należy zwrócić uwagę na sposób wywołania procedur modułów (ze względu na identyczność nazw procedur odnosimy się do nazwy odpowiedniego modułu w konwencji podobnej jak w rekordach moduł.procedura)
Zwraca uwagę powtarzanie podobnych struktur programu, zwiększa się rozmiar programu i zmniejsza jego czytelność. Dodanie nowego obiektu wymaga nowego modułu.
Aby usunąć te niedogodności wprowadzono pojęcie obiektu.
Obiekt - złożona struktura posiadająca:
pola (właściwości opisane wartościami dowolnych typów, także strukturalnych)
metody (procedury i funkcje wykonywane na polach)
Typ obiektowy nazywamy klasą. Może on być niezależny, (zdefiniowany podobnie jak typ rekordowy) lub jako potomek istniejącego. Wtedy mówimy, że obiekt dziedziczy wszystkie elementy (pola i metody) swojego przodka lub jest typem potomnym. Obiekty potomne mogą mieć własnego potomka (lub wielu). Stąd wzajemne zależności obiektów układają się w drzewo hierarchii obiektów.
Dziedziczność bezpośrednia - przodek jest niezależny (sam nie ma przodka)
Dziedziczność pośrednia - przodek już dziedziczy (sam ma przodka)
Obiekty mogą opisywać własności obiektów rzeczywistych lub być abstrakcyjne.
Przykład:
type polozenie = object {obiekt niezależny}
x,y:integer;
end;
punkt = object (polozenie) {obiekt potomny}
widocznosc: Boolean
end;
Obiekt punkt jest zdefiniowany jako potomny obiektu polozenie dziedziczy jego własności x, y oraz posiada własne dodatkowe pole widocznosc.
Metody określają czynności na obiekcie - przy ich pomocy mamy dostęp do pól. Metoda jest to procedura lub funkcja mająca deklarację w ramach typu obiektowego (sam nagłówek procedury lub funkcji). Definicja metody występuje poza definicją typu obiektowego i po niej. W nagłówku definicji nazwa jest kwalifikowana, czyli wskazuje na obiekt, którego dotyczy i ma postać:
nazwa_typu_obiektowego . nazwa_metody
Przykład:
type polozenie = object {obiekt niezależny}
x,y:integer;
procedure przesun (nx, ny: Integer)
end;
procedure polozenie.przesun
begin
x:=nx;
y:=ny;
end;
Obiekty (klasy) grupuje się też modułach. W części opisowej modułu (interface) podajemy opisu obiektów, w części implementacyjnej zaś definiujemy metody. W części implementacyjnej mogą też wystąpić wewnętrzne definicje obiektów i innych zmiennych, typ obiektu zdefiniowany w części opisowej może też mieć swojego potomka w części implementacyjnej.
Potomek może mieć tę samą nazwę metody jak przodek, „przykrywa” ona wówczas metodę przodka. Definiując metodę potomka, (np. gdy jest ona rozszerzeniem metody nadrzędnej), można odwołać się do metody dziedziczonej od przodka.
Przykładowo, istnieje klasa osoba i jej metoda drukuj, wypisująca na ekranie nazwisko i imię osoby, oraz potomek uczen (poszerzony o pole klasa), którego metodę drukuj definiujemy:
procedure uczen.drukuj
inherited drukuj; {wywołanie metody dziedziczonej}
writeln('numer klasy :', klasa)
end;
Fakt, że dostęp do pól odbywa się jedynie przy użyciu metod nazywa się hermetyzacją. Jest to ważne z punktu widzenia dyscypliny programowania, w jednym miejscu mamy dane i dozwolone operacje na nich. Ułatwia to kontrolę poprawności złożonych programów. W tradycyjnym programowaniu niebezpieczne jest modyfikowanie struktur danych, konsekwencje takiej zmiany należy uwzględnić w całym programie. W programowaniu obiektowym zmiana dotyczy tylko obiektu.
Programowanie strukturalne: procedury i przekazywanie im danych.
Programowanie obiektowe: aktywacja metod dla umieszczonych w polach obiektu danych
Przykłady:
program obiekty1;
{deficja i wykorzystanie prostego typu obiektowego} uses crt; type TOsoba=object
nazwisko:string;
imie:string;
miasto:string;
procedure czytaj;
procedure pisz;
end;
procedure TOsoba.czytaj;
begin
readln(nazwisko);
readln(imie);
readln(miasto);
end;
procedure TOsoba.pisz;
begin
writeln('Oto dane osoby');
writeln(nazwisko);
writeln(imie);
writeln(miasto);
end;
var n,m,i:string;
czlowiek:TOsoba;
begin
clrscr;
czlowiek.czytaj;
czlowiek.pisz;
end.
program obiekty1_1;
{definicja i wykorzystanie prostego typu obiektowego tablicowego}
uses crt;
type TOsoba=object
nazwisko:string;
imie:string;
miasto:string;
procedure czytaj;
procedure pisz;
end;
procedure TOsoba.czytaj;
begin
writeln('Podaj dane osoby: nazwisko, imie, miasto');
readln(nazwisko);
readln(imie);
readln(miasto);
end;
procedure TOsoba.pisz;
begin
writeln('Oto dane osoby');
writeln('Nazwisko':nazwisko);
writeln('Imie: ',imie); writeln('Miasto: ',miasto); end;
var n,m,i:string; grupa:array[1..10] of TOsoba;
k:integer;
begin
clrscr;
for k:=1 to 10 do
grupa[k].czytaj;
for k:=1 to 10 do grupa[k].pisz;
end.
program obiekty2_1;
{dziedziczenie proste - wlasciwosci}
uses crt;
type TOsoba=object
nazwisko:string;
imie:string;
miasto:string;
procedure czytaj;
procedure pisz;
end;
TUczen=object(TOsoba) {typ dziedziczony od TOsoba}
ocena:2..5; {dodatkowe pole}
procedure czytaj_ocene; {dodatkowe metody}
procedure pisz_ocene;
end;
procedure TOsoba.czytaj;
begin
write('Podaj nazwisko:':20);
readln(nazwisko);
write('Podaj imie:':20);
readln(imie);
write('Podaj miasto:':20);
readln(miasto);
end;
procedure TOsoba.pisz;
begin
writeln;
writeln('Oto dane osoby':20);
writeln('Nazwisko:':20,nazwisko);
writeln('Imie:':20,imie);
writeln('Miasto:':20,miasto);
end;
procedure TUczen.Czytaj_ocene;
begin
write('Podaj ocene :':20);
readln(ocena);
end;
procedure TUczen.Pisz_ocene;
begin
writeln('Ocena:':20,ocena);
end;
var n,m,i:string;
k:1..5;
czlowiek:TOsoba;
student:TUczen;
grupa:array[1..5] of TUczen;
{poczatek programu}
begin
for k:=1 to 5 do
begin
clrscr;
writeln(k);
student.czytaj;
student.czytaj_ocene;
student.pisz;
student.pisz_ocene;
grupa[k]:=student
end;
for k:=1 to 5 do writeln(grupa[k].nazwisko);
repeat until keypressed
end.
program rysuj2;uses crt, graph, grafika;var st,tryb :integer;
znak:Char;
ob1:kolo;
ob2:ramka;
begin
repeat
writeln('1 - kolo, 2 - ramka. Wybieraj ');
znak:=readkey
until (znak='1') or (znak='2');
st:=Detect; {detekcja sterownika graficznego}
InitGraph(st,tryb, 'e:\TP\BGI'); {zainicjowanie trybu graficznego}
case znak of
'1': begin
ob1.inicjuj( 100, 200, 50);
ob1.styl ( LightRed, SolidFill);
ob1.rysuj
end;
'2' : begin
ob2.inicjuj( 10, 10, 50, 50);
ob2.styl ( LightBlue, SlashFill);
ob2.rysuj
end
end;
repeat until keypressed;
CloseGraph
end.
Przykład modułu z wykorzystaniem dziedziczenia.
unit grafika;
interface
type figura = object
wzorzec, kolor :Word;
procedure styl (k, w: Word);
end;
kolo = object (figura)
sx,sy,pr:Word;
procedure inicjuj(x, y, r : Word);
procedure rysuj;
end;
ramka = object (figura)
lgx,lgy,pdx,pdy:Word;
procedure inicjuj(x1,y1,x2,y2: Word);
procedure rysuj;
end;
implementation
uses graph;
procedure figura.styl;
begin
kolor:=k;
wzorzec:=w;
end;
procedure kolo.inicjuj (x, y, r : Word);
begin
sx:=x;
sy:=y;
pr:=r;
kolor:= GetMaxColor;
wzorzec:= SolidFill;
end;
procedure kolo.rysuj;
begin
SetColor(kolor);
SetFillStyle (wzorzec, kolor);
FillEllipse(sx, sy, pr, pr);
end;
procedure ramka.inicjuj(x1,y1,x2,y2:Word);
begin
lgx:=x1;
lgy:=y1;
pdx:=x2;
pdy:=y2;
kolor:= GetMaxColor;
wzorzec:= SolidFill;
end;
procedure ramka.rysuj;
begin
SetColor(kolor);
SetFillStyle (wzorzec, kolor);
Bar3D(lgx, lgy, pdx, pdy, 0, TopOff);
end;
end .
51
sekcja
instrukcji
blok
główny
Sekcja
deklaracji
Dopisanie na końcu
Przewijanie listy do końca NIL
Przepisanie wskazania do pomocniczej zmiennej
Pom1^.kod
to zawartość pola rekordu wskazywanego przez zmienną pom1
Zmienne tego typu wskazują na adres w pamięci
WYJĄTEK:
Użycie typu, który jest definiowany później
Typ wskaźnikowy
zamiana wartości zmiennych z użyciem pomocniczej zmiennej