background image

1

Wykład X

Języki programowania

Object Pascal: Proste typy 

danych

Podstawy informatyki
Semestr I Transport
Semestr II Elektrotechnika

background image

2

Interesuje nas 

wykonywanie algorytmów 

przy pomocy komputera

Naszym 

największym 

zainteresowaniem  są  jednak  objęte 
algorytmy  przeznaczone  do  wykonania 
przez  komputery,  a  zatem  powinniśmy 
poświęcić  nieco  czasu  na  odniesienie 
algorytmów 

do 

prawdziwych 

komputerów.

background image

3

Komputer potrafi zwykle 

wykonać niewielką ilość 

prostych operacji

Nawet  najbardziej  wyrafinowany  komputer  jest  w 

rzeczywistości  tylko  ogromną,  dobrze  zorganizowaną 

masą bitów i, co więcej, normalnie potrafi on wykonywać 

na  nich  jedynie  niewielką  liczbę  krańcowo  prostych 

operacji, 

takich 

jak 

zerowanie, 

przerzucanie 

i sprawdzanie.
W  jaki  sposób  przedstawiamy  algorytm  prawdziwemu 

komputerowi  i  jak  sprawiamy,  że  wykonuje  on 

odpowiedni proces tak, jak to zamierzono?
Powiedzmy  to  jeszcze  bardziej  bezceremonialnie.  Jak 

sprawiamy,  że  głupia  maszyna  o  tak  małych 

zdolnościach  w  imponujący  sposób  realizuje  nasze 

subtelne i starannie opracowane algorytmy?

background image

4

Algorytmy muszą być 

zapisane w jednoznaczny i 

formalny sposób

Pierwszym  spostrzeżeniem  jest  to,  że  nasze  algorytmy 

muszą  być  zapisane  w jednoznaczny  i  formalny 

sposób
Zanim  spróbujemy  zrozumieć,  w  jaki  sposób  obracając 

bitami  można  wypełnić  proste  zadanie,  np.  „przebiegnij 

listę,  dodając  każdą  płacę  do  liczby  «na  boku»”,  musimy 

zadanie to dokładnie określić odpowiadając na pytania:

– Gdzie komputer znajdzie tę listę?
– Jak ją przebiegnie?
– Gdzie znajdzie płacę i liczbę ,,na boku”? Itd.

Zadanie  „przebiegnij  listę”  nie  jest  wcale  wiele  bardziej 

dokładne  i  jednoznaczne  niż  „ubijaj  białka  aż  do 

spienienia”.

background image

5

Języki programowania, 

programy, programiści

Aby  opisać  algorytm  na  użytek  komputera, 
posługujemy  się  językiem  programowania,  
którym piszemy programy.
Program
 to oficjalne i formalne wydanie algorytmu, 
nadające się do wykonania przez komputer.
Język  programowania  składa  się  z notacji  i  reguł, 
według których pisze się programy, a osoba pisząca 
program zwie się programistą. (Ta osoba nie musi 
być  autorem  algorytmu,  na  którym  opiera  się 
program.)

background image

6

Programy wymagają 

precyzyjnej składni

Język  programowania  wiąże  się  zwykle  ze  sztywną  składnią, 

dopuszczającą używanie jedynie specjalnych kombinacji wybranych 

symboli i słów kluczowych.
Każda próba nadużycia tej składni może okazać się fatalna: jeśli np. 

napisze się wczytaj X w języku, którego instrukcje wczytywania są 

postaci 

wprowadź 

X

możliwe, 

że 

wynikiem 

będzie 

bezceremonialne  BŁĄD  SKŁADNIOWY  E5414  W  WIERSZU  108.  To 

oczywiście  wyklucza  nawet  tak  uprzejme,  ale  nieprecyzyjne 

żądania, jak „proszę wczytać wartość X z wejścia”.
To prawda,  że  uprzejme,  obszerne  instrukcje  są  przyjemniejsze  dla 

ludzi i być może są dla nich bardziej jednoznaczne niż ich zwięzłe i 

bezosobowe odpowiedniki; jest także prawdą, że chcielibyśmy, aby 

komputery  były  tak  przychylne  użytkownikowi,  jak  to  tylko  jest 

możliwe.  Jednakże  trzeba  przeciwstawić  te  fakty  aktualnemu 

brakowi  zdolności  rozumienia  przez  komputery  swobodnie 

mówionego (lub pisanego) języka naturalnego.

background image

7

Co zawiera formalna 

składnia języka 

programowania ?

Formalna  składnia  typowego  języka  programowania 

zawiera:
– systematyczne warianty kilku struktur sterujących,
– systematyczne  sposoby  definiowania  rozmaitych 

struktur danych 

– systematyczne wzorce podstawowych instrukcji. 
Muszą  one  należeć  do  zbioru  dopuszczalnych 

instrukcji  stosowanego  języka  programowania, 

ponieważ  komputer  nie  wykona  żadnej  instrukcji, 

nawet najbardziej jasnej i jednoznacznej, jeśli nie ma 

jej wśród tych, które dopuszcza dany język.

background image

8

Przykład

Algorytm sumowania liczb 

od 1 do N

W  typowym  (hipotetycznym) 

języku 

programowania 

JP 

można 

by 

zapisać, 

jak 

następuje:

wczytaj N;
X:=0;
dla od 1 do N wykonaj
X:=X+Y
koniec; wypisz X.

X:=0 

jest 

instrukcją 

przypisania,  która  nadaje 

zmiennej 

X 

wartość 

początkową  0  (w algorytmach 

zapisywaliśmy ją jako X←0).

Zwróć  uwagę  na  słowa  kluczowe 

zapisane grubszą czcionką; są one 

częścią składni JP
Oznacza  to,  że  formalna  definicja 

składni 

najprawdopodobniej 

zawiera klauzulę stwierdzającą, że 

jednym  z  poprawnych  rodzajów 

instrukcji  w  tym  języku  jest 

instrukcja-dla

której 

ogólny 

wzorzec  składa  się  ze  słowa 

kluczowego 

dla, 

po 

czym 

następuje  poprawny  nagłówek-

dla,  po  czym  następuje  wykonaj, 

po  czym  następuje  poprawna 

instrukcja,  po  czym  następuje 

koniec

background image

9

Notacja BNF (Backus-Naur 

Form, od nazwisk 

wynalazców)

Definicje składni można zapisać symbolicznie w notacji 

zwanej BNF w następujący sposób (,,|” oznacza ,,lub”):

<instrukcja>:<instrukcja-dla>|<instrukcja-

przypisania>|...
<instrukcja-dla>: 

dla  <nagłówek-dla> 

wykonaj 

<instrukcja> koniec
Opis klauzuli nagłówka mógłby brzmieć:

<nagłówek-dla>:  <zmienna>  od  <wartość>  do 

<wartość>

<wartość> można wtedy określić jako zmienną, jawnie 

podaną liczbę lub jakiś inny obiekt.

background image

10

Schematyczny sposób 

przedstawiania reguł 

składniowych

background image

11

Schematyczny sposób 

przedstawiania reguł 

składniowych

background image

12

Podobnie są narzucane 

wzorce definiowania 

struktur danych

 Np. tablicę TA o wymiarach 50 na 100, której wartości 

mogą być liczbami całkowitymi, można by zdefiniować 

w hipotetycznym języku JP instrukcją

definiuj TA tablica [1..50, 8..107] w niej liczby 

całkowite

a  język  mógłby  dopuścić  odwołania  do  elementów 

tablicy TA wyrażeniami postaci

TA(wartość, wartość)

Zauważ,  jak  określiliśmy  nie  tylko  wymiary  TA,  lecz 

także  jej  wartości  indeksów;  wiersze  tablicy 

ponumerowano  1,  2,  ...,  50,  ale  jej  kolumnom  (z 

jakiegoś powodu) nadano numery 8, 9, ..., 107.

background image

13

Składnia wyznacza 

znacznie więcej

W  rzeczywistości  składnia  wyznacza  znacznie 

więcej  niż  tylko  dostępne  struktury  sterujące  i 

struktury danych oraz operacje elementarne.
Zwykle  język  ma  sztywne  reguły  nawet  w  tak 

drobnych  kwestiach,  jak  poprawne  ciągi  symboli, 

których  można  używać  do  nazywania  zmiennych 

lub  struktur  danych,  i  maksymalna  liczba  cyfr 

dopuszczalna w wartościach numerycznych.
Niektóre 

języki 

ograniczają 

długości 

nazw 

zmiennych  do  najwyżej,  powiedzmy,  ośmiu 

symboli, z których pierwszy ma być literą alfabetu.

background image

14

Ważna jest także sprawa 

interpunkcji

W językach programowania nie należy do rzadkości 
wymaganie,  aby  po  pewnych  rodzajach  instrukcji 
następował  średnik,  a  po  innych  -  odstęp,  aby 
komentarze były ujęte w specjalne nawiasy, itd.
Biada  tym,  którzy  do  tych  wymagań  się  nie 
zastosują  (dopadnie  ich  zapewne  „choroba 
średnika”).
Niedługo  poznamy  szczegółowy  opis  składni 
konkretnego  języka  programowania,  z  regułami 
stosowania średników i całą resztą.

background image

15

Programy wymagają 

precyzyjnej semantyki

Wyposażenie  języka  w  precyzyjną  składnię  stanowi 

tylko  część  zadania  stojącego  przed  projektantem 

języka programowania.
Bez formalnej i jednoznacznej semantyki a więc bez 

znaczenia 

każdego 

wyrażenia 

dozwolonego 

składniowo, składnia jest niemal bezwartościowa.
Gdyby  nie  podano  znaczenia  instrukcji,  w  naszym 

hipotetycznym języku JP taki oto fragment programu

dla Y od 1 do N wykonaj

mógłby, oznaczać „odejmij Y od 1 i zapamiętaj wynik 

N”.

background image

16

Bez reguł semantycznych 

nie poznamy 

przeznaczenia instrukcji

Co  gorsza,  któż  powiedział,  że  słowa  kluczowe  dla

od,  do  itp.  mają  mieć  coś  wspólnego  z  ich 

znaczeniem w konwencjonalnej polszczyźnie?
A może ten sam fragment programu oznacza „wyzeruj 

całą  pamięć  komputera,  zmień  wartości  wszystkich 

zmiennych  na  0,  wypisz  »DO  DIABŁA  Z  JĘZYKAMI 

PROGRAMOWANIA« i zatrzymaj się!”?
Któż  powiedział,  że  „:=”  oznacza  „przypisz”  i  że  „+” 

oznacza  „plus”?  Któż  powiedział,  że  instrukcje 

wykonuje się w takiej kolejności, w jakiej są napisane? 

A  może  „;”  oznacza  „po  wykonaniu  tego,  co 

następuje”, nie zaś ,,a potem wykonaj, co następuje”?

background image

17

Na szczęście w językach 

znaczenia symboli są podobne do 

znaczeń w języku angielskim

Oczywiście  moglibyśmy  odgadnąć,  co  to  oznacza, 

ponieważ projektant języka JP tak dobrał zapewne słowa 

kluczowe  i  symbole  specjalne,  aby  ich  znaczenia  były 

możliwie najbardziej zbliżone do ogólnie przyjętych.
Ale komputer na podstawie takich przypuszczeń działać 

nie  może.  Gdyby  nawet  mógł  w  jakiś  sposób 

wywnioskować  konwencjonalne  znaczenie  słów  i  takich 

symboli,  jak  „+”,  skąd  wiedziałby,  bez  wyraźnego 

pouczenia, co zrobić z nagłówkiem pętli

dla Y od 1 do N wykonaj

gdy wartością N jest powiedzmy -314.1592?

background image

18

W poznawaniu składni i 

semantyki języka wspiera 

nas dokumentacja

Wydaje 

się 

zatem 

jasne, 

że 

język 

programowania  wymaga  nie  tylko  sztywnych 
reguł 

definiowania 

postaci 

poprawnego 

programu,  ale  także  równie  sztywnych  reguł 
definiowania jego znaczenia.
Projektanci  i  producenci  dostarczają  jednak 
szczegółową  dokumentację  języka,  całe  jej 
tomy.  Te  podręczniki  języka  zawierają 
bogactwo  informacji  dotyczących  zarówno 
składni, jak i semantyki.

background image

19

Przystępujemy do 

kodowania

Mamy  zatem  język  programowania  JP,  składnię, 

semantykę  i  całą  resztę,  i  właśnie  skończyliśmy 

opracowywanie  algorytmu  A  rozwiązania  pewnego 

zadania algorytmicznego.
Przystępujemy  teraz  do  zaprogramowania  tego 

algorytmu  w  języku JP, czynności określanej  niekiedy 

jako  kodowanie  A  w  JP,  i  chcemy  przedstawić 

powstały  program,  nazwijmy  go  A

P

  naszemu 

komputerowi.
Cóż dzieje się dalej? Odpowiedź brzmi, że w zasadzie 

istnieją  dwie  możliwości,  zależnie  od  tego,  jakiego 

języka i komputera użyjemy.

background image

20

Od algorytmu do języka 

maszynowego

Program  A

P

  możemy  wprowadzić  do  pamięci  komputera 

wystukując  go  na  klawiaturze,  wczytując  z  urządzenia 

takiego  jak  dysk,  odbierając  z  innego  komputera  za 

pośrednictwem elektronicznego kanału komunikacyjnego lub 

w  jakiś  inny  sposób  (same  nośniki  fizyczne  i  sposób  ich 

używania,  nas  tutaj  nie  interesują,  w przeciwieństwie  do 

tego, co dzieje się potem).
Program  A

P 

przechodzi  pewną  liczbę  przekształceń,  które 

stopniowo  sprowadzają  go  „w  dół”  do  poziomu,  na  którym 

komputer  już  może  sobie  poradzić.  Ostatecznym  wynikiem 

tych  przekształceń  jest  program  A

M

  na  poziomie  maszyny 

(mówi  się  o  nim  również,  że  jest  napisany  w  języku 

maszyny), gdyż już teraz komputer „rozumie” jego operacje 

podstawowe, takie jak instrukcje manipulowania bitami.

background image

21

Języki programowania 

wysokiego poziomu

Liczba  przekształceń  bywa  różna,  zależnie  od  języka  i 

komputera, ale najczęściej jest ich od dwóch do czterech. 
Obiektami pośrednimi  są zwykle poprawne programy  w coraz 

to  prymitywniejszych  językach  programowania.  Ich  repertuar 

struktur sterujących i struktur danych stopniowo, podobnie jak 

instrukcji  podstawowych,  staje  się  coraz  skromniejszy,  aż 

wreszcie 

pozostają 

jedynie 

najbardziej 

elementarne 

możliwości działania na bitach.
Dopiero po tej ostatecznej fazie przekształceń komputer może 

uruchomić (lub wykonać) pierwotny program A

M

.

Jest  już  dla  nas  teraz  oczywiste,  dlaczego  języki  takiego 

rodzaju  jak  ten,  w  którym  napisano  pierwotny  program 

użytkownika  A

P

,  nazywają  się  językami  programowania 

wysokiego poziomu

background image

22

Przypomina to 

podprogramy

Przekształcenia, 

których 

mówiliśmy 

przypominają  nieco  zastępowanie  procedur  ich 
treścią.
Na 

instrukcję 

języku 

programowania 

wysokiego  poziomu  można  patrzeć  jak  na 
wywołanie  podprogramu  lub  jak  na  instrukcję 
podstawową,  która  jednak  dla  komputera  nie 
jest dostatecznie podstawowa.
W  konsekwencji  trzeba  ją  uściślić  i  sprowadzić 
do poziomu kompetencji komputera.

background image

23

Kompilacja, asembler

Pomówmy o pierwszym przekształceniu, zwanym kompilacją, 

którym  program  wysokiego  poziomu  A

P

  zostaje  przetłumaczony 

na  program  A

S

  w  języku  niższego  poziomu,  zwanym  językiem 

adresów symbolicznych lub asemblerem.
Języki adresów symbolicznych różnią się dla różnych maszyn, ale 

z  reguły  stosuje  się  w  nich  dość  proste  struktury  sterujące, 

przypominające  instrukcje  skocz  oraz  konstrukcje  jeśli-to; 

operują  nie  tylko  bitami,  lecz  także  liczbami  całkowitymi  i 

ciągami symboli.
Mogą  one  odwoływać  się  bezpośrednio  do  adresów  w  pamięci 

komputera (ogromnego obszaru zawierającego całe stosy bitów), 

mogą  odczytywać  spod  tych  adresów  wszelkie  zakodowane 

liczby i napisy, i mogą tamże zapamiętywać kody liczb i napisów.

background image

24

Przykład (hipotetycznego) 

asemblera

Typową konstrukcję pętli wysokiego poziomu:

dla Y od 1 do N wykonaj
   <treść pętli>  koniec

można  przetłumaczyć  na  jej  odpowiednik  w  języku  adresów 

symbolicznych:

LDS 0,Y

(załaduj stałą 0 pod adres Y)

PĘTLA POR N, Y

(porównaj wartości pod adresami N i Y)

SKR RESZTA(jeśli równe, skocz do instrukcji o etykiecie RESZTA)
DDS 1,Y

(dodaj stałą 1 do wartości pod adresem Y)

    <przetłumaczona treść pętli>
SKO PETLA (skocz z powrotem do instrukcji o etykiecie PĘTLA)

RESZTA

(reszta programu)

background image

Przekształcanie 

programu 

wysokiego 

poziomu na kod 

maszynowy

Proces  kompilacji,  tłumaczący 

programy 

komputerowe 

wysokiego  poziomu  na  język 

adresów  symbolicznych  sam 

jest również wykonywany przez 

program 

komputerowy 

(kompilator)
Proces 

przekształcania 

na 

niższy 

poziom, 

którym 

kompilacja  jest  pierwszą  i 

najbardziej 

zawiłą 

częścią, 

ilustruje rys.
Pozostałe 

kroki 

tłumaczą 

asembler na język maszynowy. 

background image

26

Oprogramowanie 

systemowe

Warto  zaznaczyć,  że  kompilatory  różnych  języków 

wysokiego  poziomu,  jakie  obsługuje  dany  komputer, 

często  (choć  nie  zawsze)  należą  do  dużej  grupy  różnych 

programów  dostarczanych  przez  producenta  (komputera 

bądź 

systemu 

operacyjnego), 

zwykle 

zwanych 

oprogramowaniem systemowym.
Ich  ogólną  rolą  jest  ułatwianie  współpracy  z  komputerem 

na  wysokim  poziomie  i  jednoczesne  odgrodzenie 

użytkownika  od  wielu  szczegółów  niskiego  poziomu 

związanych  z  trybem  współpracy,  np.  uruchomieniem 

programów 

napisanych 

przez 

użytkownika, 

komunikowaniem się z innymi komputerami, sprzęganiem 

się ze specjalnym wyposażeniem zewnętrznym...

background image

27

Interpretatory i 

natychmiastowe 

wykonanie

Jest  jeszcze  inny  sposób,  w  jaki  komputery  wykonują 

przedstawione  im  programy,  który  nie  obejmuje 

tłumaczenia całego programu na język niższego poziomu.
Każda 

z instrukcji 

wysokiego 

poziomu 

zostaje 

przetłumaczona 

na 

instrukcje 

poziomu 

maszyny 

natychmiast  po  jej  napotkaniu,  a  te  z  kolei  od  razu  się 

wykonuje.  W  pewnym  sensie  interpreter  pełni  rolę 

„pseudoprocesora”  wykonując  instrukcje  wysokiego 

poziomu jedną po drugiej, dokładnie tak, jak są podane. 
Mechanizm  odpowiedzialny  za  to  lokalne  tłumaczenie  i 

natychmiastowe 

wykonanie 

jest 

też 

fragmentem 

oprogramowania 

systemowego, 

nazywanym 

interpretatorem (interpreterem).

background image

28

Zalety i wady 

interpretowania 

programów

Podejście interpretacyjne ma pewne oczywiste zalety, m.in.

zwykle  łatwiej  napisać  byle  jaki,  ale  użyteczny 

interpretator niż sensowny kompilator;
wykonywanie  prowadzone  przez  interpretator  pozwala  na 

łatwiejsze śledzenie i podsumowanie wykonania programu.

Są  jednak  cechy  interpretacji  niekorzystne  w  stosunku  do 

kompilacji
nie ma zwartego pliku wykonywalnego
trzeba  rozpowszechniać  kod  źródłowy  (trudno  ochronić 

prawa autorskie)
wolniejsze  wykonanie  (każdorazowo  trzeba  dokonywać 

interpretacji)

background image

29

Kompilować czy 

interpretować ?

To,  czy  komputer  będzie  kompilował,  czy 
interpretował  dany  program,  zależy  od 
przeznaczenia  danego  programu,  samego 
komputera, 

języka 

programowania, 

konkretnego 

pakietu 

oprogramowania 

systemowego, którego używamy.
Niektóre  języki  programowania  nadają  się  do 
interpretowania  bardziej  niż  inne,  wszystkie 
jednak mogą w zasadzie być kompilowane.

background image

30

Dlaczego nie 

algorytmiczne Esperanto?

Od czasu, gdy we wczesnych latach pięćdziesiątych 

zaczęły 

pojawiać  się  języki  programowania 

wysokiego  poziomu,  zaprojektowano  ich  setki  oraz 

napisano dla nich kompilatory i (lub) interpretatory, 

a  nadal  nowe  języki  pojawiają  się  jak  grzyby  po 

deszczu.
Dlaczego?  Czynie  byłoby  lepiej  mieć  jeden  język 

uniwersalny,  takie  algorytmiczne  Esperanto,  w 

którym  zapisywałoby  się  wszystkie  algorytmy  i 

którego  każdy  mógłby  się  łatwo  nauczyć?  Skąd 

taka  mnogość  języków?  Czym  się  różnią  ?  Kto 

używa których języków i w jakich celach?

background image

31

Dlaczego nie 

algorytmiczne Esperanto? 

Odpowiedź

Zasadniczo są dwie przyczyny tego zjawiska:

– nowe  osiągnięcia  sprzętowe  (choć  dziś  w  dużej 

mierze  udaje  się  uwolnić  wiele  języków  od 
bezpośredniego, ścisłego związku ze sprzętem).

– oraz nowe i zróżnicowane dziedziny zastosowań

;

Obie  stwarzają  zapotrzebowanie  na  nowe  języki 
programowania. 

Badania 

nad 

językami 

programowania  należą  do  z  najbardziej  się 
rozwijających  i przyciągających  powszechną  uwagę 
dziedzin informatyki.

background image

32

Badania nad językami 

programowania

Ludzie  chcą  języków  zarówno  uniwersalnych,  jak  i  przeznaczonych 

do szczególnych zastosowań oraz ich precyzyjnej definicji i sprawnej 

realizacji.
Wymyśla się wyrafinowane techniki kompilacji i tłumaczenia, proponuje 

się  nowe  struktury  sterujące  i  nowe  struktury  danych  oraz  wprowadza 

się  silne  mechanizmy  umożliwiające  programistom  definiowanie  ich 

własnych struktur danych.
Pożądane  są  języki  zachęcające  do  dobrego  stylu  programowania 

i wszyscy  próbują  zaprojektować  je  tak,  aby  zawrzeć  w  nich  rozmaite 

zalecane idee budowy algorytmów.
Badacze 

interesują 

się 

opracowaniem 

środowisk 

programistycznych,  czyli  przychylnych  użytkownikowi  systemów 

konwersacyjnych,  pozwalających  programiście  pisać,  redagować, 

zmieniać, wykonywać, analizować, poprawiać i symulować programy.
Fascynujące  badania  dotyczą  wizualnych  języków  programowania

umożliwiających rysowanie programów zamiast ich pisania.

background image

33

Uniwersalność języków 

programowania

Ostatnia  nasza  uwaga  dotyczy  uniwersalności  języków 

programowania.
W pewnym technicznym sensie praktycznie wszystkie języki 

programowania  są  równoważne  pod  względem  swojej  siły 

wyrazu.  Każde  zadanie  algorytmiczne  rozwiązywalne  w 

jednym  języku  jest  w  zasadzie  rozwiązywalne  również  w 

każdym innym języku.
Różnice  między  językami  są  pragmatyczne  i  dotyczą 

przydatności  do  pewnych,  zastosowań,  przejrzystości, 

struktury,  sprawności  realizacji  i  algorytmicznych  sposobów 

myślenia.
Wobec  znaczących  różnic  między  językami  programowania 

ten fakt może być przyjmowany jako coś niespodziewanego. 

background image

34

Wybór języka 

programowania

W tym miejscu rozpoczniemy kursu jednego 

z  języków  programowania:  Object  Pascala 

(czy jeśli ktoś woli Delphi dla Windows).
Pisanie  programów  w  tym  języku  będzie 

podstawowym 

elementem 

ćwiczeń 

realizowanych 

na 

laboratorium 

(w 

następnym semestrze).
Dziś  poznamy  jedynie  podstawowe  typy 

danych języka Object Pascal.

background image

35

Po co są typy danych ?

O  znaczeniu  właściwej  reprezentacji  reprezentacji 

danych mówiliśmy wiele wcześniej (wykład 2 i 8-9).
W  matematyce zmienne  klasyfikuje  się  zgodnie  z ich pewnymi 

istotnymi właściwościami.
Rozróżnia się zmienne rzeczywiste, zespolone i logiczne lub też 

zmienne  reprezentujące  pojedyncze  wartości,  zbiory  wartości, 

zbiory zbiorów, a także funkcje, funkcjonały, zbiory funkcji, itd.
W  przetwarzaniu  danych  klasyfikacja  zmiennych  jest  pojęciem 

równie ważnym (jeśli nie ważniejszym).
Każda  stała,  zmienna,  wyrażenie,  czy  funkcja  jest 

pewnego typu.
Typ  ten  dokładnie  charakteryzuje  zbiór  wartości,  do  którego 

może  należeć  stała,  bądź  jakie  może  przyjmować zmienna czy 

wyrażenie, bądź jakie mogą być generowane przez funkcję.

background image

36

Cechy charakterystyczne 

pojęcia typu

Typ  danych  określa  zbiór  wartości,  do  którego  należy  stała 

bądź  które  może  przyjmować  zmienna  lub  wyrażenie  albo 

które mogą być generowane przez operator lub funkcję.
Typ  wartości  oznaczonej  przez  stałą,  zmienną  lub  wyrażenie 

można określić na podstawie ich postaci bądź deklaracji , bez 

konieczności wykonywania procesu obliczeniowego.
Każdy  operator  lub  funkcja  ma  argumenty  ustalonego  typu, 

jak  również  daje  wynik  ustalonego  typu.  Jeśli  operator 

dopuszcza  argumenty  wielu  typów  (np.  „+”  oznacza 

dodawanie zarówno liczb całkowitych jak i rzeczywistych), to 

typ  uzyskiwanego  wyniku  jest  określany  za  pomocą 

specyficznych dla danego języka reguł.

 

background image

37

Typy nadają monotonnym 

bitom interpretację

W konsekwencji kompilator może korzystać z informacji o typach 

w celu sprawdzenia poprawności wielu konstrukcji.
Na  przykład  przypisanie  wartości  logicznej  (prawda-fałsz)  do 

zmiennej  arytmetycznej  (liczba)  może  zostać  wykryte  bez 

potrzeby wykonywania programu, na etapie jego kompilacji.
Ten  rodzaj  redundancji  w  tekście  programu  jest  niezwykle 

pomocny  przy  tworzeniu  programów  i  należy  go  uznać  za 

podstawową  zaletę  dobrych  języków  programowania  wysokiego 

poziomu  (w  stosunku  do  kodu  maszynowego  czy  też  kodu 

adresów symbolicznych).
Ostatecznie dane w pamięci będą stanowiły jednolitą masę bitów 

bez  jakiejkolwiek  struktury.  Jednakże  to  właśnie  ta  struktura 

abstrakcyjna  umożliwia  programistom  rozpoznawać  znaczenie 

danych w monotonnym krajobrazie pamięci maszyny.

background image

38

Moc typu

Liczbę  różnych  wartości  należących 
do  typu  T  nazywa  się  mocą 
(cardinalityT.
Moc  typu  pozwala  określić  wielkość 
pamięci 

potrzebnej 

do 

reprezentowania zmiennej x typu T.

background image

39

Typy standardowe

Ze 

względu 

na 

znaczenie 

reprezentacji 

informacji 

programiści 

mają 

możność 

definiowania nowych typów danych.
Oprócz  typów  definiowanych  przez  programistę 
muszą  istnieć  pewne  typy  standardowe 
(standard 

types), 

które 

są 

zdefiniowane 

wcześniej (przez producenta kompilatora).
W  Object    Pascalu  typy  standardowe  zawierają 
m.in.    liczby,  wartości  logiczne,  znaki  i 
łańcuchy tekstowe (ciągi znaków).

background image

40

Klasyfikacja 

najważniejszych typów 

danych w Object Pascalu

Typy proste

– Typy porządkowe

• Typ 

wyliczeniowy

• Typy logiczne
• Typy całkowite
• Typ znakowy

• Typy okrojone

– Typy rzeczywiste
– Typy łańcuchowe

Typy strukturalne

– Typy tablicowe
– Typ rekordowy
– Typ zbiorowy
– Typ plikowy

Typy wariantowe
Typy wskaźnikowe
Typy proceduralne
Typ obiektowy

background image

41

Typ logiczny

Dwie  wartości  standardowego  typu  logicznego  są 
najczęściej  oznaczane  identyfikatorami  false  i 
true.
Do  operatorów  logicznych  zaliczamy  koniunkcję 
(,  and,  iloczyn  logiczny),  alternatywę  (,  or

sumę logiczną) i negację (~, not).

p

q

pq

pq

~p

true

true

true

true

false

true

false

true

false

false

false

true

true

false

true

false

false

false

false

true

background image

42

Porównania dają wyniki typu 

logicznego

Zauważmy, 

że 

zastosowanie 

operatora 

porównania daje wynik typu logicznego.
W związku z tym wynik porównania może być 
przypisany do zmiennej logicznej  bądź użyty 
jako argument operatora logicznego.
Np.  dla  zmiennych  p  i  q  typu  logicznego  i   
zmiennych całkowitych x=5y=8z=10 dwie 
instrukcje  przypisania:  p:=x=y  i  q:=(x<y)   

(yz) dają w rezultacie p=false i q=true

background image

43

Typy logiczne w Object 

Pascalu

Przedstawione typy różnią się pomiędzy sobą sposobem 

reprezentacji danych w pamięci operacyjnej.

Typ

Rozmiar [B]

Boolean
ByteBool

1

WordBool

2

BOOL, LongBool

4

background image

44

Typ całkowity

Typ Integer (podstawowy z typów całkowitych) 
stanowi  podzbiór  wszystkich  liczb  całkowitych, 
którego  zakres  zależy  od  możliwości  danej 
maszyny.
Jednakże  zakłada  się,  że  wszystkie  operacje  na 
danych  tego  typu  są  dokładne  i  odpowiadają 
podstawowym  prawom  arytmetyki  oraz,  że 
wykonanie  programu  zostanie  przerwane  jeśli 
wynik  znajdzie  się  poza  reprezentowanym 
podzbiorem.

background image

45

Działania na danych typu 

całkowitego

Standardowe  operatory  dostarczają  tu  czterech 
podstawowych 

operacji: 

dodawania 

(+), 

odejmowania (-), mnożenia (*) i dzielenia (div)
Wprowadza  się  też  operację  „modulo”  (w  Pascalu 
mod)  spełniającą  równość  (m  div  n)*n+(m  mod 
n)=m
. Wobec tego m div n stanowi całkowitą część 
tego  ilorazu,  natomiast  m  mod  n  stanowi  resztę  z 
tego ilorazu.
Podobnie  operatory  działają  dla  pozostałych  typów 
całkowitych dostępnych w językach programowania.

background image

46

Typy całkowite w Object 

Pascalu

Typ

Zakres

Rozmiar 

[B]

Rozmia

r [b]

ShortInt

-128..127 (-2

7

..2

7

-

1)

1

8

Byte

0..255 (0..2

8

-1)

1

8

SmallInt

-32768..32767(- 

2

15..

2

15

-1)

2

16

Word

0..65535 (0..2

16

-1)

2

16

Integer, 
LongInt

-

2147483648..214

7483647

(-2

31

..2

31

-1)

4

32

Cardinal, 
LongWord

0..2

32

-1

4

32

Int64, 
Comp

*

-2

63

.. 2

63

-1

8

64

background image

47

Typ rzeczywisty

Oznacza  pewien  podzbiór  liczb  rzeczywistych.  Podczas 

gdy  zakłada  się,  że  arytmetyka  liczb  całkowitych  daje 

wyniki  dokładne,  to  dla  arytmetyki  liczb  rzeczywistych 

dopuszcza  się  wyniki  niedokładne  w  ramach  pewnych 

błędów  zaokrąglenia  spowodowanych  wykonywaniem 

obliczeń na skończonej licznie cyfr.
Jest  to  zasadniczy  powód  dla  którego  w  większości 

języków  programowania  wyraźnie  odróżnia  się  typy 

całkowite i rzeczywiste.
Oferowany  zestaw  działań  jest  tożsamy  z  zestawem 

zdefiniowanym  dla  liczb  całkowitych,  z  tym  że  dzielenie 

oznacza  się  symbolem  /  oznaczającym  dzielenie 
zwracające wartość rzeczywistą

.

background image

48

Typy rzeczywiste w Object 

Pascalu

Typ

Rozdzielczość..Z

akres***

Liczba 

cyfr 

znaczącyc

h****

Rozm

iar 

[B]

Single

1.510

-45

..3.410

38

7-8

4

Real48

*

2.910

-39

..1.710

38

11-12

6

Double, 

Real

5.010

-

324

..1.710

308

15-16

8

Extended

3.610

-

4951

..1.110

4932

19-20

10

Currency

**

-

922337203685477

.5808.. 

922337203685477

.5807

19-20

8

background image

49

Typ znakowy

Obejmuje zbiór znaków alfanumerycznych.
Niestety  jak  mówiliśmy  na  wcześniejszych  wykładach 

nie istnieje ogólnie przyjęty standardowy zbiór znaków 

stosowany we wszystkich systemach komputerowych.
Typ  znakowy  domyślnie  reprezentuje  obecnie  dane  z 

kodu  właściwego  dla  języka  systemu  operacyjnego 

kodu  ANSI.  Nie  należy  jednak  tego  uznawać  za 

niezmiennik 

sposób 

kodowania 

zależy 

od 

konkretnego  komputera  i  zainstalowanego  na  nim 

systemu  operacyjnego,  a  nawet  od  stosowanego 

oprogramowania  (możemy  np.  stosować  znaki 

standardu UNICODE).

background image

50

Założenia dotyczące 

zbioru znaków

Aby  konstruować  niezależne  od  komputera  algorytmy,  w 

których  korzysta  się  ze  znaków  musimy    przyjąć  pewne 

założenia dotyczące typu znakowego:
Zawiera znaki łacińskie, cyfry arabskie i pewną liczbę innych 

znaków graficznych, jak np. znaki przystankowe.
Podzbiory liter i cyfr są uporządkowane spójne, tzn.

– (‘A’x)  (x‘Z’)x jest literą
– (‘0’x)  (x‘9’)x jest cyfrą

Zawiera  znak  pusty  (spację),  którego  można  używać  jako 

separatora.
W  większości  języków  wprowadza  się  wzajemnie  odwrotne 

funkcje  pozwalające  dokonywać  konwersji  typu  znakowego 

na całkowity i odwrotnie.

background image

51

Typy znakowe w Object 

Pascalu

Do  oznaczenia  typu  znakowego  służą  predefiniowane 

identyfikatory  Char,  ANSIChar,  WideChar.  Elementami 

typu  znakowego  są  znaki  ANSI  (Char,  ANSIChar)  lub 

UNICODE  (WideChar),  z  których  każdy  jest  pamiętany  w 

jednym  (Char,  ANSIChar)  lub  na  dwóch  bajtach  pamięci 

(WideChar).

CHAR

ANSIChar

WideChar

Przykłady wartości typu znakowego:

’A’

’1’

#65 ^H

#$21’ß’

background image

52

Typy łańcuchowe

Typy  łańcuchowe  służą  do  reprezentowania  ciągu  znaków. 

Definicja  może  zawierać  (lub  nie)  ograniczenie  długości 

ciągu  znaków.  Podstawowym  typem  łańcuchowym  w 

Object Pascalu jest
String, ANSIString ShortString
String 
[rozmiar] 

ShortString[rozmiar]

gdzie rozmiar jest liczbą typu Byte. Brak 

wyspecyfikowania rozmiaru powoduje, że rozmiar jest 

zależny od długości przechowywanego tekstu (String, 

ANSIString do 2 gigabajtów tekstu -wartość maksymalna, 

zalecany format) lub dla typu ShortString jest stała i 

wynosi 255 znaków.
Istnieje odpowiednio typ WideString (UNICODE)

background image

53

Przykłady łańcuchów 

tekstowych

’Object Pascal jest jednym z języków 
programowania’
‘Kepler’’s law’
’’’’
^H (Ctrl-H)
#127 (znak Del)
#$7F (znak Del)
’Delphio’#$8^M

background image

54

Definiowanie własnych 

typów danych w Object 

Pascalu

Lokowane  jest  w  części  nagłówkowej 
programu 

bądź 

podprogramu 

(ich 

struktura  zostanie  przedstawiona  na 
następnych wykładach)

Składnia

type sekwencja-definicji-typów

gdzie każda definicja typu ma postać

identyfikator-typu=opis-typu;

background image

55

Typy wyliczeniowe

Najprostszą  narzucająca  się  metoda 
definicji  nowego  typu  danych  polega  na 
wyliczeniu wartości tworzących typ.
Np.  w  programie  dotyczącym  figur 
geometrycznych  można  określić  typ 
prosty o nazwie kształt, którego wartości 
mogą  być  oznaczone  identyfikatorami 
prostokątkwadratelipsaokrąg.

background image

56

Typy wyliczeniowe 

(enumerated)

W  wielu  programach    stosuje  się  liczby 

całkowite wtedy, gdy właściwości numeryczne 

nie  są  potrzebne,  a  liczba  całkowita 

reprezentuje  wybór  spośród  pewnej  małej 

liczby wartości.
W  tych  wypadkach  dobrze  jest  wprowadzić 

nowy  prosty  typ  danych  T,  wyliczając  zbiór 

wszystkich możliwych wartości c

1

, c

2

, ..., c

n

.

T=(c

1

, c

2

, ..., c

n

) 

Mocą typu jest wartość funkcji moc(T)=n .

background image

57

Przykłady typów 

wyliczeniowych

kształt=(prostokąt, kwadrat, elipsa, okrąg)
kolor=(czerwony, żółty zielony)
płeć=(mężczyzna, kobieta)
Boolean=(false, true)
dzieńtygodnia=(poniedziałek,  wtorek,  środa,  czwartek,  piątek, 

sobota, niedziela)

waluta=(euro, funt, dolar, korona, rubel, jen)
przeznaczenie=(piekło, czyściec, niebo)
środeklokomocji=(pociąg, autobus, samochód, statek, samolot)
ranga=(szeregowiec, kapral, sierżant, porucznik, major, pułkownik, 

generał)

obiekt=(stała, typ, zmienna, procedura, funkcja)
struktura=(plik, tablica, rekord, zbiór)

background image

58

Typy wyliczeniowe

są bardziej obrazowe

Definicja  typu  wyliczeniowego  wprowadza  nie  tylko  nowy 

identyfikator  typu,  ale  jednocześnie  zbiór  identyfikatorów 

oznaczających poszczególne wartości definiowanego typu.
Identyfikatorów  tych  można  używać  w  programie  jako 

stałych,  a  ich  wystąpienia  czynią  program  bardziej 

zrozumiałym.
Wprowadźmy na przykład zmienne r: ranga czy p: płeć.
Możliwe wówczas są przypisania p:=mężczyznar:=major.
Są  one  bardziej  obrazowe  niż  ich  numeryczne  odpowiedniki 

p:=0;  r:=4  oparte  na  założeniu,  że  do  oznaczeń  używamy 

liczb naturalnych według kolejności ich wyliczania.

background image

59

Uporządkowanie w typach 

wyliczeniowych

Ponadto  translator  może  dzięki  temu 

wykrywać  „nierozważne”  stosowanie 

operatorów  do  typów  nienumerycznych 

np. p:=p+1;
Wprowadza  się  jednak  operatory  funkcji 

generujących 

następnik 

bądź 

poprzednik argumentu.
Uporządkowanie 

wartości 

typu 

te 

określa następująca reguła (c

i

<c

j

)

(i<j)

background image

60

Typy okrojone

Często  się  zdarza,  że  zmienna  przyjmuje  wartości 

jedynie  z  pewnego  przedziału  wartości  określonego 

typu.
Wyraża  się  to  definiując  typ  okrojony,  zgodnie  z 

formatem  T=min..max,  gdzie  min  i  max  stanowią 

granice przedziału.
Przykłady

rok=1900..2099
litera=‘A’..’Z’
cyfra=‘0’..’9’
oficer=porucznik..generał

background image

61

(nie) Dozwolone użycie 

typu okrojonego

Dla zmiennych y: rok i L: Litera
– dozwolone  są  przypisania  y:=1973  i 

L:=‘W’

– natomiast 

niedozwolone 

y:=1291 

L:=‘9’.

Dopuszczalność  przypisań  y:=i  czy  L:=c
gdzie  i  jest  liczbą  całkowitą,  a  c  wartością 
znakową  można  sprawdzić  dopiero  podczas 
wykonania programu.


Document Outline