Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 357

1.

ELEMENTI PROGRAMSKIH JEZIKA

Prilikom definicije jezika polazi se od osnovnog skupa znakova, azbuke jezika koja sadri sve
zavrne simbole (terminalne simbole) jezika. Nad azbukom jezika definiu se ostali elementi
jezika, konstante, rezervisane rei, identifikatori od kojih se dalje grade druge sloene sintaksne
kategorije kao to su npr. opisi, upravljake naredbe i si.

1.1. Azbuka jezika


Azbuka jezika predstavlja osnovni skup simbola (znakova) od kojih se grade sve
sintaksne kategorije jezika. Broj znakova azbuke se obino razlikuje od jezika do jezika i kree
se od najmanje 48 do 90 znakova. Azbuka programskog jezika obino obuhvata skup velikih i
malih slova engleske abecede, skup dekadnih cifara i odreeni skup specijalnih znakova. Dok je
kod starijih programskih jezika bilo uobiajeno da se koriste samo velika slova (na primer
FORTRAN IV), danas se skoro redovno dozvoljava i ravnopravno korienje malih slova
abecede. Azbuke programskih jezika se najvie razlikuju po skupu specijalnih znakova koje
obuhvataju. Narednih nekoliko primera azbuka programskih jezika to ilustruje.
Azbuka jezika Pascal:
slovo: "A" | " B "
"O" | "P"
"a" | "b"
"n" | "o"

| " C " | " D " | " E " | " F " | " G " | " H" | " l " | " J " | " K " | "L" | "M" | "N" |
| "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y"| "Z"|
| "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k"| "l" | "m" |
| "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" |

cifra: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
specijalni znak: "+" | "-" | "*" | "/" | "=" | " < " | " > " | " [ " | "]" | "." | "," | ";" |
":" | "^" | "(" | ")" | "'" | "<>" | "<=" | ">=" | ":=" | ". ." |
rezervisana re: "AND" | "ARRAY" | "BEGIN" | "CASE" | "CONST" | " D I V " |
"DOWNTO" | "DO" | "ELSE" | "END" | " F I L E" | " FO R" |
"FU NCTION" | "GOTO" | " IF" | "IN" | "LABEL" | "MOD" | "NIL" | "NOT" | "OF" |
"OR" | "PACKED" | "PROCEDURE" | "PROGRAM" | "RECORD" | "REPEAT" |
"SET" | "THEN" | "TO" | "TYPE" | "UNTIL" | "VAR" | "WHILE" |"WITH"

Azbuka jezika C
velika slova: A| B| C | D| E | F | G | H | I | J | K | L | M | N | 0 | P|Q| R|S|T|U | V | W | X | Y | Z
cifre: 0 |1 |2|3|4|5|6|7|8|9
specijalni znaci: + | - | * | / |= | ( | ) | { \ } \ [ | ] \ < | > | ' | " | ! | # | \ | % | & | | |
|_| ^| |~ \, \ ; |:|?
znak blanko
mala slova: a | b | c | d | e | f | g | h | i | j | k|l | m | n |o | p | q |r | s | t | u | v |w |x |y|z

Azbuka jezika Ada


velika slova: A| B| C | D| E | F | G | H | I | J | K | L | M | N | 0 | P|Q| R|S|T|U | V | W | X | Y | Z
cifre: 0 |1 |2|3|4|5|6|7|8|9
specijalni znaci: " | # | & | ' | ( | ) | * | + | , | - | / | : | ; | < | = | > | _ | /
znak blanko
mala slova: a | b | c | d | e | f | g | h | i | j | k|l | m | n |o | p | q |r | s | t | u | v |w |x |y|z
drugi specijalni znaci: ! | $ | % | @ | [ | ] | ^ | ' | { | } | ~

Danas se obino skup specijalnih znakova azbuke programskog jezika standardizuje i svodi
na skup znakova meunarodnog standardnog koda ISO7 (ASCII kod).
b | ! | " | $ | % | & | ' | ( | ) | * | + | , | - | . | / | : | ; | < | = | > | ? | @ | [ | ] | \ | ^ ili _ | ` | { | } | ~

eto se pored osnovnog skupa specijalnih znakova koriste i sloeni simboli, obino
dvoznaci, kao na primer:
| ** | >= | <= | => | =< | << | <> | >< | := | -> | /* | */ |
U nekim programskim jezicima (FORTRAN), zbog nedovoljnog broja odgovarajuih
znakova umesto specijalnih znakova koriste se posebne simbolike oznake .EQ., .NE., .GT.,
.GE., .LT., .LE., kojima se oznaavaju relacije jednako, razliiti, vee, vee ili jednako, manje i
manje ili jednako, redom.

1.2. Identifikatori i rezervisane rei


Identifikatori su uvedene rei kojima se imenuju konstante, promenljive, potprogrami,
programski moduli, klase, tipovi podataka i slino.
U svim programskim jezicima postoji slina konvencija za pisanje identifikatora.
Identifikatori su nizovi koji se obino sastoje od slova i cifara i obavezno zapoinju slovom. Ovo
ogranienje omoguava jednostavniju implementaciju leksikog analizatora i razdvajanje
identifikatora od drugih sintaksnih kategorija (numerikih i znakovnih konstanti na primer). U
nekim jezicima dozvoljeno je da se i neki specijalni znaci pojave u okviru identifikatora. Najee
je to crtica za povezivanje "_" kojom se postie povezivanje vie rei u jedan identifikator. Na
primer, u jeziku C crtica za povezivanje se moe koristiti na isti nain kao i slova, to znai da
identifikator moe da zapone ovim znakom. Slede primeri nekih identifikatora:
ALFA

B1223

Max_vrednost

PrimerPrograma

U jeziku C velika i mala slova se razlikuju. Programski jezik PASCAL ne razlikuje velika i
mala slova.
Dobra je programerska praksa da identfikatori predstavljaju mnemonike skraenice.
Nizovi znakova azbuke koji u programu imaju odreeni smisao nazivaju se lekseme.
Leksema moe da bude i samo jedan znak.
Re jezika ije je znaenje utvreno pravilima tog jezika naziva se rezervisana re.
Rezervisane rei mogu da budu zabranjene, kada se ne mogu koristiti kao identifikatori u
programu. Takav je sluaj u programskom jeziku C. Meutim, i u jezicima u kojima je to
dozvoljeno ne preporuuje se korienje kljunih rei kao identifikatora jer moe da smanji
preglednost programa, a u nekim sluajevima da dovede i do ozbiljnih greaka u programu.
Poznat je, na primer, sluaj greke sa DO naredbom koji je doveo do pada letilice iz satelitskog
programa Geminy 19. U programu za upravljanje letilicom stajala je DO naredba nagisana kao:
DO 10 I = 1. 10
umeto ispravnog koda
DO 10 I = 1, 10.

Predrag S. Stanimirovi

Programski jezici

Greka pri prevoenju meutim nije otkrivena jer je leksiki analizator ovu liniju koda
protumaio kao naredbu dodeljivanja
D010I = 1.10
u kojoj se promenljivoj D010I dodeljuje vrednost 1.10. Greka je otkrivena tek u fazi
izvravanja programa kada je prouzrokovala pad letilice.
Rezervisane rei jezika C:
auto, break, case, char, const, continue, default, do, double, else, enum, extern, float, for, goto, if, int,
long, register, return, short, signed, sizeof, static, struct, switch, typedef, union, unsigned, void, voatile,
while.

U poreenju sa ostalim programskim jezicima, C poseduje mali broj slubenih rei.


Kod nekih programskih jezika (COBOL) potoje kategorije obaveznih rei i kategorija
neobaveznih rei. Obavezne rei ne smeju da budu izostavljene iz naredbe u kojoj je po sintaksi
definisana njihova upotreba i na osnovu njih kompilator analizira i prevoi naredbu, dok
neobavezne rei imaju samo dokumentacioni karakter i upotrebljavaju se da dopune naredbu i
njen tekst priblie govornom jeziku. Razmotrimo sledei primer definicije naredbe READ
kojom se ita slog datoteke:
READ ime -dato teke [ NE XT ] RECORD [INTO im e - p o d a t k a ] AT END i s k a z

Rei READ, NEXT, INTO i END su obavezne prilikom pisanja odgovarajuih delova
naredbe, njima je odreena sintaksa naredbe, odnosno koristi ih sintaksni analizator pri
prevoenju naredbe. Rei RECORD i AT su neobavezne, ali se mogu koristiti da bi se poveala
jasnoa naredbe.

1.3. Konstante
Bilo koji niz znakova u programu, posmatran nezavisno od njegovog logikog znaenja,
nad kojim se mogu izvravati odreena dejstva (operacije) naziva se podatak. Deo podatka nad
kojim se mogu izvravati elementarne operacije naziva se element podatka. Elementu podatka
u matematici priblino odgovara pojam skalarne veliine. Podatak je ureeni niz znakova
kojim se izraava vrednost odreene veliine.
Veliina koja u toku izvravanja programa uvek ima samo jednu vrednost, koja se ne moe
menjati, naziva se konstanta. Kao oznaka konstante koristi se ona sama. U nekim programskim
jezicima (Pascal, Ada, C) postoji mogunost imenovanja konstante. Konstantama se dodeljuju
imena koja se u programu koriste umesto njih. Na taj nain nastaju simbolike konstante.
Tipovi konstanti koje se mogu koristiti u odreenom programskom jeziku odreeni su
tipovima podataka koje jezik predvia.
U jeziku C koristi se vie vrsta konstanti i to su:
- celobrojne konstante;
- relane konstante;
- karakteri: 'a', 'b', ... ;
- stringovi: sekvence karaktera izmeu navodnika.
Slede neki primeri razliitih vrsta konstanti:
Celobrojne dekadne konstante: 1; 50; 153; +55; -55
Realne konstante u fiksnom zarezu: 3.14; 3.0; -0.314; -.314; +.314
Realne konstante u pokretnom zarezu:
3.14 E 0; -0.314 E 1; -.314 E +0; +.314 E -2 (FORTRAN, Pascal, Ada, C)

4
Realne konstante dvostruke tanosti:
3.14 D0;-3,14 Dl;+.314 D2 (FORTRAN)
Kompleksne konstante:
(3.14, 0.13);(0, -23) (FORTRAN)
3.14+0.13 I (MATHEMATICA)
Oktalne konstante (C): 0567; 0753; 0104
Heksadecimalne konstante (C): 0X1F; 0XAA; 0X11
Long konstante (C): 123L; 527L;321L;+147L
Logike konstante: true; false (Pascal, Ada)
.TRUE.; .FALSE. (FORTRAN)
Znakovne konstante: 'A'; 'B' (Pascal, Ada, C)
String konstante: "Beograd"; "Alfa 1" (Pascal, C)
Simbolike konstante: ZERO; ZEROS; SPACE (COBOL)
Pi, E (MATHEMATICA)
Racionalni brojevi: 2/3; -4/5 (MATHEMATICA)
Poznate simboli~ke konstante u paketu MATHEMATICA imaju svoja posebna,
rezervisana imena:
Pi
3.14159
E
e2.71828
Degree /180: faktor konverzije stepena u radijane
I
i= 1
Infinity

1.4. Promenljive
Veliine ije se vrednosti menjaju u toku izvravanja programa nazivaju se promenljive.
Promenljivoj se u programu dodeljuje ime, i u svakom trenutku ona je definisana svojom
vrednou. Kaemo da je svaka promenljiva u programu povezana sa tri pojma:
imenom
- identifikatorom promenljive.
referencom - pokazivaem koji odreuje mesto promenljive u memoriji i
vrednou - podatkom nad kojim se izvravaju operacije.
Veza izmeu imena, reference i vrednosti promenljive moe se predstaviti sledeim
dijagramom:
ime

referenca

vrednost

Ovaj dijagram u sluaju imenovane konstante dobija oblik:

ime

vrednost

Na primer naredbu dodeljivanja X := 3.141592 itamo: X dobija vrednost 3.141592, pri


emu imamo u vidu da je X simboliko ime memorijske lokacije gde se u toku izvravanja
programa pamti vrednost 3.141592. Pri tome je potrebno imati na umu sledee pojmove:

Predrag S. Stanimirovi

Programski jezici

vrednost 3.141592, koja predstavlja vrednost promenljive X,


adresu memorijske lokacije u kojoj se pamti vrednost broja 3.141592,
ime promenljive X, identifikator koji se u datom programu koristi kao ime promenljive
koja ima datu brojnu vrednost.

1.5. Komentari
U svim programskim jezicima postoji mogunost proirenja izvrnog koda programa
komentarima kojima se kod dodatno pojanjava. Ovi komentari se u toku prevoenja programa
ignoru od strane kompilatora i ne ulaze u sastav izvrnog koda koji se generie prevoenjem
programa. Meutim komentari su veoma vaan deo programa kojim se podeava njegova
dokumentarnost, i bitno utiu na efikasnost analize programa. Konvencija za zapisivanje
komentara se razlikuje od jezika od jezika. Slede primeri komentara u nekim programskim
jezicima:
{Komentari se u Pascal-u zapisuju izmeu velikih zagrada.}
-- Komentari u jeziku Ada zapoinje sa dve crtice i mogu
-- da se nau bilo gde u programu.
/* Ovo je primer komentara u jeziku C */
// Kratak C komentar u okviru jednog reda
(* Komentar u PASCAL-u i jeziku MATHEMATICA *)

Svakoj funkciji u paketu MATHEMATICA se moe dodeliti kratak tekst u kojem se opisuje
ta funkcija radi i kakve parametre oekuje. Ovakav opis se funkciji f dodeljuje kao vrednost
simbola f::usage, a dobija se pomou naredbe ?f.
f::usage="tekst"
?f
??f

@
D@
@
DD
@
D
@D

dodeljivanja opisa funkciji f


informacije o funkciji f
detaljnije informacije o funkciji f

f x_ := x^2
f::usage = "f x kvadrira x"
f x kvadrira x
?? f
f x kvadrira x

f x_ := x2

1.6. Struktura programa


Globalna struktura programa zavisi od toga da li jezik zahteva deklaraciju tipova promenljivih
kao i da li su u jeziku zastupljeni stariji koncepti sa implicitnim definicijama tipova promen Ijivih
ili je zastupljen noviji koncept sa eksplicitnim definicijama.

1.6.1. Struktura programa u FORTRAN-u


Kod jezika koji dozvoljavaju implicitne definicije tipova podataka program moe da se
sastoji samo od izvrnog dela kojim se kodira algoritam koji se programom realizuje. Primer
takvog jezika je FORTRAN. U ovom jeziku moe se napisati program koji sadri samo izvrne
naredbe, a da se pri tome tip promenljivih odreduje implicitno po poetnim slovima njihovih
imena. Sledei primer je ilustracija jednog takvog programa.
Primer. Program u jeziku FORTRAN 77.
C Moe da se zapone odmah izvrnim delom

100

A = 0.
B = A
WRITE (*, 100) A, B
FORMAT (1H, 2F8. 3)
END

Vei broj jezika danas podrava koncept eksplicitnih definicija tako da programi u ovim
jezicima imaju strukturu modula koji se sastoji od dela sa specifikacijama tipova podataka i
samih podataka i izvrnog dela u kome se kodira algoritam koji se realizuje. Ova struktura
zastupljena je u mnogim savremenim jezicima pa emo napraviti mali pregled nekih od njih.

1.6.2. Struktura programa u Pascal-u


Programi u Pascal-u se sastoji iz sledeih elemenata, redom:
- odeljak deklaracija obeleja,
- odeljak definicija konstanti,
- odeljak definicija tipova,
- odeljak deklaracija promenljivih,
- odeljak deklaracija procedura i/ili funkcija, i
- izvrni deo programa obuhvaen izmeu begin i end.
Primer. Struktura programa u Pascal-u,
program Primer (input, output); {Zaglavlje programa}
const n = 10; {Opis konstanti}
type {Definicije tipova}
Vektor = array{l..10] of integer;
var {Deklaracije promenljivih}; :
a, b : integer;
v : Vektor;
begin {Poetak tela samog programa}
{...}
end. {Kraj glavnog programa}

Primer. Jednostavni program u Pascal-u.


Definisati konstantu PI=3.14159 a zatim izraunati vrednosti 2*PI, SIN(2*PI) i COS(2*PI).
Rezultate prikazati u fiksnom zarezu sa dva decimalna mesta.
PROGRAM dvapi (output);
{izlaz sa dve decimale}
CONST
pi= 3.14159;
BEGIN
WRITELN(2*pi:8:2,sin(2*pi):8:2, cos(2*pi):8:2);
END.

1.6.3. Struktura programa u C


Programi pisani u C-u imaju strukturu bloka, ali se za ograniavanje bloka koriste vitiaste
zagrade umesto zagrada be gi n i end. Zastupljen je takoe stariji koncept bloka, poznat iz
jezika Algol 60 i PL/1, gde se opisi elemenata koji pripadaju jednom bloku nalaze unutar
zagrada { i }, za razliku od novijeg koncepta koji smo imali u primerima iz Pascal-a, kod kojih
opisi elementa bloka prethode zagradi be gin kojom se otvara blok. Svaki blok u C-u takoe
moe da sadri opise promenljivih i funkcija.
C program se moe nalaziti u jednom ili vie fajlova. Samo jedan od tih fajlova (glavni
programski modul) sadri funkciju main sa kojom zapoinje izvrenje programa. U programu se

Predrag S. Stanimirovi

Programski jezici

mogu koristiti funkcije iz standardne biblioteke. U tom sluaju se moe navesti direktiva
pretprocesora oblika
#include <ime>.
esta je direktiva oblika #include<stdio.h> kojom se ukljuuju funkcije iz fajla stdio.h (standard
input/output header).
Glavni program, main(), takoe predstavlja jednu od funkcija. Opis svake funkcije se sastoji
iz zaglavlja i tela funkcije. U ovom sluaju, zaglavlje funckije je najjednostavnije, i sadri samo
ime funkcije i zagrade (). Iza zaglavlja se navodi telo funkcije koje se nalazi izmeu zagrada
{ i }. Izmeu ovih zagrada se nalaze operatori koji obrazuju telo funkcije. Svaki prost operator
se zavrava znakom ';' a sloeni operator se pie izmeu zagrada { i }. .
U jeziku C sve promenljive moraju da se deklariu. Opti oblik jednostavnog programa je:
void main()
{
<deklaracije>
<naredbe>
}

Primer. Prikazivanje teksta na ekranu.


#include <stdio.h>
void main()
{
printf("Prvi primer\n");

2. TlPOVI PODATAKA

Jedan od najznaajnijih pojmova u okviru programskih jezika je pojam tipa podataka. Atribut
tipa odreuje skup vrednosti koje se mogu dodeljivati promenljivima, format predstavljanja
ovih vrednosti u memoriji raunara, skup osnovnih operacija koje se nad njima mogu izvravati
i veze sa drugim tipovima podataka. Na primer, promenljivoj koja pripada celobrojnom tipu
mogu se kao vrednosti dodeljivati samo celi brojevi iz odreenog skupa. Nad tako definisanim
podacima mogu se izvravati osnovne aritmetike operacije sabiranja, oduzimanja, mnozenja,
deljenja, stepenovanja, kao i neke specifine operacije kao to je odreivanje vrednosti jednog
broja po modulu drugog.
Koncept tipova podataka prisutan je, na neki nain, ve kod simbolikih asemblerskih jezika
gde se za definiciju tipa koriste implicitne definicije preko skupa specijalnih znakova kojima se
odreuju podaci razliitog tipa.

8
Kod viih programskih jezika tip podataka moe da bude definisan implicitno po odreenom
automatizmu (dogovoru), preko implicitnog opisa tipa ili preko eksplicitnih definicija tipova.
Kao primer moe da se uzme jezik FORTRAN kod kojeg postoje sva tri tipa definicija.
Deklaracija tipa promenljive u FORTRANU moe se izvriti na tri naina: unutranjom
konvencijom, eksplicitnom i implicitnom deklaracijom.

Unutranja konvencija
Unutranja konvencija FORTRAN-jezika oslobaa programera od posebne deklaracije tipa
promenljive, i predpostavlja da je deklaracija izvrena samim izborom imena promenljive. Ova
konvencija se sastoji u sledeem:
ako ime promenljive pocinje slovom I, J, K, L, M ill N, to je celobrojna promenljiva,
ako ime promenljive ne pocinje jednim od navedenih slova, to je realna promenljiva.
Primer. Celobrojne promenljive po unutrasnjoj konvenciji su:
I J 125 IAB MASA NETO Po istoj konvenciji sledee
promenljive su realnog tipa:
A B A34 XYZ CENA BRUTO

Eksplicitna deklaracija
Da bi se omoguilo imenovanje promenljivih u suprotnosti sa unutranjom konvencijom,
uvode se opisne naredbe kojima se moe deklarisati tip promenljive po elji programera.
Deklaracija tipa promenljive opisnim naredbama, moe biti: eksplicitna i implicitna. I jedna i
druga deklaracija su starije od unutranje konvencije FORTRAN-jezika.
Opti oblik eksplicitne deklaracije tipa promenljive je
tip lista
gde su: tip - slubena re INTEGER, REAL ili ime nekog drugog tipa.
lista - imena promenljivih meusobno razdvojena zarezima.
Promenljive u listi se deklariu kao celobrojne ako je navedena slubena re INTEGER,
odnosno kao realne ako je navedena re REAL.
Primer: Naredbe
INTEGER A, GODINA, B12
REAL JOT, MASA, 16
deklariu, u programu na ijem se poetku nalaze, promenljive A, GODINA i B12 kao
celobrojne, a JOT, MASA i 16 kao realne.

Implicitna deklaracija
Eksplicitna deklaracija slui za deklarisanje tipa promenljive po konkretnom imenu
promenljive. Pored ovakve deklaracije, moe se tip promenljive deklarisati po poetnom slovu
imena promenljive. Ovakva deklaracija se zove implicitna deklaracija tipa promenljive i zadaje
se opisnom naredbom
IMPLICIT lista
gde je IMPLICIT slubena re, a lista se sastoji od elemenata koji se meusobno razdvajaju
zarezima, oblika
tip (lista1)
gde su:

tip - slubena re INTEGER ill REAL,

Predrag S. Stanimirovi

Programski jezici

lista1 - velika slova latinske azbuke, koja se meusobno razdvajaju zarezima.


Znaenje ove naredbe je sledee: sve promenljive u programu ija imena poinju slovima
navedenim u lista1, pripadaju po tipu celobrojnim ili realnim promenljivim, saglasno slubenoj
rei (INTEGER ili REAL), koja stoji namesto rei tip.
Ako se u jednom programu koriste sve tri vrste deklaracije, tada je eksplicitna deklaracija
najvieg prioriteta, zatim implicitna i na kraju unutranja konvencija. Deklaracije promenljivih
se navode na poetku programa, pri emu se prvo navodi IMPLICIT-deklaracija.
Primer: Naredba za implicitnu deklaraciju
IMPLICIT REAL(I.J), INTEGER(A-F,Q)
deklarie promenljive ija imena poinju slovima I i J kao realne promenljive, a promenljive
cija imena poinju slovima A, B, C, D, E, F i Q kao celobrojne promenljive.
Na osnovu toga kako je postavljen koncept tipova podataka programski jezici mogu da se
svrstaju u dve grupe: na programske jezike sa slabim tipovima podataka i na jezike sa jakim
tipovima podataka.

2.1. Koncept slabih tipova


U sluaju jezika sa slabim tipovima podataka informacija o tipu promenljive koristi se, i
korektna je samo na mainskom nivou, u fazi izvrenja programa. Ovako postavljen koncept
podrazumeva sledee mogunosti:
(1) Operacija koja se od strane kompilatora prihvati kao korektna, na nivou izvornog koda
programa, moe da bude potpuno nekorektna. Razmotrimo sledei primer:
var
c : char;
c := 4;

Promenljiva c definisana je da pripada tipu c har, to podrazumeva da joj se kao vrednosti


dodeljuju znaci kao podaci. Meutim umesto korektnog dodeljivanja c:='4', promenljivoj c je
dodeljena vrednost broja 4 kao konstante celobrojnog tipa. Kod jezika sa slabim tipovima
podataka kompilator ne otkriva ovu greku i informaciju o tipu koristi samo na mainskom
nivou kada promenljivoj c dodeljuje vrednost jednog bajta memorijske lokacije u kojoj je
zapisana konstanta 4. Oigledno je da ovako postavljen koncept tipova moe da dovede do
veoma ozbiljnih greaka u izvravanju programa koje se ne otkrivaju u fazi kompilovanja
programa.
(2) Koncept slabih tipova podrazumeva odreeni automatizam u transformaciji tipova
podataka u sluaju kada se elementi razliitih tipova nalaze u jednom izrazu ija se vrednost
dodeljuje promenljivoj odreenog tipa. Razmotrimo sledei primer:
var
x, y : real ;
i, j, k : integer;
i:= x;
k:= x-j ;

Promenljive x i y su realne (tipa real), a i, j i k celobrojne ( i n t e g e r tipa). Naredbom i:=x;


vri se dodeljivanje vrednosti tipa re a l promenljivoj celobrojnog tipa. Kod jezika sa slabim
tipovima ovo dodeljivanje je dozvoljeno iako se pri tome x svodi na drugi format i pravi greka
u predstavljanju, njegove vrednosti. Kod ovako postavljenog koncepta tipova, da bi se napisao
korektan program potrebno je tano poznavati mehanizme transformacije tipova. U drugoj
naredbi iz primera (k:=x-j;) od broja x koji je tipa real treba oduzeti broj j, tipa i n t e g e r i

10
rezultat operacije dodeliti promenljivoj tipa i n t e g e r. Da bi smo bili sigurni u korektnost
rezultata potrebno je da znamo redosled transformacija koje se pri tome izvravaju, odnosno da
li se prvo x prevoi u i nt e g e r i onda izvrava oduzimanje u skupu celih brojeva i vrednost
rezultata dodeljuje promenljivoj tipa i n t e g e r ili se j prevoi u tip r e a l , izvrava sabiranje u
skupu realnih brojeva, a zatim rezultat prevoi u tip i nt eger i dodeljuje promenljivoj k.
Koncept slabih tipova podataka doputa puno slobode kod zapisivanja izraza u naredbama
dodeljivanja; meutim cena te slobode je nejasan program sa skrivenim transformacijama, bez
mogunosti kontrole i korienja informacije o tipu u fazi kompilovanja programa.

2.2. Koncept jakih tipova podataka


Koncept jakih tipova podataka obuhvata nekoliko osnovnih principa:
Tip podataka odreuju sledei elementi:
-

skup vrednosti,
format registrovanja podataka,
skup operacija koje se nad podacima mogu izvravati,
skup funkcija za uspostavljanje veza sa drugim tipovima podataka.

Sve definicije tipa moraju da budu javne, eksplicitne. Nisu dozvoljene implicitne
definicije tipova.
Objektu se dodeljuje samo jedan tip.
Dozvoljeno je dodeljivanje vrednosti samo odgovarajueg tipa.
Dozvoljene su samo operacije obuhvaene tipom.
Tip je zatvoren u odnosu na skup operacija koji obuhvata. Ove operacije se mogu
primenjivati samo nad operandima istog tipa. Meoviti izrazi nisu dozvoljeni.
Dodeljivanje vrednosti raznorodnih tipova mogue je samo uz javnu upotrebu funkcija za
transformaciju tipa.
U sledeim primerima date su naredbe koje po ovom konceptu nisu dozvoljene:
var
x: real;
i: integer;
c: char;
i := A
c := 10

{
{
{
{

x je realnog tipa }
i je celobrojnog tipa }
c je znakovnog tipa }
nekorektno, promenljivoj celobrojnog tipa
dodeljuje se znakovna vrednost }
{ nekorektno, promenljivoj znakovnog tipa
dodeljuje se celobrojna vrednost }

Koncept jakih tipova poveava pouzdanost, dokumentarnost i jasnou programa. Kako se


zahteva eksplicitna upotreba operacija za transformaciju tipa, onda je nedvosmisleno jasno da je
odreena transformacija na nekom mestu namerna i potrebna. Ovaj koncept omoguava da se
informacija o tipu moe koristiti u fazi kompilovanja programa i na taj nain postaje faktor
pouzdanosti programa.

2.3. Ekvivalentnost tipova


Kada kompilator jezika sa jakim tipovima podataka treba da obradi naredbu dodeljivanja
oblika:
x := izraz
on vri dodeljivanje samo u sluaju ekvivalentnosti tipa promenljive sa leve strane dodeljivanja
i rezultata izraza na desnoj strani naredbe, osim u sluaju kada je na desnoj strani celobrojni
izraz a na levoj strani promenljiva nekog realnog tipa.

Predrag S. Stanimirovi

11

Programski jezici

U sluaju eksplicitne ekvivalentnosti, vrednost jedne promenljive se moe dodeliti drugoj


samo ako obe eksplicitno pripadaju istom tipu, to ilustruje sledei primer:
var
i, u : real ;
u := i ;

Primer. Sledei program u PASCAL-u je korektan:


program primer;
var i:integer;
u:real;
begin
readln(i);
u:=i;
writeln('i = ',i,' u = ',u);
end.

Na primer, za vrednost 2 promenljive i dobija se:


2
i = 2 u = 2.0000000000E+00
Prilikom kompilovanja sledeeg programa prijavljuje se sintaksna greka type mismatch.
program primer;
var i:integer;
u:real;
begin
readln(u);
i:=u;
writeln('i = ',i,' u = ',u);
end.

Eksplicitnom ekvivalentnou tipova postie se vea pouzdanost jezika. U ovom sluaju nisu
potrebne posebne procedure po kojima bi se ispitivala strukturna ekvivalentnost. Meutim, kada
je potrebno vrednost promenljive ili izraza dodeliti promenljivoj koja mu ne odgovara po tipu
ovaj koncept zahteva korienje funkcija za transformisanje tipova.

2.4. Elementarni tipovi podataka


U okviru svakog programskog jezika, sistem tipova podataka zasniva se na skupu osnovnih
tipova podataka nad kojima se dalje definiu izvedeni tipovi, podtipovi, strukturni tipovi i
specifini apstraktni tipovi podataka. Skup osnovnih tipova podataka se obino svodi na tipove
podataka za rad sa elementarnim numerikim podacima (celi i realni brojevi), znakovnim
podacima (pojedinani znaci ASCII koda) i logikim vrednostima (true i false).

2.4.1. Celobrojni tipovi (INTEGER)


Skoro bez izuzetaka, u svim programskim jezicima postoji jedan ili vie tipova podataka za rad
sa celim brojevima koji obino u nazivu imaju re INTEGER.
Obino postoji osnovni (standardni) tip INTEGER ili int, koji se zavisno od realizacije odnosi
na odreeni opseg celih brojeva. Nekad je to opseg koji odgovara formatu jedne polurei ili
formatu jedne rei. U odnosu na ovaj osnovni celobrojni tip eto postoji mogunost definisanja
i drugih celobrojnih tipova koji se odnose na neki krai ili proireni format.
U sledeoj tabeli je opisan tip INTEGER u Pascal-u.

12

Tip operacije

Operacija

mnoenje
Multiplikativne deljenje
ostatak deljenja
operacije
celobrojno deljenje
Aditivne
sabiranje
operacije
oduzimanje
Unarne operacije plus
minus
manje
manje ili jednako
vee
Relacije
vee ili jednako
jednako
nejednako

Operator
*
/
mod
div
+
+
<
<=
>
>=
=
<>

2.4.2. FLOAT tip


Promenljive ovih tipova uzimaju za svoje vrednosti podskupove skupa realnih brojeva. U
programskim jezicima postoji vie vrsta podataka realnog tipa, koji se razlikuju po tanosti
predstavljanja podataka.

2.4.3. Logiki tip podataka


Logiki tipovi podataka postoje kao osnovni tipovi podataka u svim novijim jezicima.
Obino nose naziv LOGICAL (FORTRAN) ili BOOLEAN (Pascal, Ada). Obuhvataju samo dve
vrednosti true i false, nad kojima su definisane osnovne logike operaclje not, and, or i xor.
Takoe, vai i ureenost skupa vrednosti ovog tipa tako da je false < true.

2.4.4. Znakovni tipovi


Za rad sa pojedinanim znacima u okviru programskih jezika koriste se znakovni tipovi koji
obino nose naziv CHARACTER (FORTRAN, Ada) ili CHAR (Pascal, C). Ovi tipovi obuhvataju
standardni skup znakova ASCII koda i odreene operacije nad ovako definisanim podacima.
Podrazumeva se ureenost skupa znakova u skladu sa ureenou tablice ASCII koda tako da se
kao osnovne operacije u ovim tipovima koriste relacije poreenja. U jeziku Ada tip
CHARACTER se takoe svrstava u siru kategoriju diskretnih tipova podataka to podrazumeva
i mogunost upotrebe svih standardnih atributa i funkcija diskrenih tipova. U okviru znakovnih
tipova se obino mogu koristiti funkcije kojima se uspostavlja veza izmeu odreenog znaka i
njegove dekadne vrednosti u ASCII kodu. U jeziku Pascal to je funkcija ORD.

2.5. Elementarni tipovi podataka u nekim jezicima


U mnogim programskim jezicima sistem tipova podataka se svodi samo na elementarne
tipove podataka. Kao primere takvih jezika pomenuemo FORTRAN i C.

2.5.1. Tipovi podataka u FORTRAN-u


Osnovni tipovi podataka programskog jezika FORTRAN 77 i odgovarajue konstante prikazani
su u tabeli 4.2.

Predrag S. Stanimirovi

Programski jezici

13

U FORTRAN-u takoe potoje implicitna pravila za automatsku konverziju tipova. U tabeli


je predstavljena hijerarhija tipova podataka na osnovu koje se u sloenim aritmetikim izrazima
jedni konvertuju u druge. Pri tome vai pravilo da se tipovi koji su nie u ovoj hijerarhiji
konvertuju u tipove koji su vieg hijerarhijskog nivoa.

Tipovi podataka u FORTRAN-u 77


Tip podataka
INTEGER

REAL

Konstanta
0
75
+230
-9342605
-1.5
3E5
+.123 E-3
-7.45E-14
5.
1.23 E0

Memorija u

Vrednost

0
75
+230
-9342605

-1,5
+300000
+0,000123
-7,45 * 10-14
+5
+1,23

DOUBLE
PRECISION

1D2
.123DO
6.89 D-8
-4.D+16

COMPLEX

(4. 61, -6. 98)


(-10.5)
(.4E2, -.31E-1)

4,61 - 6,98i
-10 + 5i
40 - 0,0311

LOGICAL

.TRUE.
.FALSE.

Istina
La

CHARACTER

'NIS'
'JEL'' DA'
3HNIS

3
6
3

NIS
JEL' DA
NIS

+100
+0,123
+6,89*10-8
-4 * 1016

Hijerarhija tipova u FORTRAN-u


Nivo
1
2
3
4

Tip
INTEGER
REAL
DOUBLE PRECISION
COMPLEX

2.5.2. Tipovi podataka u C-u


Programski jezik C se takoe svrstava u jezike sa slabim tipovima podataka iako su
eksplicitne definicije tipa obavezne. Mogu se koristiti samo unapred definisani tipovi podataka
uz mogunost da im se daju pogodna korisnika imena i na taj nain povea dokumentarnost
programa.
Mehanizam tipa je opti i odnosi se i na funkcije i na promenljive. Tipovi podataka u jeziku
C mogu se globalno podeliti na osnovne i sloene (struktuirane). Osnovni tipovi podataka su
celobrojni (int), realni (float), znakovni (char), nabrojivi (enumerated) i prazan (void). Ovi
tipovi podataka se koriste u graenju sloenih tipova (nizova, struktura, unija, itd.).
U sledeoj tabeli su prikazani osnovni tipovi podataka ovog jezika sa napomenom o njihovoj
uobiajenoj primeni.

14
Tipovi podataka u C-u
Tip

Memorija u
bajtovima

Opseg

Namena

char

0 do 255

PC skup znakova i mali brojevi

signed
char

-128 do 127

ASCII skup znakova i veoma mali


brojevi

enum

-32.768 do 32.767

Ureeni skup vrednosti

unsigned
int

0 do 65.535

Veliki brojevi i petlje

short int

-32.768 do 32.767

Mali brojevi, kontrola petlji

int

-32.768 do 32.767

Mali brojevi, kontrola petlji

unsigned
long
long

0 do 4.294.967.295

Astronomska ratojanja

-2.147.483.648 do
2.147.483.647

Veliki brojevi

float

3,4*10-38 do 3,4*1038

Naune aplikaije (tacnost na 6


decimala)

double

1,7*10-308 do 1,7*10308

Naune aplikaije (tacnost na 16


decimala)

long
double

10

3,4*10-4932 do 3,4*104932

Naune aplikaije (tanost na 19


decimala)

U C-u se takoe primenjuju implicitna pravila za konverziju tipova, kao u sledeoj tabeli.
Pravila za konverziju tipova u C-u
Tip
char
unsignet char

Konvertuje se u
int
int

signed char
short

int
int

unsigned short
enum
float

unsigned int
int
double

U C-u postoji skup operatora za rad sa binarnim sadrajima koji su prikazani u tabeli koja
sledi.
Operatori za manipulisanje sa binarnim sadrajima u C-u
Operator
&&
||
^
>>
<<
~

Znaenje
Logicka I operacija (AND)
Logicka ILI operacija (OR)
Iskljucivo ILI (XOR)
Pomeranje udesno
Pomeranje ulevo
Komplement

U sluaju meovitih izraza u kojima se pojavljuju razliiti operatori takoe vae implicitna
pravila kojima je definisan prioritet operacija. Nabrojaemo osnovna:
Unarni operatori (na pr. ++) su uvek vieg prioriteta u odnosu na sve binarne (npr. /)
Aritmetike operacije su vieg prioriteta u odnosu na relacije poreenja.

Predrag S. Stanimirovi

15

Programski jezici

Operatori poredenja <= i >= (manje ili jednako i vee ili jednako) su vieg prioriteta u
odnosu na jednako i nejednako.
Poreenja su uvek vieg prioriteta u odnosu na operatore kojima se manipulie bitovima.
Operatori za manipulisanje bitovima su vieg prioriteta u odnosu na sve
logike operatore.
Logiko I (&&) je vieg prioriteta u odnosu na logiko ILI ( | | ).

Celobrojni tipovi u C
Celobrojni tipovi su brojaki tipovi i javljaju se kao oznaeni ili neoznaeni.
Celobrojne vrednosti obuhvataju celobrojne konstante, celobrojne promenljive, izraze i
funkcije.
Celobrojne konstante predstavljaju podskup skupa celih brojeva iji opseg zavisi od
deklaracije ali i od konkretne implementacije. U C jeziku celobrojne konstante se predstavljaju
kao niske cifara. Ispred koje moe da stoji znak '+' za pozitivne, a obavezan je znak '-' za
negativne vrednosti.
Promenljivoj osnovnog celobrojnog tipa int obino se dodeljuje memorijski prostor koji
odgovara "osnovnoj" jedinici memorije. Na taj nain, opseg vrednosti tipa int u TURBO C na
16-bitnim raunarima je [-32768, +32767] = [-215,215-1], a na 32-bitnim raunarima je
[-2147483648, +2147483647] = [-231,231-1].
Bitno je napomenuti da se mogu koristiti 3 brojna sistema, i to: dekadni (baza 10), oktalni
(baza 8); heksadekadni (baza 16). Heksadecimalni brojevi poinju sa 0x ili 0X. Dozvoljene
cifre su 0, 1,.., 9 i slova a, b, c, d, e, f (ili A, B, C, D, E, F). Oktalni brojevi poinju sa 0 a ostale
cifre mogu biti 0, 1, ..7. Na primer, 012 je dekadno 10, 076 je dekadno 62. Takoe, 0x12 je
dekadni broj 18, 0x2f je dekadno 47, 0XA3 je dekadno 163. Celobrojne konstante koje ne
poinju sa 0 su dekadne.
Opseg celih brojeva se moe menjati primenom kvalifikatora long i short. Kvalifikator long
moe da povea opseg vrednosti celobrojnih promenljivih tipa int. Opseg vrednosti tipa long
int (ili skraeno long) je [-2147483648, +2147483647] = [-231,+231-1].
Tip long int (ili long) garantuje da promenljive tog tipa nee zauzimati manje memorijskog
prostora od promenljivih tipa int.
Celobrojne konstante koje su prevelike da bi bile smetene u prostor predvien za konstante
tipa int tretiraju se kao long konstante. Ove konstante se dobijaju dodavanjem znaka L (ili l) na
kraj konstante, kao npr. 1265378L. Ako program ne koristi velike cele brojeve ne preporuuje se
deklarisanje promenljivih sa long, jer se time usporava izvrenje programa.
Kvalifikator short int (ili skraeno short) smanjuje opseg celobrojnih promenljivih. Opseg
promenljivih tipa short uvek je [-215,215-1], tj. one se uvek smetaju u 2 bajta. Upotrebom
promenljivih ovog tipa ponekad se postie uteda memorijskog prostora. Meutim, upotreba
ovih promenljivih moe da uspori izvravanje programa, jer se pre korienja u aritmetikim
izrazima ove promenljive transformiu u tip int.
Ako smo sigurni da su vrednosti celobronih promenljivih nenegativne, one se mogu
deklarisati na jedan od sledeih naina:
unsigned int (skraeno unsigned),
unsigned short int (skraeno unsigned short),
unsigned long int (skraeno unsigned long).

16
Time se interval pozitivnih vrednosti proiruje, jer bit za registrovanje znaka gubi to znaenje.
Promenljive tipa unsigned int (skraeno unsigned) mogu uzimati samo pozitivne celobrojne
vrednosti. Promenljive tipa unsigned imaju rang [0, 2 irina_rei-1]. Prema tome, Na 16-bitnim
raunarima opseg promenljivih tipa unsigned int je [0, 65535] = [0,2 16-1], a na 32-bitnim
raunarima je [0,232-1]=[0,+4294967295].
Konstante tipa long se mogu cpecificirati eksplicitno dodajui sufiks L ili l posle broja. Na
primer, 777L je konstanta tipa long. Slino U ili u se moe koristiti za konstante tipa unsigned.
Na primer, 3U je tipa unsigned, a 3UL je tipa unsigned long.
U sluaju greke integer overflov, program nastavlja da radi, ali sa nekorektnim rezultatom.
Promenljive celobrojnog tipa se deklariu navoenjem imena promenljivih iza imena nekog
celobrojnog tipa. Imena promenljivih se meusobno razdvajaju zarezima, a iza spiska se
navodi ';'. U operatorima opisa je dozvoljeno izvriti inicijalizaciju deklarisanih promenljivih.
Primer. Navedeno je nekoliko deklaracija promenljivih celobrojnih tipova.
long int x;
short int y;
unsigned int z,v,w;
Kljuna re int se moe izostaviti u deklaracijama, pa se moe pisati
long x;
short y, k=10;
unsigned z;

Realni tipovi podataka


Promenljive ovih tipova uzimaju za svoje vrednosti podskupove skupa realnih brojeva. U
jeziku C postoje tri vrste podataka realnog tipa, koji se razlikuju po tanosti predstavljanja
podataka: float (za jednostruku tanost), double (za dvostruku tanost) i long double. U TURBO
C vrednosti tipa float se pamte u 4 bajta (32 bita), a double u 8 bajtova (64 bita). Efekat je da
vrednosti tipa float zauzimaju 6 decimalnih mesta, a double 16 decimalnih mesta. Vrednosti tipa
long double se smetaju u 80 bitova.
U TURBO C, pozitivne vrednosti za float su iz opsega [3.4*10 -38, 3.4*1038], dok su
pozitivne vrednosti za double long double iz opsega [1.7*10 -308,1.7*10+308]. Pozitivne vrednosti
tipa long double uzimaju vrednosti iz opsega [3.4*10-4932,1.1*10+4932].
Za vrlo velike i vrlo male brojeve moe se koristiti eksponencijalni zapis, koji se sastoji iz
sledeih delova:
celobrojnog dela - niz cifara,
decimalne take,
razlomljenog dela - niz cifara,
znaka za eksponent e ili E,
eksponenta koji je zadat celobrojnom konstantom.
Primeri realnih brojeva su:

45., 1.2345, 1.3938e-11, 292e+3.

Promenljive realnog tipa deklariu se navoenjem liste imena promenljivih iza imena tipa.
Primer. Deklaracije promenljivih realnih tipova:
float x,y;
double z;

Predrag S. Stanimirovi

17

Programski jezici

float p=2.71e-34;

Tip char
Tip char je jedan od fundamentalnih tipova podataka u jeziku C. Konstante i promenljive
ovog tipa se koriste za reprezentaciju karaktera. Znakovni tip (tip char) definie ureen skup
osnovnih znakova jezika C. Takav skup obrazuje skup ASCII znakova. To znai da znakovnom
tipu pripadaju i znaci koji nemaju grafiku interpretaciju.
Svaki karakter se smeta u raunaru u jednom bajtu memorije. Ako je bajt izgraen od 8
bitova, on moe da pamti 28=256 razliitih vrednosti. Promenlijve i konstante tipa char uzimaju
za svoje vrednosti karaktere odnosno cele brojeve duine jednog bajta. To znai da se znak u
memoriji registruje u jednom bajtu. Promenljive ovog tipa se deklariu pomou kljune rei
char.
Ako ispred deklaracije char stoji rezervisana re signed, tada se specificira interval kodnih
vrednosti [-128,127]; ako je ispred char navedeno unsigned, tada se specificira interval [0,255].
Primer. Iskazom
char ca, cb, cc;
promenljive ca, cb, cc deklariu se kao promenljive tipa char. Karakter konstanta se pie
izmeu apostrofa, kao: 'a', 'b', 'c'... U Turbo C se koriste ASCII kodovi karaktera, i oni
predstavljaju njihovu numeriku vrednost.
Promenljive tipa char se mogu inicijalizovati na mestu deklarisanja.
Na primer, moemo pisati
char c='A', s='A', x;
int i=1;
Funkcije printf() i scanf() koriste %c za format karaktera.
Primer.
printf("%c", 'a');
printf("%c %c %c", 'A', 'B', 'C');

/* ABC */

Takoe, konstante i promenljive tipa char se mogu tretirati kao mali integeri.
Primer.
printf("%d", 'a'); /* 97 */
printf("%c",97); /* a */

Neke znakovne konstante se moraju specificirati kao ``escape'' sekvence, tj. moraju se navesti
zajedno sa znakom \ (backslash). Escape sekvence se koriste pri kreiranju izlaznih izvetaja u
cilju specificiranja upravljakih znakova.
'\n' prelazak na novu liniju u ispisu;
'\t' horizontalni tab (pomera kursor za 5 ili 8 pozicija);
'\r' carriage return (pomeranje kursora na poetak linije);
'\b' vraa kursor za jednu poziciju (povratnik, backspace);
'\f' form feed (pomera hartiju tampaa na poetak sledee strane);
'\a' alarm;
'\'' apostrof;
'\v' vertikalni tabulator;
'\\' backslash.

18
Primer.

printf("\"ABC\"");

/* "ABC" */

U stringu je single quote obian karakter:


printf("'ABC'"); /* 'ABC' */
Karakter konstante se takoe mogu prikazati pomou jednocifrene, dvocifrene ili trocifrene
sekvence. Na primer '\007', ' \07' ili '\7' predstavlja bell (alarm).
Za ulaz i izlaz karaktera se mogu koristiti funkcije getchar() i putchar(). Ovi makroi su
definisani u stdio.h. Za uitavanje karaktera sa tastature koristi se getchar(), dok se putchar()
koristi za prikazivanje karaktera na ekran.

Primeri
Primer. Unoenje karaktera preko tastature i njihovo prikazivanje na ekran.
#include <stdio.h>
main()
{ char c;
while(1)
{ c=getchar();
}

putchar(c);

/* Prekid ciklusa ^Z karakterom */


#include <stdio.h>
main()
{ int c;
while((c=getchar())!=EOF)
putchar(c);
}

C obezbeuje standardni fajl ctype.h koji sadri skup makroa za testiranje karaktera i skup
prototipova funkcija za konverziju karaktera. Oni postaju dostupni pomou preprocesorske
direktive
#include <ctype.h>
Makroi u sledeoj tabeli testiraju karaktere, i vraaju vrednosti true (0) i false (=0).
makro
isalpha(c)
isupper(c)
islower(c)
isdigit(c)
isxdigit(c)
isspace(c)
isalumn(c)
ispunkt(c)
isprint(c)
iscntrl(c)

vrednost 0 se vraa za
c je slovo
c je veliko slovo
c je malo slovo
c je broj
c je heksadecimalan broj
c je blanko
c je slovo ili broj
c je interpunkcijski znak
c je terminalni karakter
c je kontrolni karakter

Takoe, u standardnoj biblioteci <ctype.h> ukljuene su i funkcije toupper(c) i tolower(c) za


odgovarajuu konverziju karaktera. Ove funkcije menjaju vrednost argumenta c koja je
smetena u memoriji.
toupper(c) menja c iz malog u veliko slovo;
tolower(c) menja veliko slovo u malo;

Predrag S. Stanimirovi

19

Programski jezici

toascii(c) menja c u ASCII kod;

Konverzija tipova podataka i kast


Mnogi jezici visokog nivoa imaju strogu tipizaciju Takvi jezici nameu tokom prevoenja
slaganje tipova podataka koji su upotrebljeni u aritmetikim operacijama, operacijama
dodeljivanja i pozivima funkcija. U jeziku C se mogu pisati operacije u kojima se koriste
razliiti tipovi podataka (meovite operacije). Svaki aritmetiki izraz poseduje vrednost i tip.
Tip rezultata aritmetikih izraza zavisi od tipova operanda. Ako su kod binarnih aritmetikih
operatora oba operanda istog tipa, tada je tip rezultata jednak tipu operanada. Kada to nije
ispunjeno, vri se automatska konverzija operanda nieg hijerarhijskog nivoa u tip operanda
vieg nivoa. Osnovni tipovi podataka imaju sledei hijerarhijski nivo
char<int<long<float<double.

Korienjem rezervisanih rei unsigned i long poviava se hijerarhijski rang, tako da je


detaljniji pregled hijerarhijskih nivoa sledei:
char< int <unsigned <long < unsigned long <float < double < long double.
Na primer, ako su oba operanda tipa int, svaki aritmetiki izraz koji je izgraen od njih uzima
vrednost tipa int. Ako je jedna od promenljivih tipa short, ona se automatski konvertuje u
odgovarajuu vrednost tipa int.
Automatska konverzija tipova se javlja i pri dodeljivanju vrednosti. Kod operatora
dodeljivanja vrednosti, uvek se vrednost izraza sa desne strane konvertuje u vrednost prema tipu
promenljive sa leve strane operatora dodeljivanja. Ako je promenljiva d tipa double, a izraz i
tipa int, tada se pri dodeljivanju d=i vrednost promenljive i konvertuje u odgovarajuu vrednost
tipa double. Ako je i promenljiva tipa int, a d je neki izraz tipa double, tada u izrazu i=d,
prevodilac vrednost izraza d konvertuje u odgovarajuu vrednost tipa int, pri emu se gube
vrednosti decimalnih pozicija.
Osim ve pomenute automatske konverzije tipova podataka moe se izvriti i eksplicitna
konverzija tipova. Eksplicitna konverzija se postie operatorom kast (cast), oblika (tip)<izraz>.
Postoje situacije kada je konverzija tipova poeljna, iako se ne izvrava automatska konverzija.
Takva situacija nastaje na primer pri deljenju dva cela broja. U takvim sluajevima programer
mora eksplicitno da naznai potrebne konverzije. Takve konverzije su neophodne da bi se izraz
tao izraunao.
Primer. Ako je promenljiva i tipa int, tada se izrazom (double)i njena vrednost prevodi u
odgovarajuu tipa double.
Operator kast je istog prioriteta i asocijativnosti kao i ostali unarni operatori. Kast se moe
primenjivati na izraze.
Primer.
(float)i+3 je ekvivalentno sa ((float)i)+3
(double)x=77 je ekvivalentno sa ((double)x)=77

Takoe, moemo pisati


x=(float)((int)y+1)
(double)(x=77)
Posle izraza x=(int)2.3+(int)4.2 vrednost za x postaje 6.

20

Sizeof operator
Unarni operator sizeof() daje za rezultat broj bajtova potrebnih za smetanje svog argumenta.
Vrednost izraza sizeof(obj) se izraunava za vreme kompilovanja. Argument moe biti ime
promenljive, ime tipa ili izraz. Ako je obj ime promenljive, tada je vrednost izraza sizeof(obj)
broj bajtova potrebnih za registrovanje te promenljive u memoriji. Ako je operand obj ime tipa,
tada je vrednost izraza sizeof(obj) duina tog tipa, odnosno broj bajtova potrebnih za
registrovanje elemenata tog tipa. Ako je argument neki tip, ime tog tipa se mora navesti izmeu
zagrada. Naredba sizeof se koristi kada se generie kod koji zavisi od veliine tipa.

Osnovne aritmetike operacije


Osnovne aritmetke operacije su:
+ sabiranje,
- oduzimanje,
* mnoenje,
/ deljenje,
Ako su oba operanda operacije deljenja / celi brojevi tada se iz realnog broja koji predstavlja
njihov kolinik odbacuje decimalna taka i razlomljeni deo.
Na primer, 15/2=7, 2/4=0, -7/2=-3, 15%2=1, 7./4=1.74.
Operacija - moe biti i unarna, i tada se koristi za promenu znaka svog argumenta (unarni
minus).
Sve operacije poseduju prioritet i asocijativnost (redosled), kojima se determinie postupak
evaluacije izraza. Ako u izrazu postoje operacije razliitog nivoa prioriteta, operacije se
izvravaju po opadajuem nivou prioriteta. Prioritet se moe promeniti upotrebom zagrada.
Asocijativnost odluuje o redosledu izvravanja operacija istog prioriteta.
Levoasocijativne operacije se izvravaju s leva na desno a desnoasocijativne s desna na levo.
Najvii priorirtet ima operacija promene znaka, zatim levoasocijativni multiplikativni
operatori *, / i %, dok su najnieg nivoa prioriteta levoasocijativni aditivni operatori + i -.
Operacija inkrementiranja (uveanja) ++ i operacija dekrementiranja (umanjenja) -- su
unarne operacije sa asocijativnou s desna na levo. U tabeli prioriteta zauzimaju sledee mesto:
unarni -; ++, --;
*, /, %;
+, -.
Operacije ++ i -- se mogu pisati ispred argumenta (prefiksno) ili iza argumenta (postfiksno).
Mogu se primenjivati nad promenljivima a ne mogu na konstantama ili izrazima.
Primer. Moe se pisati ++i, i++, --cnt, cnt-- a ne moe 777++, ++(a*b-1) .
Svaki od izraza ++i, i++, --i, i-- ima odreenu vrednost. Izrazi ++i, i++ uzrokuju
inkrementiranje vrednosti promenljive i u memoriji za 1, dok izrazi --i, i-- uzrokuju
dekrementiranje njene vrednosti za 1. Izrazom ++i vrednost za i se inkrementira pre nego to se
upotrebi, dok se sa i++ vrednost za i inkrementira posle upotrebe te vrednosti. Slina pravila
vae za izraze --i, i--, samo to se radi o dekrementiranju te vrednosti.
Operatori ++ i -- razlikuju se od operatora +, -, *, /, % po tome to menjaju vrednosti varijable u
memoriji, tj. operatori ++ i -- poseduju boni efekat.

Predrag S. Stanimirovi

21

Programski jezici

Biblioteke aritmetike funkcije


Deo C jezika jesu standardne biblioteke koje sadre esto koriene funkcije. Biblioteka
math.h sadri deklaraciju funkcija iz matematike biblioteke. Sadraj ove datoteke se ukljuuje
u program naredbom
#include<math.h>.
Neke od funkcija iz ove biblioteke su date u nastavku.
Poznate su funkcije sin(x), cos(x), tan(x), exp(x), log(x), log10(x), sqrt(x), fabs(x)=|x|.
ceil(x), rezultat je najmanja celobrojna vrednost ne manja od x (plafon od x).
Rezultat funkcije floor(x) je najvea celobrojna vrednost ne vea od x (pod od x).
pow(x,y)=x^y. Ako je x=0 mora da bude y>0. Ako je x<0 tada y mora da bude ceo broj.
asin(x) vrednost funkcije arcsin(x), x[-1,1].
acos(x) vrednost funkcije arccos(x), x[-1,1].
atan(x) vrednost funkcije arctg(x), x[-/2, /2].
atan2(x,y) vrednost funkcije arctg(x/y), x[-,]. Ne moe istovremeno da bude x=y=0.
sinh(x) vrednost funkcije sh(x).
cosh(x) vrednost funkcije ch(x).
tanh(x) vrednost funkcije th(x).
modf(x,&y) vrednost funkcije je razlomljeni deo realnog broja x sa predznakom tog broja. U
argumentu y, kao boni efekat, daje se celobrojni deo broja x sa predzankom tog broja.
Argumenti x i y su tipa double.
fmod(x,y) vrednost funkcije je ostatak realnog deljenja x/y sa predznakom argumenta x.
Standard ne precizira rezultat u sluaju y=0. Argumenti x i y su tipa double. Na primer,
fmod(4.7,2.3)=0.1.
U biblioteci <stdlib.h> nalaze se funkcije razliite namene. Navedene su neke od njih.
abs(n) apsolutna vrednost, gde su vrednost argumenta i funkcije tipa int,
labs(n) apsolutna vrednost, gde su vrednost argumenta i funkcije tipa long,
rand() vrednost funkcije je pseudosluajni broj iz intervala [0,RAND_max], gde RAND_max
simbolika konstanta ija vrednost zavisi od raunara i nije manja od 32767,
srand(n) postavlja poetnu vrednost sekvence pseudosluajnih brojeva koju generie rand().
Podrazumevana poetna vrednost je 1. Tip argumenta je unsigned int. Funkcija ne daje rezultat.
atof(s) ova funkcija vri konverziju realnog broja iz niza ASCII cifara (karaktera) oblika
cc....cc... Eee u binarni ekvivalent. Argument s je tipa string a rezultat je tipa double. Pre
konverzije se briu poetne praznine. Konverzija se zavrava kod prvog znaka koji ne moe da
bude deo broja.
atoi(s) ova funkcija vri konverziju celog broja iz niza ASCII cifara (karaktera) oblika cc... u
binarni ekvivalent. Argument s je tipa string a rezultat je tipa int. Poetne praznine se ignoriu.
Konverzija se zavrava kod prvog znaka koji ne moe da bude deo broja.

22
atol(s) ova funkcija vri konverziju celog broja iz niza ASCII cifara (karaktera) oblika cc... u
binarni ekvivalent tipa long. Argument s je tipa string a rezultat je tipa long. Poetne praznine se
ignoriu. Konverzija se zavrava kod prvog znaka koji ne moe da bude deo broja.

Operacija dodeljivanja u C
U C jeziku se operator = tretira kao operator dodeljivanja. Njegov prioritet je manji od
prioriteta do sada razmatranih operacija, a njegova asocijativnost je ``s desna na levo''.
Izraz dodeljivanja vrednosti je oblika
<promenljiva> = <izraz>;
na ijoj je desnoj strani proizvoljan izraz. Kompletan izraz je zavren sa ; (semicolon). Vrednost
izraza na desnoj strani se dodeljuje promenljivoj sa leve strane. Ako su tipovi promenljive i
izraza razliiti, vri se konverzija vrednosti izraza u odgovarajuu vrednost saglasno tipu
promenljive. Vrednost izraza dodeljivanja jednaka je vrednosti izraza sa njegove desne strane.
Primer. Sledea sekvenca izraza
y=2; z=3; x=y+z;
moe se efikasnije zapisati u obliku
x=(y=2)+(z=3);
Primer. Zbog desne asocijativnosti operatora = je izraz x=y=z=0 ekvivalentan izrazu
x=(y=(z=0)).
Primer. Operator y=x++; je ekvivalentan sledeoj sekvenci operatora: y=x; x=x+1;
Operator y=--x je ekvivalentan sledeim operatorima x=x-1; y=x;
Posle izvravanja operatora
x=y=1;
z=(x+(++y))*3;
dobijaju se sledee vrednosti promenljivih:
x=1, y=2, z=(1+2)*3=9.
Operatori
x=y=1;
z=(x+(y++))*3;
x=y=1;
t=(x+y++)*3;
daju sledee vrednosti promenljivih:
x=1, y=2, z=(1+1)*3=6, t=(1+1)*3=6.
Operatori sloenog dodeljivanja su:
=, +=, -=, *=, /=, %=, ||=, &=,^=, |=
Svi ovi operatori imaju isti prioritet i asocijativnost s desna na levo. Ako su l i r proizvoljni
izrazi, tada je izraz
l<op>=r jednak l=l<op> r.
Na primer,
x+=2; je ekvivalentno sa x=x+2;
x%=2; je ekvivalentno sa x=x%2;

Predrag S. Stanimirovi

23

Programski jezici

Operacije poreenja i logike operacije


U jeziku C postoje samo numeriki tipovi. Ne postoji ak ni logiki tip podataka. Za
predstavljanje logikih vrednosti koriste se celobrojni podaci tipa int. Vrednost 0 se tumai kao
logika neistina (false), a bilo koja vrednost razliita od nule tumai se kao logika istina (true).

OPERACIJE POREENJA
Operacije poreenja su:
<, <=, >, >=, ==, !=.
Rezultat izvrenja ovih operacija je 1 ako je ispunjeno poreenje, a inae je 0. Ove operacije se
izvravaju s leva na desno. Operacije poreenja su nieg prioriteta od aritmetikih operacija.
Unutar operacija poreenja, operacije <, <=, >, >= su vieg prioriteta od operacija == i !=.
Na primer, x>y+3 je ekvivalentno sa x>(y+3).

LOGIKE OPERACIJE
Postoje tri logike operacije:
! je operacija negacije,
&& je konjunkcija, i
|| predstavlja opreaciju disjunkcije.
Rezultat primene ovih operacija je 0 ili 1.
Operacija negacije ! je unarna, i daje rezultat 1 ako je vrednost operanda 0, a vrednost 0 ako
je vrednost operanda 1.
Operacija konjunkcije && je binarna, i daje 1 ako su oba operanda razliita od 0, a 0 u
suprotnom. Ako je levi operand jednak 0 pri izvrenju operacije konjunkcije desni operand se
ignorie.
Operacija disjunkcije || je binarna, i daje 1 ako je bar jedan operand razliit od 0, a 0 inae.
Ako je vrednost levog operanda jednaka 1 pri izvrenju operacije disjunkcije desni operand se
ignorie.
Najvii prioritet ima operacija negacije; sledeeg nivoa prioriteta je operator konjunkcije, dok
je najnieg nivoa prioriteta operator disjunkcije.
Prema tome,
p||q & & r je isto sa p||(q & & r),
x<=y& & r je isto sa (x<=y)& & r.
Primer. Napisati operatore dodeljivanja kojima se realizuje sledee:
a) Promenljivoj p se dodeljuje vrednost 1 ako se od odseaka x, y, z moe konstruisati trougao,
a inae 0.
p=((x+y>z) && (x+z>y) && (y+z>x));
b) Promenljivoj p se dodeljuje vrednost 1 ako se pravougaonik sa stranicama a i b moe ceo
smestiti u pravougaonik sa stranicama c i d, a inae 0.
p=((a<c)&& (b<d) || (a<d)&& (b<c));

2.5.3. Standardni tipovi podataka u Pascal-u


Pascal je primer programskog jezika kod kojeg je zastupljen koncept jakih tipova podataka

24
koji zahteva eksplicitne definicije tipova i podrazumeva tipove zatvorene u odnosu na operacije
koje se na njima mogu izvravati. Standardni tipovi podataka u Pascal-u su Integer, Real,
Logical i Char.

Celobrojni tip (Integer)


Celobrojni tip se koristi za rada sa celim brojevima. U standardnom Pascal-u predvia se
postojanje samo jednog celobrojnog tipa iji je opseg brojeva odreen implementacijom na
konkretnom sistemu. Za pristup graninim vrednostima postoji konstanta MAXINT, tako da je
opseg brojeva odreen granicama -MAXINT i MAXINT. U okviru celobrojnog tipa dozvoljene su
sledee operacije:
+
*
DIV
MOD

sabiranje
oduzimanje
mnoenje
celobrojno deljenje
ostatak celobrojnog deljenja

Ovde su specifine operacije DI V i MOD. Efekti ovih operacija ilustrovani su sledeim


primerima:
5
5
6
7

DIV
MOD
MOD
MOD

2
3
3
3

= 2 (a ne 2.5)
=2
=0
=1

U sloenim izrazima operacije *, DIV i MOD su vieg prioriteta u odnosu na + i -. Postoje


takoe etiri standardne funkcije koje daju rezultat celobrojnog tipa:
ABS (X)
SQR(X)
TRUNC(X)
ROUND (X)

ROUND (X) =

Izraunava apsolutnu vrednost broja X.


Izraunava X2.
Odseca se celobrojni deo argumenta X koji treba da bude realan broj.
Argument X, koji treba da bude realan broj, zaokruuje se na ceo broj
primenom pravila:

TRUNC(X+0.5),

X0,

TRUNC(X-0.5),

X<0.

Tip realnih brojeva (Real)


Standardni tip za rad sa realnim brojevima u Pascal-u je tip Re a l . Obuhvata brojeve za ije
se predstavljanje koristi standardni format pokretne take, a dozvoljene su standardne aritmetike
operacije :
+
*
/

sabiranje
oduzimanje
mnozenje
deljenje

Standardne funkcije ABS(X) i SQR(X) u sluaju argumenata tipa Real daju rezultat tipa
Real, dok su rezultati standardnih funkcija: SIN(X), COS(X), TAN(X), EXP(X), ARCTAN(X) i
SQRT(X) tipa Real za bilo koje vrednosti argumenta.

Predrag S. Stanimirovi

25

Programski jezici

Znakovni tip podataka (Char)


Prema standardu jezika Pascal znakovni tip podataka kao vrednosti obuhvata pojedinane
znakove iz nekog skupa znakova koji je odreen samom implementacijom jezika. U praksi se
najee javljaju implementacije kod kojih je to skup znakova ASCII koda.
Konstante znakovnog tipa formiraju se tako to se pojedinani znaci obuhvate apostrofima, kao
npr: ' A ' , ' B ' , ' 5 ' , ' # ' .
U skupu znakova C h a r tipa vai ureenost koja odgovara ureenosti u kodnoj tablici koja se
koristi. Vai:
' A ' < ' B ' < ' C ' < ' D ' < ' E' < < ' Z ' < ' 0 ' < ' 1 ' < ' 2 ' < ' 3 ' < ' 4 ' < ... < ' 9 '

Dve standardne funkcije omoguavaju preslikavanje skupa znakova u skup prirodnih brojeva
i obrnuto. Pri tome se koristi ureenost same kodne tablice na osnovu koje je definisan skup
znakova tipa Cha r. To su funkcije:
ORD(C)
CHR( I )

- daj e redni broj znaka C u ureenom skupu znakova tipa Char.


- daje znak koji je I-ti u skupu znakova.

Ove dve funkije su povezane sledeim relacijama:


CHR(ORD(C))) = C i
ORD(CHR(I)) = I.
Vrednosti tipa C h a r se mogu porediti. Mogu se koristiti standardni operatori poreenja =, <>,
<, <=, >, >=. Ako sa @ oznaimo bilo koju od ovih operacija, a sa CH1 i CH2 promenljive tipa
Char, onda vai relacija CH1@CH2 ako je ORD(CH1)@ORD(CH2).

2.6. Diskretnl tipovi podataka


Grupa diskretnih tipova obuhvata sve tipove podataka sa konanim, diskretnim skupom
vrednosti. U takvom skupu vrednosti je definisana relacija poretka. Diskretnost i ureenost
skupa vrednosti omoguava definisanje intervala i upotrebu nekih optih zajednikih funkcija i
atributa u ovoj grupi tipova. U diskretne tipove podataka svrstavaju se svi celobrojni tipovi
podataka, kao i svi drugi elementarni tipovi sa diskretnim skupom vrednosti kao to su znakovni
i logiki tipovi. Posebno znaajni u grupi diskretnih tipova su tipovi nabrajanja (enumerated
types) i intervalni tipovi nekih drugih jezika.

2.6.1. Diskretni tipovi u programskim jezicima


Koncept diskretnih tipova podataka se sa slinim karakteristikama javlja u mnogim
programskim jezicima sa razlikama koje se uglavnom odnose na sintaksu definicija.

Pascal
Koncept tipova nabrajanja se prvi put pojavljuje ba u jeziku Pascal. To je bila jedna od vanih
novina ovog jezika. Naveemo neke definicije diskretnih tipova podataka:
type BOJE = (crvena,bela,zelena,plava);
DANI = (ponedeljak.utorak.sreda,cetvrtak,petak,subota,nedelja);
GOD = (jan,feb.mar,apr,rnaj,jun,jul,avg.sep,okt.nov,dec);
STATUS = (ON,OFF);
PRAVCI = (sever,jug,istok.zapad);

Programski jezik C
U programskom jeziku C se u okviru definicija tipova nabrajanja eksplicitno koristi re
e num. Gore datim tipovima podataka u ovom jeziku odgovaraju sledee definicije:

26
enum BOJE (crvena,bela,zelena,plava);
enum DANI (ponedeljak,utorak,sreda.cetvrtak.petak.subota ,nedelja);
enum GOD (jan,feb,mar.apr,maj,jun,jul,avg,sep,okt,nov,dec);
enum STATUS (ON,OFF);
enum PRAVCI (sever,jug,itok.zapad);

2.7. Anonimni tipovi


Kod jezika sa jakim tipovima podataka obino postoji i mogunost anonimnih definicija
tipova podataka, kao koncept kojim se slabe zakoni eksplicitne ekvivalentnosti tipova podataka i
omoguava strukturna ekvivalentnost. To je koncept koji dozvoljava da se promenljive definiu
bez eksplicitnog navoenja imena tipa podataka kome pripadaju ve se tip definie samo
strukturno, anonimno bez imena. Na primer, umesto definicije:
type KLJUC (on, off); I.J : KLJUC;

imamo:
I,J : (on,o f f );

Ovaj koncept je opti za sve korisnike tipove podataka u jezicima koji dozvoljavaju
uvoenje korisnikih tipova. Na primer, u Moduli 2 mogui su sledei opisi promenljivih preko
anonimnih definicija intervalnih tipova podataka:
VAR
Index : [1 .. 100];
Raz : [-1 .. 1];

2.8.. Tipovi podataka u paketu MATHEMATICA


MATHEMATICA spada u programske jezike sa slabim tipovima podataka. Sve promenljive
koje nisu lokalne pripadaju globalnom okruenju. Ni globalne ni lokalne promenljive nemaju
eksplicitnu definiciju tipa. Osim toga, ista promenljiva se moe koristiti u veoma razliitim
kontekstima i moe da uzima vrednosti razliitih tipova:
Kao i u LISPu, postoje dva osnovna tipa podataka: atomi i liste. Osnovni atomini tipovi
podataka su: simboli, celi brojevi, realni brojevi, racionalni brojevi, kompleksni brojevi i
stringovi. Lista je ureeni skup objekata, i omoguuju da se razliiti objekti grupiu i da se nad
njima izvravaju operacije. Liste su najmoniji i najfleksibilniji tip podataka u MATHEMATICA.
Koristei liste mogu se izvoditi operacije sa matricama i vektorima jednostavnim pozivom
odgovarajue funkcije, a takoe su ugraene i funkcije za izraunavanje determinante, inverzne
matrice, karakteristinih korena i vektora, itd. Mnoge kombinatorne funkcije ija primena u
programskim jezicima zahteva izvestan trud i znanje, dobijaju se pozivom ugraene funkcije u
MATHEMATICA. Lista se moe definisati eksplicitnim navoenjem svih elemenata ili
definisanjem pravila kojima se odreuju:
{1,3,5,7}
{x,x^2,x^3,aabba}

lista brojeva
lista je sastavljena od simboli~nih izraza

Atomini tipovi podataka su opisani sledeom tabelom:


Symbol
String
Integer
Real
Rational

simbol ije se ime izdvaja koristei SymbolName


string iji se karakteri izdvajaju funkcijom Characters
ceo broj ije se cifre izdvajaju koristei IntegerDigits
realni broj ije se cifre izdvajaju koristei RealDigits.
racionalni broj iji se delovi izdvajaju funkcijama Numerator i

Predrag S. Stanimirovi

Complex

27

Programski jezici

Denominator
kompleksni broj iji se delovi izdvajaju pomou Re i Im

Predikatske funkcije kojima se ispituje tip podataka navedene su u sledeoj tabeli:


IntegerQ[expr]
EvenQ[expr]
OddQ[expr]
PrimeQ[expr]
NumberQ[expr]
NumericQ[expr]
PolynomialQ[expr,{x1,x2,...}]
VectorQ[expr]
MatrixQ[expr]

ispitati da li je expr ceo broj


test za paran broj
test za neparan broj
test za prost broj
test za broj bilo koje vrste
test za numeriku vrednost.
test za polinom od x1,x2,...
test za listu koja predstavlja vektor
test za listu koja predstavlja matricu

Svi strukturni tipovi podataka imaju jednoobraznu strukturu , koja ima oblik

@
D
@
D
@
D
@
D
@
D
@
D
@
D

Head[Arg1, ... ,Argn].

Eksplicitna deklaracija tipova se moe opciono primeniti jedino na formalne parametre


funkcija.
Q x_ := x^2 + 3 x
Q 5
40
Q 1.2
5.039999999999999
R x_Integer := x^3 - 2 x
R 5
115
R 1.3
R 1.3

3. ULAZ I IZLAZ PODATAKA

U programskim jezicima postoji vei broj funkcija za unoenje i izdavanje podataka.


Pomou naredbi ulaza i izlaza program dobija podatke neophodne za reavanje zadatka i izdaje
traene rezultate. Ove funkcije se koriste za standardni ulaz i izlaz podataka preko tastature i
monitora. Postoje varijante ovih funkcija koje se mogu koristiti za pristup datotekama.

28

3.1. Ulaz i izlaz u jeziku PASCAL


Za ulaz i izlaz podataka u jeziku PASCAL koriste se standardne procedure ulaza (read) i
izlaza (write) koje operiu sa standardnim fajlovima (datotekama) input i output.
Na standardnim input i output fajlovima informacije se razbijaju na linije znakova koje se
meusobno razdvajaju obelejem kraja linije. Takve linije su linije na ekranu monitora, ili
hartiji na stampau. Kraj fajla se takodje oznaava specijalnom oznakom (markerom) koja
zavisi od implementacije. (U TURBO PASCAL-u kraj linije se oznaava sa CR-Cerriage
Return, a dobija se pritiskom na taster ENTER ili RETURN. Kod ovog znaka je 13 i nema
grafiku interpretaciju. Obeleje kraja fajla se dobija istovremenim pritiskom na CTRL i Z).
Naredbe ulaza su:
a) read (a1, a2,..., an) - realizuje itanje niza od n vrednosti iz standardnog input fajla, i
dodeljuje uitane vrednosti promenljivima a1, a2,...,an, redom. Tip ulaznih promenljivih mora
odgovarati tipu ulaznih podataka. Na primer, ako celobrojnim promenljivim A, B, C, D treba
dodeliti vrednosti 2,17,4 i 9, u program treba uneti naredbu: read (A, B, C, D), i u ulazni fajl
uneti vrednosti:
2 17 4 9
b) readln(a1, a2,..., an) - realizuje itanje iz standardnog input fajla niza od n vrednosti,
dodelu redom promenljivima a1, a2, ... an, i proputanje preostalih vrednosti do poetka sledee
linije input fajla. Na primer, ako bi realnim promenljivim A, B, C, D trebalo dodeliti vrednosti
2.3, -5.2, 8.34 i 5.55, u program treba uneti naredbu:
readln (A, B, C, D),
i u ulazni fajl uneti vrednosti:
2.3 -5.2 8.34 5.55 (u TURBO PASCAL-u iza poslednjeg broja treba obezbediti obeieje
kraja linije pritiskom tastera ENTER). U sluaju da su iza etvrtog ulaznog podatka ispisane
neke vrednosti, njih bi naredba readln ignorisala.
c) readln - realizuje proputanje linije input fajla do poetka sledee linije.
Pri uitavanju informacija vri se njihovo pretvaranje iz spoljanjeg oblika u unutranji
oblik, koji zavisi od tipa promenljive. Odgovarajue vrednosti promenljivih mogu pripadati
celobrojnom, realnom ill znakovnom tipu. Nedozvoljena je upotreba promenljivih logikog
tipa.
Naredbe read i readln pri citanju vrednosti promenljivih celobrojnog i realnog tipa
zanemaruju praznine koje prethode broju. Meutim, u sluaju znakovnih promenljivih praznine
se ne ignoriu, ve se tretiraju kao ravnopravni znakovi linije i dodeljuju odgovarajuim
znakovnim promenljivim.
Na primer, ako je u odeljku za opis promenljivih dato:
var
realbroj:real;
ceobroj:integer;
zl,z2:char;

i u odeljku naredbi:
readln(realbroj, z1, z2, ceobroj)
tada e u sluaju bilo koje od sledeih ulaznih linija:
a) 320.0AB707
b) 32E1AB 707
c) +3.2E + 02AB

707

Predrag S. Stanimirovi

29

Programski jezici

d) 320.0AB 707 213 345


promenljive realbroj, z1, z2, ceobroj dobiti iste vrednosti, i to 320.0, 'A', 'B', 707.
Sledi nekoliko primera naredbe izlaza:
a) write(a1, a2, a3, ..., an) - realizuje izdavanje vrednosti promenljivih a1, a2,..., an u
jednu liniju standardnog output fajla;
b) writeln(a1, a2,..., an) - realizuje izdavanje vrednosti promenljivih a1, a2, ..., an u jednu
liniju i posle ispisa poslednje vrednosti prelazak na poetak sledee linije output fajla;
c) writeln - realizuje proputanje linije output fajla i prelazak na poetak sledee linije.
Promenljive a1, a2,... , an iz liste naredbe izlaza mogu pripadati celobrojnom, realnom,
znakovnom ili logikom tipu.
Primer.
program ulazizlaz(input, output);
var
x,y,z:integer;
begin
readln(x,y); (*dodela vrednosti promenljivim x i y iz
jedne ulazne linije i prelazak na
pocetak sledece linije *)
readln; (*propustanje linije pri citanju *)
readln(z); (* dodela vrednosti promenljivoj z i prelazak na
sledecu liniju *)
writeln(x); (*ispis vrednosti x i prelazak na sledecu liniju *)
writeln; (*propustanje tekuce linije i prelazak na sledecu*)
writeln(y);(* ispis vrednosti y i prelazak na
sledecu liniju *)
writeln(z) (* ispis vrednosti z i prelazak na sledecu
liniju *)
end.

Ako se na ulazu unesu sledede vrednosti:


-11
55
452

25

34

35

na izlazu se dobija (TURBO-PASCAL):


-11
25
452

irina izlaznog polja, odnosno prostora rezervisanog za prikazivanje jednog podatka, zavisi
od implementacije jezika. Oblik ispisa promenljive u izlaznom polju odgovara tipu promenljive:
celobrojne promenljive se ispisuju kao cell brojevi, realne promenljive - kao realni brojevi sa
pokretnom decimalnom takom i normalizovanom mantisom, logike promenljive kao logike
konstante true ili false, znakovne promenljive kao znak. irina izlaznog polja za svaku
promenljivu se moe zadati eksplicitno u naredbi izlaza. Na primer, naredbom write(a:8) se za
ispis promenljive a odvaja izlazno polje od osam pozicija. U naredbi write(a: izlaznopolje)
irina izlaznog polja za a se definie konstantom izlaznopolje. Ako promenljiva zauzima manje
pozicija nego to joj dozvoljava irina polja, tada se suvine pozicije popunjavaju prazninama
leve strane. Ako irina polja nije dovoljna za ispis promenljive, tada se polje proiruje za
potreban broj pozicija.

30
Radi ispisa promenljivih realnog tipa u obliku sa fiksnom decimalnom takom zadaje se
irina polja m i broj cifara iza decimalne take n. Tada naredba izlaza ima sledei oblik:
write(x:m:n). Ako se ne zada broj znaajnih cifara iza decimalne take, to se realna promenljiva
izdaje u obliku sa pokretnom decimalnom takom.
Ako je radi ispisa logike promenljive u naredbi izlaza dat broj pozicija, to se suvine
pozicije popunjavaju prazninama ispred 'true' ili 'false'.
Pri ispisu promenljivih znakovnog tipa, ako je irina polja vea od jedan, to se suvine
pozicije ispunjavaju prazninama levo od znaka koji se ispisuje.
Prvi znak u listi naredbe izlaza write sluzi za zadavanje intervala izmeu izlaznih linija:' +'
- bez proputanja linije; praznina - proputanje jedne linije; '0' -proputanje dve linije; '1' prelazak na poetak sledee stranice.
Primer. Izvravanjem programa:
program izlaz(output);
const
a=235;
x=-4615.451;
y=22.39E2;
q=true;
c='b';
begin
write1n(a:8); writeln(x:10:3); write1n(y:11);
write1n(q:5,c:5)
end.

dobija se sledei izvetaj u output fajlu:


235
-4615.451
2.239E+03
true
b

Primeri u PASCAL-u
Primer. Izraunati obim i povrinu upisanog kruga kao i uglove trougla u radijanima.
PROGRAM trougao(input,output);
CONST
pi=3.14159;
stepen=180;
VAR
a,b,c,p,ri:real;
aa,bb,cc,st:real;
BEGIN
readln(a, b, c);
p:=(a + b + c)/2;
st:=sqrt(p * (p-a) * (p-b) * (p-c));
ri:=st/p;
aa:=2*stepen/pi*arctan(ri/(p-a));
bb:=2*stepen/pi*arctan(ri/(p-b));
cc:=2*stepen/pi*arctan(ri/(p-c));
writeln('krug: obim= ', 2*p:6:2,' povrsina = ',st: 6:2);
writeln(' poluprecnik = ', ri:6:2);
writeln('uglovi a=',aa:6:2,' b=',bb:6:2,' c=',cc:6:2);
END.

3.2. Ulaz i izlaz podataka u jeziku C


3.2.1. Funkcije printf() i scanf()

Predrag S. Stanimirovi

31

Programski jezici

Funkcija printf() se koristi za formatizovani izlaz podataka, a scanf() za formatizovano


uitavanje podataka. Ove funkcije se nalaze u standarnoj biblioteci stdio.h. Datoteka stdio.h
sadri podake neophodne za pravilno funkcionisanje ulazno-izlaznih funkcija. Njen sadraj se
ukljuuje u program naredbom
#include<stdio.h>.
Funkcija printf() se poziva izrazom oblika
printf(Upravljacki_string [, Arg1,Arg2,...]);

Lista argumenata moe da se izostavi. Tada je jedini argument funkcije printf() upravljaki
string koji se ispisuje na ekranu. U optem sluaju, funkcija printf() se primenjuje na listu
argumenata koja se sastoji iz dva dela. Prvi argument funkcije printf() je kontrolni ili
konverzioni string (upravljaki string), a drugi je lista izlaznih podataka ije se vrednosti
ispisuju. Konverzioni string odreuje format za tampanje liste izlaznih podataka. Najprostija
specifikacija formata poinje karakterom '%', a zavrava se konverzionim karakterom
(formatom ili konverzionom specifikacijom).
U sledeoj tabeli su prikazani konverzioni karakteri
konverzioni karakter
c
d
u
o
x, X
ld
lo
lx
f
lf
e, E
g, G
s
p

konverzija izlaznog niza


karakter char
ceo broj int
ceo dekadni broj bez znaka
oktalni broj int
heksadekadni broj int
dug ceo broj long int
dug oktalni broj long int
dug heksadekadni broj long int
fiksni zarez za float
double
pokretni zarez za float i double
krai zapis za f ili e
string
vrednost pointera

Konverzija g i G su jednake konverzijama e i E ukoliko je eksponent prikazanog broja manji od


-4 ili je vei ili jednak preciznosti obuhvaene specifikacijom d.
Opti oblik konverzione specifikacije je:
%[+|-| ][sirina][.tacnost]konverzioni_karakter
gde:
- konverzioni_karakter definie konverziju.
- Znak - ukazuje da se argument poravnava na levoj strani zadate irine polja.
- Znakom + se kod numerikih konverzija oznaava da ispred pozitivnih vrednosti treba da se
napie predznak +. Znak razmaka oznaava da je predznak praznina umesto +. Bez ovih
parametara konverzije, pozitivne vrednosti se prikazuju bez predznaka.
- Parametar sirina zadaje minimalnu irinu polja. Polje se proiruje za potreban broj pozicija ako
izlazna vrednost zahteva vie pozicija nego to je specificirano parametrom sirina. Ako
specifikacija irine polja poinje nulom, tada se polje umesto prazninama popunjava nulama u
neiskorienim pozicijama ako je poravnanje po desnoj margini.

32
- Parametar tacnost se koristi za realne brojeve (float ili double) i odreuje broj decimala iza
decimalne take.
Primer. (a) Posle izraza
printf("Danas je sreda \b\b\b\b\b petak \n ");

na ekranu se ispisuje tekst


Danas je petak.

(b) printf("Vrednost za x = %f\n", x);


(c) printf("n = %d x = %f %f^ %d=%lf\n", n,x,x,n,pow(x,n));
Funkcija scanf() ima za prvi argument kontrolni string koji sadri formate koji odgovaraju
ulaznim veliinama. Drugi argument jeste lista adresa ulaznih veliina.
scanf(Upravljacki_string [,Adresa1,Adresa2,...]);
Upravljaki string sadri konverzione specifikacije koje odgovaraju ulaznim veliinama. Lista
adresa sadri adrese promenljivih u koje se smetaju uitane i konvertovane vrednosti. Operator
adrese se predstavlja simbolom &. Adresa promenljive se formira tako to se ispred imena
promenljive pie operator adresiranja &.
Na primer, u izrazu scanf("%d", &x); format %d uzrokuje da se ulazni karakteri interpretiraju
kao ceo broj i da se uitana vrednost smeta u adresu promenljive x.
Neka su deklarisane celobrojne promenljive i, j, k. Tada se tri celobrojne vrednosti mogu
dodeliti ovim promenljivim preko tastature pomou operatora
scanf("%d%d%d", &i,&j,&k);
Za razdvajanje ulaznih polja u funkciji scanf() koriste se sledei znakovi: praznina (blank),
tabulator (tab) i prelaz u novi red (enter) (tzv. beli znaci). Izuzetak se ini u sluaju ako neki od
ulaznih znakova odgovara konverzionom karakteru %c, kojim se uitava sledei znak ak i kada
je on nevidljiv.
Pri ulaznoj konverziji opte pravilo je da podatak ini niz znakova izmeu dva bela znaka.
Odavde sledi da jednim pozivom funkcije scanf mogu da se uitavaju podaci iz vie redova.
Vai i obrnuto, vei broj poziva funkcije scanf moe da u itava uzastopne podatke iz istog reda.
Znaci koji se pojavljuju u upravljakom stringu a nisu konverzioni moraju se pri uitavanju
pojaviti na odreenom mestu i ne uitavaju se. Na primer, ako se unese ulazni red oblika
1:23:456
tada se operatorom
scanf("%d:%d:%d", &i,&j,&k);
celobrojnim promenljivim i, j i k dodeljuju vrednosti 1, 23 i 456, redom.
Opti oblik konverzione specifikacije je:
%[*][sirina]konverzioni_karakter
gde je:
- znak * oznaava da se obeleeno ulazno polje preskae i ne dodeljuje odgovarajuoj
promenljivoj.
- sirina zadaje maksimalnu irinu polja. Ako je irina polja vea od navedene u konverzionoj
specifikaciji, koristi se onoliko znakova koliko je zadato maksimalnom irinom.
- konverzioni_karakter je jedan od konverzionih znakova iz sledee tabele:

Predrag S. Stanimirovi

konverzioni karakter
c
h
d
ld,
o
lo,
x,
lx,
f
lf,
e
le,
s

D
O
X
F
E

33

Programski jezici

tip argumenta
pokaziva na char
pokaziva na short
pokaziva na int
pokaziva na long
pokaziva na int
pokaziva na long
pokaziva na int
pokaziva na long
pokaziva na float
pokaziva na double
pokaziva na float
pokaziva na double
pokaziva na string

Primer. (i) Neka je i celobrojna i x realna promenljiva.


Ako je ulazna linija oblika
57 769 98.
tada se operatorom
scanf("%2d%*d%f",&i,&x);
promenljivim i i x dodeljuju redom vrednosti 57 i 98.0.
(ii) Ako su i,j,k celobrojne promenljive i ako se unese ulazna linija 123 456 789, posle primene
operatora
scanf("%2d%3d%2d",&i,&j,&k);
promenljive i, j, k uzimaju vrednosti 12, 3, 45.

3.22. Direktive pretprocesora u C


Simbolika konstanta je konstanta kojoj je pridruen identifikator. U programu se kasnije
koristi identifikator, a ne vrednost konstante. Simbolike konstante u jeziku C se definiu
korienjem direktiva pretprocesora. Ovakva definicija poinje pretprocesorskom direktivom
#define (sve pretprocesorske direktive poinju znakom #). Iza direktive pretprocesora se navodi
simboliko ime konstante a zatim konstantna vrednost koja predstavlja vrednost te konstante.
Vrednost konstante se moe zadati na sledei nain:
- pomou imena ve definisane konstante;
- konstantom (celobrojnom, relanom, znakovnom, logikom);
- konstantnim izrazom.
Iza ove direktive ne koristi se znak ';' jer pretprocesorske direktive ne pripadaju jeziku C.
Pretprocesorske direktive se moraju navesti pre prvog korienja imena konstante u programu.
U praksi se direktive najee piu na poetku programa.
Direktive #define mora da se pie u posebnom redu. Jednom naredbom moe da se definie
samo jedna konstanta. Zajedno sa nekom ovakvom direktivom ne smeju da budu druge naredbe.
Jedino je dozvoljen komentar na kraju reda.
Identifikatori simbolikih konstanti piu se velikim slovima da bi se razlikovali od
identifikatora promenljivih koji se obino piu malim slovima. Ovo pravilo nije nametnuto
sintaksom jezika C ve stilom koji se ustalio u praksi.

34
Primer. Definisanje simbolikih konstanti.
#define
#define
#define
#define
#define
#define
#define

PI 3.141592
N 100
NMIN -N
PIX2 (PI*2)
LIMT 5
BELL '\007'
PORUKA "Zdravo"

Program napisan u jeziku C transformie se pomou razliitih procesora:


1. Tekst editor. Njegov ulaz je tekst koji se unosi pomou tastature, a izlaz je fajl izvornog koda.
2. Pretprocesor. Njime se fajl koji sadri izvorni kod programa transformie saglasno
pretporocesorskim direktivama koje se u njemu nalaze.
3. Kompajler. Njime se fajl izvornog koda u jeziku C prevodi u odgovarajui fajl izvornog koda
na asemblerskom jeziku.
4. Asembleri kojima se fajl na asemblerskom jeziku translira u objektni kod na mainskom
jeziku.
5. Linker. Njime se od objektnog koda i modula iz biblioteke C jezika kreira izvrni fajl (sa
ekstenzijom .exe).
Kod veine C sistema se pretprocesor, asembler i linker aktiviraju automatski startovanjem
kompajlera.
Mogunost da se konstanta definie pomou pretprocesorskih direktiva omoguuje da se
vrednost konstante jednostavno zapie i promeni na jednom mestu. Korienje konstanti u
programu navoenjem njihovih imena umesto odgovarajue vrednosti poveava itljivost
programa.
Takoe, moe da se uvede promenljiva kojoj se dodeljuje vrednost konstante.
Primer. Umesto izraza
#define POREZ 15
moe se pisati
float POREZ=15
Metod koji koristi promenljive je neefikasan, jer se pri svakom korienju vrednosti
promenljive vri obraanje memoriji za izraunavanje njene vrednosti, ime se usporava
izvrenje programa. Ovde se radi o smeni u ``vreme izvravanja'', za razliku od pretprocesorske
direktive kojom se vri smena ``u toku kompilacije''.

Primeri u C
Primer. Zbir dva broja u jeziku C.
#include <stdio.h>
main()
{ int x, y;
printf("Unesi dva cela broja");
scanf("%d %d", &x, &y);
printf("Njihov zbir je %5d\n",x+y);
}

Predrag S. Stanimirovi

35

Programski jezici

Primer. Proizvod dva broja tipa long.


#include <stdio.h>
main()
{ long x=2345678, y=67890;
printf("Njihov proizvod je %ld\n",x*y);
}

Primer. Zadavanje i prikazivanje karaktera.


#include <stdio.h>
main()
{ char c='A';
printf("%c%d\n",c,c);
}

Primer. Rad sa odreenim brojem decimala.


#include <stdio.h>
void main()
{float x=23.45678888, y=7.8976789;
printf("Njihov proizvod je:%f,%0.16f,%0.20f\n",
x*y,x*y,x*y);
}

Primer. Napredno korienje #define.


#include <stdio.h>
#define veci(X,Y) X>Y
#define kvad(X) X*X
#define kvadrat(X) ((X)*(X))
void main()
{printf("To su %d%d%d%d\n",
veci(3,2),kvad(5),kvad(5+5),kvadrat(5+5));
}
#include <stdio.h>
#define MAX
23
#define Ako
if
#define Onda
#define Inae else
main()
{ int n=24;
Ako (MAX > n) Onda printf("veci\n");
Inae printf("manji\n");
}

3.3. Ulazne i izlazne naredbe u paketu MATHEMATICA


Ulazne naredbe obezbeu naknadni unos podataka u program. U MATHEMATICA se podaci
mogu unositi interaktivno, direktno sa tastature. Funkcija Input[] uitava jedan izraz sa tastature
i vraa njegovu vrednost kao rezultat. Izraz Input[] otvara prozor za unos podataka ili itavog
niza dodatnih naredbi u program. Ova naredba utava izraze unete pomou tastature i u daljem
radu ih obrauje kao sastavni deo programa.
Naredba Read[] i OpenRead[] obezbeuju preuzimanje podataka iz datoteka ili neke elije.
Rezultat raunanja moe se videti navoenjem imena rezultujue promenljive ili neke izlazne
naredbe. Izlazna naredba Print[] vri prenos podataka ili poruka na ekran. Tekst na izlazu se
navodi izmeu apostrofa.

36

Input[ ]
Input["tekst"]
InputString[ ]
InputString["tekst"]
Print[izr1, izr2,..]

interaktivni unos jednog izraza


intraktivni unos, koristei tekst kao odziv
interaktivni unos niza karaktera
interaktivni unos niza karaktera, koristei tekst kao odziv
ispisivanje vrednosti izraza na ekran.

Za vreme rada korisnik moe da pristupi svim prethodno unetim izrazima, kao i dobijenim
rezultatima.
%n ili Out[n]
%...% ili Out[-n]

izraz n-te izlazne linije


izraz n-te izlazne linije, brojano od kraja.

4. OSNOVNE UPRAVLJAKE STRUKTURE

Svaki program sadri naredbe dodeljivanja kojima se izraunavaju vrednosti odreenih


izraza i pamte (dodeljuju) kao vrednosti odgovarajuih promenljivih. Ipak, veoma retko se bilo
koji program sastoji samo od jedne sekvence naredbi dodeljivanja kao i naredbi ulaza/izlaza.
Mnogo se ee zahteva postojanje vie razliitih tokova u zavisnosti od odreenih uslova ili
mogunost viestrukog izvravanja dela programa. Naredbe koje omoguavaju definisanje toka
programa nazivaju se upravlajke naredbe.
Upravlajke naredbe u prvom imperativnom programskom jeziku FORTRAN bile su
izvedene iz osnovnih mainskih naredbi. To je period kada metodologija programiranja tek
poinje da se razvija tako da jo nije definisan neki osnovni skup upravljakih naredbi. Poetkom
sedamdesetih Wirt definie metodologiju strukturnog programiranja i programski jezik Pascal sa
skupom upravljakih struktura kojima se implementiraju osnovne algoritamske strukture. Ovaj
koncept je iroko prihvaen, tako da danas vii programski jezici iz grupe proceduralnih jezika
obino raspolau skupom upravljakih struktura kojima se upravlja tokom izvrenja programa u
skladu sa konceptima strukturnog programiranja. Iako se od jezika do jezika ovaj skup
upravljakih struktura donekle razlikuje, moe se rei da su ipak meu njima u ovom domenu
male sutinske razlike. Smatra se da je skup naredbi kojima se upravlja tokom programa dovoljan
ako obezbeuje sledee tri osnovne upravlajke strukture:
(1)

Strukturu selekcije, koja omoguava izbor jedne od dve mogunosti. U Pascal-u se


obino implementira izrazom oblika:
If B then St else Sf ;

Predrag S. Stanimirovi

37

Programski jezici

Struktura selekcije odreena je if-then i if-then-else izrazima.


(2)

Strukturu viestruke selekcije, koja omoguava izbor jedne izmeu vie ponuenih
grana. U Pascal-u se koristi case izraz oblika:
case X of
xa : Sa;
xb : Sb;
end;

(3) Strukturu iteracije, koja omoguava viestruko izvravanje nekog bloka naredbi. U
jeziku Pascal se koristi while do petlja oblika:
while B do S;

Upravljake strukture jednog proceduralnog jezika bi trebalo da ispunjavaju sledee osobine:


smisao naredbi mora da bude jasan i jednoznaan;
sintaksa naredbe treba da bude tako postavljena da dozvoljava hijerarhijsko ugraivanje
drugih naredbi, to mora da bude jednoznano definisano i jasno iz samog teksta
programa;
potrebno je da postoji mogunost lake modifikacije naredbi.
Na primeru if naredbe u jeziku Pascal moe se pokazati sta se pod navedenim kriterijumima
podrazumeva, ali i da je to primer naredbe koja ne zadovoIjava nijedan od navedenih kriterijuma.
(1) Uzmimo kao primer sledeu naredbu:
if B1 then if B2 then Sa else Sb;

U ovoj naredbi nije potpuno jasno da li se Sb izvrava kada je B1 = false ili kada je B1 = true i
B2 = false (to je u ovom sluaju tano).
Problem postaje jo oigledniji ako se ista naredba napie u obliku:
if B1 then
if B2 then Sa
else Sb;

Ovaj izraz bi trebalo napisati u obliku:


if B1 then
if B2 then Sa
else Sb;

(2) Problemi postaju jo sloeniji kada se posmatra sledei primer:


if B1 then
if B2 then S;

Naredba S je u ovom primeru zavrna naredba i prve i umetnute if naredbe to znai da


hijerarhijsko ugraivanje naredbi u ovom jeziku znaajno umanjuje itljivost programa. Ovaj
problem donekle moe da se prevazie upotrebom begi n end zagrada, meutim to komplikuje
strukturu ime se gubi preglednost programa. To je oigledno iz sledeeg sasvim jednostavnog
primera:
if B1 then
begin
if B2 then
begin
Sa
end
end;

38
Ovaj izraz bi trebalo pisati u obliku
if B1 and B2 then Sa;

(3) Trei kriterijum ilustrovaemo sledeim primerom:


if B1 then S a ;

U then grani se izvrava samo jedna naredba, ako je potrebno proiriti tu granu jo nekom
naredbom, to se ne moe postii samo jednostavnim dopisivanjem naredbe na sledei nain:
if B1 then Sa; Sb;

Potrebno je izvriti sloeniju izmenu umetanjem i zagrada begin i end:


if B1 then
begin Sa; Sb end;

4.1. SEKVENCA NAREDBI I BLOK


Sekvenca naredbi je jedan od osnovnih koncepata u strukturnim jezicima, uveden radi lake
implementacije drugih upravljakih struktura. Prvi put se javlja u jeziku Algol 60, u kome se
naziva i sloena naredba, a definisan je kao niz naredbi ogranien zagradama begin i end:
begin
naredba_1;
.
naredba_n
end

Sekvenca naredbi se u Algol-u 60 moe pojaviti svuda gde je sintaksom dozvoljena naredba.
Time ovaj koncept postaje jako sredstvo apstrakcije naredbe.
U Algol-u 60 se prvi put javlja i koncept bloka kao uoptenje koncepta sekvence naredbi.
Blok je po definiciji upravljaka struktura koja sadri opise lokalnih promenljivih i sekvencu
naredbi. Kao i sekvenca, zatvara se zagradama b e g i n i end.
begin
deklaracija_1;

.
deklaracija_m;
naredba_1;

.
naredba_n
end

Promenljive opisane u jednom bloku su lokalne promenljive tog bloka, a globalne za sve
blokove sadrane u njemu. Ukoliko se u nekom bloku predefiniu promenljive ve definisane u
spoljanjem bloku, u unutranjem bloku vae te nove definicije kao lokalne definicije bloka. Van
bloka prestaje dejstvo lokalnih definicija unutra[njeg bloka. Razmotrimo sledei primer, koji je
konstruisan sa idejom da ilustruje dejstvo lokalnih i globalnih definicija.
Primer. Globalne i lokalne promenljive.
A: begin real a; ... Pa;
B: begin real b; ... Pb end;
C: begin real c; .. PC;
D: begin real d; . .. Pd end;
E: begin real e; ... Pe end;
end;
F: begin real f; .. Pf;
G; begin real g; ... Pg end;

Predrag S. Stanimirovi

Programski jezici

39

end;
end;

U ovom primeru postoji sedam blokova (oznaeni oznakama A:, B:, C:, D:, E:, F: i G : ) i u
svakom od ovih blokova opisana je po jedna promenljiva. Sledea tabela daje podatke o svim
blokovima u programu. Slovo L oznaava da je promenljiva lokalna, a G da je globalna.
Promenljiva A
A
L
B
C
D
E
F
G

B
G
L

C
G
L

Blok
D
E
G
G
G
L

F
G

G
G

G
L

G
L

U sledeem primeru dat je jo jedan program koji sadri blokove i ilustruje koncept lokalnih i
globalnih promenljivih.
Primer. Blok u jeziku C.

#include<stdio.h>
void main()
{ float a,b,c,d;
a=1.0; b=2.0; c=3.0; d=4.0;
printf("Spoljasnji blok a=%f b=%f c=%f d=%f\n",a,b,c,d);
{ float c,d,e,f;
c=a+10; d=b+20; e=c+30; f=d+40;
printf("Unutrasnji blok a=%f b=%f c=%f d=%f e=%f f=%f\n",
a,b,c,d,e,f);
}
printf("Spoljasnji blok a=%f b=%f c=%f d=%f\n", a,b,c,d);
}

U ovom primeru postoje dva bloka: prvi u kome se definiu promenljive a, b, c i d i drugi u
kome su promenljive c i d predefinisane i promenljive e i f prvi put definisane. Kako je drugi
blok unutar prvog dejstvo ovih definicija je sledee:

a, b, c i d su lokalne promenljive prvog bloka.


c, d, e i f su lokalne promenljive drugog bloka.
a i b vae i u drugom bloku kao globalne promenljive.
c i d su opisane i u prvom i u drugom bloku pa se u svakom od ovih blokova mogu koristiti
nezavisno od njihove namene u drugom bloku.
e i f se mogu koristiti samo u drugom bloku dok su u prvom nedefinisane.
Kao posledicu ovako postavljenih definicija promenljivih naredbom za tampanje u
umetnutom bloku tampaju se brojevi 1.0, 2.0, 11.0, 22.0, 41.0 i 62.0, dok naredba za tampanje
u spoljanjem bloku daje: 1.0, 2.0, 3.0 i 4.0.
Kako dejstvo lokalnih promenljivih prestaje po izlasku iz bloka, kod ponovnog ulaska u isti
blok one su nedefinisane i potrebno je da im se ponovo dodele neke inicijalne vrednosti.
Ovakve sluajeve imamo kada je blok sastavni deo neke petlje. Meutim, ba u tim sluajevima
korisno je da u nekom novom prolazu kroz blok raspolaemo sa vrednostima lokalnih
promenljivih iz prethodnog prolaza kroz blok. Odnosno, pogodno je da lokalne promenljive
sauvaju svoje vrednosti po izlasku iz bloka, tako da su te vrednosti dostupne u narednom
prolasku kroz isti blok.

40
Sekvenca naredbi se u istom ovom obliku pojavljuje i u Pascal-u dok je struktura bloka
izostavljena. U C-u postoje oba koncepta ali su zagrade begin i end zamenjene zagradama { i }.
To ilistruje sledei primer.
Primer. Primer sekvence naredbi u C-u.
main()
{ printf("Ovo je ");
printf("primer");
printf(" sekvence");
printf(" naredbi.");
}

Kod novijih jezika kod kojih je zastupljen koncept kljunih rei kojima se otvaraju i
zatvaraju delovi upravlajke strukture, sekvenca naredbi ne postoji kao odvojena struktura ve
je sastavni deo drugih upravljakih struktura.

4.2. Struktura selekcije


Struktura selekcije omoguava definisanje vie moguih tokova programa i jedno je od
osnovnih sredstava za pisanje fleksibilnih programa. Strukture selekcije dele se u dve osnovne
grupe. Jednoj pripadaju takozvane if-selekcije, a drugoj viestruka selekcija.
If-selekcije se obino javljaju kao if-then i if-then-else struktura, pri emu prva omoguava
izbor posebnog toka u zavisnosti od odreenog uslova, a druga izbor jedne ili druge alternative u
zavisnosti od toga da li je ili ne odreeni uslov ispunjen.

4.2.1. If-then struktura


If-then struktura se obino implementira kao poseban, jednostavniji sluaj if-then-else strukture.
Jedino kod nekih starijih jezika (BASIC, FOTRAN) ona postoji kao zasebna upravljaka
struktura. Na slici 4.1 prikazan je dijagram toka koji ilustruje ovu strukturu na nivou algoritma.
true
uslov
false

niz naredbi

Slika 4.1 If-then


U FORTRAN-u se if-then
formu:

struktura
struktura naziva logikom IF naredbom i ima sledeu
IF ( I o g i k i izra z) naredba

Naredba koja sledi iza logikog izraza izvrava se samo ako je vrednost logikog izraza
jednaka TRUE, inae se nastavlja nepromenjeni tok programa. Uobiajeni nain korienja ove
naredbe ilustruje sledei primer.
Primer. Logika IF naredba u FORTRAN-u.

20

IF (.NOT. Uslov) GO TO 20
I=1
J=2
K=3
CONTINUE

U ovom primeru, ako je vrednost promenljive U s l o v jednaka FALSE program se nastavlja od


naredbe sa oznakom 20. Za vrednost T R U E iste promenljive program se nastavlja naredbom
I=1 koja sledi neposredno iza naredbe IF.

Predrag S. Stanimirovi

41

Programski jezici

Uvoenjem koncepta sekvence naredbi, if-then naredba u Algol-u dobija neto drugaiji
smisao. U optem sluaju njena struktura je definisana kao:
if (logiki izraz) then
begin
naredba_1;
naredba_2;
naredba_n
end;

Sekvenca naredbi obuhvaena zagradama b e gi n i end je sastavni deo if naredbe. Ta se


sekvenca naredbi izvrava za vrednost t r u e logikog izraza. Za vrednost f a l s e sekvenca
naredbi se preskae i program nastavlja sa prvom naredbom koja sledi iza zagrade end.
Primer. If-then natedba u Algol-u 60.
if (uslov) then
begin
i:=1;
j:=2;
k:=3
end;

If-then struktura se javlja u razliitim oblicima u mnogim jezicima iji su koreni u Algol-u 60,
ukljuujui i FORTRAN 77 i FORTRAN 90. Obino se ova struktura implementira kao poseban
sluaj if-then-else strukture.
U FORTRAN-u se moe koristiti IF-THEN i IF-THEN-ELSE struktura, prema sledeoj
sintaksi:
IF(uslov)
naredba
END IF

ili
IF(uslov)
naredba
ELSE
naredba
END IF

Uoimo da se u ovom jeziku koriste kljune rei kojima se otvaraju i zatvaraju pojedini
delovi strukture.

4.2.2. If-then-else struktura


Dijagram toka if-then-else strukture koji ilustruje smisao ove strukture na nivou algoritma
prikazan je na slici 4.2. Ova upravljaka struktura se prvi put javlja u Algol-u 60 i to u obliku:
if (logiki_izraz)
then naredba
else naredba;

Naredba koja sledi then predstavlja then granu programa, a naredba iza else, else granu. Kada
je vrednost logikog izraza true izvrava se then grana, a kada je vrednost false - else grana
programa.

42

false

uslov

true

else-grana
then-grana
Slika 4.2 If-then-else struktura
Ova upravljaka struktura postoji u svim proceduralnim jezicima sa odreenim varijacijama
u sintaksi. U Pascal-u je prihvaena sintaksa iz Algol-a. Sledei primer ilustruje mogunosti
njene primene.
Primer.
if (broj = 0) then
res := 0
else
res := 1;

Ovako definisana if-then-else struktura ima niz nedostataka koji posebno dolaze do izraaja
kada se if naredbe ugrauju jedna u drugu. Na primer u Pascal-u je mogue napisati sledeu
sekvencu naredbi:
if (sum = 0) then
if (broj = 0)
then res := 0
else res := 1;

Ova sekvenca naredbi moe da bude protumaena na dva razliita naina u zavisnosti od
toga da li else grana pripada prvoj ili drugoj if naredbi. U Pascal-u, kao i u vie drugih jezika
koji koriste isti koncept za razreavanje ovakvih situacija, primenjuje se semantiko pravilo da
se else grana uparuje sa najbliom neuparenom then granom. Oigledno je da u ovakvim
sluajevima moe da doe do pogrenog tumaenja pojedinih segmenata programa. U Algol-u
se ovaj problem razreava na sintaksnom nivou. Naime, u Algol-u nije dozvoljeno ubacivanje if
naredbi u then granu ve se nadovezivanje if naredbi moe vriti samo po else grani. Kada je
neophodno da se po then grani vri dalje grananje obavezna je upotreba zagrada kojima se
naredba koja se ubacuje transformie u takozvane proste naredbe koje se jedino mogu nai u
then grani. Prethodni primer bi, u Algol-u, bio napisan kao u sledeem primeru.
Primer. Umetanje if naredbi u Algol-u.
if sum = 0 then
begin
if broj = 0
then res := 0
else res := 1
end;

Ako u prethodnom primeru else grana treba da bude sastavni deo prve if naredbe dati deo
programa treba da bude napisan kao u primeru koji sledi.
Primer. Umetanje if naredbi u Algol-u (druga verzija).
if sum = 0 then
begin
if broj = 0
then res := 0
end
else res := 1;

Predrag S. Stanimirovi

43

Programski jezici

Noviji i pouzdaniji koncept sa kojim se reava problem nadovezivanja if naredbi, koristi


kljune rei kojima se otvaraju i zatvaraju delovi strukture. U sluaju if-then-else naredbe imamo
da se deo sa uslovom otvara sa if, a zatvara sa then. Then ujedno otvara then blok koji se
zatvara sa else, dok se else blok otvara sa else, a zatvara posebnom kljunorn rei kojom se
ujedno zavrava i cela upravljaka struktura.
Primer. Upotreba if naredbe u FORTRAN-u 77.
IF (broj = 0) THEN
res = 0
ELSE
res = 1
END IF

U mnogim jezicima to je end, a esto se javlja i end if. FORTRAN 77 je primer jezika kod
kojeg je zastupljena ovakva sintaksa naredbe if, to ilustruje primer u nastavku.
Primer. Umetanje if naredbi u FORTRAN-u 77.
IF sum = 0
THEN
IF (broj = 0) THEN
res = 0
ELSE
res =1
END IF
END IF

U ovom jeziku if naredba koja je ubaena u else granu smatra se sastavnim delom polazne if
naredbe dok se if naredba u then grani mora zatvoriti svojom END IF zagradom .
Primer. Nadovezivanje IF naredbi po else grani.
IF sum = 0 THEN
res = 0
ELSE
IF (broj = 0) THEN
res =10
ELSE
res = 2
END IF

Primeri u C.
Primer. Izraunati minimum 3 uneta broja
void main()
{ int x,y,z,min;
printf("Unesite tri cela broja: ");
scanf("%d%d%d", &x, &y, &z);
if(x<y)
min = x;
else
min = y;
if(z<min) min = z;
printf("Minimum je %d\n", min);
}

Izraunati kvadratni koren unetog broja


#include <stdio.h>
#include <math.h>
main()

44
{ double x;
printf("Unesite x: ");scanf("%lf",&x);
if(x >= 0.0)
printf("\n%10s%16f \n%10s %16f \n",
x=",x,"sqrt(x)=",sqrt(x))
else printf("\n Negativan broj \n\n");
}

Primer. Za zadate brojeve x i y izraunati z po formuli


z=(min (x,y)+0.5)/(1+max 2(x,y)).
void main ()
{ float x,y,z;
printf(" Zadati x,y:\n");
scanf("%f%f',&x,&y);
if(x<y)
z=(x+0.5)/(1+y*y);
else
z=(y+0.5)/(1+x*x);
printf("z = %f",z);
}

Primer. Napisati program kojim se dati brojevi x,y,z udvostruavaju ako je x>=y>=z, a u
protivnom menjaju znak.
main()
{ float x,y,z;
printf("Zadati x,y,z:\n");
scanf("%f%f%f",&x,&y,&z);
if((x>=y) && (y>=z))
{ x*=2; y*=2; z*=2; }
else
{ x=-x; y=-y; z=-z; }
printf("x=%f y=%f z=%f", x,y,z);
}

Kod else-if iskaza je vano da rezervisana re else odgovara prethodnom slobodnom if, ukoliko
to nije drugaije odreeno velikim zagradama.
Primer. Na osnovu broja poena koje je uenik osvojio izraunati njegovu ocenu, prema
sledeem pravilu: 90..100: 5, 75..89: 4, 60..74: 3, 45..59: 2, 0..44: 1.
main()
{ int poeni, ocena;
scanf("%d",poeni);
if(poeni > 89) ocena=5;
else if(poeni > 74) ocena=4;
else if(poeni > 59) ocena=3;
else if(poeni > 44) ocena=2;
else ocena=1;
printf("Ocena= %d\n", ocena);
}
Primer. Izraunati
-5, x<0,
x+2, 0<=x<1,
y =
3x-1, 1<=x<5,
2x, x>=5.
main()
{ float x,y;
scanf("%f",&x);

Predrag S. Stanimirovi

45

Programski jezici

if(x<0) y=-5;
else if(x<1) y=x+2;
else if(x<5) y=3*x-1;
else y=2*x;
printf("y= %f\n", y);
}

Primer. Izraunati vrednost izraza ch = 'Y', gde je ch dati karakter.


main()
{ char ch;
scanf("%c", &ch);
if(ch=='Y') printf("%d\n", 1);
else printf("%d\n", 0);
}

Primer. Urediti tri zadata realna broja u poredak x<y<z.


#include<stdio.h>
main()
{ float x,y,z,p;
scanf("%f%f%f",&x,&y,&z);
if(x>y)
{ p=x; x=y; y=p; }
if(x>z)
{ p=x; x=z; z=p; }
if(y>z)
{ p=y; y=z; z=p; }
printf("x= %f y= %f z= %f\n",x,y,z);
}

Primer. Data su tri realna broja u poretku x<y<z. Umetnuti realni broj t tako da meu njima
bude odnos x<y<z<t.
void main()
{ float x,y,z,t,p;
scanf("%f%f%f%f",&x,&y,&z,&t);
if(t<x)
{ p=t; t=z; z=y; y=x; x=p; }
if(t<y)
{ p=t; t=z; z=y; y=p; }
if(t<z)
{ p=t; t=z; z=p; }
printf("x= %f y= %f z= %f t= %f\n",x,y,z,t);
}

Primer. Diskutovati sistem linearnih jednaina


a1x+b1y = c1
a2x+b2y = c2.
void main()
{ float a1,b1,c1,a2,b2,c2,d,dx,dy,x,y;
printf("Koeficijenti prvog sistema?");
scanf("%f%f%f", &a1,&b1,&c1);
printf("Koeficijenti drugog sistema?");
scanf("%f%f%f", &a2,&b2,&c2);
d=a1*b2-a2*b1; dx=c1*b2-c2*b1; dy=a1*c2-a2*c1;
if(d!=0){x=dx/d; y=dy/d; printf("x=%f y=%f\n",x,y);}
else if(d==0 && dx==0 && dy==0)
{ printf("Sistem je neodreen ");
printf("resenje je oblika X,(%f-%fX)/%f\n",
c1,a1,b1);
}
else printf("Sistem je nemoguc\n");

46
}

Primer. U gradu A se nalazi zaliha goriva od V (0 < V < 2000000000) litara, od koje kamioncisterna treba da dostavi to je mogue veu koliinu u grad B. Od grada do gada B ima tano
d (0 < d 2000) kilometara. Cisterna troi litar na jedan kilometar, a moe da primi ukupno C (0
< C 5000) litara za prevoz i potronju.
Napisati program koji za date V, d, C, ispisuje koliko najvie goriva moe da se dostavi iz A
u B, i koliko PRI TOME najvie moe ostati u A. Cisterna moe ostati u gradu koji daje
povoljniji ishod.
Test primer:
2000 100 1000

1700 0

#include <stdio.h>
void main ()
{ long V, d, Cap, A, B;
printf("Unesi kolicinu u gradu A: "); scanf ("%ld",&V);
printf("Unesi rastojanje izmeu gradova: "); scanf ("%ld",&d);
printf("Unesi kapacitet cisterne: "); scanf ("%ld",&Cap);
A = V; B = 0;
if ( (Cap > d) && (V >= Cap) )
{ if (Cap > 2 * d)
{ A = V % Cap;
B = (Cap - 2 * d) * (V / Cap);
if (A <= d) B = B + d;
else
{ if (A - d > d)
{B = B + A - d; A = 0;}
else
B = B + d;
}
}
else
{A = V-Cap; B = Cap-d;}
}
printf ("A = %ld B = %ld\n", A, B);
}

Primeri u Pascal-u
Primer. Detekcija tastera HOME na tastaturi.
program detect;
uses crt;
label a;
var c : char;
begin
clrscr;
a:c:= readkey;
if(c = #0)then
begin
c := readkey;
if ord(c) > 127 then c := #0
else c := chr( ord(c) + 128);
end;
if(c = #199)then writeln('Bilo je HOME');
goto a;
end.

Predrag S. Stanimirovi

47

Programski jezici

4.2.3. Operator uslovnog prelaza u C


Operator uslovnog prelaza ?: je neobian. Pre svega, to je ternarni operator, jer uzima tri izraza
za svoje argumente. Njegova opta forma je
exp1 ? exp2 : exp3;
Prvi argument je pre znaka pitanja '?'. Drugi argument je izmeu '?' i ':', a trei posle ':'.
Semantika ovakvog izraza je sledea. Prvo se izraunava izraz exp1. Ako je njegova vrednost
razliita od 0 (true), tada se evaluira izraz exp2, i njegova vrednost je vrednost celog izraza.
Ako je vrednost izraza exp1 nula (false), tada se evaluira izraz exp3, i njegova vrednost se
vraa kao rezultat. Na taj nain, ovaj izraz predstavlja zamenu za if-else naredbu.
Primer. Umesto izraza
if(y<z) x=y;
else x=z;
kojim se izraunava x=min{y,z}, moe se pisati
x=(y < z) ? y:z;
Zagrade se mogu izostaviti.
Prioritet operatora uslovnog prelaza je vei od prioriteta operatora dodeljivanja, a njegova
asocijativnost je ``s desna na levo''.
Primer. Vrednost izraza
(6>2)?1:2
jednaka je 1, dok je vrednost izraza
(6<2)?1:2
jednaka 2.

Primeri.
Primer. Izraunati abs(x)=|x|.
void main()
{ float abs,x;
scanf("%f",&x);
abs=(x<0) ? -x : x;
printf("%f\n", abs);
}

Primer. Izraunati max{x,y}.


void main()
{ float x,y;
scanf("%f%f",&x,&y);
max=(x>y) ? x : y;
printf("%f\n", max);
}

Primer.
1. Vrednost izraza

s=

-1, x < 0,
x * x, x>=0

48

moe se izraunati pomou


s=(x < 0) ? -1 : x*x;
Ako je izraz posle ':' takoe uslovni izraz, dobijamo else-if operator.
2. Vrednost s=sgn(broj) se moe izraunati pomou
s=(broj < 0) ? -1 : ((broj==0) ? 0 : 1);
Kompletan program je sledeeg oblika:
void main()
{ float broj;
scanf("%f%f",&x,&y);
printf("Unesite broj\n");
scanf("%f", broj);
printf("Znak=%d\n",
(broj<0) ? -1 : (broj==0) ? 0 : 1);
}

3. Bez korienja operatora if napisati program koji za zadate x,y izraunava


z=

min {x,y}, y>= 0,


max {x2,y2}, y<0.
z=(y>=0) ? ((x<y) ? x:y) : ((x*x>y*y) ? x*x : y*y);

4.2.4. If naredba u paketu MATHEMATICA


MATHEMATICA obezbeuje razliite naine za definisanje uslovnih izraza, koji specificiraju
parcijalne izraze koji se evaluiraju ako su odreeni uslovi ispunjeni. U MATHEMATICA se
uslovni izrazi IfThen i IfThenElse predstavljaju pozive funkcija.
If[test, thengrana]
If[test,thengrana,elsegrana]

Izvravaju se izrazi u thengrana ako test ima vrednost


True
izvrava se thengrana ako test ima vrednost True, inae se
izvrava elsegrana

@ D
@
D
@ D
@D

x=7
7
If x < 10, b = 0, b = 20
0
b
0
If 7, a = 0, a = 20
If 7, a = 0, a = 20
a
a
If 7 > 8, x, y
y
y

Takoe, jednu vrstu uslovnih izraza ine izrazi sledeeg tipa, koji omoguavaju da se
definicija koristi samo ako je odreen uslov ispunjen:

Predrag S. Stanimirovi

lhs:=rhs/; test

Programski jezici

49

koristi definiciju samo ako test evaluira u True

Pojedinane definicije funkcija koje u svojoj desnoj strani sadre naredbe uslovnog prelaska
mogu se zameniti sa nekoliko definicija, od kojih je svaka kontrolisana odgovarajuim uslovom
/;test.
1,
x 0
Na primer, u sledeem izrazu je definisana funkcija f[x]= 1, x 0
f[x_]:=If[x>0, 1, -1]
Ekvivalentna sa funkcijom f je sledea funkcija g:
g[x_]:=1/; x>0
g[x_]:=-1/; x<=0
?g
Global'g
g[x_]:=1/; x>0
g[x_]:=-1/; x<=0

(* Pozitivni deo funkcije f *)


(*Negativni deo funkcije f *)

Vaan detalj simbolikog izraunavanja u MATHEMATICA je da uslovni izrazi mogu da


produkuju rezultate koji su razliiti i od True i od False. U sluaju da test u If izrazima
produkuje rezultat koji nije ni True, ni False, tada ovi izrazi ostaju neevaluirani.

@
@D
D

If x == y, a, b
If x == y, a, b

Moe se dodati etvrti argument naredbi If, koji se koristi ako test produkuje rezultat koji nije
ni True ni False.
If[test, thengrana, elsegrana, default]

@ D

Ovakav izraz je jedna forma naredbe If koja ukljuuje izraz default, koji se koristi ako test nije
ni True ni False.
If x y, a, b, c
c

Funkcija If dozvoljava izbor izmeu dve alternative. Me|utim, esto je potrebno da se testira
vei broj uslova. To se moe uiniti pomou veeg broja umetnutih If funkcija. Mnogo je
efikasnije da se to uradi funkcijama Which i Switch.
Which[test1, value1,
test2, value2, ...]
Switch[expr,form1, value1,
form2, value2, ...]
Switch[expr,form1,value1,
form2, value2,..., def]

evaluira se redom test1,test2,... pri emu je rezultat


vrednost asocirana sa prvim testi koji je True
uporeuje se expr sa svakim od izraza form1,..., a
rezultat je vrednost izraza valuei, koji je asociran
sa prvim izrazom formi koji se slae sa expr
koristi se def kao vrednost koja se vraa ako se
nijedan od izraza formi ne slae sa expr

U poslednjoj tabeli svaki od izraza value1, value2, ... predstavlja jedan izraz ili sekvencu izraza
koji su razdvojeni znakom ;.

@
D@

Na primer, izrazom:

h x_ := Which x < 0, x^2, x > 5, x^ 3, True, 0

@
D

definisana je funkcija h sa tri grane. Trea grana je uvek ispunjena ako nisu prethodne dve.
h

-5

50

@
D
@
D@
@
D D
@
D
@ D
@
D@@@D
@
D
@
D
@
D DD

25

(*Koristi se prvi sluaj u Which*)

h 2
0

(*Koristi se tre}i slu~aj*)

residue x_ := Switch Mod x, 3 , 0, a, 1, b, 2, c

(*Rezultat zavisi od ostatka pri deljenju argumenta sa 3*)


residue 7
b

(*Mod[7,3]=1, pa se koristi drugi sluaj*)

Switch 17, 0, a, 1, b, _, g
g

(*17 se ne sla`e sa 1, ali se sla`e sa _*)

res x_ := Switch Mod x, 3 , 0, Print "Ostatak je 0 " ; a, 1, Print "Ostatak je 1 " ; b,


2, Print "Ostatak je 2 " ; c
res 17
Ostatak je 2
c

4.3. Struktura viestruke selekcije


Struktura viestruke selekcije omoguava izbor jedne od vie moguih naredbi ili grupa
naredbi u zavisnosti od vrednosti odreenog uslova. Graf na slici 4.3 ilustruje ovu upravljaku
strukturu na nivou algoritma.
Kako se svaka viestruka selekcija moe simulirati obinim if-then-else grananjem, na slici
4.4 prikazan je dijagram toka koji odgovara viestrukom grananju sa slike 4.3.
false

true

false
true

false

true

Slika 4.3 Dijagram toka algoritma sa grananjima po else grani

Predrag S. Stanimirovi

51

Programski jezici

Slika 4.4 Algoritam strukture viestrukog grananja

Slika 4.5 Viestruko grananje predstavljeno preko if-then-else strukture


Ova struktura koja je u svom razvoju pretrpela mnogo izmena do jednog modernog oblika koji
se danas u manje-vie slinim varijantama javlja u svim programskim jezicima.
Neki zaeci ove strukture nalaze se u aritmetikoj IF naredbi FORTRAN-a koja u sutini
predstavlja naredbu za viestruko grananje ali ogranienu na tri grane, koje odgovaraju
sluajevima kada je aritmetiki izraz postavljen kao uslov grananja manji od nule, jednak nuli ili
vei od nule. Aritmetika IF naredba ima sledei oblik:
IF (aritmetiki izraz) N1, N2, N3

gde su Nl, N2 i N3 oznake naredbi (u FORTRAN-u su to prirodni brojevi) na koje se prenosi


upravljanje u sluaju kada je vrednost izraza manja, jednaka ili vea od nule, respektivno.
Primer. Program za izraunavanje funkcije y u FORTRAN-u.
-x 2 ,
y=

0, x = 0
x2,

10
20
30
40

x<0

x>0.

IF (x) 10, 20, 30


y = -(x*x)
GOTO 40
y = 0
GOTO 40
y = x*x
....

U FORTRAN-u se kasnije pojavljuju jo dve varijante naredbe za viestruko grananje


poznate kao izraunato GOTO i dodeljeno GOTO. Izraunato GOTO ima sledeu formu:
GOTO (oznaka_1, oznaka_2,oznaka_k), izraz

52

Izraz u ovoj naredbi mora da ima celobrojnu vrednost. Od vrednpsti izraza zavisi kojom e
se naredbom nastaviti izvrenje programa. Za vrednost 1 izvrava se naredba programa
oznaena prvom oznakom u listi oznaka, za vrednost 2 drugom oznakom itd. za vrednost k, ktom oznakom. U sluaju da vrednost izraza izlazi iz opsega od 1 do k u programu se nita ne
dogada. U ovu naredbu nije ugraeno otkrivanje i reakcija na ovakve greke u programu.
Druga naredba FORTRAN-a, poznata kao dodeljeno GOTO, ima sledei oblik:
GOTO celobrojna_promenljiva (oznaka_1. oznaka_2, ..., oznaka_k)
Celobrojna promenljiva navedena u naredbi pamti vrednost oznake sa kojom se program
nastavlja. Njoj se vrednost dodeljuje eksplicitno naredbom ASSIGN oblika:
ASSIGN oznaka TO celobrojna_promenljiva
Oznaka koja se dodeljuje promenljivoj mora da bude definisana u samom programu (u
glavnom programu ili potprogramima koje poziva).
Korene koncepta viestrukog grananja koji se danas najvie sree u programskim jezicima
postavili su Wirt i Hoare 1966. godine u okviru jezika Algol-W. Sve grane koje se daju kao
alternative obuhvaene su jednom strukturom koja ima jedan ulaz i jedan izlaz. Kraj strukture je
ujedno i kraj svake od alternativa. Opti oblik ove naredbe definisan je na sledei nain:
case celobrojna_promenljiva of
begin
naredba_1;
naredba_2;

naredba_k;
end
Koja e se od naredbi u ovoj strukturi izvriti zavisi od vrednosti izraza. Za vrednost 1 izvrava
se prva naredba, za vrednost 2 druga itd. za vrednost k k-ta.

4.3.1. Viestruka selekcija u Pascal-u


Case struktura zauzima svoje pravo mesto u programskim jezicima sa pojavom Pascal-a. U
Pascal-u ona ima sledei oblik:
case izraz of
lista_konstanti_1: naredba_1;
lista_konstanti_2: naredba_2;

lista_konstanti_k: naredba_k;
end
Izraz naveden u naredbi mora bude diskretnog tipa (Integer, Boolea n, C h a r ili tip
nabrajanja). Naredba se izvrava tako to se izraunava vrednost i z r a z i poredi sa konstantama
u listi konstanti. Kada se pronae konstanta ija je vrednost jednaka vrednosti i z r a z izvrava
se odgovarajua naredba (ona koja je vezana za listu konstanti kojoj pripada naena konstanta).
Po zavretku izabrane naredbe program se nastavlja sa prvom naredbom iza case strukture.
Oigledno je da lista konstanti mora po tipu da odgovara izrazu na osnovu kojeg se vri
selekcija. Jedna konstanta ne moe se pojavljivati na vie grana iste case strukture ali takoe sve
vrednosti opsega kome pripada aritmetiki izraz ne moraju se navesti u listama konstanti.
U prvoj definiciji ove naredbe jednostavno je ignorisan sluaj kada u spisku alternativa ne
postoji alternativa za odreenu vrednost izraza, odnosno kada se dogodi se da izraz ima
vrednost koja nije navedena u spisku konstanti. Problem koji se pri tome javlja bio je naprosto

Predrag S. Stanimirovi

53

Programski jezici

ignorisan. Podrazumevalo se korektno korienje strukture. Kasnijim ANSI/IEEE Pascal


standardom ovaj problem je stroe sagledan, pa se taj sluaj tretira se kao greka na koju sistem
reaguje u fazi kompilovanja programa.
Primer. Case struktura u Pascal-u.
case index of
1,3: begin
nep := nep + 1;
sumnep := sumnep + index
end;
2,4: begin
par := par + 1;
sumpar := sumpar + index
end;
else writeln(Greska slucaj: index = , index)
end;

Mnoge savremene verzija Pascal-a imaju mogunost da se u posebnoj grani u case strukturi
definie ta se dogaa u sluaju kada vrednost izraza nije navedena u spisku konstanti.
Prethodni primer ilustruje tako definisanu case naredbu u Pascal-u.
U sluaju kada index izlazi iz opsega od 1 do 4 tampa se poruka o greki u programu, inae
izraunava se posebno broj parnih i broj neparnih indeksa i odgovarajue sume.

4.3.2. Viestruka selekcija u C


U programskom jeziku C naredba za viestruko grananje ima dosta zastarelu koncepciju. To
je switch naredba koja u optem sluaju ima sledei oblik:
switch (izraz)
{
case izraz_konstanta_1: operator_1;
case izraz_konstanta_2: operator_2;
case izraz_konstanta_k: operator_k;
[default: naredba_k+1]
}

Izraz prema kome se vri selekcija i konstante u pojedinim granama treba da budu integer
tipa. Naredbe u granama mogu da budu obine ili sloene naredbe i blokovi.
Iako na prvi pogled ova naredba lii na ono to imamo u Pascal-u, radi se o nestrukturnoj
naredbi koja se izvrava tako to se izborom grane odreuje samo mesto odakle naredba
poinje, a iza toga se nastavlja njen sekvencijalni tok. To konkretno znai da se naredba u default
grani izvrava uvek kao i to da se naredba u k-toj grani izvrava uvek kada je selektovana neka
od prethodnih grana. Da bi se prekinulo upravljanje pod dejstom ove naredbe kada se izvri
selektovana grana, odnosno da bi se postigla semantika case strukture u Pascal-u, potrebno je da
se na kraju svake grane upravljanje eksplicitno prenese na kraj cele switch naredbe. U te svrhe u
C-u se koristi naredba b r e a k koja predstavlja izlazak iz switch naredbe. Kodom iz primera u C-u
je realizovano viestriko grananje iz prethodnog primera gde je koriena case struktura iz Pascala.
Primer. Switch naredba u C-u.
switch
(index)
{
case 1:
case 3: nep += 1;
sumnep +== index;
break;

54
case 2:
case 4: par += 1;
sumpar + index;
break;
default: printf("Greka u switch: index - %d\n", index);
}

Primer. Program kojim se simulira digitron.


void main()
{ float op1, op2;
char op;
printf("Unesite izraz \n");
scanf("%f %c %f", &op1, &op, &op2);
switch(op)
{ case '+':
printf("%f\n", op1+op2);
break;
case '-':
printf("%f\n", op1-op2);
break;
case '*':
printf("%f\n", op1*op2);
break;
case '/':
printf("%f\n", op1/op2);
break;
default:
printf("Nepoznat operator\n");
}
}

Primer. Na osnovu ocena 1-5 ispisati odgovarajue opisne ocene.


void main()
{ int ocena;
scanf("%d",&ocena);
switch(ocena)
{ case 5: printf("Odlican\n"); break;
case 4: printf("Vrlo dobar\n"); break;
case 3: printf("Dobar\n"); break;
case 2: printf("Dovoljan\n"); break;
case 1: printf("Nedovoljan\n"); break;
default: printf("Nekorektna ocena\n");
}
}

Operator break se koristi u okviru switch operatora (kasnije i u while, do, for operatorima)
da bi se obezbedio izlaz neposredno na naredbu iza switch strukture. Ukoliko se iza neke grupe
operatora u switch operatoru ispusti break operator, tada se u sluaju izbora te grupe operatora
izvravaju i sve preostale alternative do pojave break operatora ili do kraja switch operatora.
Primer. Posmatrajmo sledei program.
void main()
{ int ocena;
scanf("%d",&ocena);
switch(ocena)
{ case 5: printf("Odlican\n); break;
case 4: printf("Vrlo dobar\n");
case 3: printf("Dobar\n");
case 2: printf("Dovoljan\n"); break;
case 1: printf("Nedovoljan\n"); break;

Predrag S. Stanimirovi

55

Programski jezici

default: printf("Nekorektna ocena\n:");


}

Ukoliko je ocena = 4 ispisuje se sledei rezultat:


Vrlo Dobar
Dobar
Dovoljan

Dozvoljeno je da se jednoj grupi operatora dodeli vie konstanti koje ine njihovo obeleje.
Opta forma switch iskaza je:
switch(izraz)
{ case vrednost11: [vrednost12: \cdots vrednost1m:]
operator11
......
break;
case vrednost21: [vrednost22: \cdots vrednost2m:]
operator21
......
break;
......
case vrednostn1: [vrednostn2: \cdots vrednostnm:]
operatorn1
......
break;
default:
operator01
......
break;
}
sledea naredba;

Semantika ove naredbe je sledea: izraunava se vrednost izraza izraz, koji se naziva
selektor. Vrednost izraza izraz mora da bude celobrojna (ili znakovna, koja se automatski
konvertuje u odgovarajuu celobrojnu vrednost). Dobijena vrednost se uporeuje sa
vrednostima vrednost11, vrednost12, ..., vrednostnm, koji moraju da budu celobrojne konstante
ili celobrojni konstantni izrazi. Ove vrednosti se mogu posmatrati kao obeleja za odreenu
grupu operatora. Ako je pronaeno obeleje ija je vrednost jednaka vrednosti izraza izraz,
izraunavaju se iskazi koji odgovaraju toj vrednosti. Kljuna re break predstavlja kraj jedne
case grane, odnosno kraj grupe operatora sadranih u nekoj case grani. Ako nije pronaena
vrednost u case granama jednaka vrednosti izraza izraz, izraunavaju se iskazi u default grani;
ako je izostavljena alternativa default, nee se izvriti ni jedna od alternativa operatora switch.
Operator switch se moe realizovati pomou veeg broja if operatora. Meutim, programi
napisani pomou switch operatora su pregledniji.
Primer. Za zadati redni broj meseca ispisati broj dana u tom mesecu.
void main()
{ int mesec;
char ch;
/* Da li je godina prestupna */
printf("Unesi redni broj meseca: ");
scanf("%d", &mesec);
switch(mesec)
{ case 1:case 3:case 5:case 7:case 8:case 10:case 12:

56

printf("31 dan\n");
break;
case 4: case 6: case 9: case 11:
printf("30 dana\n);
break;
case 2: printf("Da li je godina prestupna? ");
scanf("%c%c",&ch,&ch);
/* prvo ucitavanje je fiktivno, uzima enter */
if((ch=='D') || (ch=='d')) printf("29 dana\n);
else printf("28 dana\n");
break;
default: printf("Nekorektan redni broj\n");

Primer. Odrediti sutranji datum.


void main()
{unsigned int d,m,g,prestupna;
printf("Unesi datum u obliku ddmmgg:\t");
scanf("%2d%2d%4d",&d,&m,&g);
if(d<1 || d>31 || m<1 || m>12)
{ printf("Nepravilan datum\n"); exit(0); }
prestupna=((g%4==0) && (g%100!=0)) ||
((g%100==0) && (g%400==0));
if(m==2 && d>28+prestupna)
{ printf("Nepravilan datum\n"); exit(0); }
switch(d)
{ case 31:
switch(m)
{ case 1:case 3:case 5:case 7:case 8:case 10:
d=1; m++; break;
case 12:
d=1; m=1; g++; break;
default:
{ printf("%2d. mesec ne moze imati 31 dan\n",m);
exit(0);
}
}
break;
case 28: if(!prestupna && (m==2)) { d=1; m=3; }
else d=29;
break;
case 29: if(prestupna && (m==2))
{ d=1; m=3; }
else d=30;
break;
case 30: switch(m)
{ case 4: case 6: case 9: case 11:
d=1; m++;
break;
case 2:printf("Februar ne moze imati 30 ana\n");
exit(0);
default:d=31;
}
break;
default:d++;
}
printf("Sledeci dan ima datum:\t%2d\t%2d\t%4d\n",d,m,g);

Predrag S. Stanimirovi

57

Programski jezici

Operator switch se moe koristiti umesto if operatora. Na primer, umesto operatora


if(a>b) max=a;
else max=b;

moe se pisati
switch(a>b)
{ case 0: max=b; break;
case 1: max=a;
}

Oigledno da ovo nije praktino.


Primer. Uitati tekui datum u formi DDMMGG. Na izlazu prikazati isti datum, pri emu je
ime meseca ispisano tekstualno. Uneti dan, mesec i godinu roenja, i na osnovu toga odrediti
odgovarajui horoskopski znak.
program zodiac;
type dd=1..31;
mm=1..12;
gg=1900..2000;
var mesec:mm;
dan:dd;
begin
writeln;
writeln('Unesite dan i mesec roenja'); readln(dan,mesec);
writeln('Vas horoskopski znak je:');
case mesec of
1:if dan<21 then write('jarac')
else write('vodolija');
2:if dan<21 then write('vodolija')
else write('ribe');
3:if dan<21 then write('ribe')
else write('ovan');
4:if dan<21 then write('ovan')
else write('bik');
5:if dan<21 then write('bik')
else write('blizanci');
6:if dan<21 then write('blizanci')
else write('rak');
7:if dan<21 then write('rak')
else write('lav');
8:if dan<21 then write('lav')
else write('devica');
9:if dan<21 then write('devica')
else write('vaga');
10:if dan<21 then write('vaga')
else write('skorpija');
11 :if dan<21 then write('skorpija')
else write('strelac');
12:if dan<21 then write('strelac')
else write('jarac');
end;
end.

4.3.2. Viestruka selekcija u paketu MATHEMATICA

58
Funkcija If dozvoljava izbor izmeu dve alternative. Me|utim, esto je potrebno da se testira
vei broj uslova. To se moe uiniti pomou veeg broja umetnutih If funkcija. Mnogo je
efikasnije da se to uradi funkcijama Which i Switch.
Which[test1, value1,
test2, value2, ...]

evaluira se redom test1,test2,... pri emu je rezultat


vrednost asocirana sa prvim testi koji je True
uporeuje se expr sa svakim od izraza form1, ..., a
rezultat je vrednost izraza valuei, koji je asociran
sa prvim izrazom formi koji se slae sa expr
koristi se def kao vrednost koja se vra}a ako se
nijedan od izraza formi ne sla`e sa expr

Switch[expr,form1, value1,
form2, value2, ...]
Switch[expr,form1,value1,
form2, value2,..., def]

U poslednjoj tabeli svaki od izraza value1, value2,... predstavlja jedan izraz ili sekvencu izraza
koji su razdvojeni znakom ;.

@
D@

Na primer, izrazom:

h x_ := Which x < 0, x^2, x > 5, x^ 3, True, 0

@
D
@
D
@
D@
@
D D
@
D
@ D
@
D@@@D
@ D @ D
D
D
@
D

definisana je funkcija h sa tri grane. Trea grana je uvek ispunjena ako nisu prethodne dve.
h -5
25

(*Koristi se prvi sluaj u Which*)

h 2
0

(*Koristi se trei sluaj*)

residue x_ := Switch Mod x, 3 , 0, a, 1, b, 2, c

(*Rezultat zavisi od ostatka pri deljenju argumenta sa 3*)


residue 7
b

(*Mod[7,3]=1, pa se koristi drugi sluaj*)

Switch 17, 0, a, 1, b, _, g
g

(*17 se ne slae sa 1, ali se slae sa _*)

res x_ := Switch Mod x, 3 , 0, Print "Ostatak je 0 " ; a, 1, Print "Ostatak je 1 " ; b,


2, Print "Ostatak je 2 " ; c
res 17
Ostatak je 2
c

4.4. Programske petlje


U svakom programskom jeziku obino postoje upravljake strukture kojima moe da se
definie viestruko ponavljanje odreene sekvence naredbi. To su programske petlje ili
strukture iteracije. Moe se rei da je to jedan od mehanizama koji omoguava da se sloeni
problemi, u okviru kojih se zahteva da se viestriko ponovi ista sekvenca naredbi na istim ili
razliitim podacima, ree jednostavnim programima. U savremenim programskim jezicima
skoro bez izuzetaka postoje naredbe za definisanje petlji sa unapred odreenim brojem prolaza.
To su tzv. brojake petlje (slika 4.6) kod kojih postoji broja (indeks petlje) kojim se upravlja
izvravanjem petlje. Sa prihvatanjem strukturnog programiranja u novijim jezicima se
pojavljuje i logiki kontrolisana petlja kojom se realizuje while (while-do) struktura. Ova
struktura prikazana je na sledeoj slici.

Predrag S. Stanimirovi

Programski jezici

for I:= poc 59


to kraj
niz naredbi

Slika 4.6 Struktura for petlje


i predvia ponavljanje izvravanja tela petlje sve dok u s l o v u zaglavlju petlje ima vrednost
tr ue . Kod ovakvih petlji nije unapred poznat broj izvravanja tela petlje. Za ove petlje se esto
koristi i termin pretest petlje, jer se ispitivanje uslova vri pre svakog izvravanja petlje.
Strukturnim programiranjem definisana je i until struktura (do-while struktura) koja predvia
post-test uslova, odnosno ispitivanje uslova posle izvrenja tela petlje (slika 4.8).

ne

uslov
da

niz naredbi

Slika 4.7 Struktura while petlje

niz naredbi

uslov
Slika 4.8 Struktura repeat-until petlje

da

Prvi put se naredbe za definisanje petlji pojavljuju u programskom jeziku FORTRAN I. Taj
koncept je preneen i u FORTRAN IV da bi bio izmenjen tek sa standardom za FORTRAN od
1977. godine. Na primeru ove naredbe moe se sagledati razvoj jednog koncepta kako iz jezika
u jezik tako i u okviru jednog jezika.
U FORTRAN-u IV se za definisanje petlji koristi DO naredba, koja u optem obliku ima
sledeu sintaksu:
DO ozna ka var = pocetni, krajnji [, korak],

VAR<-POCETNI

telo petlje

60

VAR<-VAR + KORAK
da

VAR<= KRAJNJI
ne
Slika 4.9 Naredba DO u FORTRAN-u IV

Oznakom navedenoj u DO naredbi treba da bude oznaena zadnja naredba u petlji. Korak
petlje moe da bude izostavljen kada se podrazumeva da je jednak 1. Promenljiva koja se koristi
za upravljanje petljom mora da bude celobrojna i mogu joj se dodeljivati samo pozitivne
vrednosti. Dijagram toka prikazan na slici 5.9 ilustruje tok izvravanja ove naredbe.
INICIJALNA_VREDNOST <- INICIJALNI_IZRAZ
Izracunaj ITERACIONI_BROJA
KORAK <- VELIINA_KORAKA_IZRAZ
VAR <- INICIJALNA_VREDNOST
netano

ITERACIONI_BROJA > 0

VAR <- VAR + KORAK


ITERACIONI_BROJA <- ITERACIONI_BROJA - 1
telo petlje
Slika 4.10
FORTRAN-u 77

Dijagram toka DO naredbe u

U jeziku FORTRAN 77 je zadrana ista DO naredba, ali generalisana u nekoliko


aspekata. Na primer, promenljiva petlje moe da bude integer, re al ili double precision tipa.
Granice petlje mogu da budu pozitivne ali i negativne. Ovaj koncept se implementira tako to se za
odbrojavanje prolaza kroz petlju koristi poseban broja, a ne sama promenljiva petlje. Dijagram
toka prikazan na slici 4.10 ilustruje implementaciju ove naredbe.
Jedan interesantan detalj dodat je sintaksi same naredbe. Po novom konceptu, iza oznake pie
se zapeta tako da umesto
DO 10 K = 1,10
imamo
DO 10, K = 1,10
Izmena je mala all spreava da se niz znakova koji se nalazi levo od znaka = protumai kao
ime promenljive i leva strana naredbe dodeljivanja. Poznate su bile greke u praksi, nastale kao
posledica pravila da se praznine u FORTRAN-u ne tretiraju kao razdelnici izmeu leksema kao i
da u FORTRAN-u ne postoje rezervisane kljune rei.
U standardu za FORTRAN 90 zadrzana je DO naredba iz FORTRAN-a 77 i pridodati su joj
neki novi elementi. Njena sintaksa je definisana sa:
[ime] DO promenljiva = po_vednost, kraj_vrednost [, korak]

END DO [ime]

Predrag S. Stanimirovi

61

Programski jezici

Novina u ovoj definiciji je to to se naredba eksplicitno zatvara sa END DO, ime je


izbegnuta potreba za oznaavanjem zadnje naredbe petlje. Ovim je postignuta vea
dokumentarnost programa.
Za definisanje logikih naredbi u FORTRAN-u 77 i FORTRAN-u 90 postoji samo WHILE
naredba ija je sintaksa definisana sa
WHILE(uslov)DO
naredba_l
...
naredba_k
END DO

Primer. WHILE naredba u FORTRAN-u.


GR = 0.0001
SUM = 0.
I = 0
WHILE (1.0/I .GT. GR) DO
SUM = SUM + 1.0/I
I = I + 1
END DO

U programskom jeziku Algol 60 uvedena je for naredba koja na neki nain predstavlja
generalizaciju DO naredbe iz FORTRAN-a. Meutim to je i primer koji pokazuje kako se
nastojanjem da se postigne vea fleksibilnost naredbe poveava i kompleksnost jezika a time
gubi na jednostavnosti i preglednosti koncepta.
Sinatksa for naredbe data je sa:
<for_naredba> ::= for var := <lista_elemenata>
{ , < lista_elemenata> } do <naredba>
<lista_elemenata> ::= <izraz>
| <izraz> step <izraz>
until <izraz>
| <izraz> while <Bool-ov_izraz>
Sintaksom naredbe predvidene su tri vrste upravljanja. Sve vrste upravljanja su ilustrovane
sledeim primerima:
for index := 1,2,3,4,5,6,7,8,9,10 do vektor[index] := 0
to je ekvivalentno sledeoj naredbi:
for index := 1 step 1 until 10 do vektor[index] := 0

odnosno sledeoj:
for index := 1 index+1 while (index <= 10) do vektor[index] := 0

Ono to je najinteresantnije to je da je ovde dozvoljeno kombinovanje upravljanja petljom,


tako da se moe napisati petlja u kojoj se upravljanje menja i obuhvata sva tri koncepta.
for index := 1, 4, 13,
41 step 2 until 47,
3* index while index < 1000,
34, 2, -24 do
sum := sum + index

Ovom naredbom se na sumu dodaju sledee vrednosti:


1, 4, 13, 41, 43, 45, 47, 141, 423, 34, 2, -24.
Kako je ve reeno u Pascal-u postoje upravlajke strukture koje omoguavaju definisanje
logikih petlji sa pred-uslovom i post-uslovom, odnosno while i repeat-until strukture. Pored
toga, postoji i mogunost definisanja petlje sa unapred oodreenim brojem prolaza oblika:

62
for i := poc to kraj do naredba;

Efekat ove naredbe ilustruje sledei primer.


Primer. Program u Pascal-u kojim se izraunava vrednost sume
n
1
Sum =

i
i 1

program Suma (Input.output);


var i,n : integer;
Sum : real;
begin
read(n);
Sum := 0;
for i := 1 to n do
Sum := Sum +1/i;
write (Sum);
end (Suma);

Uslovne petlje u Pascal-u imaju sledeu sintaksu:


while uslov do naredba;

i
repeat
naredba_1;
naredba_2;

naredba_k
until (uslov);

4.5. While naredba u C


Ovom naredbom se realizuju programski ciklusi sa nepoznatim brojem ponavljanja, zavisno
od odreenog uslova. Operator while se koristi prema sledeoj sintaksi:
while(izraz)
operator
Efekat ove naredbe je da se telo while ciklusa, oznaeno sa operator izvrava dok je vrednost
izraza izraz jednaka true (nenula). Kada vrednost izraza izraz postane false (nula), kontrola se
prenosi na sledeu naredbu. Telo ciklusa, oznaeno sa operator, izvrava se nula ili vie puta.
Operator moe biti prost ili sloen. Svaki korak koji se sastoji iz provere uslova i izvrenja
operatora naziva se ``iteracija''. Ako odmah po ulasku u ciklus izraz ima vrednost ``netano''
(nula), operator se nee izvriti.
Primer. Maksimum n unetih brojeva.
main()
{ int i, n;
float max, x;
printf("Koliko brojeva zelite? ");
scanf("%d", &n);
while (n<=0)
{ printf("Greska, zahtevan je ceo pozitivan broj.\n");
printf("Unesite novu vrednost: ");
scanf("%d", &n);
}
printf("\n Unesite %d realnih brojeva: ", n);
scanf("%f", &x);

Predrag S. Stanimirovi

63

Programski jezici

max = x;
i=1;
while (i<=n)
{ scanf("%f", &x);
if(max<x) max = x;
++i;
}
printf("\n Maksimalni od unetih brojeva: %g\n",max);
}

Primer. Ostatak pri deljenju dva broja a i b (a>=0, b>0) moe da se izrauna bez korienja
operatora %.
r=a;
while(r>=b) r=r-b;
printf("%d\n",r);

Primer. Program za izraunavanje n-tog stepena celog broja a.


main()
{ int i=1,a,n;
long stepen=1;
scanf("%d%d",&a,&n);
while(i++<=n)
stepen*=a;
printf("%d^ %d= %ld\n",a,n,stepen);
}

Primeri u C-u
Primer. Izraunati broj nula kojima se zavrava n!.
#include<stdio.h>
void main()
{ int n,s,step,clan,i;
scanf("%d",&n);
s=0; step=5; clan=1; i=1;
while (i)
{ clan=clan*5; i=n/clan;
printf("%d",s);
}

Primer. Izraunati

s=s+i; }

a prema iterativnoj formuli

x0=a/2; xi+1=xi-(xi2-a)/(2xi)=xi+1/2*(a/xi - xi) , i=0,1,...


Iterativni postupak prekinuti kada se ispuni uslov |x i+1-xi|<10-5.
#include <stdio.h>
main()
{ float a,x0,x1;
scanf("%f",&a)
x0=a/2;
while(fabs(x1-x0)<1E-5) { x0=x1; x1=(x0*x0-a)/(2*x0); }
printf("%f\n",x1);
}

Primer. Izraunati aritmetiku sredinu niza brojeva razliitih od nule. Broj elemenata u nizu
nije unpred poznat.
void main()
{ int brojac=0;
float suma=0, stopcode=0, broj;

64
printf("Daj niz znakova zavrsen sa %d\n",stopcode);
scanf("%f",&broj);
while(broj != stopcode)
{ suma+=broj; brojac++;
scanf("%f",&broj);
}
printf("Srednja vrednost= %f\n",suma/brojac);
}

Primer. Dejstvo operatora ++ i -- u ciklusima.


#include <stdio.h>
main()
{ int i=0;
printf("Prva petlja :\n");
while(i<5)
{ i++;printf("%5d",i); }
/* 1
printf("\nDruga petlja :\n");
i=0;
while(i++<5) printf("%5d",i); /* 1
i=0;
printf("\nTreca petlja :\n");
while(++i<5) printf("%5d",i); /* 1
}

5*/

5*/

4*/

Primer. Suma celih brojeva unetih preko tastature.

#include <stdio.h>
main()
{ int x,sum=0;
while(scanf("%d",&x)==1)
sum+=x;
printf("Ukupan zbir je %d\n",sum);
}

Primer. Suma prvih deset prirodnih brojeva.


void main()
{ int i=1, suma=0;
while(i<=10)
{ suma=suma+i; i= i+1; }
printf("Suma = %d\n",suma);
}

Primer. Ispitati da li je zadati prirodan broj n prost.


void main()
{ int i,n,prost;
scanf("%d",&n);
prost=(n%2!=0) || (n==2);
i=3;
while(prost && (i<=n/2)
{ prost=n%i !=0; i+=2; }
if(prost) printf("%d je prost\n",n);
else printf("%d nije prost\n",n);
}

Primer. Rastaviti prirodan broj na faktore.


void main()
{ int broj, faktor=2;
scanf("%d",&broj);

Predrag S. Stanimirovi

Programski jezici

65

while(faktor <= broj)


if(broj%faktor ==0)
{ printf("%5d",faktor); broj/=faktor; }
else faktor++;

Primer. Izraunati

cos(x)=

(1)
k 0

x 2k
( 2k )!

, x /2.

Sumiranje prekinuti kada je apsolutna vrednost poslednjeg dodatog lana manja od zadate
tanosti e.
Koristi se
ak

x2
k ( 2k 1)

a k 1

void main()
{ double c,a,e,x;
int k=0;
scanf("%lf%lf",&x, &e);
while(fabs(a)>=e)
{ k++; a=-(x*x/(2*k*(2*k-1)))*a; c+=a; }
printf("cos(%.2lf)=%.7lf",x,c);
}

Primer. Heksadekadni broj prevesti u dekadni. Unoenje heksadekadnog broja prekinuti kada se
unese karakter koji ne pripada skupu karaktera '0', ... , '9', 'A', ... , 'F'.
#include <stdio.h>
void main()
{int broj,u,k;
char cif;
broj=0;u=1;
printf("unesi heksadekadni broj\n");
scanf("%c",&cif);
u=((cif<='F')&&(cif>='0'));
while (u)
{ if ((cif>='A')&&(cif<='F')) k=cif-55;
else
k=cif-48;
broj=broj*16+k;
scanf("%c",&cif);
u=((cif<='F')&&(cif>='0'));
}
printf("%d\n",broj);
}
/* Drugo resenje */
#include<stdio.h>
main()
{int broj,p; char cif;
broj=0;
scanf("%c",&cif);
while (cif>='0' && cif<='F')
{ switch(cif)
{case '0': p=0; break;
case '1': p=1; break;
case '2': p=2; break;

66
case '3': p=3; break;
case '4': p=4; break;
case '5': p=5; break;
case '6': p=6; break;
case '7': p=7; break;
case '8': p=8; break;
case '9': p=9; break;
case 'A': p=10; break;
case 'B': p=11; break;
case 'C': p=12; break;
case 'D': p=13; break;
case 'E': p=14; break;
case 'F': p=15; break; }
broj=broj*16+p;
scanf("%c",&cif);
}
printf("%d\n",broj);
}

Primer. Napisati program koji simulira rad depnog kalkulatora. Program uitava niz brojnih
vrednosti razdvojenih znakovima aritmetikih operacija +,-,*,/ kao i izraunavanje vrednosti
izraza koji je definisan na ovaj nain. Aritmetike operacije se izvravaju s leva na desno, bez
potovanja njihovog prioriteta.
#include <stdio.h>
void main()
{ double result, num;
char op;
printf("\n\n");
scanf("%lf" , &num); scanf("%c" , &op);
result = num ;
while (op != '=')
{ scanf("%lf" , &num) ;
switch (op)
{ case '+' : result += num ; break;
case '-' : result -= num ; break;
case '*' : result *= num ; break;
case '/' : result /= num ; break;
}
scanf("%c" , &op);
}
printf("Rezultat je %.10lf." , result) ;
}

Primer. Izraunati priblino


a ( a 1)...(a n 1) n
x
2
n!
gde je a zadati realan broj. Izraunavanje prekinuti kada je dodati lan po apsolutnoj vrednosti
manji od zadate tanosti (ukljuiti i prvi takav broj).

S = 1+ax+

a ( a 1)

x 2 ...

#include<stdio.h>
#include<math.h>
void main()
{ int n=1;
float a,x,e,s=1,b;
scanf("%f%f%f",&a,&x,&e);
b=a*x; s+=b;

Predrag S. Stanimirovi

while (fabs(b)>=e)
{ n++;
b=(a-n+1)*x/n*b;
printf("%f\n",s);

Programski jezici

67

s+=b;

Primer. Napisati program koji bez korienja nizova uitava prirodan broj n, a zatim n celih
brojeva, i tampa vrednost koja je druga po veliini i koliko se puta ponavlja.
void main()
{
scanf("%d",&max);
max1=max;
br=br1=1;
for(i=1; i<=n-1; i++)
{ scanf("%d",&x);
if(x>max)
{ max1=max; max=x; br1=br; br=1; }
else if (x==max) br++;
else if (x>max1)
{ max1=x; br=1; }
else if (x==max1) br1++;
}
printf("%d %d",max1,br1);
}

4.5.1. Primena while ciklusa u obradi teksta u C


esto puta se pri radu sa tekstovima umesto funkcija scanf() i printf() koriste biblioteke
funkcije getchar() i putchar(). Pre korienja ovih funkcija mora da se navede pretprocesorska
direktiva #include<stdio.h>. Ove funkcije se koriste za ulaz i izlaz samo jednog karaktera.
Funkcija putchar() ima jedan znakovni argument. Pri njenom pozivu potrebno je da se unutar
zagrada navede znakovna konstanta, znakovna promenljiva ili funkcija ija je vrednost znak.
Ovaj znak se prikazuje na ekranu. Funkcija getchar() nema argumenata. Rezultat njenog
poziva je znak preuzet iz tastaturnog bafera. Ovom funkcijom se ulazni znak unosi u program.
Primer. Izraunati koliko je u zadatom tekstu uneto znakova 'a', 'b', zajedno 'c' i 'C', kao i broj
preostalih karaktera.
#include <stdio.h>
void main()
{ int c, a_count=0, b_count=0, cC_count=0, other_count=0;
while((c=getchar()) != EOF)
switch (c)
{ case 'a':
++a_count;
break;
case 'b':
++b_count;
break;
case 'c':
case 'C':
++cC_count;
break;
default:
++other_count;
}
printf("\n%9s%5d\n%9s%5d\n%9s%5d\n%9s%5d\n%9s%5d\n",
"a_count:", a_count, "b_count:", b_count,
"cC_count:", cC_count, "other:", other_count,
"Total:", a_count+b_count+cC_count+other_count);
}

Primer. Unos teksta je zavren prelazom u novi red. Prebrojati koliko je u unetom tekstu

68
znakova uzvika, znakova pitanja a koliko taaka.
#include <stdio.h>
void main()
{ char c;
int uzv,upt,izj;
uzv=upt=izj=0;
while((c=getch())!='\n')
switch(c)
{ case '!':++uzv; break;
case '?':++upt; break;
case '.':++izj; break;
}
printf("\n");
printf("Uzvicnih ima %d\n",uzv);
printf("Upitnih ima %d\n",upt);
printf("Izjavnih ima %d\n",izj);
}

Kod organizacije while ciklusa mora se voditi rauna o tome da telo ciklusa menja
parametre koji se koriste kao preduslov za ciklus, tako da posle odreenog broja iteracija
postane netaan. U protivnom, ciklus e biti beskonaan.

4.6. Do-while naredba u C


Do-while naredba je varijanta while naredbe. Razlikuje se od while naredbe po tome to je
uslov na kraju ciklusa:
do
operator
while(izraz);
sledea naredba;
Telo ciklusa je operator, i izvrava se jedanput ili vie puta, sve dok izraz ne dobije vrednost 0
(false). Tada se kontrola prenosi na sledeu naredbu.

Primeri
Primer. Pisanje celog broja s desna na levo.
void main()
{ long broj;
printf("Unesite ceo broj"); scanf("%ld",&broj);
printf("Permutovani broj");
do { printf("%d",broj%10); broj /= 10; }
while(broj);
printf("\n");
}

Primer. Izraunati sumu parnih brojeva od -100 do 100.


void main()
{ int i=-100,s=0;
do
{ s+=i; i+=2; }
printf("%d\n",s);
}

while(i<=100);

Primer. Napisati program za izraunavanje stepena promenljive x>1: x 2,x4,x8,... , dok stepen od
x ne bude vei od 108.

Predrag S. Stanimirovi

69

Programski jezici

void main()
{ float x,st=x;
do
{ printf("%lf\n",st); st*=st; }
while(st<=1E08);
}

Primer. Izraunati priblino vrednost broja =3.14159 koristei formulu


/4 = 1-1/3+1/5-1/7+
Sumiranje prekinuti kada apsolutna vrednost lana koji se dodaje bude manja od zadate
vrednosti eps.
void main()
{ int znak=1;
float clan,suma,eps,i=1.0;
scanf("%f",&eps);
clan=suma=1.0;
do
{ clan=znak/(2*i+1); suma+=clan; znak=-znak; i++; }
while(1/(2*i+1)>=eps);
printf("Broj Pi=%f\n",4*suma);
}

4.7. For naredba u C


Naredba for je povezana sa while naredbom. Preciznije, konstrukcija
for(pocetak; uslov; korekcija)
operator
sledea naredba
ekvivalentna je sa sa
pocetak;
while(uslov)
operator
korekcija;
pod uslovom da uslov nije prazan.
Operator koji predstavlja telo ciklusa moe biti prost ili sloen.

Primeri
Primer. Uitavanje neodreenog broja prirodnih brojeva i izraunavanje njihove sume.
for(sum=0; scanf("%d", &x) ==1; )

sum +=x;

Suma prvih n prirodnih brojeva.


void main()
{ int i,n,sum;
sum=0;
for(i=1; i<=n; ++i) sum += i;
printf("suma = %d\n", sum);
}

70

Primer. Ovaj ciklus se moe zapisati na sledei nain:


sum=0; i=1;
for(; i<=n;) sum += i++;
ili
for(sum=0, i=1; i<=n; sum += i, i++);
Prirodni brojevi se mogu sumirati u sledeem ciklusu.
sum=0; i=0;
for(; ;) sum +=i++;

/* beskonacni ciklus */

Primer. Faktorijel prirodnog broja.


void main()
{ int i,n;
long fak=1;
printf("\n Unesite broj"); scanf(" %d",&n);
for(i=1; i<=n; ++i) fak *=i;
printf("%d! = %ld \n",n,fak);
}
void main()
{ int i,n;
long fak=1;
printf("\n Unesite broj"); scanf(" %d",&n);
for(fak=1,i=1; i<=n; fak*=i,++i);
printf("%d! = %ld \n",n,fak);
}

Primer. Tablica stepena


#define LIMIT 5
#include <stdio.h>
main()
{ int i;
printf("\n%s\n%s\n%7s%12s%12s%12s%12s\n\n",
"Tablica stepena",
"---------------",
"ceo broj","kvadrat","kub","cetvrti","peti");
for (i=1; i<=LIMIT; ++i)
printf("%7d%12d%12d%12d%12d\n",i,i*i,i*i*i,i*i*i*i,i*i*i*i*i);
}

Primer. Tabela ASCII kodova.


void main()
{ char ch='a';
for(; ch<='z'; ch++)
printf("ASCII kod za %c je %d\n", ch,ch);
for(ch='A'; ch<='Z';)
{ printf("ASCII kod za %c je %d\n", ch,ch); ch++; }
}

Primer. Izraunati 1!+2!++n!.

Predrag S. Stanimirovi

71

Programski jezici

void main()
{ int i,n; long fakt,s;
scanf("%d",&n);
for(s=0, fakt=1, i=1; i<=n; fakt*=i, s+=fakt, i++);
printf("Suma=%ld\n",s);
}

Isti izraz se moe izraunati na sledei nain


void main()
{ int n; long s;
scanf("%d",&n);
for(s=0; n>0; s=s*n+n--);
printf("Suma=%ld\n",s);
}

Primer. Izraunati sve trocifrene Armstrongove brojeve.


main()
{ int a,b,c, i;
for(i=100;i<=999;i++)
{ a=i%10;
b=i%100/10;
c=i/100;
if(a*a*a+b*b*b+c*c*c==i) printf("%d\n",i);
}
}

Primer. Program za odreivanje savrenih brojeva do zadatog prirodnog broja. Savren broj je
jednak sumi svojih delitelja.
main()
{ int i,m,n,del,s;
scanf("%d",&m)
for(i=2;i<=m;i++)
{ n=i; s=1;
for(del=2; del<=i/2; del++)
if(n%del==0) s+=del;
if(i==s) printf("%d\",i);
}
}

Primer. Ispitati da li je dati prirodan broj prost.


#include <math.h>
void main()
{ int n,i=3;
scanf("%d", &n);
while( (i<=sqrt(n)) && (n%i != 0)) i+=2;
if(i>sqrt(n))
printf("Broj je prost\n);
else printf("Broj nije prost\n);
}

For ciklus oblika


for(; uslov ;) operator

ekvivalentan je while ciklusu


while(uslov) operator

72
Takoe, ekvivalentni su sledei beskonani ciklusi:
for(;;) operator

i
while(1) operator.

Primer. Stepen celog broja.


void main()
{ int i=1,a,n;
long stepen=1;
scanf("%d%d",&a,&n);
for(i=1; i<=n; i++)
stepen*=a;
printf("%d^%d= %ld\n",a,n,stepen);
i=stepen=1;
for(;i<=n;) { stepen *= a; i++; }
printf("%d^%d= %ld\n",a,n,stepen);
for(i=1,stepen=1; i<=n; i+=1,stepen*=a);
printf("%d^%d= %ld\n",a,n,stepen);
stepen=i=1;
for(;;){stepen*=a; printf("%d^%d= %ld\n", a,i,stepen); i++;}
}

Primer. Tablica ASCII kodova.


void main()
{ char ch='a';
for(; ch<='z'; ch++)
printf("ASCII kod za %c je %d\n", ch,ch);
for(ch='A'; ch<='Z';)
{ printf("ASCII kod za %c je %d\n", ch,ch); ch++; }
}
void main()
{ signed char c; unsigned char d;
for(c=-128; c<=127; c++) printf("c = %d %c\n",c,c);
for(d=0; d<=255; d++) printf("d = %d %c\n",d,d);
}

4.8. Uslovne petlje u jeziku C


U jeziku C se za definisanje petlje sa unapred definisanim brojem izvrenja tela petlje koristi for
naredba oblika
for (izraz_1; izrat_2; izraz_3) operator

Primer. Petlja-u C-u sa unapred definisanim brojem prolaza.


for (index = 0; index <= 10; index ++) sum = sum + index:

Meutim, for naredba u C je mnogo optija. Dijagramom toka prikazanom na slici 4.11
ilustrovan je tok programa upravljan for naredbom u C.
Izrazi u zaglavlju petlje mogu da budu i izostavljeni. Npr. petlja bez drugog izraza izvrava se kao
da je njegova vrednost true, to znai kao beskonana petlja. Ako su izostavljeni prvi i trei izraz
nema izvravanja petlje.
izraunava se prvi izraz
netano

drugi izraz <> 0

Predrag S. Stanimirovi

73

Programski jezici

tano

telo petlje
izvrava se trei izraz
Slika 4.11 Dijagram toka for naredbe u C-u
For naredba u C-u je mnogo fleksibilnija od odgovarajuih naredbi u drugim jezicima.
Naime, izrazi u zaglavlju petlje mogu da objedine vie naredbi koje se odnose na razliite
promenljive. To znai da se u okviru petlje moe istovremeno definisati vie uslova upravljanja
vezanih za razliite promenljive koje ak mogu da budu i razliitih tipova. Razmotrimo sledei
primer.
Primer. For naredba u C-u koja ima vie uslova upravljanja.
for ( s u m = 0 . 0 , broj = 0;
broj <= 10 && sum < 1 0 0 0 . 0 ;
sum = sum + broj++);

Ekvivalentni kod u Pascal-u bi bio:


sum := 0.0;
broj := 0;
while (broj <= 10) and (sum < 1000.0) do
begin
sum := sum + broj;
broj := broj +1
end.

U C-u postoje i dve naredbe za definisanje logikih petlji koje odgovaraju algoritamskim
strukturama while i until. Njihov format je:
while (izraz) naredba

i
do naredba while (izraz)

Prva od ovih naredbi odgovara while strukturi i izvrava se tako da se naredba u telu petlje
ponavlja sve dok je vrednost izraza t r u e (razliit od nule). Primer koji sledi ilustruje njenu
primenu.
Primer. Petlja kojom se izraunava suma brojeva koji se uitavaju sa tastature.
sum = 0;
scanf("%d", &indat);
while (indat >= 0)
{
sum = sum + indat ;
scanf("%d", &indat);
}

U ovom programu, promenljiva s um se inkrementira sve dok se ne uita vrednost jednaka


nuli.
U drugoj verziji while logike petlje naredba u telu petlje izvrava se sve dok je vrednost
izraza jednaka nuli, odnosno sve dok ne postane razliita od nule (true). Primer koji sledi
ilustruje ovu varijantu while naredbe u C-u.

74
U svakoj od gore opisanih naredbi za definisanje petlji u C-u dozvoljeno je da se telo petlje
definie kao sloena naredba.
Primer. Do-while petlja u C-u.
do
{
Indat = indat / 10;
br_cifara = br_cifara + 1;
}
while (indat > 0);

Pomenuli smo da se broja petlje (promenljiva kojom se upravlja tokom petlje) implicitno
definie njenim navodenjem u samom zaglavlju petlje. To je lokalna promenljiva petlje i u
sluaju da u istom programu ve postoji promenljiva pod istim imenom, one se tretiraju kao dve
potpuno razliite promenljive koje pripadaju okruzenju u kome su definisane.
Petlje razmatrane u prethodnim primerima imaju zajedniku karakteristiku da se iz petlje
izlazi ili na kraju kada se zavri sekvenca naredbi koja ini telo petlje ili na samom poetku pre
nego i zapone ta sekvenca naredbi. Tvledutim, u odreenim sluajevima pogodno je da
programer sam odredi mesto izlaska iz petlje. U novijim programskim jezicima, obino postoji
jednostavan mehanizam za uslovan ili bezuslovan izlazak iz petlje. U Adi, FORTRAN-u 90 i
Moduli 2 to je exit naredba, a u C-u i Pascal-u break.
Napomenimo da se naredbe exit obino koriste da se definie nastavak programa u sluaju
pojave izuzetka ili greke u toku petlje.
U programskom jeziku C za bezuslovni izlazak iz petlje moe se koristiti naredba b r e a k
koja se sa oodreenim znaenjern koristi i kod switch naredbe. Smisao njene upotrebe je isti kao
u sluaju exit naredbe upotrebljene bez drugih elemenata u Adi. Primer to ilustruje.
Primer. Naredba break za bezuslovni izlazak iz petlje u C-u.
sum=0;
while (sum < 2000)
{
scanf(%d, &podatak);
1f (podatak < 0) break;
sum = sum + value;
}

U svakom prolazu kroz petlju u ovom primeru uitava se po jedan podatak i dodaje sumi.
Zaglavljem petlje je definisano da se sumiranje izvrava sve dok se ne dostigne vrednost 2000.
Meutim, ukoliko se uita negativni podatak, petlja se prekida i program se nastavlja sa prvom
naredbom iza petlje.
U C-u postoji i naredba continue koja se takoe koristi za upravljanje tokom petlje, ali sa
nesto drugaijim efektima. Ovom naredbom se samo preskae ostatak petlje i program nastavlja
novim prolazom kroz petlju poevi od prve naredbe petlje, Efekat te naredbe na prethodnom
primeru dat je kao naredni primer.
Primer. Efekat naredbe continue u C-u.
sum=0;
while (sum < 2000)
{
scanf(%d, &podatak);
if (podatak < 0) continue;
sum = sum + value;
}

Predrag S. Stanimirovi

75

Programski jezici

U ovom sluaju, kada se uita negativni podatak preska se naredba za izraunavanje sume i
program nastavlja ponovnim prolaskom kroz petlju. To znai da e u ovom sluaju petlja uvek
da se zavri kada se dostigne vrednost sum>=2000, to u prethodnom primeru nije uvek bio
sluaj.

4.9. Uslovne petlje u Pascal-u


Uslovne petlje u Pascal-u imaju sledeu sintaksu:
w h i l e u s l o v do n a r e d b a ;

i
repeat
naredba_1;
naredba_2;
naredba_k
until (uslov);

Uslovne petlje su posebno pogodne kod iterativnih izraunavanja kada je odreeno


izraunavanje potrebno ponavljati sve dok vai neki uslov ili se ne ispuni neki uslov. Na primer
prethodni primer moe da se definie tako da treba odrediti za koje n vai sledei uslov:
n

Gran,

i 1

gde je Gran vrednost koja se unosi sa tastature. Ovaj zadatak se moe reiti pomou while i
repeat-until petlje.
Primer. While petlja u Pascal-u.
program Suma1(input, output);
var i : integer;
Sum, Gran
;
real ;
begin
read(Gran);
Sum := 0;
i := 0;
while Sum < Gran do
begin
i:=i+1;
Sum := Sum + 1/i
end;
write(i);
end. {Suma1}

Primer. Primer sa repeat-until petijom.u Pascal-u.


program Suma2 (input.output);
var i
;
integer;
Sum,Gran : real ;
begin
read(Gran);
Sum := 0 ;
i
:= 0;
repeat
i
:= i + 1;
Sum := Sum + 1/1;
until Sum > Gran;
w r i t e (i);

76
end {Suma2};

Primer. Izraunati sumu

xk

k 0 k!
sa tanou . Sumiranje prekinuti kada bude ispunjen uslov
xn/(n!) <

k 0

xk
,
k!

gde je zadata tanost


PROGRAM enax (input, output);
VAR i :integer;
x, epsilon, clan, zbir : real;
BEGIN
read(x, epsilon);
clan := 1;
zbir := 1;
i := 1;
WHILE clan >= epsilon * zbir DO
BEGIN
clan := clan * x/i;
zbir := zbir + clan;
END;
writeln(zbir)
END.

i := i+ 1

Primer. Za zadati broj n izraunati


S=

12

16 ... ( 1) n1

4n

program korenje;
var i,n:integer;
s,znak:real;
begin
repeat
write('Zadati n>=1 '); readln(n); writeln;
znak:=1;
for i:=1 to n-1 do znak:=-znak;
s:=sqrt(4*n);
for i:=n-1 downto 1 do
begin
s:=sqrt(4*i+znak*s);
znak:=-znak;
end;
writeln('Rezultat = ',s:20:18);
until false;
end.

4.10. Naredbe za bezuslovno grananje


Za bezuslovno grananje u programu koristi se GOTO naredba. U sutini, to je jedna od
najmonijih naredbi koja u sprezi sa naredbom selekcije omoguava da se implementiraju i
najsloeniji algoritmi. Problem je jedino u tome, to tako definisan kod moe da bude veoma
nepregledan, a takvo programiranje podlono grekama.

Predrag S. Stanimirovi

77

Programski jezici

Po konceptu strukturnog programiranja GOTO naredba je izbaena iz upotrebe, jer se nastoji


da se program definie umetanjem struktura jednu u drugu i da pri tome sve strukture imaju
jedan ulaz i jedan izlaz. Postoji nekoliko jezika u kojima GOTO naredba uopte ne postoji, npr.
Modula 2. Meutim u mnogim jezicima koji podravaju koncept strukturnog programiranja
naredba GOTO je zadrana i ostaje pogodno sredstvo za reavanje mnogih problema.

4.10.1. Oznake (labele)


Za oznaavanje naredbi, na koje se pod dejstvom GOTO naredbe prenosi upravljanje, u
programskim jezicima se koristi koncept oznaka (labela). U nekim jezicima (C-u, Algol-u 60
npr.) koriste se identifikatori kao oznake. U drugim (FORTRAN i Pascal npr.) to su neoznacene
celobrojne konstante. U Adi su oznake takoe identifikatori, ali obuhvaeni zagradama << i >>,
dok se za razdvajanje oznaka od naredbi na koje se odnose u mnogim jezicima koristi dvotaka
(:). Evo nekih primera:
Primer naredbe GOTO za skok na oznaenu naredbu u Adi.
goto KRAJ;

<<KRAJ>> SUM := SUM + PODATAK;

Isti primer napisan u C-u bio bi sledeeg oblika:


goto

kraj;

kraj: sum := sum + podatak;

U svim programskim jezicima obino su definisana odreena pravila koja ograniavaju


korienje naredbe GOTO. Na primer, u Pascal-u oznake moraju eksplicitno da budu opisane u
odeljku u kome se opisuju i drugi elementi programa. One se ne mogu prenositi kao argumenti
potprograma niti modifikovati. Kao deo GOTO naredbe moe da bude samo neoznaena
konstanta, ali ne i izraz ili promenljiva koja dobija vrednost oznake.
Primer. U beskonanom ciklusu unositi dva realna broja i raunati njihov proizvod.
program mnozi;
uses crt;
label 1;
var a,b,p:real;
ch:char;
begin
1:
write(' unesi prvi broj '); readln(a);
write(' unesi drugi broj '); readln(b);
writeln(' Njihov proizvod je '); writeln(a*b:20:0);
goto 1;
end.

4.11. Ciklusi u paktu MATHEMATICA


U MATHEMATICApostoje upravljake strukture kojima se definie viestruko ponavljanje
odreene sekvence naredbi. Kao i u ostalim savremenim programskim jezicima, postoje naredbe
za definisanje petlji sa unapred zadatim brojem izvrenja tela petlje. To su tzv. brojake petlje,
kod kojih postoji broja kojim se upravlja izvrenjem petlje. Takoe, postoje pre-test i post-test
petlje kojima se definiu iterativni programski ciklusi.

78

4.11.1. Do ciklusi
Do ciklusi se koriste za definisanje brojakih programskih ciklusa. Razliite varijante ovih
ciklusa prikazane su u sledeoj tabeli.
evaluirati expr za espektivno, pri emu i uzima
vrednosti iz skupa {1, ..., imax}
evaluirati expr sa vrednostima i od imin do imax
sa korakom di
evaluacija izraza expr n puta

Do[expr, {i, imax}]


Do[expr,{i, imin, imax, di}]

@@
D
8<
D
@
HL8 <
D

Do[expr, {n}]

Do Print i^2 , i, 4
1
4
9
16
t = x; Do t = 1
1
1+

(* Evaluira Print[i^2] sa vrednostima za i od 1 do 4 *)

1 +k t ,

k, 2, 6, 2

; t

6
1+ 4
1+2x

@
@
8<
D
8<
8<
D
8
<
8
<
8
<
8
<
8
8<
<
@
HL8<
D
@@
D@

D
8<
D

Moe se postaviti vie ugnjedenih brojakih.


Do Print
2, 1
3, 1
3, 2
4, 1
4, 2
4, 3

i, j

i, 4 , j, i - 1

(*Dvostruki ciklus za i=1,4,

j=1, i-1*)

Ponekad je potrebno da se odreena operacija ponovi odreeni broj puta, bez promene
vrednosti neke iterativne promenljive.
t = x; Do t = 1
1
1+

1 +t ,

; t

1
1+ 1
1+x

t = 67; Do Print t ; t = Floor t 12 ,


67
5
0

@8 <
D

Suma prvih 1000 prirodnih brojeva se moe izraunati na sledei nain:


sum = 0;
Do sum += i, i, 1000
sum
500500

4.11.2. While i For ciklusi


Pored Do petlje, MATHEMATICA ima petlje For i While, koje podseaju na istoimene petlje
u programskim jezicima PASCAL i C. Za razliku od Do petlje koja se uvek izvrava zadati broj

Predrag S. Stanimirovi

Programski jezici

79

puta, broj izvravanja petlji For i While je odre|en nekim izlaznim kriterijumom. Tanije, te
petlje se izvravaju samo dok odreeni uslov ima vrednost True.
While[test,body]

izvrava body sve dok je test=True

@@
D@

D
D

While petlja je pogodna kada se ne zna koliko je puta potrebno ponoviti odreene operacije.
n = 17; While n 0, Print n ; n = Floor n 2
17
8
4
2
1
t = MATHEMATICA, Pi, 15 ; While t
, Print First t
MATHEMATICA

<@
8
<@@
D
D@
D
D
; t = Rest t

15

U nekim sluajevima je potrebna vea kontrola nad izvravanjem programa. U tim


sluajevima se koristi fleksibilnija, ali i komplikovanija For petlja.
For[start,test, incr, body]

izvrava start, zatim respektivno evaluira body i


incr sve dok test ne postane False

U sluaju izraza For[start, test, incr] izvrava se ciklus sa praznim telom.


Sve do evaluacije izraza Return[expr] ili Throw[expr], finalna vrednost For ciklusa je
Null.

@
D
@
@
D
D
@ @
D
D
@
@
D
D
LLM
IHH

Primer.

f x
x2
For tot = 0; i = 0, i
tot
5

<

3, i ++, tot

+=

f i

Napomenimo da su uloge znakova , i ; obrnute u odnosu na programski jezik C.


For i = 1, i < 4, i++, Print i
1
2
3
For i = 1; t = x, i ^2 < 10, i ++, t = t^2 + i; Print t
1 + x2
2

2 + 1 + x2
3 + 2 + 1 + x2

2 2

U While i For ciklusima se uslovni izraz test kojim se prekida ciklus, evaluira pre evaluacije
tela ciklusa. Telo ciklusa se izvrava sve dok je vrednost izraza test jednaka True.

4.11.3. Kontrola petlji


Ponekad je potrebno preskoiti neki korak u petlji, ili ak izai iz petlje pre nego to se ona
zavri. MATHEMATICA ima dve funkcije koje slue za takve intervencije. Naredbom
Break[] u telu ciklusa For[start,test, incr, body], koji je oznaen sa body, zavrava se
izvrenje For ciklusa. Naredba Continue[] zavrava evaluaciju tela body, i nastavlja ciklus
evaluacijom izraza incr.

80

@@
D@ @
D
D
8<
D
@ @ @
D
D@
D
D
Break[ ]
Continue[ ]

izlazak iz petlje
prelazak na sledei korak u petlji

Do Print i ; If i == 3, Break
, i, 10
1
2
3
For i = 1, i < 5, i++, If i == 3, Continue
1
2
4

; Print i

4.11.4. POSEBNE VRSTE CIKLUSA


Pored opisanih tipova ciklusa koje poseduje veina savremenih programskih jezika,
MATHEMATICA poseduje specifine funkcije za realizaciju brojakih i iterativnih programskih
ciklusa.
Nest[f, expr, n]
FixedPoint[f, expr]
FixedPoint[f, expr,
SameTestcomp]

primenjuje n puta funkciju f na expr


poinje sa expr i primenjuje funkciju f sve dok se rezultat
ne menja vie
zaustavlja se kada je funkcija comp primenjena na dva
susedna rezultata daje True

@
D
@
@
@
D
D
D
@@
HL
DD
@@@
D@

D
DD

Ciklusi definisani funkcijom Nest su brojaki, dok se funkcijom FixedPoint definiu


iterativni programski ciklusi.
Nest f, x, 3
f f f x
Nest Function t, 1
1
1+

1+t

, x, 3

1
1+ 1
1+x

FixedPoint Function z, Print z ; Floor z 2


67
33
16
8
4
2
1
0
0

, 67

4.11.5. Bezuslovni skok


Pomou funkcija Label i Goto se moe izvriti bezuslovni skok na odreeno mesto u
proceduri. Kada se funkcija Label navede u proceduri, funkcijom Goto se izvravanje programa
nastavlja poevi od elementa oznaenog sa Label.
Label[ime]
Goto[ime]

oznaka za funkciju Goto


prelazi na funkciju Label[ime] u trenutno aktivnoj proceduri

Predrag S. Stanimirovi

Programski jezici

81

Funkcija Goto se moe koristiti samo kada se u istoj proceduri nalazi i odgovarajua funkcija
Label. U optem sluaju treba izbegavati upotrebu Goto, jer ona naruava strukturu programa,
pa su praenje izvravanja i kasnije modifikacije time oteani.

H @D@
D @ @D
D
L
t = 5; Label start ; Print t ; t - = 2;
5
3
1

If t > 0, Goto start

5. POTPROGRAMI

U programiranju se esto javlja potreba da se neki deo programa vie puta ponovi u jednom
programu. Takoe, esto puta se ista programska celina javlja u vie razliitih programa. Ovi
problemi se reavaju pomou potprograma.
Potprogrami se uvek koriste sa idejom da se izbegne ponavljanje istih sekvenci naredbi u
sluaju kada u programu za to postoji potreba. Meutim, danas su potprogrami mnogo
znaajniji kao sredstvo za struktuiranje programa. Pri razradi programa metodom dekompozicije
odozgo nanie, svaka pojedinana aktivnost visokog nivoa moe da se zameni pozivom
potprograma. U svakoj sledeoj etapi ide se sve nie i nie u torn procesu dekompozicije sve
dok se reenje kompleksnog programa ne razbije na jednostavne procedure koje se konano
implementiraju.
Moe se rei, da su potprogrami osnovno sredstvo apstrakcije u programiranju.
Potprogramom se definie skup izlaznih veliina u funkciji ulaznih veliina. Realizacija tih
zavisnosti definisana je lokalno u samom potprogramu.
Potprogrami se definiu kao programske celine koje se zatim po potrebi pozivaju i realizuju,
bilo u okviru istog programa u kome su i definisani, bilo u drugim programima.
Primer. Kao primer kojim se ilustruje korienje potprograma uzmimo program kojim se
unosi i sumira niz celih brojeva, koji se zavrava nulom. Na kraju programa tampa se
aritmeticka sredina unetog niza brojeva. Program je napisan u Pascal-u.
program SREDNJA_VRENOST;
var
x,Sum, k : Integer;
Zadnji : Boolean;
procedure Sredina(Vred:Integer; var Zadnji:Boolean);
begin
Zadnji := Vred = 0;
If not Zadnji then

82
begin
Sum = Sum + Vped; k := k+1

end;

end; { Kraj opisa potprograma }


begin
Sum := 0; K := 0; Zadnji := false;
while not Zadnji do
begin
input(x);
Sredina( x , Z a d n j i ) {Poziv potprograma }
end;
print(Sum/k);
end.

Pre nego razmotrimo neke pojedinosti oko definisanja i korienja potprograma, istaknimo
neke opste karakteristike potprograma kakvi se najee sreu u savremenim programskim
jezicima.
(1) Svaki potprogram ima jednu ulaznu taku. Izuzetak od ovog pravila postoji jedino u
FORTRAN-u, gde je mogue definisati vie razliitih ulaza u potprogram.
(2) Program koji poziva potprogram prekida svoju aktivnost sve dok se ne zavri pozvani
potprogram. To znai da se u jednom trenutku izvrava samo jedan potprogram.
(3) Po zavretku pozvanog potprograma upravljanje se vraa programu koji ga je pozvao, i
to na naredbu koja sledi neposredno iza poziva potprograma.
Potprogram karakteriu etiri osnovna elemental
ime potprograma,
lista imena argumenata (fiktivni argumenti),
telo potprograma,
sredina (okruenje) u kojoj potprogram definisan.
Tipian opis potprograma je sledeeg oblika:
procedure Ime_Potprograma ( L i st a f i k t i vn i h argumenata);
Opisi l o ka l n i h promenljivi h ;
Tel o potprograma
end Ime_potprograma;

Ime potprograma je uvedena re kojom se potprogram imenuje i preko kojeg se vri


njegovo pozivanje.
Fiktivnim argumentima definie se skup ulazno-izlaznih veliina potprograma. Kod poziva
potprograma se fiktivni argumenti (parametri) zamenjuju stvarnim argumentima. Fiktivni i
stvarni argumenti moraju da se slau po tipu, dimenzijama i redosledu navoenja u listi
argumenata.
Lista parametara moe da sadri samo imena fiktivnih argumenata, ime je odreen njihov
broj i redosled navoenja, Kod novijih programskih jezika u listi argumenata navode se i
atributi o tipu argumenata kao i o nainu prenoenja u potprogram.
U samoj proceduri, u delu Opisi l o ka l n i h promenljivi h , mogu da budu definisani lokalni
elementi procedure i to promenljive, konstante, oznake, drugi potprogrami.
Telo potprograma ini sekvenca naredbi koja se izvrava nakon poziva potprograma. U telu
potprograma se realizuje kd potprograma.

Predrag S. Stanimirovi

83

Programski jezici

Okolinu potprograma predstavljaju vrednosti globalnih promenljivih okruenja u kome je


potprogram definisan i koje se po mehanizmu globalnih promenljivih mogu koristiti u
potprogramu.
U programskim jezicima se obino sreu dva tipa potprograma:
funkcijski potprogrami (funkcije),
potprogrami opteg tipa (procedure).

5.1. Funkcije
Funkcijski potprogrami po konceptu odgovaraju matematikim funkcijama. Lista argumenata
kod ovih potprograma sastoji se samo od ulaznih argumenata, na osnovu kojih se u telu
potprograma izraunava vrednost koja se prenosi u pozivajuu programsku jedinicu. Ulazne
vrednosti se u funkciji ne menjaju. U programskim jezicima se standardno za opis funkcija koristi
re FUNCT I ON. Uzmimo kao primer funkciju za izraunavanje sume prvih n prirodnih
brojeva. Radi poreenja isti potprogram napisan je u razliitim programskim jezicima:
Pascal
function SUM ( n : integer) : integer;
var
i, POM : integer; { Opis l ok al ni h promenljiv i h }
begin { Telo funkcije }
POM := 0:
for i := 1 to n do POM := POM + i;
SUM := POM {Vrednost koja se prenosi u glavni program}
end.

FORTRAN

10

INTEGER FUNCTION SUM ( N )


INTEGER N
DO 10 I = 1, N
SUM = SUM + I
END

C
int SUM ( i n t n)
{ int POM = 0;
for ( i n t i = 0: i < n; i++)
POM = POM + i ;
return P O M ;
}

U jezicima Pascal i FORTRAN se za prenoenje vrednosti iz potprograma u pozivajuu


jedinicu koristi se promenljiva koja odgovara imenu funkcije. U telu takvih funkcija mora da
postoji bar jedna naredba dodele kojom se rezultat dodeljuje imenu funkcije. Kae se da
funkcija prenosi vrednost u glavni program preko imena.
U novijim programskim jezicima obino postoji naredba return kojom se eksplicitno
navodi vrednost koja se iz potprograma prenosi u glavni program. U gore navedenim primerima
to se vidi u jeziku C. Svaka funkcija mora de prenese neku vrednost u glavni program to znai
da se u ovim jezicima rei function i return koriste u paru.
Funkcijski potprogrami se pozivaju slino matematikim funkcijama, tako to se u okviru
izraza navede ime funkcije sa imenima stvarnih parametara umesto fiktivnih. Koristei gore

84
navedene primere, suma prvih 999 celih brojeva se moe izraunati pozivom funkcije SUM na
sledei nain:
SUMA := SUM(999)

(Pascal)

SUMA = SUM(999)

(C).

ili
Funkcija se koristi u sluaju kada se vraa jedna veliina u rezultujuu programsku jedinicu.

5.2. PROCEDURE
Procedurama se definiu potprogrami opteg tipa, kojima se moe realizovati svaki algoritam
koji sam za sebe ima odreeni smisao. Procedurama se obino u glavni program prenosi jedan ili
skup rezultata.
Opis potprograma opteg tipa obino ima sledeu strukturu:
procedure IME_PROCEDURE (Lista argumenata)
Opisi lokalnih promenljivlh;
Telo procedure
end;
Opis poinje kljunom rei kojom se eksplicitno navodi da definiemo proceduru. U mnogim
programskim jezicima koristi se re procedure, mada ma i izuzetaka, na primer
S U B R O U T I N E u FORTRAN-u. I M E _ P R O C E D U R E je uvedena re kojom se imenuje
potprogram. Ime potprograma se koristi kod poziva potprograma. Za razliku od funkcija, lista
argumenata kod procedura moe da sadri ulazne, izlazne i ulazno-izlazne argumente. Obino
se zahteva da se u listi argumenata navede njihov tip i nain prenoenja vrednosti izmeu
glavnog programa i potprograma. U Adi npr., argumenti mogu da budu ulazni, izlazni i ulaznoizlazni to se eksplicitno navodi reima in, out i i n o u t uz odgovarajue argumente. Postoje
razliite tehnike prenosa vrednosti izmeu glavnog programa i potprograma.

5.3. Prenos argumenata


Funkcije i procedure se koriste tako to se tamo gde je potrebno u kodu programa, pozivaju
sa spiskom stvarnih argumenata. Pri tome, stvarni argument zamenjuju fiktivne. Prenos
argumenata izmeu glavnog programa i potprograma moe da se ostvari na vie razliitih
naina. Semanticki posmatrano, to moe da bude po jednom od tri sematicka modela.
Potprogram moe da primi vrednost od odgovarajueg stvarnog parametra (koji se stavlja na
mesto ulaznog parametra), moe da mu preda vrednost (ako se postavlja na mesto izlanog
formalnog parametra) ill da primi vrednost i preda rezultat glavnom programu (kada se stvarni
parametar postavlja na mesto ulazno-izlaznog parametra). Ova tri semantika modela nazivaju se
in, out i inout, respektivno i prikazana su na slici 5.1. Sa druge strane, postoje dva
konceptualna modela po kojima se ostvaruje prenos parametara izmeu glavnog programa i
potprograma. Po jednom, vrednosti parametara se fiziki prebacuju (iz glavnog programa u
potprogram ili u oba smera), a po drugom prenosi se samo informacija o tome gde se nalazi
vrednost parametra. Najee je to jednostavno pokaziva (pointer) na memorijsku lokaciju
parametra.

Predrag S. Stanimirovi

Programski jezici

85

Slika 5.1 Tri semantika modela za prenos parametara

5.3.1. Prenos po vrednosti (Call by Value)


Ovaj nain prenosa se obino sree kod funkcijskih potprograma. Sastoji se u tome to se pri
pozivu funkcije vrednosti stvarnih argumenata kopiraju u pomone memorijske lokacije
fiktivnih argumenta koje su sastavni deo potprograma. Sve promene argumenata odvijaju se u
lokacijama potprograma i nedostupne su glavnom programu. Zbog toga se ova tehnika prenosa
moe koristiti samo za prenos ulaznih argumenata potprograma, a ne i za vraanje rezultata
glavnom programu. Razmotrimo situaciju koja nastane kada se potprogram PP sa argumentima
x i y pozove sa stvarnim argumentima p i q. To znai imamo opis potprograma sa
P P ( x , y: i n t e g e r ) i poziv PP(p,q). Za smetaj vrednosti x i y u potprogramu su rezervisane
memorijske lokacije iji sadrzaj je u trenutku prevoenja potprograma nedefinisan. U glavnom
programu, sa druge strane, postoje memorijske lokacije za smetaj stvarnih vrednosti p i q.
Vrednosti ovih memorijskih lokacija mora da budu definisane pre poziva potprograma. Kada
se pozove potprogram, vri se kopiranje vrednosti iz memorijskih lokacija p i q u lokacije
fiktivnih argumenata x i y u potprogramu, to je ilustrovano na slici 5.2
Funkcija
Glavni program

Slika 5.2 Prenos parametara po vrednosti


Osnovni nedostatak prenosa po vrednosti je u tome to se za formalne parametre potprograma
rezervie memorijski prostor. Uz to i sama operacija kopiranja vrednosti moe da utie na
efikasnost programa. Ovi nedostaci posebno dolaze do izraaja kada se prenose strukture
podataka, kao na primer veliki vektori i matrice.
Obino se u okviru programskih jezika implicitno ili eksplicitno navodi da se argumenti
prenose po vrednosti. U Algol-u se to ba navodi pomou rei v a l ue, u Adi sa in, dok se u

86
Pascal-u ovaj nain podrazumeva kada nije navedeno v a r uz spisak argumenata. U FORTRAN-u
se argumenti prenose po vrednosti kada su stavljeni izmeu kosih crta.

5.3.2. Prenos po rezultatu (Call by Result)


Prenos po rezultatu je tehnika koji se primenjuje za prenos izlaznih (out) parametara. Kada se
argumenti prenose po rezultatu, njihove vrednosti se izraunavaju u lokalnim memorijskim
lokacijama formalnih argumenata potprograma (nema prenosa vrednosti iz glavnog programa u
potprogram). Meutim, pre vraanja upravljanja glavnom programu, ove vrednosti se kopiraju u
memorijske lokacije stvarnih argumenata. Stvarni argumenti u ovom sluaju moraju da budu
promenljive. Kao i kod prenosa po vrednosti, za fiktivne argumente potprograma rezerviu se
lokalne memorijske lokacije.
Kod ovog naina prenosa mogui su i neki negativni efekti, kao to je na primer kolizija
stvarnih argumenata, koja nastaje u sluajevima kada se potprogram poziva tako da isti stvarni
argument zamenjuje vie fiktivnih argumenata. Razmotrimo sledei primer u kome se
potprogram definisan kao procedure PP( x, y: r e a l ) poziva sa P P ( p l , p l ) . U ovom primeru
problem je u tome to se u potprogramu aktuelni parametar p1 modifikuje u dve razliite
memorijske lokacije (koje odgovaraju formalnim parametrima x i y) odakle vrednosti treba da
budu kopirane u istu memorijsku lokaciju stvarnog argumenta p1. Pitanje je koju e od ovih
vrednosti argument p1 imati po zavretku potprograma.

5.3.3. Prenos po vrednosti i rezultatu (Call by Value-Result)


Prenos po vrednosti i rezultatu je nain prenosa ulazno-izlaznih argumenata sa kopiranjem
vrednosti argumenata. To je u sutini kombinacija prenosa po vrednosti i prenosa po rezultatu.
Vrednosti stvarnih argumenta kopiraju se u memorijske lokacije fiktivnih argumenata
potprograma. To su lokalne memorijske lokacije potprograma i sve izmene nad argumentima
pamte se u ovim lokacijama. Pre vraanja upravljanja glavnom programu rezultati potprograma
se iz ovih lokalnih memorijskih lokacija ponovo kopiraju u memorijske lokacije stvarnih
argumenata. Ovaj nain prenosa se esto naziva i prenos kopiranjem (call by copy) jer se stvarni
argumenti najpre kopiraju u potprogram, a zatim ponovnim kopiranjem rezultati vraaju u glavni
program.
Nedostaci i negativni efekti koji su prisutni kod prenosa po vrednosti i prenosa po rezultatu
ostaju i kod ovog naina prenosa.

5.3.4. Prenos po referenci (Call by Reference)


Kod ovog naina prenosa nema kopiranja vrednosti parametara iz glavnog programa u
potprogram ill obrnuto. Potprogramu se samo prenosi referenca (obino samo adresa)
memorijske lokacije u kojoj je vrednost stvarnog argumenta. Efekat je kao da se reference
stvarnih argumenata preslikavaju u reference fiktivnih, slika 5.3. Potprogam pristupa istim
memorijskim lokacijama kojima i glavni program, nema rezervisanja memorijskih lokacija za
fiktivne argumente u okviru potprograma. Sve promene nad argumentima koje se izvre u
okviru potprograma vidljive su i glavnom programu. Zbog toga je ovo nain prenosa koji se
koristi za prenos ulazno-izlaznih argumenata. U mnogim programskim jezicima to je osnovni
nain prenosa argumenata i podrazumeva se implicitno (Algol, FORTRAN). U Pascal-u se
koristi uvek kada uz argumente stoji var, a u Adi inout.

Predrag S. Stanimirovi

Programski jezici

87

Glavni program

Funkcija

Slika 5.3 Prenos parametara po referenci


Prednosti prenosa po referenci su u njegovoj efikasnosti kako u pogledu vremena tako i u
pogledu memorijskog prostora. Nema potrebe za dupliranja memorijskog prostora niti se gubi
vreme u kopiranju vrednosti argumenata iz jednih memorijskih lokacija u druge. Meutim, treba
imati u vidu da se ovaj prenos implementira indirektnim adresiranjem pa se tu ipak neto gubi
na efikasnosti. Takoe, mogui su i odreeni boni efekti u oodreenim posebnim sluajevima
poziva potprograma. Razmotriemo neke od njih.
Kao u sluaju prenosa po rezultatu i ovde je mogua kolizija izmeu stvarnih argumenata.
Uzmimo na primer potprogram PP u Pascal-u sa dva argumenta koji se prenose po vrednosti, a
koji je opisan sa:
procedure PP(var x , y : i n t e g e r ) ;

Ako se ovaj potprogram pozove tako da se oba fiktivna argumenta zamene istim, npr sa
PP(p1, p1);, dolazi do kolizije jer se oba fiktivna argumenta referenciraju na istu memorijsku
lokaciju stavarnog argumenta p1.
Takoe je mogua kolizija izmeu dva ili vie elementa istog niza. Npr. pretpostavimo da se
potprogram PP poziva sa:
P P ( v e k [ i ] , ve k [ j ] ) ;

Ako se dogodi da je i jednako j, tada ce doi do kolizije referenci oba fiktivna argumenta,
odnosno promene i jednog i drugog treba da se upisuju u istu memorijsku lokaciju.
Do kolizije dolazi i u sluaju kada je jedan argument ceo niz koji se prenosi tako to se navodi
njegovo ime, a drugi argument element istog tog niza. Neka je potprogram PP1 definisan sa:
procedure PP1(x: integer, y. a r r a y [ 1 . . 1 0 ] of integer);

i neka je pozvan sa:


PP(vek[i], vek).
U ovom sluaju dolazi do kolizije jer prvi argument pristupa i-tom elementu niza, a drugi
svim elementima niza pa i-tom.
Kod prenosa po referenci kolizija moe da nastane izmeu elemenata programa koji se prenose
kao stvarni argumenti potprograma i onih koji se prenose kao globalni parametri. Razmotrimo
sledei primer u Pascal-u:
procedure PPG;
var global: integer;
procedure PPS (var local: integer);
begin
local := local + 1;
local := local + global;

88
end;
begin
global := 2;
PPS(global); print(global)
end.

Problem je koja e vrednost biti odtampana po pozivu potprograma PPS. Odgovor je 6, jer
se dodeljena vrednost 2 u potprogramu najpre koriguje naredbom local := local + 1;, a zatim i
naredbom 1ocal := local + global;. Promenljiva global se u potprogramu koristi i kao globalna
promenljiva i kao stvarni argument, pa se i promene argumenta potprograma i promene same
promenljive global registruju u istoj memorijskoj lokaciji. Napomenimo da bi u ovom primeru
prenos sa kopiranjem (call by value-result) dao sasvim drugi rezultat. U tom sluaju, vrednost
stvarnog argumenta global kopira se u memorijsku lokaciju fiktivnog argumenta x i u
potprogramu se sve promene argumenta registruju u toj lokaciji. U prvoj naredbi dodeljivanja x
dobija vrednost 3, a u drugoj se ova vrednost inkrementira za 2, to je vrednost globalne
promenljive global (dodeljena pre ulaska u potprogram). Time argument x dobija vrednost 5 i
to je vrednost koja se sada kopira natrag u memorijsku lokaciju stvarnog argumenta global . Ta
vrednost se i tampa. To znai da se u ovom sluaju tampa vrednost 5. Slina analiza istog
programa mogua je i za sluaj prenosa argumenta potprograma po vrednosti. U tom sluaju
vrednost stvarnog argumenta global se kopira u potprogram ali su sve promene u potprogramu
nevidljive za glavni program, pa se tampa vrednost 2 koja je dodeljena promenljivoj global pre
poziva potprograma.
Primer. Potprogram za ureivanje vektora u FORTRAN-u 77.
SUBROUTINE (A,N)
DIMENSION A(100)
DO 10 I = 1, N-1
AMAX = A(I)
K = I
DO 20 J = I+1,N
IF (A(J).GT.AMAX) THEN
AMAX = A(J)
K = J
END IF
20
CONTINUE
A(K) = A(I)
A(I) = AMAX
END

U jeziku Pascal se koristi slubena re var ispred izlaznih parametara.


Primer. Potprogram za sortiranje napisan u Pascal-u.
procedure (var a : array[l..100] of real; n:integer);
i,j,k : integer;
MAX : real;
begin
for i := 1 to n-1 do
begin
MAX := a[i];
k := i;
for j := i+1 to n do
if (a[j] > MAX) then
begin
MAX := a[j];
k := j;

Predrag S. Stanimirovi

89

Programski jezici

end;
a[k] := a[i];
a[i] := MAX;
end;
end.

5.3.5. Prenos po imenu (Call by Name)


Prenos po imenu je nain prenosa ulazno-izlaznih argumenata potprograma koji se razlikuje
od prethodnih po tome to nema ni kopiranja vrednosti ni prenosa reference, ve se pri pozivu
potprograma imena stvarnih argumenata ubacuju u tekst potprograma svuda umesto imena
fiktivnih argumenata. Potprogram se izvrava kao da se radi o kodu koji je napisan sa imenima
stvarnih argumenata. Ovde se odvija jedno zakasnelo povezivanje u trenutku poziva
potprograma. Implementacija prenosa po imenu zavisi od toga ta se prenosi kao stvarni
argument. Ako je stvarni argument skalarna promenljiva, onda je prenos po imenu isti kao i
prenos po referenci. Ako je stvarni argument konstanta, onda se prenos vri kao u sluaju
prenosa po vrednosti. Ako se kao stvarni parametar prenosi element niza, onda se ovaj prenos
razlikuje od svih prethodnih i moe da ima sasvim specifine efekte.
Razmotrimo sledei primer programa iz programskog jezika Algol 60 u kome se za prenos
parametara koristi prenos po imenu.
procedure BPP;
integer GLOBAL;
integer array LIST [1:2];
procedure PP (PARAM)
integer PARAM;
begin
PARAM:=3; GLOBAL:=GLOBAL + 1; PARAM:=5
end;
begin
LIST[1]:=2; LIST[2]:=2; GLOBAL:=1;
PP(LIST[GLOBAL])
end;

Kada se naredbom PP(LIST[GLOBAL]) pozove potprogram PP, njegovo telo se izvrava


kao da je napisan sledei kod:
begin
LIST[GLOBAL] := 3;
GLOBAL := GLOBAL+1;
LIST[GLOBAL] := 5
end;

Pozivom potprograma PP menjaju se elementi niza LIST u 3 i 5.


Prenos po imenu moe da se iskoristi za postizanje nekih efekata koji su kod drugih naina
prenosa tesko izvodljivi. Razmotrimo sledei potprogram u Algol-u 60:
real procedure SUMA(x,j,n);
value n; real x;
integer j,n;
begin
real S;
S := 0.0;
for j := 1 step 1 until n do S := S + x;
SUMA := S
end;

90
Ako je A skalar i potprogram SUMA pozove sa SUMA(A, I,100), potprogram se izvrava
kao da je napisan kod
begin
real
S;
S := 0.0;
for I := 1 step 1 until 100 do
S := S + A;
SUMA := S
end;

i bie izraunata vrednost 100*A, koja se preko imena potprograma prenosi u glavni program.
Meutim, pretpostavimo da je A niz sa 100 elemenata tipa real i pozovimo potprogram SUMA sa:
S U M A ( A [ I ] , I, 1 0 0 ) .

Efekat je potpuno neoekivan. Telo potprograma se izvrava kao da je napisan kod:


begin
real S;
S := 0.0;
for I := 1 step 1 until 100 do S :- S + A[I];
SUMA := S
end;

Oigledno je da se u ovom sluaju izraunava suma 100 elemenata niza A.


Mogue je i vie od toga. Jednostavnim pozivom istog potprograma pmou izraza
SUMA(A[I]*A[I], I, 100) izraunava se suma kvadrata elemenata vektora A jer se telo
potprograma izvrava kao da je napisano:
begin
real
S;
S:=0.0;
for I:=1 step 1 until 100 do
SUMA := S
end;

S:=S+A[I]*A[I];

Istim potprogramom moe se izraunati i skalarni proizvod dva vektora. Potrebno je samo da
se potprogram pozove sa:
SUMA(A[I]*B[I],I,100)

kada se izvrava telo potprograma kao da je napisano:


begin
real
S;
S := 0.0;
for I := 1 step 1 until 100 do
S :=S+A[I]*B[I];
SUMA := S
end;

Ovde navedeni primeri ilustruju pozitivne efekte prenosa argumenata po imenu, meutim
mogui su i neki negativni efekti ako se funkcionisanje koncepta ne poznaje dobro i ne koristi
pravilno. Razmotrimo sledei primer potprograma kojim se vri meusobna zamena vrednosti
para promenljivih:
procedure PERM (PRVI,DRUGI);
integer PRVI,DRUGI;
begin
integer POM;

Predrag S. Stanimirovi

Programski jezici

91

POM := PRVI;
PRVI := DRUGI;
DRUGI := POM
end;

U ovom potprogramu realizovan je dobro poznati algoritam za zamenu vrednosti para


promenljivih koji za par skalarnih promenljivih i u mnogim drugim sluajevima funkcionie
sasvim korektno. Meutim, ako se potprogram pozove tako da je jedan stvarni argument i-ti
element nekog niza, a drugi argument indeks tog elementa, rezultat koji se pri tome dobija moe
da bude i sasvim neoekivan i nekorektan. Pretpostavimo da je potprogram pozvan sa:
(1)

PERM(A[I], I)

(2)

PERM(I, A[I])

i da je pre poziva potprograma I = 1, A[l] = 2, a A[2] = 5. Oekuje se da se i u jednom i u


drugom sluaju vri izmena vrednosti izmeu prvog elementa niza A i vrednosti promenljive I
koja se koristi za indeksiranje. Meutim zbog prenosa po imenu u ova sluaja izvravaju se
potpuno razliite sekvence naredbi. U prvom sluaju redosled naredbi je:
POM := A[I];
A[I] := I;
I := POM;

Tako da se dobija A[1] := 1 i I = 2, to je korektan rezultat. Meutim u drugom sluaju


izvrava se sekvenca naredbi:
POM := I;
I := A [ I ] ;
A[I] := POM

i dobija se da je I = 2, a A[2] = 1, to se potpuno razlikuje od rezultata u prethodnom sluaju i ne


odgovara onome to je trebalo postii permutacijom.

5.4. Globalne promenljive kao parametri potprograma


Potprogram se u odnosu na programski modul u kome je definisan tretira kao blok u bloku.
Sve promenljive definisane u okruenju u kome je definisan i sam potprogram mogu se koristiti
i u potprogramu po konceptu globalnih promenljivih. Potprogram moe da bude i bez spiska
argumenata i da sve veze sa okruzenjem ostvaruje preko globalnih promenljivih. Na primer,
potrebno je napisati program kojim se izraunava izraz dat sa:

tanh(a n b)
tanh 2 (a 2 b 2 )

tanh 2 (a m b)
tanh(a 2 b 2 )

Za izraunavanje vrednosti tanh(x) treba koristiti potprogram kojim se ova funkcija


izraunava prema jednoj od relacija:
tanh

e x ex
e x ex

ili tanh

e2x 1
.
e2x 1

Slede etiri mogua reenja ovog problema u kojima se koriste razliiti potprogrami sa i bez
parametara. Reenja su data u programskom jeziku Pascal.
(a) Reenje funkcijskim potprogramom bez argumenata:
program TANH1(input, output);
var D,a,b.m,n.Rl,R2,R3,x : real;
function th: real;
var R :real;
begin
R:=exp(2*x); th := (R-1)/(R+1)
end;

92
begin
read(a,b,m,n);
x:=a*n+b; R1:=th;
x:=a+m*b; R2:=th;
x:=a*a-b*b;
D:=R1/(R3*R3)-R2*R2/th;
writeln(D);
end.

(b) Reenje pomou procedure bez argumenata


program TANH2(input, output);
var D , a , b , m , n , R 1 , R 2 , R 3 , x , y : real;
procedure th;
begin
y := exp(2*x);
y := ( y - l ) / ( y + l )
end;
begin
r ea d( a, b, m, n) ;
x := a*n + b;
th;
Rl := y;
x := a + m*b;
th;
R2 := y;
x := a*a + b*b; th;
R3 := y;
x := a*a - b*b; th;
D := Rl/(R3*r3)- R2*R2/y;
writeln(D);
end.

(c) Program sa funkcijskim potprogramom sa argumentima.


program TANH(input, output);
var D,a ,b,m,n : real;
function th(x: r e a l ) of real;
var R : real;
begin
R := e x p ( 2 * x ) ;
th:= ( R - 1 ) / ( R + 1 )
end;
begin
real( a . b . m . n ) ;
D := th (a *n + b)/th(a*a + b*b) * th (a *a + b*b)
t h ( a +m*b)* t h ( a +m*b)/th(a*a -b*b);
writel n ( D )
end.

(d) Reenje pomou procedure sa argumentima.


pr og ra m TA NH 4( in pu t, ou tp ut );
v ar D ,a ,b ,m ,n .R l. R2 .R 3, R4
:
re al ;
p ro ce du re t h( va r y: r ea l; x : re al );
b eg in
y := e xp (2 *x ); y : = (y -l )/ (y +l )
e nd ;
b eg in
r ea d( a, b, m, n) ;
t h( Rl , a* n+ b) ;
th (R 2, a +m *b );
t h( R3 ,a *a +b *b );
th (R 4, a* a- b* b) ;
D := rl /( R3 *R 3) -R 2* R2 /R 4;
w ri te ln (D )
e nd .

Predrag S. Stanimirovi

Programski jezici

93

U programskom jeziku FORTRAN konceptu globalnih promenljivih na neki nain odgovara


koncept COMMON podruja. Sve promenljive koje su zajednike za vie programskih modula
obuhvataju se sa COMMON i pamte se u zasebnom memoriskom bloku koji je dostupan svim
potprogramima koji se referenciraju na isto COMMON podruje.

5.5. Imena potprograma kao argumenti potprograma


Mogu se navesti mnoge situacije u kojima je pogodno da se u spisku fiktivnih argumenata
navede i argument koji bi u pozivu potprograma bio zamenjen potprogramom kao stvarnim
argumentom. Primer koji to najbolje ilustruje je potprogram za izraunavanje integrala funkcije.
Ako se takav potprogram pie samo za jednu funkciju, onda se on moe koristiti samo u tom
posebnom sluaju. Mnogo je pogodnije da se napie potprogram koji bi se koristio za razliite
funkcije, koje se definiu kao stvarni argumenti kod poziva potprograma.
Na primer, potrebno je napisati program kojim se izraunava dvostruka suma definisana
sledeom relacijom:
10

20

S ( a 2 b 2 ).
a 0 b 1

Ako se problem reava u programskom jeziku koji dozvoljava da se potprogrami koriste kao
argumenti potprograma i uz to ima prenos vrednosti po imenu (kao na primer u jeziku Algol 60)
onda se za izraunavanje dvostruke sume moe iskoristiti potprogram za izraunavanje
jednostruke sume definisan sa:
real procedure Sum ( k , m , n , f ) ;
value m,n;
real f;
integer
begin
real S;
S := 0;
for k := m Step 1 until n do
S:=S+f:
Sum := S;
end;

k,m,n;

Da bi se izraunala gore data dvostruka suma potrebno je potprogram Sum pozvati sa:
S:= Sum(a,0,10,Sum(b,l,20,a^2+b^2)).
U sluaju kada se potprogram javlja kao argument drugog potprograma mogu da nastanu
mnogo sloeniji sluajevi posebno ako se u potprogramu koriste globalne i lokalne promenljive.
Razmotrimo sledei primer:
procedure SU B1 ;
var x: integer;
procedure SUB2;
begin
write('x=', x )
end;
{ kraj
SUB2}
procedure SUB3;
var x : integer;
begin
x := 3;
SU B4 (S UB 2)
end;
{ k r a j SUB3]
procedure S U B 4 ( X U B X ) ;
var x : integer;
begin
X := 4;

94
SUBX
end;
{ k r a j SUB4}
begin
{p oc et ak S U B 1 }
x := 1;
SUB3
end;
{kr aj S U B 1 }

U ovom primeru potprogram SUB2 se poziva kao agument u pozivu potprograma SUB4. U
potprogramu SUB2 tampa se vrednost promenljive x koja se u potprogram prenosi kao
globalna promenljiva. Koja ce vrednost biti odtampana pri izvravanju potprograma SUB2,
zavisi od toga sta se uzima kao okruenje iz kojeg on preuzima vrednost globalne promenljive
x. Mogua su tri sluaja od kojih, u datom primeru, svaki daje drugi rezultat. Prvo globalna
promenljiva moe da bude preuzeta iz potprograma koji poziva dati potprogram. U naem
primeru to je potprogram SUB4 i u torn sluaju bi bila tampan rezultat x = 4. Druga mogunost
je da se vrednost preuzima iz potprograma u kome je posmatrani potprogram opisan.
Potprogram SUB2 je opisan u potprogramu SUB1 pa bi u ovom sluaju bila tampana vrednost
x - 2. Trea mogunost je da se vrednost prenosi iz okuenja (potprograma) u kome se nalazi
poziv potprograma u kome je posmatrani potprogram argument. U datom primeru poziv
SUB4(SUB2) nalazi se u potprogramu SUBS pa bi bila tampana vrednost x = 3 koja je
promenljivoj x dodeljena u potprogramu SUBS.
U praksi se obino potprogram koristi kao argument u potprogramu u kome je i opisan tako
da se drugi i trei sluaj praktino izjednaavaju. Sa druge strane prvi sluaj kada se u
potprogramu koriste vrednosti iz potprograma u kome je argument, je nepogodan za realizaciju
kod jezika zasnovanih na blokovima i statikoj implementaciji.

5.6. Rekurzivni potprogrami


Funkcija, odnosno procedura je rekurzivna ako sadri naredbu u kojoj poziva samu sebe.
Rekurzija moe biti direktna, kada funkcija direktno poziva samu sebe. Takoe, rekurzija moe
biti i indirektna, kada funkcija poziva neku drugu proceduru ili funkciju, koja poziva polaznu
funkciju (proceduru).
U realizaciji rekurzije moraju se potovati dva osnovna principa:
- Mora da postoji rekurentna veza izmeu tekueg i prethodnog (ili narednog) koraka u
izraunavanju.
- Mora da postoji jedan ili vie graninih uslova koji e prekinuti rekurzivno izraunavanje.
Neki programski jezici dozvoljavaju poziv potprograma u telu samog tog potprograma. Takvi
potprogrami nazivaju se rekurzivnim i pogodno su sredstvo za reavanje problema koji su
rekurzivno definisani.
Tipian primer rekurzivnog potprograma je potprogram za izraunavanje faktorijela funkcije
definisanog sa:
n*(n-l)!,

za n>l

1,

za n = 0

n! =

Primer. Program za izraunavanje faktorijela realizovan u Pascal-u:


function FAKT(N: integer): integer;
begin
if N > 0 then FAKT := N*F A K T ( N - l )
else FAKT := 1

Predrag S. Stanimirovi

95

Programski jezici

end;

Radi poreenja pogodno je razmotriti i potprogram koji reava isti problem bez rekurzije:
function FAKT(N: integer): integer;
var i,k:integer;
begin
k := 1;
for i:= 1 to n do k := k*i;
FAKT := k
end;

Koncept rekurzivnih potprograma se najbolje moe sagledati pomou grafa poziva


potprograma na kome se predstavlja svaki od poziva potprograma. Na slici 5.4 prikazan je graf
poziva potprograma FACT za N = 4.

Slika 5.4 Graf poziva potprograma FACT za N = 4


U praksi se esto sreu i problemi u kojima postoji viestruka rekurzija. Jedan od takvih je
problem izraunavanja lanova Fibonaijevog niza brojeva. Fibonaijeva funkcija je definisana
kao:
f(n-l)+f(n-2),
n>1
f(n) =
1, n=1
1, n = 0
Potprogram za izraunavanje lanova Fibonaijevog niza bie dvostruko rekurzivan. Dajemo
implementaciju u Pascal-u:
function Fib(n: Integer):
integer;
begin
if n > 1 then
Fib := Fib(n-l) + Fib(n-2)
else
Fib := 1;
end;

U ovom potprogramu rekurzija dakle nije u stvaranju jedne, ve dve kopije iste funkcije.
Mogue su i trostruke, cetvorostruke, itd. rekurzije jer broj poziva kopija niim nije ogranien.
Graf poziva ovakve dvostruke rekurzije razlikuje se od grafika rekurzija iz prethodnog primera
(slika 5.5).

96

Slika 5.5 Graf poziva funkdje Fib


Jo jedan od klasinih rekurzivnih problema je uveni problem Hanojskih kula.
Primer. Hanojske kule.
procedure Hanoj (n,sa,na,preko : integer);
begin
if n > 0 then
begin
Hanoj (n-1 , sa preko, na);
Write(sa, ' ->, na);
Hanoj (n-1, preko, na, sa);
end
end;

Stara indijska legenda kaze da je posle stvaranja sveta Bog Brama (Brahma) postavio tri
dijamantska stuba i na prvi postavio 64 zlatna prstena razliitih prenika tako da svaki naredni
bude manji od prethodnog. Svetenici hrama moraju da prebacuju te prstenove sa prvog na trei
stub koristei pri tome drugi, all samo jedan po jedan i to tako da se vei prsten ne moe nai
iznad manjeg. Kad svi prstenovi budu prebaeni na trei stub nastupie kraj sveta.
Ovde ce biti prikazan primer programa koji vri ovu operaciju prebacivanja i koji ne zavisi
od broja prstenova. Meutim uobiajeno je da se ovaj primer izvodi za manji broj krugova 3 do 5
ve samim tim to je najmanji broj potrebnih poteza 2n - 1. Za sluaj sa 64 kruga dolazimo do
broja od 18.446.744.073.709.551.615 poteza.
U opstem sluaju, meutim, problem se sastoji u tome da se n prstenova prebaci sa prvog stuba
(1) na treci stub (3) preko drugog stuba (2), to moemo zapisati kao (n, 1, 2, 3). Cilj je, dakle,
ostvarljiv u tri "koraka". Sve prstenove osim najveeg (n-tog), prebaciti na drugi stub. Zatim n-ti
prsten prebaciti na trei stub, a onda na njega staviti pomonu gomilu sa drugog stuba. Da bi se
ovo izvelo potrebno je ceo postupak izvesti za n -1 prsten, a za to je potrebno izvriti istu
proceduru za n - 2 krug itd. Tako dolazimo do rekurzije.
Procedura se poziva za naprimer Hanoj(3, 1, 3, 2).
Razmotriemo jo primer rekurzivnog potprograma za generisanje svih moguih permutacija
bez ponavljanja skupa sa n elemenata P(n), dat kao prethodni primer.
Primer. Potprogram za generisanje permutacija.
procedure P(niz: array[l..10] of integer; n,duz:integer);
var
i,j,pom:integer;
begin
for j := 1 to n do
if n > 1 then
begin
P(niz, n-1, duz);

Predrag S. Stanimirovi

end;

Programski jezici

97

for i := 1 to n-1 do
niz[i] := niz[i+1];
niz[n] := pom;
end
else
for i := 1 to duz do print(niz[i]);

Reenje dato u ovom potprogramu pored klasine rekurzije sadri i iteraciju, to dovodi do
toga da njegovo izvravanje ima veoma zanimljiv tok, to se dobro vidi na grafu poziva (slika
5.6). Karakteristino je da je ovo vie rekurzivan algoritam. Uoljivo je takoe da on generie
sve permutacije bez ponavljanja generiui neke od njih vie puta, tampajui ih pritom samo
jednom.

Slika 5.6 Graf poziva funkcije za generisanje svih permutacija bez ponavljanja

5.6.1. Primeri rekurzivnih funkcija u C


Primer. Jedmostavni primeri rekurzivnih funkcija.
#include <stdio.h>
void fun1(int); void fun2(int); void fun3(int);
void main()
{ printf("\n fun1(5)\n");
fun1(5);
printf("\n fun2(5)\n");
fun2(5);
printf("\n fun3(5)\n");
fun3(5);
}
void
fun1(int n)
{ printf("%2d",n);
void fun2(int n)
{ if(n) fun2(n-1);
void fun3(int n)
{ printf("%2d",n);
if(n) fun3(n-1);
}

Numeriki rezultati:
fun1(5)
543210
fun2(5)
012345

if(n) fun1(n-1);
printf("%2d",n);

printf("%2d",n);

return;
return;

return;

}
}

98

fun3(5)
543210012345
Primer. Rekurzivno izraunavanje faktorijela.
#include <stdio.h>
long fact(short);
void main()
{ short n;
long rezultat;
scanf("%d",&n);
rezultat = fact(n);
printf("Faktorijel od %d = %ld\n", n,rezultat);
}
long fact(short n)
{ if(n<=1)return(1L);

else return(n*fact(n-1));

Primer. Napisati rekurzivnu funkciju za izraunavanje n-tog lana Fibonaijevog niza:


fib(n)=

1, n=1 ili n=0,


fib(n-1)+fib(n-2), n>1 .

#include <stdio.h>
long fib(short);
void main()
{ short n;
scanf("\n %d", &n);
printf("%d-ti clan Fibonacijevog niza = %ld\n",
}

n,fib(n));

long fib(short n)
{ if(n<=1)return((long)1); else return(fib(n-1)+fib(n-2));}

Broj rekurzivnih poziva pri izraunavaju Fibonaijevih brojeva moe se smanjiti na sledei
nain:
#include <stdio.h>
long fib(long a, long b, short n);
void main()
{ if(n==2)return b;
else { b=a+b; a=b-a; n--;
return(a,b,n);
}

Primer. Zadati broj tipa int ispisati znak po znak.


#include <stdio.h>
void printd(int n)
{ if(n<0)
{ putchar('-'); n=-n; }
if(n/10) printd(n/10);
putchar(n%10+'0'); }
void main()
{int n; scanf("%d", &n);
printd(n); }

Primer. Rekurzivno izraunavanje najveeg zajednikog delioca dva cela broja.


#include <stdio.h>
int nzd(int n, int m)

Predrag S. Stanimirovi

Programski jezici

99

{ if(n==m) return(m);
if(n<m) return(nzd(n,m-n));
else return(nzd(n-m,m));
}
void main()
{ int p,q;
scanf("%d%d",&p,&q); printf("nzd(%d,%d)=%d\n",p,q,nzd(p,q));
}

Primer. Rekurzivno izraunati Akermanovu funkciju A(n,x,y), koja je definisana na sledei


nain:
A(n,x,y)=x+1, za n=0
A(n,x,y)= x, za n=1,y=0,
A(n,x,y)=0, za n=2,y=0
A(n,x,y)=1, za n=3,y=0
A(n,x,y)=2, za n>3,y=0
A(n,x,y)=A(n-1,A(n,x,y-1),x), inae.
#include <stdio.h>
long aker(int,int,int);
void main()
{ int x,y,n;
printf("Unesit n"); scanf("%d",&n);
printf("Unesit x");
scanf("%d",&x);
printf("Unesit y"); scanf("%d",&y);
printf("A(%d,%d,%d)=%ld\n",n,x,y,aker(n,x,y));
}
long aker(int n, int x, int y)
{ int pom;
if(n==0)return(x+1);
if(n==1 && y==0) return(x);
if(n==2 && y==0) return(0);
if(n>3 && y==0) return(2);
else { pom=aker(n,x,y-1); return(aker(n-1,pom,x)); }
}

Primer. Koristei rekurzivnu definiciju proizvoda dva prirodna broja napisati odgovarajuu
funkciju.
#include <stdio.h>
long p(int a, int b)
{ if(b==1) return(a); return(a+p(a,b-1));
void main()
{ int x,y;
printf("Unesi dva prirodna broja ");
printf("%d*%d=%ld\n",x,y,p(x,y));
}

}
scanf("%d%d",&x,&y);

Primer. Napisati rekurzivni program za izraunavanje sume cifara zadatog prirodnog broja.
#include <stdio.h>
int sumacif(long n)
{ if(!n)return(0);

else

return(n%10+sumacif(n/10));

void main()
{ long k;
printf("Unesi dug ceo broj "); scanf("%ld",&k);
printf("Suma cifara od %ld=%d\n",k,sumacif(k));
}

100
Primer. Napisati rekurzivni program za izraunavanje kolimika dva prirodna broja na
proizvoljan broj decimala.
#include <stdio.h>
void kolicnik(int ind, int n, int m, int k)
{ if(ind) printf("%d.",n/m);
else printf("%d",n/m);
if(k) kolicnik(0,(n%m)*10,m,k-1); }
void main()
{ int n,m,k;
printf("Brojilac? "); scanf("%d",&n);
printf("Imenilac? "); scanf("%d",&m);
printf("Broj decimala? "); scanf("%d",&k);
kolicnik(1,n,m,k);
}

Primer. Hanojske kule.


#include <stdio.h>
void main()
{ int bd;
void prebaci();
printf("Broj diskova = ? "); scanf("%d",&bd);
prebaci(bd,1,3,2);
}
void prebaci(int n, int sa, int na, int preko)
{ if(n) { prebaci(n-1,sa,preko,na);
printf("%d->%d ",sa,na); prebaci(n-1,preko,na,sa);
}

5.7. Implementacija potprograma


Prilikom prevoenja programa kompilator vri planiranje memorijskog prostora koji e biti
dodeljen programu (Storage allocation}. Pored toga to treba da se rezervie memorijski prostor
za smetaj koda programa i podataka koji se obrauju u njemu, za svaki od potprograma koji se
poziva iz programa generie se i jedan aktivacioni slog u koji se smetaju podaci koji se
preuzimaju od glavnog programa, lokalni podaci potprograma i takozvane privremene
promenljive koje generie sam kompilator prilikom generijsanja mainskog koda. Struktura
jednog aktivacionog sloga data je na slici 5.7.
Rezultati koje vraa potprogram
Stvarni argumenti
Opcioni upravljaki linkovi aktivacionog sloga glavnog programa
Opcioni linkovi za pristup podacima u drugim aktivacionim
slogovima
Podaci
o statusu
Lokalni podaci
Privremene promenljive koje generie kompilator
Slika 5.7 Struktura aktivacionog sloga
Za smetaj aktivacionih slogova koristi se jedna od sledee tri strategije: statika, pomou
steka i dinamika. U zavisnosti od toga koja je strategija primenjena zavisi da li e ill ne biti
mogui rekurzivni pozivi potprograma.

Predrag S. Stanimirovi

101

Programski jezici

Kod statikog smetanja aktivacionih slogova, kompilator unapred rezervie fiksan


memorijski prostor iji se sadrzaj obnavlja kod svakog poziva potprograma. To znai da kod
ovakvog smestanja nisu mogui rekurzivni pozivi potprograma jer se kod svakog novog poziva
potprograma gubi informacija o prethodnom pozivu. Ovakva tehnika primenjuje se na primer
kod realizacije kompilatora za programski jezik FORTRAN, pa se u njemu zbog toga ne mogu
koristiti rekurzije.
Kod strategije koja se zasniva na primeni steka za smetaj aktivacionih slogova koristi se
stek u koji se za svaki poziv potprograma smeta jedan aktivacioni slog. Ova tehnika dozvoljava
rekurziju jer se kod svakog novog poziva potprograma generie novi slog i smeta u stek. Na
kraju potprograma slog se izbacuje iz steka. To znai da je u toku izvravanja programa ovaj
stek dinamiki zauzet aktivacionim slogovima onih potprograma koji su trenutno aktivni. Od
veliine memorijskog prostora koji je dodeljen steku zavisi i dubina rekurzivnih poziva
potprograma. Na slici 5.8 prikazana je promena strukture steka u toku izvravanja programa u
kome se poziva rekurzivni potprogram za izraunavanje Fibonaijevih brojeva za i = 4.

102

Slika 5.8. Graf poziva funkcije Fib


Trea, dinamika strategija sastoji se u tome da se za svaki poziv potprograma generie
aktivacioni slog koji se smeta u poseban deo memorije nazvan Heap. U ovom sluaju
aktivacioni slogovi potprograma povezuju se u dinamiku strukturu podataka koja odgovara
stablu poziva potprograma. Oigledno je da i ova tehnika dozvoljava rekurziju.

5.7. Funkcije u c
5.7.1. Poziv i definicija funkcija
Program se sastoji iz jedne ili vie funkcija, pri emu se jedna od njih naziva main(). Kada
programska kontrola naie na ime funkcije, tada se poziva ta funkcija. To znai da se
programska kontrola prenosi na pozvanu funkciju. Kada se funkcija zavri upravljanje se
prenosi u pozivajuu programsku jedinicu. Izvrenje poinje sa main().

Predrag S. Stanimirovi

103

Programski jezici

Funkcije se dele u dve grupe: funkcije koje vraaju vrednost u pozivajuu programsku jedinicu i
funkcije koje ne vraaju vrednost.
Za svaku funckiju moraju se definisati sledei elementi:
- tip vrednosti koju funkcija vraa,
- ime funkcije,
- lista formalnih parametara,
- telo funkcije.
Opta forma definicije funkcija je:
tip ime(lista_parametara)
deklaracije parametara
{ deklaracije lokalnih promenljivih
operator1

operatorN
}
Sve to se nalazi pre prve zagrade '{' naziva se zaglavlje funkcijske definicije, a sve izmeu
zagrada se naziva telo funkcijske definicije.
Tip funkcije zavisi od tipa vrednosti koja se vraa. Takoe, koristi se slubena re void ako
funkcija ne vraa vrednost. Ako je tip rezultata izostavljen podrazumeva se int.
Parametri su po sintaksi identifikatori, i mogu se koristiti u telu funkcije (formalni
parametri). Navoenje formalnih parametara nije obavezno.
Poziv funkcije koja daje rezultat realizuje se izrazom
ime(spisak_stvarnih_parametara)
dok se u sluaju da funkcija ne vraa rezultat dopisuje znak `;', ime ona postaje operator:
ime(spisak_stvarnih_parametara);
Izmeu formalnih i stvarnih parametara mora da se uspostavi odreena korespodencija.
Primer. Jednostavna funkcija bez parametara.
void main() { void poruka(); }
void poruka() { printf("Program pocinje"); printf("Srecan rad!\n"); }
Primer. Jednostavna funkcija sa paremetrom.
void main()
{ int n;
printf("Uneti mali pozitivan ceo broj:");scanf("%d",&n);
poruka1(n);
}
void poruka1(int k)
{ int i;
printf("Poruka \n");
for(i=0; i<k; ++i)
printf("Srecan rad!\n");
}

ANSI C standard dozvoljava da se formalni parametri definiu u zaglavlju funkcije, ali se tada
za svaki parametar posebno navodi tip:
tip ime(tip param1,...,tip paramn)

104

Na primer, funckija poruka1() iz prethodnog primera moe da se deklarie na sledei nain:


void poruka1(int k)
{ int i;
printf("Poruka \n");
for(i=0; i<k; ++i) printf("Srecan rad!\n");
}

Ako tip vrednosti koju vraa neka funkcija nije int, ona se mora deklarisati i u funkciji u kojoj
se ta funkcija poziva.
Sve funkcije u C su ravnopravne, tj. meu njima nema prioriteta. Jedino se funkcija main() prva
izvrava.
Primer. Iscrtavanje drveta na ekranu.
#include<stdio.h> #include<stdlib.h> #define BRLIN 10 void
znak(int , char);
void main()
{ int n;
for(n=1; n<=BRLIN; ++n)
{ znak(BRLIN-n,' '); znak(2*n-1,'^'); putchar('\n'); }
for(n=1; n<=3; ++n)
{ znak(BRLIN-1,' '); znak(3,'-');
putchar('\n'); }
}
}
void znak (int n, char ch)
{ while(n-- >0) putchar(ch); }

5.7.2. Return naredba


Meu operatorima u telu funkcije moe se nalaziti operator return, koji predstavlja operator
povratka u pozivajuu funkciju. Ako se operator return ne navede, funkcija se zavrava
izvrenjem poslednjeg operatora u svom telu.
Naredba return se koristi iz dva razloga:
-Kada se izvri naredba return, kontrola toka programa se vraa u pozivajuu jedinicu.
-Osim toga, ako neki izraz sledi iza kljune rei return, tj. ako se naredba return koristi u obliku,
return izraz ili return(izraz), tada se vrednost izraza izraz vraa u pozivajuu jedinicu. Ova
vrednost mora da bude u skladu sa tipom funkcije u zaglavlju funkcijske definicije.
Naredba return ima jednu od sledee dve forme:
return;

ili
return(izraz); tj return izraz;

Na primer, moe se pisati


return (3);
return (a+b);
Dobra je praksa da se izraz ija se vrednost vraa pie izmeu zagrada.

Predrag S. Stanimirovi

Programski jezici

105

Primer. Izraunati minimum dva cela broja. Funkcija min(x,y) vraa rezultat tipa int, te se
eksplicitno navoenje tipa rezultata moe izostaviti. Osim toga, nije neophodna definicja ove
funckije u pozivajuoj funkciji (u ovom sluaju je to funkcija main()).
void main()
{ int j,k,m;
printf("Unesi dva cela broja:");scanf("%d%d",j,&k);
m=min(j,k);
printf("\n%d je minimum za %d i %d\n\n", m,j,k);
}
min(int x,int y)
{ if (x<y) return(x);
else
return(y);
}

Primer. U sledeem primeru funkcija max radi sa vrednostima tipa double i vraa vrednost tog
tipa. Zbog toga je potrebna deklaracija njenog tipa.
double max(double x, double y)
{ if(x>y) return(x);
else return(y);

5.7.3. Prototip funkcije


U tradicionalnom stilu C jezika, funkcija se moe koristiti pre nego to je definisana.
Definicija funkcije moe da sledi u istom ili u nekom drugom fajlu ili iz biblioteke.
Nepoznavanje broja argumenata odnosno tipa funkcije moe da uzrokuje greke. Ovo se moe
spreiti prototipom funkcije, kojim se eksplicitno ukazuje tip i broj parametara koje funkcija
zahteva i tip rezultujueg izraza. Opta forma prototipa funkcije je sledea:
tip ime (lista_tipova_parametara);

U ovom izrazu je lista_tipova_parametara lista tipova odvojenih zarezima. Kada je funkcija


pozvana, argumenti se konvertuju, ako je mogue, u navedene tipove.
Na primer, sintaksno su ispravni izrazi
void poruka1(int);
int min(int, int);
Takoe, prototip funkcije moe da ukljui i imena parametara, ime se moe obezbediti
dodatna dokumentacija za itaoca.
Na primer, moemo pisati
double max(duble x, double y);

Primeri
Primer. Minimum i maksimum sluajnih brojeva.
void main()
{ int n;
void slucajni(int);
printf("Koliko slucajnih brojeva?"); scanf("%d",&n);
slucajni(n);
}
void slucajni(int k)
{ int i,r,mini,maxi;
int min(int, int), max(int, int), rand(void);

106

r=mini=maxi=rand();
for(i=1;i<k;++i)
{ printf("\n");r=rand();
mini=min(r,mini);maxi=max(r, maxi);
}
printf("Minimum: %7d\n Maximum:%7d\n, mini,maxi);

Primer. Izraunavanje n-tog stepena celog broja a.


void main()
{ int a,n;
long stepen();
scanf("%d%d", &a,&n);
printf("%d\^ %d=%ld\n",a,n,stepen);
}
long stepen(int a, int n)
{ int i;
long an=1;
for(i=1; i<=n; i++) an*=a;
}

return(an);

Primer. Izraunavanje broja kombinacija m-te klase od n elemenata po formuli

n n!
m
!( mnm )!
void main()
{ int m,n;
long bk;
long fakt();
scanf("%d%d",&n,&m);
bk=fakt(n)/fakt(m)/fakt(n-m);
printf("Broj kombinacija je %ld\n",bk);
}
long fakt(int k)
{ int i;
long p=1;
for(i=1; i<=k; i++) p*=i;
return(p);
}

Primer. Izraunati
sin( x ) x

x3
3!

x5
5!

... ( 1) n 1

x 2 n 1
( 2n 1)!

...

Sumiranje prekinuti kada se ispuni uslov a/S<= , gde je zadata tanost, S predstavlja tekuu
vrednost sume, dok a predstavlja vrednost lana koji se dodaje.
void main()
{ double x,eps;
double sinus();
scanf("%lf%lf",&x,&eps);
printf("Sinus je %lf\n", sinus(x,eps));
}
/* apsolutna vrednost */

Predrag S. Stanimirovi

double abs(x)

Programski jezici

107

{ return (x>0)?x:-x; }

/* sinus */
double sinus(double x, double eps)
{ double sum, clan;
int k;
clan=x; k=1;
sum=clan;
while(abs(clan)>eps*abs(sum))
{ k+=1;
clan*=-(x*x)/(2*k*(2*k+1));
return(sum);
}

sum+=clan;

Primer. Svi prosti brojevi do datog prirodnog broja


#include <math.h>
int prost(int k)
{ int i=3;
if(k%2==0) return(0);
if(k==3)
return(1);
while((k%i!=0) && (i<=sqrt(k)))
i+=2;
if(k%i==0) return(0);
else return(1);
}
void main()
{ int i,n;
int prost(int);
printf("Dokle? "); scanf("%d", &n);
for(i=3; i<=n; i++)
if(prost(i)==1)
printf("%d\n",i);
}

Primer. Trocifreni brojevi jednaki sumi faktorijela svojih cifara


#include<stdio.h>
long fakt(int k)
{ long f=1,i=1;
for(;i<=k;i++)
return(f);
}

f*=i;

void main()
{ long i;
unsigned a,b,c;
for(i=100;i<=999;i++)
{ a=i%10;
b=i%100/10;
c=i/100;
if(fakt(a)+fakt(b)+fakt(c)==i) printf("%d\n",i);
}
}

Primer. tampati sve brojeve do 10000 koji su jednaki sumi svojih delioca.
#include<stdio.h>
long sdelioca(long n)
{ long i,s=0;
for(i=1; i<n/2+1;i++)
}
void main(void)
{long i,j,k, sdelioca(long);
for(i=1; i<10000; i++)
}

if(n%i==0)s+=i;

return(s);

if(i== sdelioca(i)) printf("%ld\n",i);

108
Primer. Unositi prirodne brojeve dok se ne unese vrednost <=0. Izracunati NZS unetih brojeva.
/* Bez funkcija */
void main()
{ int k,ns,nzs=0;
scanf("%d", &k);
if(k<=0) printf("%d\n",nzs);
else
{ ns=nzs=k;
scanf("%d", &k);
while(k>0)
{ if(ns>k)nzs=ns;
else nzs=k;
while( ((nzs%ns)!=0) || ((nzs%k)!=0) )
nzs++;
ns=nzs; scanf("%d",&k);
}
printf("nzs =%d\n",nzs);
}
}
/* Pomou funkcija */
void main()
{int k,ns,nzs=0;
scanf("%d", &k);
if(k<=0) printf("%d\n",nzs);
else
{ ns=nzs=k;
scanf("%d", &k);
while(k>0)
{nzs=funnzs(ns,k); ns=nzs; scanf("%d",&k); };
printf("nzs = %d\n",nzs);
} }
int funnzs(int a, int b)
{ int nz;
if(a>b)nz=a;
else nz=b;
while( ((nz % a) !=0) || ((nz % b)!=0) ) nz++;
return(nz);
}

Primer. Dekadni broj iz intervala [0, 3000] prevesti u rimski brojni sistem.
#define hi 'M' #define ps 'D'
#define st 'C' #define pd 'L' #define ds 'X' #define pe 'V'
#define je 'I'
void rim(int);
void main()
{ int n;
printf("Unesi prirodan broj -> "); scanf("%d", &n);
printf("\nOdgovarajuci rimski broj je: "); rim(n);
printf("\n");
}
void rim(int n)
{ while(n>= 1000)
{ printf("%c",hi); n-=1000; }
if(n>=900) {printf("%c",st); printf("%c",hi); n-=900;}
if(n>= 500)
{ printf("%c",ps); n-=500; }
if(n>=400)
{ printf("%c",st); printf("%c",ps); n-=400; }
while(n>=100)
{ printf("%c",st); n-=100; }
if(n>=90)

Predrag S. Stanimirovi

109

Programski jezici

{ printf("%c",ds); printf("%c",st); n-=90; }


if(n>= 50)
{ printf("%c",pd); n-=50; }
if(n>=40)
{ printf("%c",ds); printf("%c",ps); n-=40; }
while(n>= 10)
{ printf("%c",ds); n-=10; }
if(n==9)
{ printf("%c",je);
printf("%c",ds); n-=9; }
if(n>= 5)
{printf("%c",pe); n-=5; }
if(n==4)
{printf("%c",je); printf("%c",pe); n-=4; }
while(n>=1)
{ printf("%c",je); n--; } }

Primer. Najblii prost broj datom prirodnom broju.


#include<stdio.h>
int prost(int n)
{ int i=2,prosti=1;
while ((i<=(n/2))&&(prosti))
return(prosti); }

{prosti=(n%i)!=0; i++;}

void main()
{int m,n,i=1,prosti=1;
int prost(int n);
printf("Broj za koji se racuna najblizi prost broj");
scanf("%d",&m);
if(m==1) printf("najblizi prost broj je 2\n");
else if (prost(m))
printf("najblizi prost broj je%d\n",m);
else
{ while (i<=(m-1)&&(prosti))
{ if (prost(m+i))
{ prosti=0; printf("najblizi prost je%d\n",(m+i));
}
if(prost(m-i))
{prosti=0; printf("najblizi prost je %d\n",(m-i));
}
i++;
}
}
getch();
}

5.7.4. Makroi u jeziku C


Makro je ime kome je pridruena tekstualna definicija. Postoje dve vrste makroa: makro kao
objekat i makro kao funkcija.
Primer. Primeri makroa kao objekata.
#define OPSEG "Greska: Ulazni parametar van opsega"
Definicija makroa moe da se napie u vie redova.
Primer. Definicija makroa u vie redova.
#define PROMPT "Pre stampanja izvestaja \
proverite da li je stampac spreman \
i pritisnite return"
Makro kao funkcija se definie izrazom oblika
#define ime(lista_identifikatora) tekst_zamene

110
Pri definiciji makroa definie se lista njegovih formalnih parametara, dok se prilikom pozivanja
makroa koriste se stvarni parametri.
Primer. Makro kojim se ispituje da li je njegov argument paran broj.
#define NETACNO 0 #define TACNO 1
#define PARAN(broj) broj%2 ? NETACNO : TACNO
void main()
{ int n1=33;
if(PARAN(n1)) printf("%d je paran\n",n1);
else printf("%d je neparan\n",n1);
}

U pozivu makroa paran(a+b) ispituje se parnost broja a+b pomou izraza a+b%2 umesto
izraza (a+b)%2. Da bi se ovakve greke izbegle, potrebno je da se formalni parametri piu
izmeu zagrada. U naem sluaju, pravilnija je sledea definicija makroa PARAN:
#define PARAN(broj) ((broj)%2) ? NETACNO : TACNO

5.7.4. Poziv po vrednosti u C


Funkcija se moe pozvati stavljajui posle njenog imena odgovarajuu listu stvarnih
argumenata izmeu zagrada. Ovi argumenti se moraju slagati brojem i tipom formalnih
parametara u definiciji funkcije. Svaki argument se izraunava, i njegova vrednost se uzima
umesto formalnog parametra. Meutim, vrednost stvarnog parametra ostaje nepromenjena u
pozivajuoj programskoj jedinici.
Primer. Funkcija kojom se izraunava suma prvih n prirodnih brojeva.
#include<stdio.h>
void main() { int n=3, s, sum(int);
printf("%d\n", n); /* 3 */
s=sum(n);
printf("%d\n", n);
printf("%d\n", s); /* 6 */ }

/* 3 */

int sum(int n)
{ int s=0;
for(; n>0; --n) s+=n;
return(s);
}

Primer. Pronai sve brojeve-blizance do zadatog broja n. Dva broja su blizanci ako su prosti i
razlikuju se za 2.
#include<stdio.h>
#include<math.h>
void main()
{ int n,i;
int prost(int);
scanf("%d",&n);
for (i=3;i<=n;i++)
if ((prost(i)) && (prost(i-2))) printf("%d %d\n",i-2,i);
}
int prost(int k)
{ int i=2,prosti=1;
while((i<=sqrt(k)) && (prosti))
{ prosti=((k%i)!=0);
i++; }
return(prosti);
}

Predrag S. Stanimirovi

111

Programski jezici

Kada se koristi poziv po vrednosti, u momentu kada se izraz koristi kao argument funkcije,
pravi se kopija njegove vrednosti, i ona se koristi u funkciji. Pretpostavimo da je v promenljiva,
a f() funkcija. Tada poziv funkcije f(v) ne menja vrednost promenljive v u funkciji f, jer se
koristi kopija vrednosti v u f(). U nekim drugim programskim jezicima (FORTRAN), takav
poziv funkcije moe da promeni vrednost za v. Mehanizam izvren u tom sluaju se naziva
poziv po adresi (call by Reference). Da bi se u C postigao efekat poziva po adresi moraju se
koristiti pointeri promenljivih u listi parametara prilikom definisanja funkcije, kao i adrese
promenljivih koje su argumenti u pozivu funkcije.

Deklaracije pointera i dodeljivanje


Pointeri se koriste za pristup memoriji i manipulaciju adresama. Vrednosti pokazivaa jesu
adrese promenljivih. Do sada smo ve videli upotrebu adresa kao argumenata u naredbi
scanf(). Ako je v promenljiva, tada je &v adresa (lokacija) u memoriji u kojoj je smetena
vrednost za v. Operator & je unarni, ima asocijativnost sdesna na levo, a prioritet kao i ostali
unarni operatori. Pointerske promenljive se mogu deklarisati u programu, a onda koristiti tako
da uzimaju adrese za svoje vrednosti.
Na primer, deklaracija
int *p;
deklarie promenljivu p tipa ``pointer na int''. Rang vrednosti svakog pointera ukljuuje
posebnu adresu 0, definisanu kao NULL u <stdio.h>, kao i skup pozitivnih celih brojeva koji se
interpretiraju kao mainske adrese.
Primer. Pointeru p se vrednosti mogu dodeljivati na sledei nain:.
p=&i;
p=0;
p=NULL;
/* isto to i p=0; */
p=(int*)1507 /* apsolutna adresa u memoriji */ }
U prvom primeru p je ``pointer na i'', odnosno ``sadri adresu od i''. Trei i drugi primer
predstavljaju dodelu specijalne vrednosti 0 pointeru p. U etvrtom primeru kast je nuan da bi
se izbeglo upozorenje kompajlera, a koristi se aktuelna memorijska lokacija kao vrednost
promenljive p. Ovakve naredbe se ne koriste u korisnikim programima, ve samo u
sistemskim.

Adresiranje i operator indirekcije


Neka su date deklaracije
int i, *p;
Tada naredbe
p=&i;

scanf("%d",p); }

uzrokuju da se sledea uneta vrednost smeta u adresu zadatu pointerom p. Ali, s obzirom da p
ukazuje na i, to znai da se vrednost smeta u adresu od i.
Operator indirekcije * je unarni i ima isti prioritet i asocijativnost sa desna ulevo kao i ostali
unarni operatori. Ako je p pointer, tada *p predstavlja vrednost promenljive na koju ukazuje p.
Direktna vrednost za p je memorijska lokacija, dok je *p indirektna vrednost od p, tj. vrednost
memorijske lokacije sadrane u p. U sutini, * je inverzni operator u odnosu na operator &.
Na taj nain, pointeri se mogu koristiti za dodelu vrednosti nekoj promenljivoj. Na primer,
neka su date deklaracije

112
int *p,x;
Tada se izrazima
p=&x; *p=6;
promenljivoj x dodeljuje vrednost 6.
Primer. Uoimo deklaracije
float x,y, *p;
i naredbe
p=&x; y=*p;
Prvom naredbom se adresa od x pridruuje pointeru p, a drugom se vrednost na koju ukazuje p
dodeljuje y. Ove dve naredbe su ekvivalentne sa
y=*&x;
odnosno
y=x.
Primer. Neka je dat sledei kod:
char c1,c2='A',*p,*q;
p=&c1; q=&c2; *p=*q;
Adrese od c1 i c2 pridruuju se promenljivima p i q u prva dva izraza. Poslednja naredba
izjednauje vrednost na koju ukazuje p i vrednost na koju ukazuje q. Ove tri naredbe su
ekvivalentne sa c1=c2.
Primer.
void main()
{ int i=777,*p;
p=&i;
printf("Vrednost za i:%d\n",*p);
printf("Adrese za i: %u ili %p\n",p,p);
}

Formati %u i %p se koriste za prikazivanje vrednosti promenljive p u obliku neoznaenog


decimalnog broja, odnosno heksadecimalnog broja, respektivno.
Primer. Izrazima
int i=777, *p=&i;
je inicijalizovano p, a ne *p. Promenljiva p je tipa ``pointer na int'', i njena poetna vrednost je
&i.
Primer.
#include <stdio.h>
void main()
{ int x=7, y=10;
printf("x=%d &x=%p\n", x,&x);
printf("y=%d &y= %p%u\n",y,&y, &y);
}
void main()
{ int i=5, *pi=&i;

printf("i= %d ili = %d\n", i, *pi); }

Call by reference (poziv po adresi)


Prenos vrednosnih parametara je pogodan kada funkcija vraa jednu izlaznu veliinu bez

Predrag S. Stanimirovi

Programski jezici

113

izmene svojih stvarnih parametara. Meutim, kada je potrebno da funkcija menja vrednosti
svojih stvarnih parametara, ili ukoliko funkcija vraa vie izlaznih veliina, moe se koristiti
druga tehnika predaje parametara: prenos adrese stvarnih parametara.
Adrese promenljivih se mogu koristiti kao argumenti funkcija u cilju izmene zapamenih
vrednosti promenljivih u pozivajuoj programskoj jedinici. Tada se pointeri koriste u listi
parametara pri definisanju funkcije. Kada se funkcija poziva, moraju se koristiti adrese
promenljivih kao argumenti.
Primer. Date su vrednosti za dve celobrojne promenljive i i j. Urediti ih u poredak i<= j.
void main()
{ int i=7,j=3; void order(int*, int*);
printf("%d %d\n",i,j);
/* 7 3 */
order(&i,&j);
printf("%d %d\n",i,j);
/* 3 7 */
}
void order(p,q)
{ int pom;
if(*p>*q)
}

int *p,*q;
{ pom=*p; *p=*q; *q=pom; }

Ako je vrednost na koju ukazuje p vea od vrednosti na koju ukazuje q, tada se vri izmena te
dve vrednosti.
Vrednosti promenljivih i, j se mogu zadavati pomou tastature. To je uraeno u sledeem
programu.
#include <stdio.h>
void upis(int *x, int *y); void sredi(int *x, int *y);
void ispis(int x,int y);
void main()
{ int x,y;
upis(&x,&y); sredi(&x,&y); ispis(x,y); }
void upis(int *x, int *y)
{ printf("Unesi dva cela broja"); scanf("%d%d",x,y);

void sredi(int *x, int *y)


{ int pom;
if(*x>*y)
{ pom=*x; *x=*y; *y=pom; }
}
void ispis(int x, int y)
{ printf("\n To su brojevi %d %d\n",x,y); }

Tehnika predaje parametara po adresi (Call by reference) se sastoji iz sledeih baznih pravila:
1. deklarisati formalne parametre funkcije kao pointere;
2. koristiti operatore indirekcije u telu funkcije;
3. pri pozivu funkcije koristiti adrese kao argumente.
Primer. Neka su ulazne veliine dva cela broja m i n. Izlazne veliine su
n

p i , q i3
im

im

114
Umesto da se uvedu dve funkcije (jedna za p a druga za q), moe se napisati jedna funkcija u
kojoj se izraunava i jedna i druga izlazna veliina.
void main()
{ int m,n,k,l,p,q,r;
void kvadrat_kub();
kvadrat_kub(2,4,&p,&q);
printf("p=%d q=%d\n",p,q);
scanf("%d%d%d%d",&m,&n,&k,&l);
kvadrat_kub(m,n,&p,&q);
printf("p=%d q=%d\n",p,q);
kvadrat_kub(m-k,n+l,&p,&r);
printf("p=%d q=%d\n",p,r); }
void kvadrat_kub(int m,int n,int *kv,int *kub)
{ int i;
*kv=*kub=0;
for(i=m;i<=n;i++)
{ *kv+=i*i;
*kub+=i*i*i; }
}

Primer. Minimum i maksimum dva cela broja.


void minimax(int aa, int bb, int *min,int *max)
{ if(aa>bb)
{ *min=bb; *max=aa; }
else { *min=aa; *max=bb; } }
main()
{ int a,b, mn, mx;
scanf("%d%d", &a,&b);
minimax(a,b,&mn, &mx);
printf("Minimum = %d maksimum=%d\n",mn,mx);
}

Primer. Urediti tri broja x, y, z u neopadajui poredak x <= y <= z.


void razmeni(int *a, int *b)
{ int pom;
pom=*a; *a=*b; *b=pom;

void main()
{ int x,y,z;
void razmeni(int*, int*);
scanf("%d%d%d", &x,&y,&z);
if(x>y) razmeni(&x,&y);
if(x>z) razmeni(&x,&z);
if(y>z) razmeni(&y,&z);
printf("x= %d y= %d z= %d\n",x,y,z);
}

Primer. Napisati proceduru kojom se


zajedniki delilac dva prirodna broja.

izraunava najvei zajedniki sadralac i najvei

#include<stdio.h>
void unos(int *,int *); void nzds(int,int, int *,int *);
void main()
{ int x,y, nzd,nzs;
unos(&x, &y);
nzds(x,y,&nzd,&nzs);
printf("Nzd unetih brojeva = %d a nzs= %d\n",nzd,nzs);
}
void unos(int *a, int *b)
{ printf("\nZadati dva cela broja: "); scanf("%d%d",a,b);
void nzds(int a, int b, int *nd, int *ns)
{ if(a>b) *ns=a; else *ns=b;
while(*ns%a !=0 || *ns%b !=0)(*ns)++;

Predrag S. Stanimirovi

while(a!=b)
*nd=a;

Programski jezici

115

{ if(a>b)a-=b;

else if(b>a)b-=a;

Primer. Sa tastature se unosi jedan ceo broj, a za njim neodreen broj celih brojeva. Napisati
proceduru kojom se izraunava minimum i maksimum unetih brojeva.
#include<stdio.h>
void minmax(int *,int*);
void main()
{ int mn,mx; minmax(&mn,&mx);
printf("Minimum je %d a maksimum
}

%d\n",mn,mx);

void minmax(int *min, int *max)


{ int n;
*min=*max=scanf("%d",&n);
while(scanf("%d",&n)==1)
if(n<*min)*min=n;
else if(n>*max)*max=n;
}

Primer. Napisati funkciju za izraunavanje determinante kvadratnog trinoma ax 2+bx+c.


Napisati proceduru kojom se izraavaju sledee aktivnosti:
a) Odreuje da li su reenja realna i razliita, realna i jednaka ili konjugovano-kompleksna;
b) u sluaju da su reenja realna izraunava njihove vrednosti, a u sluaju da su reenja
konjugovano-kompleksna izraunava realni i imaginarni deo tih reenja.
Napisati proceduru za tampanje odgovarajuih izvetaja. U glavnom programu unositi
koeficijente kvadratnih jednaina u beskonanom ciklusu i prikazivati odgovarajue rezultate
koristei proceduru za prikazivanje izvetaja.
#include<stdio.h>
#include<math.h>
float diskriminanta(float, float, float);
void solution(float, float, float, float *, float *,int *); void
rezultati(float, float, float, float *,float *,int *);
void main()
{ float a,b,c, x1,x2;
int tip;
while(1)
{ printf("Unesi koeficijente -> "); scanf("%f%f%f", &a,&b,&c);
rezultati(a,b,c,&x1, &x2, &tip);
} }
float diskriminanta(float a, float b, float c)
{ return(b*b-4.0*a*c); }
void solution(float a,float b,float c, float *x,float *y,int *t)
{ float d;
d=diskriminanta(a,b,c);
if(d>0){*t=0; *x=(-b+sqrt(d))/(2*a);*y=(-b-sqrt(d))/(2*a); }
else if(d==0) { *t=1; *x=*y=-b/(2*a);}
else { *t=2; *x=-b/(2*a); *y=sqrt(-d)/(2*a); }
}
void rezultati(float a,float b,float c, float *x, float *y, int *t)
{solution(a,b,c,x,y,t);
if(*t==0)
{printf("Resenja su realna i razlicita\n");
printf("x1=%f x2=%f\n",*x,*y);}

116
else if(*t==1)
{printf("Resenja su realna i jednaka\n");
printf("x1=x2=%f\n",*x);}
else
{ printf("Resenja su konjugovano-kompleksna\n");
printf("x1 =%f + i* %f\n",*x,*y);
printf("x2 = %f -i* %f\n",*x,*y);
}
}

Primer. Napisati proceduru za deljenje dva cela broja na proizvoljan broj decimala. Deljenik,
delilac i broj decimala zadati u posebnoj proceduri.
#include<stdio.h>
#include<conio.h> void unos(int *, int*, int *); void
deljenje(int, int, int);
main()
{ int n,i,bdec, brojilac, imenilac;
clrscr(); printf("Koliko puta? "); scanf("%d", &n);
for(i=1; i<=n; i++)
{unos(&brojilac, &imenilac, &bdec);
deljenje(brojilac, imenilac, bdec);
}
}
void unos(int *br, int *im, int *bd)
{ printf("Brojilac = ?"); scanf("%d",br);
printf("Imenilac = ? "); scanf("%d",im);
printf("Broj decimala = ? "); scanf("%d",bd);
}
void deljenje(int br, int im, int bd)
{ int i;
if(br*im<0) printf("-");
br=br<0?-br:br; im=im<0?-im:im;
printf("\n%d.",br/im);
br %= im;
for(i=1; i<=bd; i++)
{ br *=10; printf("%d",br/im); br %=im; }
printf("\n");
}

Primer. a) Napisati proceduru za unoenje brojioca i imenioca jednog razlomka. U toj


proceduri, po potrebi, vrednost imenioca promeniti tako da bude pozitivan.
b) Napisati rekurzivnu funkciju za izraunavanje najveeg zajednikog delioca dva prirodna
broja.
c) Napisati funkciju za izraunavanje najveeg zajednikog sadraoca dva prirodna broja.
d) Napisati proceduru za kraenje brojioca i imenioca zadatim prirodnim brojem.
e) Napisati proceduru za sabiranje dva razlomka. Pri sabiranju razlomaka koristiti najvei
zajedniki sadralac za imenioce jednog i drugog razlomka. Zatim skratiti brojilac i imenilac
izraunatog razlomka najveim zajednikim deliocem za brojilac i imenilac.
f) U glavnom programu uitati brojilac i imenilac za n razlomaka i izraunati zbir svih
razlomaka.
#include<stdio.h>
#include<math.h>
#include<conio.h>
/* razlomci.c */
int nzd(int, int); int nzs(int, int); void unos(int *, int *); void
sabiranje(int, int,int, int, int *, int *);
void kracenje(int *, int*, int); main()

Predrag S. Stanimirovi

117

Programski jezici

{ int i,n, broj,imen, brojilac, imenilac, brez, irez;


clrscr();
printf("Koliko razlomaka sabirate? ");
scanf("%d",
&n);
for(i=1; i<=n; i++)
{unos(&brojilac, &imenilac);
if(i==1){ brez=brojilac; irez=imenilac;
}
else
{broj=brez; imen=irez;
sabiranje(brojilac,imenilac,broj,imen, &brez,&irez);
}
printf("%d/%d\n", brez, irez);
}
void unos(int *br, int *im)
{ printf("Brojilac -> " ); scanf("%d",br); printf("Imenilac -> " );
scanf("%d",im);
if(*im<0) {*br=-*br; *im=-(*im); }
}
int nzd(int br, int im)
{ if(br == im) return(br);
else if(br>im)return(nzd(br-im,im));
else return(nzd(br,im-br));
}
int nzs(int br, int im)
{ int ns;
if(br>im) ns=br; else ns=im;
while((ns %br !=0) || (ns %im != 0))ns++;
return(ns);
}
void kracenje(int *br, int *im, int k) { *br /=k; *im /=k; }
void sabiranje(int pb,int pi,int db,int di,int *rb,int *ri)
{ int ns, nd;
ns=nzs(pi,di); *ri=ns; *rb=pb*ns/pi+db*ns/di;
nd=nzd(*rb,
*ri);
kracenje(rb, ri, nd);
}

Primer. Napisati proceduru za uitavanje i ispis kompleksnih brojeva kao i procedure za


izvoenje osnovnih aritmetikih operacija sa kompleksnim brojevima. Napisati test program.
#include<stdio.h>
#include<math.h>
void unos(float *,float *, float *, float *);
void saberi(float, float, float, float, float *, float *);
void oduzmi(float, float, float, float, float *, float *);
void mnozi(float, float, float, float, float *, float *);
void deli(float, float, float, float, float *, float *);
void ispis(float, float);
void main()
{ float x1,y1,x2,y2,re,im;
unos(&x1,&y1,&x2,&y2);
saberi(x1,y1,x2,y2, &re,&im); printf("\nNjihov zbir je: ");
ispis(re,im); printf("\n");
oduzmi(x1,y1,x2,y2, &re,&im);
printf("\nNjihova razlika je: "); ispis(re,im); printf("\n");
mnozi(x1,y1,x2,y2,&re,&im);
printf("\nNjihov proizvod je: "); ispis(re,im); printf("\n");
deli(x1,y1,x2,y2,&re,&im);

118
printf("\nNjihov kolicnik je: "); ispis(re,im);
printf("\n");

}
void unos(float *re1, float *im1, float *re2, float *im2)
{ printf("Prvi kompleksni broj? "); scanf("%f%f", re1,im1);
printf("Drugi kompleksni broj? "); scanf("%f%f", re2,im2);
}
void saberi(float re1,float im1,float re2,float im2,
float *rez, float *imz)
{*rez=re1+re2; *imz=im1+im2; }
void oduzmi(float re1, float im1, float re2, float im2,
float *rez, float *imz)
{*rez=re1-re2; *imz=im1-im2; }
void mnozi(float re1, float im1, float re2, float im2,
float *rez, float *imz)
{*rez=re1*re2-im1*im2; *imz=re1*im2+re2*im1; }
void deli(float re1, float im1, float re2, float im2,
float *rez, float *imz)
{*rez=(re1*re2+im1*im2)/(re2*re2+im2*im2);
*imz=(-re1*im2+re2*im1)/(re2*re2+im2*im2);
}
void ispis(float x, float y)
{ printf("\n %f",x);
if(y<0) printf("-"); else printf("+");
printf("i*%f\n",fabs(y));
}

5.7.5. Scope rules (domen vaenja)


Komponovana naredba (blok) je serija deklaracija iza koje sledi serija naredbi izmeu
zagrada { i }. Funkcije se mogu tretirati kao imenovani blokovi sa parametrima i dozvoljenom
return naredbom.
Bazino pravilo domena vaenja je da su identifikatori dostupni samo u bloku u kome su
deklarisani. Jedno ime u spoljaanjem bloku vai dok se ne redefinie u unutranjem. Tada je
ime u spoljanjem bloku skriveno (ili maskirano) tim imenom unutranjeg bloka.
Primer.
/* spoljasnji blok */
int a=2;
printf("%d\n",a) /* 2 */
/* unutranji blok */
int a=3;
print("%d\n",a);
/* 3 */
printf("%d\n",a);
/*2 */

5.7.6. Memorijske klase


Svaka promenljiva i funkcija u C ima dva atributa: tip i memorijsku klasu. Memorijske klase
su definisane kljunim reima
auto extern static register
Promenljive deklarisane unutar tela funkcije jesu, by default, memorijske klase automatic.
promenljive ove klase deklariu se eksplicitno kljunom reju auto.
Primer. Deklaracija
char c;
int i,j,k;
je ekvivalentna sa

Predrag S. Stanimirovi

auto char c;

auto int i,j,k;

119

Programski jezici

Kada je blok unet, sistem rezervie adekvatnu memoriju za promenljive klase auto. Ove
promenljive se tretiraju kao ``lokalne'' za blok. Kada se izae iz bloka sistem vie ne pamti
vrednosti ovih promenljivih.
Sve funkcije i promenljive deklarisane izvan tela funkcija imaju memorijsku klasu external,
tj. one su globalne za sve funkcije deklarisane posle njih.
Primer.
int a=7; main() { void f(void);
void g(void);
{ printf("%d\n",a);
f();
printf("%d\n",a);
g(); printf("%d\n",a);
}
void f()
{ printf("%d\n",a);
a++;
printf("%d\n",a);
}
void g()
{ int a=10;
printf("%d\n",a);
}

/* 7 */
/* 8 */
/* 8 */

/*7 */
/* 8 */

/* 10 */

Promenljiva je globalna na nivou modula ako je deklarisana van svih funkcija u modulu.
memorijski prostor se trajno dodeljuje, a memorijska klasa te promenljive je extern. Globalnost
je odreena mestom deklaracije. Globalna promenljiva moe da bude maskirana lokalnom
promenljivom istog imena.
Da bi globalna promenljiva bila dostupna iz drugih modula, ona mora da se u tim modulima
definie pomou kljune rei extern.
Primer. Izrazom oblika
extern int a;

promenljiva a se ne deklarie, ve definie, tj. ne dodeljuje se memorijski prostor, nego se C


prevodilac informie o tipu promenljive. Eksterna promenljiva se moe inicijalizovati
iskljuivo na mestu svoje deklaracije.
Primer. Dat je sledei program koji se nalazi u dve datoteke (dva modula). U datoteci modul1.c
se nalazi program
#include "modul2.c" char c = 'w';
void main()
{ int f(void);
printf("Pre funkcije f : c =%c\n", c);
/* c=w */
f(); printf("Posle funkcije f : c = %c\n", c); /* c=a */
g(); printf("Posle funkcije g : c = %c\n", c); /* c=a */
}

Promenljiva c je globalna, pa se njoj moe pristupiti iz drugih modula pomou kljune rei
extern. Neka je datoteka modul2.c sledeeg sadraja

120
extern char c;
f() { c = 'a'; }
g() { char c='b'; }
Dobijaju se sledei rezultati:
Pre funkcije f: c=w
Posle funkcije f: c=a
Posle funkcije g: c=a

Funkcija f menja vrednost eksterne promenljive c, a to mogu i druge funkcije iz ove datoteke
(modula).
Ako datoteka modul2.c ima sadraj
f() { extern char c; c='a'; }
takoe se menja vrednost promenljive c. Meutim, to nebi mogle da uine druge funkcije iz
datoteke modul2.c.
Statike promenljive se koriste u dva sluaja. U prvom sluaju, omoguava lokalnoj
promenljivoj da zadri vrednost kada se zavri blok u kome je deklarisana. Druga primena je u
vezi sa globalnom deklaracijom, i omoguuje mehanizam privatnosti globalnih promenljivih.
Primer. (1.primena)
int fun1()
{ static int x=0; int y=0;
printf("static=%d auto = %d\n",x,y);
}
void main()
{ int i; for(i=0; i<3; ++i)

++x,++y;

fun1(); }

Izlaz je:
static=0 auto=0
static=1 auto=0
static=2 auto=0
U vezi sa drugom primenom, koristi se injenica da su statike promenljive lokalne u okviru
modula, jer im mogu pristupiti samo funkcije iz istog modula.
Pored promenljivih, i funkcije mogu da se definiu kao extern ili static. Memorijska klasa
extern se uzima po definiciji. Statike funkcije su dostupne samo funkcijama iz istog modula.
Korienje registarskih promenljivih omoguava programeru da utie na efikasnost
izvrenja programa. Ako funkcija esto koristi neku promenljivu, moe se zahtevati da se njena
vrednost memorie u brzim registrima centralne procesorske jedinice (CPU), uvek kada se
funkcija izvrava. Registarske promenljive su najee promenljive za kontrolu petlje i lokalne
promenljive u funkcijama. Promenljiva se moe uiniti registarskom pomou kljune rei
register.
Primer.
register char c;
register int i;

Predrag S. Stanimirovi

121

Programski jezici

Promenljiva deklarisana kao registarska takoe je i automatska. Ako nema slobodnih registara
u CPU C prevodilac ne prepoznaje greku.
Primer. Promenljiva i deklarie se kao registarska neposredno pre upotrebe u for petlji.
register int i; for(i=0;i<5;++i)

Zavretak bloka u kome je deklarisana registarska promenljiva oslobaa registar.

5.8. Potprogrami u paketu MATHEMATICA


Potprogrami u MATHEMATICA poseduju osnovne osobine kao i u veini drugih programskih
jezika. Za svaki potprogram su karakteristina sledea etiri elementa:
ime potprograma,
lista imena argumenata
telo potprograma,
okruenje u kome je potprogram definisan.

5.8.1. Lokalne promenljive


U programiranju je esto potrebno koristiti promenljive koje se koriste samo za vreme
izvravanja potprograma ili nekog izraza. Takve promenljive ne treba da postoje izvan takvih
struktura, pa se zato nazivaju jo i lokalne promenljive. Stukture koje omoguavaju korienje
raznih vrsta lokalnih promenljivih u MATHEMATICA su Module, With i Block.

5.8.2. Moduli i lokalne promenljive


Lokalne promenljive u MATHEMATICA se mogu koristiti u modulima. U modulu se zadaje
lista lokalnih simbola, koji postoje samo u modulu, i ne utiu na simbole istog imena van tog
modula. Modul je posebno oznaeni deo programa koji se definie naredbom
Module[{promenljiva1, promenljiva2,...}, program ]
ili

Module[{promenljiva=vrednost,...}, program ]
Module[{x, y, ...}, procedura],
Module[{x=x0, y=y0,...}, procedura]

modul sa lokalnim promenljivim x, y, ...


postavljanje poetnih vrednosti za x, y, ...

Pri definisanju poetnih vrednosti za lokalne promenljive x, y, ... izrazi x0, y0, ... se raunaju
pre izvrenja procedure.
Svakoj lokalnoj promenljivoj u modulu se dodeljuje jedinstveno ime oblika ime$broj, gde se
broj, pri svakom narednom dodeljivanju poveava za 1. Lokalnoj promenljivoj u modulu se u
toku rada nikada nee dva puta dodeliti ista vrednost.
Primer.
nula := n Pi
nula
np
nula - nula
0
nula := Module n , n Pi
nula
n$30 p
nula - nula

@
8<D

122

@
8<D@D@ D
@
D@
@
8

<
@
D
D
<
8<
D
D 8@
@
D
:8<
:>
8<
: >
8<
>

n$31 p - n$32 p
nula := Module
n$9 p
n$10 p - n$11 p

n , n * Pi ; Print nula ; Print nula - nula

Primer. Pomou modula moemo definisati funkcije.


s n_ := Module
Table

h = 2 * Pi n ,

i * h, N Sin i * h

i, 0, n

Promenljiva h se definie odmah na poetku, tako da s[4] daje vrednost:


s 4

0, 0. ,

, 1. ,

p,

0. ,

3p
, - 1. , 2 p , 0.
2

Promenljiva h je lokalna i ne vidi se izvan modula. Izraz ?h potvruje da ne postoje definicije


vezane za ovaj simbol.
Izlazak iz funkcije sa vraanjem vrednosti se zadaje naredbom
Return[izraz].

@
D@
8<
@
@
D
D
@
8
<
D
D
@
D
8
@
D<
@D
@
8<
@
@
D
D
@
8
<
D
D
@
D
8
@D<

Ova naredba vraa vrednost izraza kao rezultat tekue funkcije i zatim se kontrola programa
prenosi u pozivajuu programsku jedinicu.
f k_ :=

Module

m ,

m = 4 - k;

If m < 0, Return m je negativno

Table a, i, 1, m

f 1
a, a, a
f 7
- 3 je negativno

Posmatrajmo funkciju
g m_, n_ :=
Module

k ,

k = m + n;

If k <= 0, Return brojevi nisu pozitivni

Table 1, i, 1, k

Za g[2,3] dobijamo rezultat {1,1,1,1,1}, ali za g[-2,-3] poruku da brojevi nisu pozitivni:
g 2, 3

1, 1, 1, 1, 1
g - 2, - 3
brojevi nisu pozitivni

Naredba Return se moe korisiti i za izlazak iz ciklusa.

Predrag S. Stanimirovi

123

@
@
D
@
@
D
D
8
<
D

Do Print i ; If i == 5, Return izlaz

Programski jezici

i, 1, 6

1
2
3
4
5
izlaz

5.8.3. Blokovi i lokalne promenljive


U modulima se imena promenljivih se tretiraju kao lokalna. Meutim, pnekad je potrebno da
promenljiva bude globalna, ali da dobije lokalnu vrednost. U programu MATHEMATICA
gloabalne i lokalne promenljive postoje unutar strukture Block.
Block[{x, y, ...}, procedura]}
Block[{x=x0, y=y0, ...}, procedura]

@
D
@
D
@
8
<D

blok sa lokalnim rednostima simbola x, y, ...


postavljanje po~etnih vrednosti za x,y, ...

Sin n Pi
Sin n p

Block n = 1 2 , %

(*U bloku je n dobila konkretnu vrednost i izraunava se Sin[Pi/2]*)


Out[8]=1
n

(*Van bloka, n i dalje nema vrednost *)

@
D
@
D@
@
8

<
@
D
D
D
@
D

Primer. Posmatrajmo sledeu sekvencu izraza:


f n_ := Sin n * Pi ;
Block

n = 1 2 , Print f n

Print n ;
1
n
Null3

Unutar bloka n dobija konkretnu vrednost (n=1/2), i izraunava se sin(n/2)=sin(/2)=1. Van


bloka, n i dalje ne poseduje vrednost.

6.1.3. Razlika izmeu modula i blokova


Promenljiva x u modulu Module[{x}, procedura] predstavlja jedinstven simbol koji dobija
razliita imena svaki put kada se modul koristi, i nezavisan je od globalnog simbola x ako on
postoji. Nasuprot tome, promenljiva x u bloku Block[{x}, procedura] je i dalje globalni simbol.
Blok samo ini njegovu vrednost lokalnom. Originalna vrednost simbola x se vraa nakon
izlaska iz bloka.

@
8<@
D
D
@
8<@
D
D

t = 42
42
Module t , Print t
t$33
Block t , Print t
t

124

t
42

U modulu lokalna promenljiva t dobija jedinstveno ime t$33, a u bloku njeno ime ostaje
globalno dok vrednost postaje lokalna. Meutim, im se iz bloka kao rezultat vrati izraz koji
sadri promenljivu t, ona ponovo dobija svoju globalnu vrednost 42 i rezultujui izraz se
ponovo izraunava. Da bi se prikazala vrednost promenljive t akva je bila u bloku, koristi se
funkcija Print[t].

@
D@
D
@
D
@
D@
@
8
<
D
D
@
D@
@
8
<
D
D
@
D@
@
8
<
@
D
D
D
@
D

f x_ := Sin 42 x - 2
f a
- 2 + Sin 42 a
Block t = 3 , f a
- 2 + Sin 42 a
Block a = 3 , f a
- 2 + Sin 126
Block a , Print f a
- 2 + Sin 42 a

6.1.4. Lokalne promenljive u With


U modulima se definiu lokalne promenljive, kojima se u okviru modula mogu proizvoljno
dodeljivati razne vrednosti. Meutim, u praksi su esto potrebne lokalne konstante kojima se
samo jednom dodeljuje vrednost. Struktura With slu`i za definisanje konstanti.

@
D
@
8
<
D
@
DL
H

With[{x=x0, y=y0, ...}, procedura]


W x_ := With
W a
2 + - 1 +a 2
t
42

lokalne konstante x,y,... u proceduri procedura.

t = x - 1 , 2 + t^2

Naredba With[{x=x0,, ... }, procedura] zamenjuje sve pojave simbola x, ... u procedura
izrazima x0, ... a zatim je izvrava. Prednost upotrebe strukture With umesto modula je itljivost
programa. Za razliku od modula, ve iz liste zaglavlja strukture With jasno se vidi koji su
simboli konstante i koju vrednost imaju u proceduri.
Konstrukcije With mogu biti ugnjedene jedna u drugoj. U sluaju da se vie struktura With
koje definiu iste konstante, nalaze jedna unutar druge, u proceduri vae vrednosti konstanti iz
unutranje strukture. Dakle, lokalne promenljive iz unutranje strukture imaju prioritet nad
onima iz spoljanje (preklapaju spoljanje).
Primer.

@
8<@
8<D
D
@
8<@
8<D
D
@
8<@
8<D
D

With t = 5 , With t = 7 , t^2


49
Module t = 8 , With t = 9 , t^2
81
With t = a , With n = b , t + n
a+b

Primer. injenica da vrednosti konstanti iz unutranje strukture preklapaju vrednosti iz


spoljanje strukture ilustruje se sledeim primerima. Vrednost izraza

Predrag S. Stanimirovi

Programski jezici

125

With[{t=0}, With[{t=1},t] ]
jednaka je 1. U izrazu
With[{t=0}, (With[{t=1},Print[t+1]]; Print[t])

@
8<
H@
8<@D
D@
D
L
D
@
D
@
8
<
D
@
DL
H

prvo se tampa 2, a zatim 0:


With
2
0

t=0 ,

With

t = 1 , Print t + 1

; Print t

Primer. Posmatrajmo sledee izraze:


t = 1; f x_ := With
f a
2+ 1 +a 2

t = x + 1 , 2 + t^2

Globalna vrednost promenljive t jednaka je 1. U funkciji f[x_], x je lokalna promenljiva.


Vrednost funkcije f[a] jednaka je 2+(1+a)^2, ali je globalna vrednost za t ostala 1.
t
1

@
8 <D

Primer. Poetne vrednosti u strukturi With se izra~unavaju pre nego to se pone izvravati
sekvenca naredbi u njenom telu. Zbog toga dobijamo slede}e:
t = 5; With
18

t =t + 1 , 3* t

Primer 5. Konstanta iz spoljanje strukture se vidi u unutranjoj strukturi, iako nije tamo
definisana. Tako je vrednost izraza
With[{t=a}, With[{u=b},t+u]

jednaka a+b.

6. MODULI

Kod projektovanja sloenih programa kompleksan problem reava se tako to se rastavlja na


potprograme koji se mogu razvijati odvojeno kao nezavisne programske celine. Ovakav pristup
reavanju problema zasniva se na dekompoziciji i top-down projektovanju. Koncept
potprograma je takoe prvi nivo apstrakcije, jer se jednom definisani potprogrami mogu
koristiti u reavanju razliitih problema. Razvoj ovog koncepta doveo je do pojma modula u
smislu kako je on postavljen u programskom jezicima Pascal, Modula ill Ada. Dva osnovna
principa modularnog programiranja mogu se opisati na sledei nain:

126

Modularno programiranje odgovara konceptu botom-up projektovanja, kada se polazi od


gotovih, unapred definisanih modula i oni medusobno povezuju u sloenije celine cime se
konacno reava postavljeni problem. lako je ovakav pristup projektovanju na prvi pogled
jednostavan i prihvatljiv on ima smisla samo u onom sluaju kada definisani moduli odgovaraju
okruenju u kome se koriste. U suprotnom moe se dogoditi da se u program unose greke koje
nas polako udaljavaju od postavljenih zahteva. U principu, projektovanje odozgo prema dole je
pouzdaniji put ka reenju problema. Moe se rei da se dekompozicija i apstrakcija nalaze u
meusobnom odnosu u kakvom su projektovanje odozgo prema dole i projektovanje odozdo
prema gore.
Moduli su osnovno sredstvo apstrakcije u programskim jezicima. Mogu se definisati kao
strukture koje obuhvataju strukture podataka i potprograme (procedure i funkcije) kojima se nad
podacima mogu izvravati odreeni algoritmi. Razmotriemo ovaj koncept na primeru unit-a u
Pascal-u.

6.1. Moduli u pascal-u (unit)


U Pascal-u za definisanje modula koristi se slubena re u n i t . Moduli omoguavaju pravljenje
biblioteka funkcija i procedura ili za deljenje programa na delove koji predstavljaju zasebne
celine.
U n i t se sastoji od sledeih delova:
Zaglavlje - Ime modula, koje slui za referenciranje na odreeni modul.
Interface- Deo u kome se opisuje interfejs sa drugim modulima, ono to se preuzima od
drugih modula i ono to se nudi drugim modulima. Tu se nalaze opisi konstanti, tipova
podataka, promenljivih, funkcija i procedura koje modul nudi. To je vidljivi deo modula koji
dokumentuje njegov sadraj. U ovom delu modula daju se samo zaglavlja funkcija i procedura.
Odnosno, interfejs modula prua informacije i svim elementima funkcija i procedure potrebnim
za njihovo korisenje.
Implementation - Deo u kome se daje realizacija koda funkcija i procedura koje modul
sadri.
Telo modula (obuhvaeno zagradama begi n i end) - Deo u kome se daje kod za
inicijalizaciju modula. Pa novom konceptu moe da postoji i deo kojim se zavrava korisenje
modula.
U delu za inicijalizaciju modula definie se u sutini blok kome pripadaju sve funkcije i
procedure unit-a, odnosno okruenje za ove potprograme. Tu se takoe definiu konstante, tipovi,
promenljive, funkcije i potprogrami koji su privatni deo modula. Svi elementi definisani ovde su
dostupni samo unutar modula i ne mogu se koristiti spolja. Primer koji sledi ilustruje koncept
modula u Pascal-u.
Primer. Primer modula u Pascal-u
unit Demo;
Interface

Predrag S. Stanimirovi

127

Programski jezici

uses
Crt, Graph;
type
DemoType = array[1..12] of String[70];
const
DemoStart = 0;
DemoEnd = 70;
Procedure A(x,y:Integer);
function C(a,b: String) : Integer;
Implementation
Uses Dos;
var L: Integer;
procedure A(x,y: Integer);
begin
GoToXY(x,y);
Write('Ova procedura je deo modula Demo);
end;
function C(a,b:String) : Integer;
var x: Integer;
begin
x := Length(a) + Length(b);
C :=x;
end;
begin
WriteLn('Ovaj tekst se Stampa kada se Demo navede u uses');
end.

U programskom jeziku Delphi preuzeta je struktura modula iz Pascal-a s tim da je pridodat


jo i zavrni deo modula koji nosi naziv f i n a l ization. U ovom delu modula daje se kd kojim
se zavrava korienje modula. To je obino deo programa u kome se vri oslobaanje memorije
i drugih resursa raunarskog sistema.

7. STRINGOVI

7.1. Stringovi u C
7.1.1. Inicijalizacija i obrada stringova

128
U jeziku C, string je jednodimenzionalni niz elemenata tipa char koji se zavrava
karakterom \0. Karakteru u stringu moe da se pristupi ili kao elementu niza ili pomou pointera
na char. Svaki string se zavrava karakterom '\0'. String je u stvari pointer na char. String
konstanta je proizvoljan niz znakova izmeu navodnika. Svi znaci zahvaeni znacima navoda,
kao i null znak '\0' smetaju se u uzastopnim memorijskim lokacijama.
Na primer, string s="ABC" moe da se zapamti u memoriju kao sekvenca od 4 karaktera
s[0]='A', s[1]='B', s[2]='C', s[3]='\0', od kojih je poslednji null karakter '\0'. Bez poslednjeg
karaktera '\0' niz nije kompletiran, te predstavlja samo niz karaktera.
Primer.
#define MAXREC 100
void main()
{ char w[MAXREC];

w[0]='A'; w[1]='B'; w[2]='C'; w[3]='\0';


}

Sada je jasno da su 'a' i "a" dva razliita objekta. String "a" je niz koji sadri dva karaktera: 'a' i
'\0'.
Stringovi su nizovi karaktera, pa se mogu inicijalizovati kao i nizovi brojeva. Osim toga,
praktinije je da se string inicijalizuje konstantnom vrednou tipa string umesto ``znak po
znak''.
Primer. Moemo pisati
char s[ ]="abc"; umesto char s[ ]={'a', 'b', 'c', '\0'};
Takoe, moe se inicijalizovati pointer na char kao konstantni string:
char *p="abc";
Efekat ove naredbe da se string "abc" smeta u memoriju, a pointer p se inicijalizuje baznom
adresom tog stringa.
U sluaju kada se niz znakova zadate duine inicijalizuje string konstantom, tada se
neiskorieni elementi niza inicijalizuju null karakterom '\0'.
Primer. Suma ASCII kodova karaktera koji su sadrani u zadatom stringu, kao i ispisivanje tog
stringa sdesna ulevo.
#include <stdio.h>
#define MAX 50
void main()
{ char c, line[MAX];
int i, sum=0;
printf("\n Unesite vase ime u jednom redu");
for (i=0; (c=getchar()) != '\n'; ++i) line[i]=c;
line[i]='\0';
printf("\n%s%s%s\n", "Zdravo", line, ".");
printf("Vase ime unazad je : ");
while (i>0) putchar(line[--i]); putchar('.');
for(i=0; line[i]!='\0'; ++i) sum+=line[i];
printf("\n%s%d%s\n\n", "Suma karaktera u vasem imenu je ",
sum,".");
}

Primer. Transformacija stringa. U stringu se svaki znak 'e' zamenjuje znakom 'E', dok se svaka

Predrag S. Stanimirovi

129

Programski jezici

praznina zamenjuje prelazom u novi red i tabulatorom. Unos karaktera se zavrava prelazom u
novi red ili EOF karakterom.
#include <stdio.h>
#define MAX 50
void main()
{ char line[MAX], *change(char *);
void read(char *);
printf("Unesi jedan red");
read(line);
printf("\n%s\n\n%s\n\n",
"Posle promene red je : ", change(line));
}
void read(char *s)
{ int c, i=0;
while ((c=getchar()) !=EOF && c !='\n') s[i++]=c;
s[i]='\0';
}
char *change(char *s)
{ static char new_string[MAX];
char *p=new_string;
/* pointer p je inicijalizovan na baznu adresu od new_string */
for (; *s != '\0'; ++s)
if(*s=='e') *p++='E';
else if(*s==' ') { *p++='\n'; *p++='\t'; }
else *p++=*s;
*p='\0';
return(new_string);
}

7.1.2. Testiranje i konverzija znakova


Standardna biblioteka <ctype.h> sadri deklaracije funkcija za testiranje znakova. Sve
funkcije iz te biblioteke imaju jedan argument tipa int, ija vrednost je ili EOF ili je
predstavljena kao unsigned char. Rezultat svake od ovih funkcija je tipa int. Funkcije vraaju
rezultat razliit od nule (tano), ako argument zadovoljava opisani uslov, a 0 ako ne
zadovoljava. Najee koriene funkcije iz ove biblioteke su:
isdigit(c) ispituje da li je c decimalna cifra;
islower(c) ispituje da li je c malo slovo;
isupper(c) ispituje da li je c veliko slovo;
isalpha(c) islower(c) ili isupper(c) je tano;
isalnum(c) isalpha(c) ili isdigit(c) je tano;
iscntrl(c) ispituje da li je c kontrolni znak (kontrolni znaci imaju kodove 0... 31);
isspace(c) razmak, novi red, povratnik, vertikalni ilihorizontalni tabulator.
Takoe, postoje i dve funkcije za promenu veliine slova.
int tolower(int c) konvertuje c u malo slovo;
int toupper(int c) konvertuje c u veliko slovo.
Ako je karakter c veliko slovo, tada funkcija tolower(c) vraa odgovarajue malo slovo, a inae
vraa c. Ako je karakter c malo slovo, tada funkcija toupper(c) vraa odgovarajue veliko slovo,
a inae vraa c.

130
Primer. Prebrojavanje rei unutar stringa. String se zavrava prelazom u novi red ili karakterom
eof. Rei unutar stringa su razdvojene prazninama.
#include <stdio.h>
#include <ctype.h>
#define MAX 30
void main()
{ char line[MAX];
void read(char *);
int cnt(char *);
printf("\n Unesi string : "); read(line);
printf("\n Broj reci = %d\n", cnt(line));
}
void read(char s[ ])
{ int c;
while ((c=getchar()) !=eof && c!='\n')
s[i]='\0';
}

s[i++]=c;

int cnt(char *s)


{ int br=0;
while (*s!='\0')
{ while (isspace(*s)) ++s;
/* preskoci praznine izmeu reci na pocetku */
if(*s!='\0') /* naci rec */
{ ++br;
while(!isspace(*s)&& *s!='\0')
/*preskoci rec*/
++s;
}
}
return(br);
}

Primer. String je deklarisan kao statiki niz karaktera a zatim je inicijalizovan nekom string
konstantom. Napisati program koji ispisuje string u direktnom i inverznom poretku.
#include<stdio.h>
void main()
{ static char s[]="Konstantni string";
char *p;
p=s;
printf("\nIspis stringa:\n");
while(*p)
putchar(*p++);
printf("\nIspis u inverznom poretku:\n");
while(--p>=s) putchar(*p);
putchar('\n');
}

Uitavanje stringova.
Vrednosti stringova se mogu i uitavati. Pri uitavanju stringova bitno je da se rezervie
dovoljno memorijskog prostora za smetanje stringova. Program ne moe da predvidi
maksimalnu duinu stringa i da rezervie potreban memorijski prostor. Zbog toga je programer
obavezan da predvidi maksimalnu duinu stringova koji se uitavaju. String moe da dobije
vrednost pomou funkcije scanf(), koristei format %s. Na primer, moemo pisati:
scanf("%s", w);

Predrag S. Stanimirovi

131

Programski jezici

Svi znaci, do prvog znaka EOF ili do prve praznine se uzimaju kao elementi stringa w.
Posle toga se null karakter stavlja kao kraj stringa. Napomenimo da nije koriena adresa &w u
drugom argumentu funkcije scanf(). Kako je ime niza u stvari bazna adresa niza, oigledno je
w ekvivalentno sa &w[0]. Stoga je operator adresiranja ispred imena niza w nepotreban.
Za uitavanje stringova najee se koristi funkcija gets(). Ovom funkcijom se prihvataju svi
znaci sa tastature, sve dok se ne unese znak za novi red '\n'. Znak za prelaz u novi red se
ignorie, dok se svi ostali karakteri dodeljuju stringu koji se uitava. Kao poslednji znak
uitanog stringa uvek se postavlja null karakter '\0'.
Prototip funkcije gets() je oblika

char *gets(char *)

Ukoliko je uitavanje zavreno korektno, vrednost ove funkcije je pokaziva na adresu u


kojoj je smeten prvi znak stringa s. U suprotnom sluaju, vraena vrednost je NULL (nulta
adresa, koja je u datoteci stdio.h definisana sa 0). To znai da se kontrola pravilnosti ulaza
moe kontrolisati izrazom
while(gets(ime)==NULL);

Primer. Uitavanje stringa i njegovo prikazivanje na ekran.


#include<stdio.h>
void main()
{ char ime[100];
char *pok;
pok=gets(ime);
printf("1. nacin: %s\n",ime);
}

printf("2. nacin: %s\n",pok);

Primer. Re je data kao niz od n karaktera (n<300). Napisati program koji nalazi najdui
palindrom u toj rei. Palindrom je podniz od uzastopnih elemenata koji se jednako ita s leva i s
desna.
void main()
{ char a[300];
int i,j,n,maxi,maxl,maxj,ind,l;
int pal(char *, int, int);
printf("Unesi broj karaktera reci\n"); scanf("%d",&n);
printf("Unesi rec:\n");
scanf("%c", &a[0]);
for (i=0; i<n; i++) scanf("%c", &a[i]);
maxl=0;
for (i=0; i<n; i++)
for (j=i; j<n; j++)
{ if(pal(a,i,j))
{ l=(j-i)+1; if (l>maxl){ maxl=l; maxj=j; maxi=i; }
}
}
printf("\Najduzi palindrom je od pozicije %d do %d\n", maxi,maxj);
for (i=maxi; i<=maxj; i++) printf("%c",a[i]);
printf("\n");
}
int pal (char *a, int i, int j)
{ int p;
int l,k,m;
char b[300];
l=(j-i)+1;
k=0;
for (m=i; m<=j; m++)
b[++k]=a[m];
p=1; k=1;

132

while(p && k<=l/2)


if(b[k] != b[l-k+1]) p=0;
else k++;
return(p);

Primer. U beskonanom ciklusu se uitavaju stringovi i ispituje da li su palindromi. Stringovi


se tretiraju kao pointeri na karaktere.
void main()
{ char s[30];
printf("\n Stringovi u beskonanom ciklusu\n");
while(1)
{ printf("Zadati string\n");
gets(s);
if(palindrom(s)) printf("Jeste palindrom\n");
else printf("Nije palindrom\n");
}
}
int palindrom(char *strpok)
{ char *strpok1=strpok;
while(*strpok1)++strpok1;
--strpok1;
while(strpok < strpok1)
if(*strpok++ != *strpok1--) return(0);
return(1);
}

Primer. Uitava se tekst, sve do znaka EOF. tampati izvetaj, u kome se nalaze duine rei
sadranih u tekstu, kao i broj rei date duine.
#include<stdio.h>
#include<string.h>
#define MAX 80
int separator(char ch)
{ return(ch==','||ch==''||ch==';'||ch=='('||ch==')'
||ch==' '||ch=='!'||ch=='?'); }
void main()
{ char ch;
int i,j,l=0;
int b[MAX];
for(i=1;i<=MAX; i++)b[i]=0;
ch=getchar();
while(ch != EOF)
{ while(ch != '\n')
{ ch=getchar();
if(!separator(ch)) l++;
else if(l>0)
{ b[l]++; l=0; }
}
ch=getchar();
if(l>0)
{ b[l]++; l=0; }
}
if(l>0) b[l]++;
printf("%s
%s\n","Broj reci","Broj ponavljanja");
for(i=1;i<=MAX;i++)
if(b[i]>0)
printf("%d
%d\n",i,b[i]);
}

Predrag S. Stanimirovi

133

Programski jezici

Ve je pokazano da se vrednosti stringova mogu ispisivati pomou unkcije printf, koristei


format %s. Takoe, za ispis stringova e moe koristiti standardna funkcija puts. Funkcija puts
ima jedan argument, koji predstavlja pokaziva na poetnu adresu tringa koji se ispisuje.
Funkcija puts ispisuje sve karaktere poev od pozicije odreene argumentom funkcije do
zavrnog karaktera \0'.
Primer. Zadati string s koristei funkciju gets(). Napisati funkciju za izbacivanje svih nula sa
kraja stringa, kao i funkciju za izbacivanje nula sa poetka uitanog stringa. U glavnom
programu izbaciti sve poetne i zavrne nule u zadatom stringu.
void main()
{ char s[30];
void ukloni_kraj(char *);
void ukloni_pocetak(char *);
printf("\n Zadati string:\n");
gets(s);
ukloni_kraj(s);
printf("\nString bez zadnjih nula = ");
puts(s);
ukloni_pocetak(s);
printf("\nString bez pocetnih i zadnjih nula = "); puts(s);
}
void ukloni_pocetak(char *s)
{ char *t=s;
while(*t && *t=='0') t++;
/* Naen je prvi karakter razlicit od \0 */
while(*t) *s++=*t++;
/* Kopira preostale karaktere na pocetak stringa */
*s='\0';
}
void ukloni_kraj(char *s)
{ char *t=s;
while(*t)t++;
t--;
while(*t=='0')t--;
t++;
*t='\0';
}

5.1.3. Standardne funkcije za rad sa stringovima


Standardna biblioteka sadri vei broj funkcija za manipulaciju stringovima. Ove funkcije nisu
deo C jezika, ali su napisane u jeziku C. U njima su esto promenljive deklarisane u
memorijskoj klasi register, da bi se obezbedila njihovo bre izvravanje. Sve te funkcije
zahtevaju da se string zavrava null karakterom, a njihov rezultat je integer ili pointer na char.
Prototipovi ovih funkcija su dati u header fajlu <string.h>.
unsigned strlen(char *s)

Prebrojava sve karaktere pre '\0' u s, i vraa


broj.

naeni

int strcmp(char *s1, char *s2)

Rezultat je ceo broj <0, =0 ili >0, zavisno od toga da li


je s1 u leksikografskom poretku manje, jednako ili vee
od s2.

int strncmp(char *s1, char *s2, int n) Slina je funkciji strcmp, osim to ova funkcija
uporeuje najvie n karaktera niske s1 sa odgovarajuim
karakterima niske s2.
char *strcat(char *s1, char *s2)

Stringovi s1 i s2 se spajaju, a rezultujui string se smeta


u s1. Rezultat je pointer na s1. U stvari, povezuje nisku

134
s2 sa krajem niske s1. Mora da se alocira dovoljno
memorije za s1.
char *strncat(char *s1, char *s2)

Nadovezuje najvie n znakova niske s2 sa krajem niske


s1. Nisku s1 zavrava karakterom \0 i vraa s1.

char *strcpy(char *s1, char *s2)

String s2 se kopira u memoriju, poev od bazne adrese


na koju ukazuje s1. Sadraj od s1 se gubi. Rezultat je
pointer s1.

char *strncpy(char *s1, char *s2)

Kopira najvie n znakova stringa s2 u memoriju, poev


od bazne adrese na koju ukazuje s1. Rezultat je pointer
s1.

char *strchr(char *s, char c)

Rezultat primene ove funkcije je pointer na prvo


pojavljivanje karaktera c u stringu s, ili NULL ako se c
ne sadri u s.

Na primer, funkcija strlen moe da se implementira na sledei nain:


unsigned strlen(s)
register char *s;
{ register unsigned n;
for (n=0; *s!='\0'; ++s) ++n;
return(n);
}

Primer.
char s1[100], s2[100], t[100], *strcat(), *strcpy();
strcpy(s1, "recenica 1"); strcpy(s2, "rec 2");
strlen(s1);
/* 10 */
strlen(s1+9);
/* 1 */
strcmp(s1, s2); /* pozitivan broj */
strpy(t,s1+9);
/* t="1" */
strcat(t," ");
/* t="1 " */
strcat(t,s1+9); /* t="1 1"*/
printf("%s",t); /* 1 1*/ }

Primer. Funkcija strcpy se moe implementirati na sledei nain:


char *strpy(char *s1, char *s2)
{ char u;
u=s2;
while(s1++=s2++);
return(u);
}

Primer. Testiranje nekih funkcija u vezi stringova.


#include <stdio.h>
void STRCAT(char *s,char *t);
char STRCMP(char *s,char *t);
void STRCPY(char *s,char *t);
void main()
{ char v[80],w[80]; int c;
while(1)
{ /*POCETAK */
printf("Daj dve reci :");scanf("%s%s",v,w);

Predrag S. Stanimirovi

135

Programski jezici

printf("Unesi 1 za STRCAT, 2 za STRCMP, 3 za STRCPY\n");


scanf("%d",&c);
switch(c)
{char cc;
case 1: STRCAT(v,w);
printf("Njihov dopis je %s \n",v);
break;
case 2: cc=STRCMP(v,w);
if (cc==0) printf("Jednaki\n");
else printf("Razliciti\n");
break;
case 3: STRCPY(v,w);
printf("Novo v je %s\n",v);
break;
default :printf("Taj slucaj je nov\n ");
}

void STRCAT(char *s,char *t)


{ int i,j;i=j=0;
while(s[i]!='\0') i++;
while((s[i++]=t[j++])!='\0') ;
}
char STRCMP(char *s,char *t)
{ int i=0;
while (s[i]==t[i] && (s[i]!='\0' || t[i]!='\0')) ++i;
if (s[i]==t[i]) return(0);else return(1);
}
void STRCPY(char *s,char *t)
{ int i=0;
do
{ s[i]=t[i];++i;}
while (t[i]!='\0');
s[i]='\0';
}
void STRCPY(char *s,char *t)
{ int i=0;
while((s[i]=t[i])!='\0') ++i;
s[i]='\0';
}

Primer. Re je data kao niz od n karaktera (n<300). Napisati program koji nalazi najdui
palindrom u toj reci. Palindrom je podniz od proizvoljnih elemenata koji se jednako ita s leva i
s desna.
void main()
{char a[300], maxpal[300], tpal[300];
int grupa[300], grupa1[300];
int i,j,n, k, duz,maxduz;
int pal(char *);
printf("Unesi broj karaktera reci\n"); scanf("%d",&n);
printf("Unesi rec:\n");
scanf("%c", &a[0]);
for (i=0; i<n; i++) scanf("%c", &a[i]);
a[n]='\0';
for(i=0; i<n; i++)
grupa[i]=0;
maxduz=0;
do { k=0;
for(i=0; i<n; i++)

136
if(grupa[i]) { tpal[k]=a[i]; k++; }
tpal[k]='\0';
if(pal(tpal))
{ duz=strlen(tpal);
if(duz > maxduz)
{ maxduz=duz;
strcpy(maxpal, tpal);
for(i=0; i<n; i++) grupa1[i]=grupa[i];
}
}
j=n;
while(j>=0 && grupa[j]) j--;
if(j>=0) { grupa[j]=1; for(i=j+1; i<n; i++) grupa[i]=0;}

}
while(j>=0);
printf("Najduzi palindrom je podstring %s\n", maxpal);

int pal (char *b)


{ int p;
int l,k,m;
p=1; k=0; l=strlen(b);
while(p && k<l/2)
if(b[k] != b[l-k-1]) p=0;
else k++;
return(p);
}

Primer. Kaemo da se string U pojavljuje u stringu T sa pomakom s, ili da se U pojavljuje u T


poev od pozicije s ako su ispunjeni sledei uslovi:
0 <= s <= Tn-Un,
T[s+j] = U[j] za 0 <= j < Un,
gde je Tn broj elemenata u stringu T a Un duina stringa U.
Odrediti sva pojavljivanja stringa U u stringu T.
#include<string.h>
void sekv_sm (char *t, char *u)
{ int s, j;
int tn, un;
tn = strlen(t);
un = strlen(u);
for (s = 0; s <= tn-un; s++)
{ for (j = 0; j < un; j++)
if (t[s+j] != u[j]) break;
if(j == un) printf("Uzorak se pojavljuje sa pocetkom %d.\n", s);
}
}
void main()
{ char *s1, *s2;
printf("Prvi string? "); gets(s1);
printf("Drugi string? "); gets(s2);
sekv_sm(s1,s2);
}

Predrag S. Stanimirovi

137

Programski jezici

8. Strukturni tipovi podataka

Pojam struktura podataka, nizova, slogova, skupova i datoteka je poznat i prisutan u viim
programskim jezicima od samog njihovog nastanka. Meutim, dok se kod starijih jezika
(FORTRAN, Algol, PL/1, COBOL) svaka struktura podataka definie pojedinano, sa pojavom
jezika Pascal uvodi se i pojam strukturnih tipova podataka, odnosno eksplicitnih definicija
tipova podataka. U okviru strukturnih tipova podataka, vrednosti koje tip obuhvata definisane su
kao jednorodne ili raznorodne strukture podataka. U jeziku Pascal postoji mogunost
definisanja strukturnih tipova koji omoguavaju rad sa nizovima, slogovima, skupovima i
datotekama. Skupovi se kao strukturni tipovi podataka ree sreu kod drugih programskih
jezika, dok su nizovi, slogovi i datoteke postali standardni koncept, prisutan u mnogim
programskih jezicima (Ada, C).

8.1. Polja
Polja su u programskim jezicima jednodimenzionalne ili viedimenzionalne strukture
podataka koje obuhvataju vie vrednosti istog tipa. Moe se rei, da jednodimenzionalna polja
odgovaraju pojmu vektora, a viedimenzionalna pojmu matrica. Za opis ovih struktura u
jezicima se koristi kljuna re a r r a y . Razmotrimo sledei primer:
type VE KTOR = a rra y [1..1 0 ] of real;
var A , B : VEKTOR;

Ovom definicijom opisan je tip VEKTOR koji u potpunosti odgovara pojmu vektora u
linearnoj algebri, ali i A i B kao promenljive tipa VEKTOR. Svakoj od promenljivih A i B
odgovara struktura podataka koja se sastoji od 10 komponenti tipa real. Svakoj od komponenti
vektora opisanog na ovaj nain moe se pristupiti preko indeksa koji je odreuje u okviru
strukture. Tako na primer, treoj komponenti vektora A pristupamo preko A(3), ili u optem
sluaju A(J). U nekim jezicima (Pascal) koristi se i notacija sa uglastim zagradama na primer
A[3] i A[J]. U ovakvim sluajevima indeks moe da bude definisan i kao celobrojni izraz. Ove
indeksirane promenljive mogu se u programu upotrebiti svuda gde se javljaju i proste
promenljive odgovarajueg tipa. U datom primeru A(J) i B(J) su promenljive tipa real. Evo
nekih primera koji to ilustruju:

138
A(3) : = 0.0;
X : = A (3);

- Treem elementu vektora A dodeljuje se vrednost 0;


- X dobija vrednost treeg elementa vektora A.

Polja se realizuju kao statike strukture podataka, to znai da se za svaki odreeni vektor
rezervie unapred definisani prostor u memoriji raunara. Granice indeksa u definiciji tipa mogu
da budu date i preko promenljivih ili ak i preko izraza, ali ove vrednosti treba da budu poznate
u taki programa u kojoj se pojavljuje definicija tipa. Evo nekih definicija tog oblika:
type VEKTOR1 is array (1 .. N) of float;
type VEKTOR2 is a rra y (N .. N+M) of f l o a t ;

U svim ovim primerima, za definisanje indeksa je iskorien interval u skupu celih brojeva
(integer). To je i prirodno, jer se najee za indeksiranje i u matematici koriste celobrojne
vrednosti. U Pascal-u i Adi se za definisanje indeksa moe koristiti bilo koji diskretni tip
podataka. Razmotrimo sledei primer u kome se kreira tabela sa podacima o koliini padavina u
svakom mesecu jedne godine:
type PADAVINE is delta 0 . 1 range 0 . 0 .. 2 0 0 . 0 ;
type MESECI is (JAN, FEB, MAR, AP R, MAJ, JUN,
JUL, AVG , SEP, OKT, NOV, DEC);
type KOL_PAD is a rra y ( M E S E C I ) of PADAVI NE ;
PODACI : KOL_PAD;

U ovom primeru definisan je strukturni tip podataka KOL_PAD, za ije indeksiranje se


koristi diskretni tip nabrajanja MESECI, tako da vektor PODACI ima ukupno 12 komponenti,
od kojih svaka odgovara jednom mesecu u godini. Svakoj od ovih komponenti pristupa se preko
imena meseca kao indeksa. Na taj nain, u programu e PODACI(MART) biti promenljiva
kojoj se dodeljuje vrednost koja odgovara padavinama u mesecu martu. Pored ovako korienih
diskretnih tipova, oni se mogu koristiti za definisanje opsega indeksa, tako to se u okviru skupa
vrednosti odreenog diskretnog tipa koristi samo interval vrednosti. Na primer, u razmatranom
primeru moglo je da bude postavljeno ogranienje da se razmatraju padavine u letnjem periodu
godine. U tom sluaju, pogodno je indeks vektora PODACI definisati tako da ima samo
komponente koje odgovaraju letnjim mesecima.

8.1.1. Anonimne definicije strukturnih tipova


Definicije strukturnih tipova mogu u programu da budu date i bez eksplicitnog definisanja i
imenovanja tipa u vidu anonimnih definicija tipa.
Sledei primer ilustruje ovaj koncept.
Primer. Strukturno ekvivalentni vektori.
procedure VEKTOR_DOD3 is
A : a r r a y ( 1 . . 5 ) of integer;
B : a r r a y ( 1 . . 5 ) of integer;
begin
B := A;
B(1):= A ( 1 ) ;
end VEKTOR_DOD3;

Vektori A i B su definisani u okviru razliitih tipova podataka koji su meutim strukturno


jednaki. U jeziku Pascal kod ovakvih definicija vai strukturna ekvivalentnost na nivou naredbi
dodeljivanja, tako da bi sva dodeljivanja u primeru bila korektna. U jeziku Ada, meutim, i u
ovakvim sluajevima se zahteva eksplicitna ekvivalentnost, tako da su navedena dodeljivanja
nekorektna. Ako elimo da koristimo anonimne definicije tipova podataka, onda i vektor A i
vektor B treba da budu opisani u okviru iste definicije, odnosno da i eksplicitno pripadaju istom
tipu, kako je to uraeno u primeru koji sledi.

Predrag S. Stanimirovi

139

Programski jezici

Primer. Eksplicitno ekvivalentni vektori.


procedure VEKTOR_DOD4 is
A , B : a r r a y ( 1 . . 5 ) of integer;
begin
B := A;
B(1) := A ( 1 ) ;
end VEKTOR_DOD4;

Primer. Sortiranje elemenata niza dovoenjem maksimalnog na poetak.


program sortniz;
type niz=array[1..20] of real;
var x:niz;
n,i,j:1..20;
p:real;
begin
writeln;
write('Duzina niza? ');
readln(n);
writeln('Elementi niza? '); for i:=1 to n do read(x[i]);
for i:=1 to n-1 do
for j:=i+1 to n do
if x[i]<x[j] then
begin
p:=x[i]; x[i]:=x[j]; x[j]:=p;
end;
writeln;
writeln('Sortirani niz je: ');
for i:=1 to n do write(x[i]:14:6);
writeln
end.

Primer. Napisati proceduru za sortiranje elemenata niza. Napisati proceduru kojom se zadati
broj umee u sortirani niz, tako da niz ostane sortiran. U glavnom programu testirati napisane
procedure.
program umetanje;
type vektor = array[1..50] of real;
var
a:vektor;
i,j,n:0..51;
x, pom:real;
begin
{ Ucitavanje niza i broja koji se umece }
writeln;
write(' Koliko elemenata u nizu? '); readln(n);
writeln(' Unesite elemente niza ');
for i:= 1 to n do read(a[i]);
write(' Unesite broj koji se umece '); readln(x);
writeln;
{ Sortiranje niza }
for i:=1 to n-1 do
for j:= i+1 to n do
if a[j]<a[i] then begin
pom:=a[i]; a[i]:=a[j]; a[j]:=pom
end;

140

writeln(' Sortirani niz je ');


for i:=1 to n do write(a[i]:10:6);
{ Umetanje u niz }
i:=1;
while (i<=n) and (x>a[i]) do i:= i+1;
if i=1 then {Umetanje na pocetak niza }
begin
for j:=n downto 1 do
a[j+1]:=a[j];
a[1]:=x
end
else if i=n+1 then a[n+1]:=x {Postavljanje na kraj niza }
else
{Umetanje u nizu }
begin
for j:=n downto i do
a[j+1]:=a[j];
a[i]:=x
end;
writeln; writeln;
writeln(' Niz sa umetnutim elementom je: ');
write(a[i]:10:6);
end.

for i:=1 to n+1 do

Primer. Odrediti poetnu poziciju i duinu najveeg podniza datog niza koji se sastoji od
uzastopnih parnih brojeva.
program uzastopni_parni;
type pozitivni =0..maxint;
niz=array[1..100] of pozitivni;
var a:niz;
i,n,k: 1..100;
l,lmax,kmax:0..100;
begin
writeln(' Koliko elemenata? '); readln(n);
writeln(' Uneti elemente ');
for i:=1 to n do read(a[i]);
i:=1; lmax:=0; kmax:=0;
while i<=n do
begin
while (a[i] mod 2 = 1) and (i<=n) do i:= i+1;
k:=i; l:=0;
while (a[i] mod 2 = 0) and (i<=n) do
begin
i:= i+1; l:=l+1;
end;
if lmax<l then
begin
lmax:=l; kmax:=k;
end;
end;
writeln(' Maksimalni podniz poinje od pozicije ', kmax);
writeln(' Duzina maksimalnog podniza je ',lmax);
end.

Primer. Formirati novi niz koji se sastoji od razliitih elemenata datog niza.

Predrag S. Stanimirovi

141

Programski jezici

program razliciti_elmenti_niza;
type niz=array[1..50] of real;
var n,i,j,k:integer;
a,b:niz;
lg:boolean;
begin
writeln;
writeln('Unesite broj elemenata niza');
readln(n);
writeln('Unesite elemente niza');
for i:=1 to n do
read(a[i]);
k:=0;
for i:=1 to n-1 do
begin
lg:=true;
for j:=i+1 to n do if a[i]=a[j] then lg:=false;
if lg then begin
k:=k+1;
b[k]:=a[i];
end;
end;
k:=k+1;
b[k]:=a[n];
writeln('Niz bez visestrukih elemenata izgleda ovako:');
for i:=1 to k do write(b[i]:10:5);
end.

Primer. Izraunati broj nula kojima se zavrava broj n!, 1<=n<=10000. Zatim odrediti dve
posledenje cifre koje ostaju posle precrtavanja krajnjih desnih nula.
program nulefak;
var i,j,n,bnula:integer;
p:longint;
b:array[1..10001] of integer;
begin
write('n = ? '); readln(n);
for i:=1 to n do b[i]:=i;
bnula:=0;
for i:= 1 to n do
while (b[i] mod 5) = 0 do
begin
j:=1;
while (b[j] mod 2) = 1 do j:=j+1;
b[j]:=b[j] div 2; b[i]:=b[i] div 5;
bnula:=bnula+1;
end;
writeln;
writeln(n,'! se zavrsava sa ',bnula,' nula');
p:=1;
for i:=1 to n do p:=(p*b[i]) mod 100;
writeln('Poslednje dve cifre posle izbacivanja nula su ');
if p<10 then writeln('0',p)
else writeln(p);
end.

Primer. Svaki od dva pozitivna cela broja zadaje se brojem svojih cifara i nizom svojih cifara.
Napisati program za mnoenje zadatih brojeva.
program mnozenje;

142
var a,b:array[1..20] of 0..9;
c:array[1..40] of 0..9;
m,n,i,j,p,q:integer;
begin
write('Duzina prvog broja? '); readln(m);
writeln('Cifre prvog broja?');
for i:=m downto 1 do read(a[i]);
write('Duzina drugog broja? '); readln(n);
writeln('Cifre drugog broja?');
for i:=n downto 1 do read(b[i]);
writeln('Proizvod ovih brojeva je ');
for i:=1 to m+n do c[i]:=0;
for i:= 1 to m do
begin
p:=0;
for j:=1 to n do
begin
q:=c[j+i-1]+a[i]*b[j]+p;
c[i+j-1]:= q mod 10;
p:=q div 10;
if j=n then c[j+i]:=p;
end;
end;
if c[m+n]<>0 then write(c[m+n]);
for i:=m+n-1 downto 1 do write(c[i]);
end.

8.2. Jednodimenzionalni nizovi u C


Niz je sekvenca memorijskih lokacija koje slede jedna za drugom i u kojima se pamte
objekti istog tipa. Kao i sve druge promenljive u programu, i niz se mora deklarisati pre nego
to se upotrebi. Deklaracijom niza kompajleru se saoptavaju sledei podaci o nizu: ime, tip i
veliinu. Deklaracija jednodimenzionalnog niza se sastoji od imena tipa iza koga sledi
identifikator (ime niza) i na kraju celobrojni izraz izmeu srednjih zagrada. Vrednost ovog
izraza mora da bude pozitivan ceo broj i predstavlja veliinu niza. Indeksiranje elemenata niza
poinje od 0.
Opta forma izraza kojom se deklarie niz je sledea:
tip ime[velicina].

Veliina niza zadaje se konstantom ili konstantnim izrazom. Na primer, izrazom int broj[100]
deklarie se niz sa 100 celobrojnih vrednosti. Niz broj se sastoji od 100 celobrojnih
(indeksiranih) promenljivih sa imenima broj[0],... broj[99].
Komponentama niza se pristupa navoenjem imena niza i celobrojnog izraza izmeu srednjih
zagrada. Ovim izrazom se definie indeks eljenog elementa niza. Ako je indeks manji od 0 ili
vei ili jednak od broja elemenata u nizu, nee se pristupiti elementu niza.
Primer. Program koji formira niz ai = i2, i = 1,... ,n, tampa njegove elemente i sumira ih.
#define N 5
void main()
{ int a[N];
/* prostor za a[0]\dots a[N-1] se alocira */
int i,sum=0;
for(i=0;i<N;++i) a[i]=i*i;
for(i=0;i<N;++i) printf("a[%d]=%d",i,a[i]);
for(i=0;i<N;++i) sum +=a[i];
printf("\n sum=%d\n",sum);

Predrag S. Stanimirovi

143

Programski jezici

Nizovi mogu da imaju memorijsku klasu auto, extern, static, a ne mogu register. U Turbo C se
nizovi mogu inicijalizovati u naredbi deklaracije.
Primer. Posle inicijalizacije
float x[7]={-1.1,0.2,33.0,4.4,5.05,0.0,7.7};
dobija se
x[0]=-1.1, x[1]=0.2, \dots x[6]=7.7.
Lista elemenata koji se koriste za inicijalizaciju vektora moe biti manja od broja njegovih
elemenata. Ako je niz memorijske klase static ili extern, njegovi preostali elementi postaju 0. U
sluaju da je niz memorijske klase auto, za ove vrednosti e biti neke vrednosti koje su zaostale
od ranije u delu memorije koja se koristi za smetanje elemenata niza. Ako extern ili static niz
nije inicijalizovan, tada kompajler automatski inicijalizuje sve elemente na 0.
Ako je niz deklarisan bez preciziranja duine, i pritom inicijalizovan, tada se duina niza
implictno odreuje prema broju inicijalizatora.
Na primer, izraz int a[ ]={3,4,5,6}; proizvodi isto dejstvo kao i izraz int a[4]={3,4,5,6};

Primeri.
Primer. Izraunati aritmetiku sredinu niza x od n<= 50 elemenata.
main()
{ int i,n;
float suma, x[50];
printf("Broj elemenata? "); scanf("%d", &n);
for(suma=0, i=0; i<n; i++)
{ printf("%3d.element =? ",i); scanf("%f", &x[i]);
suma +=x[i];
}
printf("\n Srednja vrednost = %f\n", suma/n);
}

Primer. Izraunati broj pojavljivanja svakog velikog slova u unetom tekstu.


#include <stidio.h>
#include <ctype.h>
void main()
{ int c,i, slova[26];
for(i=0;i<26;++i) slova[i]=0;
while((c=getchar()) !=EOF)
if(isupper(c))
++slova[c-'A'];
for(i=0;i<26;++i)
{ if(i%6==0) printf("\n");
printf("%5c:%4d", 'A'+i, slova[i]);
}
printf("\n\n");
}

Primer. Napisati program kojim se izraunava n-ti stepen broja 2, gde je n<= 500, i traeni
stepen nema vie od 200 cifara.
void main()
{ int i,n,d=0,j,p, x[200];
printf("\n Unesi stepen --> "); scanf("%d",&n);

144

x[0]=1;
for(i=0; i<n; i++)
{ p=0;
for(j=0; j<=d; j++){x[j]=x[j]*2+p; p=x[j]/10; x[j] %=10; }
if(p!=0) { d++; x[d]=p; }
}
printf("%d. stepen broja 2 je ",n);
for(i=d; i>=0; i--)printf("%d",x[i]);

Primer. Binarno traenje.


Posmatra se sledei matematiki problem: zadat je ureen realni niz a[0]<a[1]<<a[n-1] i
realan broj b, ustanoviti da li se b nalazi u nizu, i ako se nalazi odrediti indeks p za koji vai
a[p]=b.
Najjednostavnije, ali i najneefikasnije je takozvano linearno pretraivanje: redom se
uporeuju elementi niza a sa brojem b, do prvog elementa niza a za koji je a[i]>=b. Ako je
a[i]=b, tada je p=i traeni indeks. Ako je a[i]>b, tada se broj b ne nalazi u nizu a.
Za brzo pretraivanje se koristi algoritam binarnog pretraivanja.
Pretpostavimo da postoji p[0,n-1] takav da je a[p]=b. Izaberemo srednji element niza a sa
indeksom s=(0+n-1)/2. Ako je a[s]=b, tada je p=s traeni indeks, a pretraivanje se prekida. Ako
je ispunjen uslov b<a[s], tada se indeks p nalazi u intervalu [0,s-1], a inae se nalazi u intervalu
[s+1,n-1]. U oba sluaja, prepolovljen je interval pretraivanja.
Primer. Napisati funkciju koja prema opisanom algoritmu odreuje indeks onog elementa
rastueg niza a koji je jednak zadatoj vrednosti b, a inae vraa rezultat -1.
#include<stdio.h>
void main()
{ float br, a[100];
int n,i,p;
int bintra(float a[], int n, float b);
printf("\nBroj elemenata? "); scanf("%d",&n);
printf("Elementi niza ");
for(i=0; i<n; i++)scanf("%f", &a[i]);
printf("Jedan realan broj? "); scanf("%f",&br);
p=bintra(a, n, br);
printf("Pozicija broja %f u nizu je %d\n",br,p);
}
int bintra(float a[], int n, float b)
{ int l,d,s;
l=0; d=n-1;
while(l<=d)
{ s=(l+d)/2;
if(b==a[s]) return(s);
else if(b<a[s])d=s-1;
else l=s+1;
}
return(-1);
}

Odgovarajua rekurzivna funkcija je

Predrag S. Stanimirovi

Programski jezici

145

#include<stdio.h>
main()
{ float br, a[100];
int n,i,p;
int bintra1(float a[], int l, int d, float b);
printf("\nBroj elemenata? "); scanf("%d",&n);
printf("Elementi niza ");
for(i=0; i<n; i++)scanf("%f", &a[i]);
printf("Jedan realan broj? "); scanf("%f",&br);
p=bintra1(a, 0, n-1, br);
printf("Pozicija broja %f u nizu je %d\n",br,p);
}
int bintra1(float a[], int l, int d, float b)
{ int s;
if(l>d) return(-1);
else
{ s=(l+d)/2;
if(b==a[s]) return(s);
else if(b<a[s])return bintra1(a,l,s-1,b);
else return bintra1(a,s+1,d,b);
}
}

8.3. Veza izmeu nizova i pointera u C


Ime niza je konstantni pokaziva na poetak niza, tj. adresa njegovog nultog elementa. Ime
niza je samo po sebi jedna adresa, ili vrednost pointera (pointer je promenljiva koja uzima
adrese za svoje vrednosti). Kada je niz deklarisan, kompajler alocira baznu adresu i dovoljan
memorijski prostor za smetanje svih elemenata niza. Kompajler jezika C sam prevodi oznake
niza u pokazivae, pa se korienjem pokazivaa poveava efikasnost u radu sa nizovima.
Primer. Neka je data deklaracija
#define N 100
long a[N], *p;
Pretpostavimo da je prva adresa za smetanje niza a jednaka 300 (ostale su 304,308,,696).
Naredbe
p=a;

p=&a[0];

su ekvivalentne. U oba sluaja promenljiva p uzima za svoju vrednost adresu nultog elementa
niza a. Preciznije, promenljivoj p se dodeljuje vrednost 300.
Takoe, naredbe
p=a+1;

p=&a[1];

su ekvivalentne i dodeljuju vrednost 304 promenljivoj p. Analogno, naredbe p=a+i i p=&a[i]


su ekvivalentne, za svaki element a[i] niza a. Ako su elementima niza a pridruene vrednosti,
one se mogu sumirati koristei pointer p, na sledei nain:
sum=0;
for(p=a; p<&a[N]; ++p, sum += *p);
Isti efekat se moe postii sledeim postupkom:
sum=0;

146
for(i=0;i<N;++i) sum += *(a+i);
Napomenimo da je izraz *(a+i) ekvivalentan sa a[i]. Takoe, moe se pisati { p=&(*(a+i))}
umesto p=a+i, odnosno p=&a[i].
Primer. Jo jedan nain sumiranja nizova.
p=a; sum=0;
for(i=0;i<N;++i) sum += p[i]; }
Meutim, postoji razlika izmeu pointera i nizova. Kako je ime niza a konstantni pointer, a ne
promenljiva, ne mogu se koristiti izrazi
a=p++a

a+=2.

To znai da se adresa niza ne moe menjati.


Primer. Napisati program koji transformie niz celih brojeva tako da na poetku budu negativni
a na kraju nenegativni elementi tog niza.
#include<stdio.h>
void main(void)
{ int niz[100], p,i,k,n;
printf("\nBroj elemenata --> "); scanf("%d",&n);
for(i=0; i<n; i++)
{ printf("niz[%d]=--> ",i+1); scanf("%d",niz+i); }
p=0; k=n-1;
while(p<k)
if(niz[p]<0)p++;
else if(niz[k]>=0)k--;
else
{ int pom;
pom=niz[p]; niz[p]=niz[k]; niz[k]=pom;
}
for(i=0; i<n; i++)printf("niz[%d] = %d ",i,niz[i]);
}
#include<stdio.h>
void main(void)
{ int niz[100], *p,*k,i,n;
printf("\nBroj elemenata --> "); scanf("%d",&n);
for(i=0; i<n; i++)
{printf("niz[%d]= --> ",i+1); scanf("%d",niz+i); }
p=niz; k=niz+n-1;
while(p<k)
if(*p<0)p++;
else if(*k>=0)k--;
else
{ int pom;
pom=*p; *p=*k; *k=pom;
for(i=0; i<n; i++)printf("niz[%d]= %d ",i,*(niz+i));
}

Napomena. Program radi i sa deklaracijom int *niz, ali alje upozorenje.


Primer. Sortiranje niza pointerskom tehnikom. Kao algoritam izabrano je sortirane izborom
uzastopnih minimuma.
#include<stdio.h>
void upis(int *a, int *n)

Predrag S. Stanimirovi

147

Programski jezici

{ int i;
printf("Broj elemenata? "); scanf("%d",n);
printf("Elementi? ");
for(i=0; i<*n; i++) scanf("%d",a+i);
}
void ispis(int *a, int n)
{ int i;
for(i=0; i<n; i++)printf("%d ",*(a+i));
}
void ureenje(int *a, int n)
{ int i,j,pom;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(*(a+i)>*(a+j))
{pom=*(a+i); *(a+i)=*(a+j); *(a+j)=pom; }
}
void main()
{ void upis(int *, int*); void ispis(int *, int);
int x[100],k;
upis(x, &k);
ureenje(x,k);
ispis(x,k);
}

8.3.1. Pointerska aritmetika


U jeziku C dozvoljene su aritmetike operacije nad pokazivaima. Dozvoljeno je:
- dodeliti pokazivau adresu promenljive ili nulu;
- uveati ili umanjiti vrednost pokazivaa;
- dodati vrednosti pokazivaa neki ceo broj;
- oduzeti od vrednosti pokazivaa neki ceo broj;
- porediti dva pokazivaa pomou operacija ==, != itd.;
- oduzeti od jednog pokazivaa drugi, ako ukazuju na objekte istog tipa.
Pointerska aritmetika predstavlja veliku prednost jezika C u odnosu na druge jezike visokog
nivoa.
U sledeoj tabeli su uvedene pretpostavke:
a: vektor sa elementima tipa T,
n: celobrojni izraz,
v: zraz tipa T,
pa1, pa2: ukazatelj na tip T, kojima se ukazuje na elemente vektora a.
U njoj su prikazana neka pravila pointerske (adresne) aritmetike:
Oznaka
a
&a[0]
&a[n]
*pa1
*pa1=v
++pa1
--pa1
*++pa1

Znaenje
ukazatelj na prvi element vektora a
ukazatelj na prvi element vektora a
ukazatelj na n+1 element vektora a
element vektora na koji pa1 ukazuje
dodeljuje vrednost v elementu na koji pa1 ukazuje
postavlja pa1 na sledei element vektora a
postavlja pa1 na prethodni element vektora a
inkrementira pa1, a zatim pristupa elem. na koji pa1 ukazuje

Tip rezultata
T
ukazatelj na T
ukazatelj na T
T
T
ukazatelj na T
ukazatelj na T
T

148
*pa1++
pa1n
*(pa1+n)=v
pa1>pa2
*(a+n)

pristupa elem. vekt. a na koji pa1 ukazuje, zatim inkrementira


pa1
ukazuje na n-ti naredni (prethodni) element poev od
elementa na koji pa1 ukazuje
vrednost v dodejluje n-tom narednom elementu u odnosu na
elem. na koji pa1 ukazuje
ispituje vrednosti adresa u pa1 i pa2 pomou relacionih
operatora
n-ti element vektora a

T
ukazatelj na T
T
int
T

Primer.
void main()
{ double a[2], *p, *q;
p=&a[0]; q=p+1;
printf("%d\n",q-p);
printf("%d\n",(int)q-(int)p);
}

/* 1 */
/* 8 */

Primer. Date su deklaracija


int x[4], *pti;
i dodela
pti=x;
Ako je niz x smeten poev od adrese 56006(=&x[0]), odrediti lokacije i elemente niza x na koji
ukazuju pti, pti+1, pti+2 i pti+3.
Reenje. Dodavanje jedinice pokazivau pti automatski uveava sdresu na koju on ukazuje za
2, jer se radi o pokazivau na tip int. Znai, pti, pti+1, pti+2 i pti+3 ukazuju redom na adrese
56006, 56008, 56010, 56012 i na elemente x[0], x[1], x[2], x[3] niza x.
Iz prethodnog primera zakljuujemo
*(x+2)=x[2], x+2=&x[2].
Izraz *x+2 jednak je izrazu (*x)+2 i predstavlja uveanje vrednosti nultog elementa niza za 2.

8.4. Neograniena polja


U nekim jezicima (Ada) postoji mogunost definisanja struktura tipa polja sa neogranienim
opsegom indeksa. U tom sluaju definie se u sutini klasa strukturnih tipova koji se u
konkretnoj definiciji tipa blie odreuju. Primer 6.5 ilustruje ovaj koncept.
U ovom primeru opisan je tip VEKTOR za ije indeksiranje moe da se koristi bilo koji
interval vrednosti u okviru opsega vrednosti tipa integer. U primeru su takoe definisana dva
vektora koja pripadaju tipu VEKTOR, ali tako da se za indeksiranje vektora A koristi interval
vrednosti od 1 do 5, a za indeksiranje vektora B indeksi iz intervala 6..10. Iako se za
indeksiranje vektora A i B koriste razliiti intervali, dodeljivanje dato u primeru e biti
prihvaeno zbog toga to A i B pripadaju eksplicitno istim tipovima i imaju isti broj
komponenti, znai i strukturno su ekvivalentni. U sluaju da ne vai strukturna ekvivalentnost
navedeno dodeljivanje bi bilo nekorektno.
Primer : Vektori sa neogranienim opsegom indeksa.

Predrag S. Stanimirovi

149

Programski jezici

procedure VEKTORI is
type VEKTOR is array(integer range <>) of integer;
A : VEKTOR(1..5);
B : VEKTOR(6..10);
begin
B := A;
en d VEKTORI;

U okviru grupe tipova podataka sa nedefinisanim opsegom indeksa mogu se definisati


konkretni tipovi podataka, kao njegovi podtipovi. Prethodni primer dobija oblik dat u primeru
6.6.
Primer . Strukturni tipovi.
procedure VEKTORI2 is
type VEKTOR is array(integer range <>) of i nt eg er ;
subtype VEKTOR1 is VEKTOR ( 1 . . 5 ) ;
subtype VEKTOR2 is VEKTOR ( 6 . . 1 0 ) ;
A : VEKTOR1;
B : VE KT OR 2;
begin
B := A;
end VEKTORI2;

U ovom sluaju podtipovi VEKTOR1 i VEKTOR2 su meusobno kompatibilni jer su


potomci istog tipa i uz to su strukturno ekvivalentni, tako da je navedeno dodeljivanje korektno.

8.5. Viedimenzionalna polja


Kod reavanja mnogih problema postoji potreba za radom sa viedimenzionalnim
strukturama podataka. U programskim jezicima se za rad sa ovakvim strukturama podataka
mogu definisati viedimenzionalna polja, kao jednorodne strukture podataka u okviru kojih se
pojedinanim elementima pristupa preko dva ili vie indeksa. Posebno su znaajne
dvodimenzionalne strukture, koje odgovaraju pojmu matrica i omoguavaju reavanje veoma
iroke klase problema u okviru kojih se javljaju matrine reprezentacije podataka.
Viedimenzionalne strukture mogu da budu definisane na vie razliitih naina. Razmotriemo
neke mogunosti.
type MATRICA is array (1 .. 1 0 , 1 ..1 0 ) of integer;
P : MATRICA;

U ovom sluaju definisan je strukturni tip podataka MATRICA i matrica P kao struktura tipa
MATRICA. Elementima ovako definisane matrice pristupa se sa P(I, J). Strukturni tip
MATRICA moe da se definie i kao vektor vektora, to ilustruju sledea dva primera. U prvom
koristi se eksplicitna definicija tipa VEKTOR, a u drugom anonimna definicija strukturno istog
tipa. U oba ova sluaja elementima matrice P pristupa se preko P (I) (J), to kod reavanja nekih
problema moe da bude pogodno, jer omoguava pristupanje svim elementima jedne vrste.
type VEKTOR is array(1..1 0 ) of integer;
type MATRICA is array(1..1 0 ) of VEKTOR;
P : MATRICA;
type MATRICA is array(1..1 0 ) of array ( 1 . . 1 0 )
integer; P : MATRICA;

of

Definicija matrice u programu moe da bude data i kombinacijim eksplicitnih i anonimnih


tipova podataka. Sledei primer ilustruje jednu od mogunosti, gde je najpre eksplicitno
definisan strukturni tip VEKTOR, a zatim matrica P definisana preko anonimne definicije tipa
kao vektor vektora.
type VEKTOR is array(1..1 0 ) of integer;

150
P : array(1..1 0 ) of VEKTOR;

Sledea dva sluaja odnose se na potpuno anonimne definicije tipa. U prvom je matrica P
definisana opet kao vektor vektora, a u drugom direktno kao dvodimenzionalna struktura.
P : array(1.. 1 0 ) of array(1.. 1 0 ) of integer;
P : array(1.. 1 0 , 1 . . 1 0 ) of integer;

Vano je napraviti razliku izmeu prve i zadnje definicije na jednoj strani, kada se matrica
definie direktno kao dvodimenzionalna struktura i svih ostalih definicija na drugoj strani, kada
se definie kao vektor vektora. U prvom sluaju elementima matrice P pristupa se preko
P ( I , J ) , a u drugom sluaju preko P (I) (J), kada postoji mogunost da se pristupi svakoj vrsti
matrice kao posebnom vektoru:
P ( 6 ) : = ( 1 . . 1 0 => 0 ) ;

-- Svi elementi u estoj vrsti matrice P


-- dobijaju vrednost 0;

Sledei primer ilustruje korienje viedimenzionalnih polja. Zadatak je napisati program


koji koristi dve osnovne boje kao ulaz i odreduje koja se boja dobija kada se one pomeaju. Na
primer meanjem crvene i ute dobija se narandasta. Najvei deo problema u ovom sluaju
moe da se rei definisanjem odgovarajuih strukturnih tipova podataka. Reenje se moe lako
pratiti:
Primer. Indeksiranje pomou tipa nabrajanja.
type BOJA is
(crvena,zuta, p l a v a , zelena, l j u b i c a s t a , narandzasta );
subtype OSNOVNE is BOJE range c rv en a ..p l a v a ;
MIX : a r r a y ( O S N O V N E , O S N O V N E ) of BOJE :=
-- crvena
-- zuta
-- plava
( ( c r v e n a , narandzasta, l j u b i c a s t a ) ,
-- c r v e n a ;
( n a r a n z a s t a , zuta,z e l e n a ) ,
-zuta;
( l j u b i c a s t a , zelena,p l a v a ) )
-- plava;

Za indeksiranje dvodimenzionalne strukture u ovom primeru koristi se podtip OSNOVNE,


dok su vrednosti elemenata strukture definisane tipom BOJE. Npr., vrednost elementa MIX(crvena,
zut a) je narandzasta.

8.5.1. Viedimenzionalni nizovi u C


Jednim parom zagrada definiu se jednodimenzionalni nizovi. Svaki par zagrada definie
jednu dimenziju niza. Na primer, sledee deklaracije su korektne:
int a[100]; int b[3][5]; int c[7][9][2];
k-dimenzionalni niz poseduje veliinu svake od svojih k dimenzija.
Primer. Zadavanje elemenata matrice na mestu njene deklaracije.
#include <stdio.h>
main()
{ int i,j,a[2]={1,2}, b[2][3]=45,67,88},{67,777,54, s=0;
for(i=0;i<2;++i) s+=a[i];
printf("\nSuma elemenata niza je:%d\n",s);
for(i=0;i<2;i++)
for(j=0;j<3;j++)
printf("b[%d%d]=%d\n",i,j,b[i][j]);
}

Predrag S. Stanimirovi

151

Programski jezici

Ako je p dvodimenzionalni niz, moe se deklarisati pomou **p. Neka je mat[][7]


dvodimenzionalni niz. Tada je
mat[i][j]=*(mat[i]+j)=(*(mat+i))[j]=*(mat+i*7+j)= *(&mat[0][0]+i*7+j)= *((*(mat+i))+j).
U gornjim primerima zagrade su neophodne zbog toga to operator selekcije ima vii prioritet u
odnosu na operator indirekcije.
Primer. Napisati potprogram koji pronalazi minimalni element niza i njegov indeks. U
glavnom programu uitati matricu mn i uz pomo formiranog potprograma nai minimalni
element u matrici i njegove indekse.
#include <stdio.h>
void minunizu(int a[], int n, int *mn, int *k)
{ int i;
*k=0; *mn=a[0];
for(i=1; i<n; i++)if(a[i]<*mn)
{ *k=i; *mn=a[i]; }
}
void main()
{ int m,n,i,j, min, ind;
int a[10][10], b[10], p[10];
printf("Dimenzije matrice?: "); scanf("%d%d", &m,&n);
printf("\nElementi matrice?: ");
for(i=0; i<m; i++)
for(j=0; j<n; j++) scanf("%d", &a[i][j]);
for(i=0; i<m; i++)
minunizu(a[i], n, &b[i], &p[i]);
minunizu(b,m, &min, &ind);
i=ind; j=p[ind];
printf("Minimalni je na poziciji [%d,%d] i jednak je
%d\n",i,j,min);
}

Ovaj zadatak se moe reiti koristei vezu izmeu nizova i pointera.


#include <stdio.h>
void minunizu(int *a, int n, int *mn, int *k)
{ int i;
*k=0; *mn=*a;
for(i=1; i<n; i++)if(*(a+i)<*mn)
{ *k=i; *mn=*(a+i); }
}
void main()
{ int m,n,i,j, min, ind;
int a[10][10], b[10], p[10];
printf("Dimenzije matrice?: "); scanf("%d%d", &m,&n);
printf("\nElementi matrice?: ");
for(i=0; i<m; i++)
for(j=0; j<n; j++) scanf("%d", &a[i][j]);
for(i=1; i<m; i++)
minunizu(a[i], n, b+i, p+i);
minunizu(b,m, &min, &ind);
i=ind; j=p[ind];
printf("Minimalni je na poziciji [%d,%d] i jednak je %d\n",
i,j,min);
}

152

Primer. Konstruisati magini kvadrat dimenzija nn, za n-neparno. Magini kvadrat se sastoji
od brojeva rasporeenih u tabelu koja ima isti broj vrsta i kolona. Broj vrsta, odnosno kolona,
naziva se redom kvadrata. Prirodni brojevi su rasporeeni tako da je njihov zbir u svakoj vrsti,
koloni i svakoj dijagonali jednak.
void main()
{ int i,j,k,n, mag[29][29];
printf("Dimenzije kvadrata? ");
scanf("%d", &n);
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
mag[i][j]=0;
i=1; j=(n+1)/2; k=1;
while(k<=n*n)
{ mag[i][j]=k++;
if(i==1 && j==1) i++;
else if(i==1)
{ i=n; j--; }
else if(j==1)
{ j=n; i--; }
else if(mag[i-1][j-1]!=0) i++;
else { i--; j--; }
}
for(i=1; i<=n; i++)
{ for(j=1; j<=n; j++) printf("%4d",mag[i][j]); printf("\n"); }
}

Primer. Data je celobrojna matrica A reda nn, gde je n neparan broj. Matrica A predstavlja
magini kvadrat sa jednim pogrenim brojem. Napisati program koji pronalazi greku, ispravlja
je, tampa odgovarajuu poruku i ispravljeni magini kvadrat.
void main()
{ int i,j,n, ik,iv, s1,s2,s3,s,suma, mag[29][29];
printf("Dimenzije kvadrata? ");
scanf("%d", &n);
printf("Zadati magicni kvadrat sa jednom greskom\n");
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
scanf("%d", &mag[i][j]);
s1=s2=s3=0;
for(j=1; j<=n; j++)
{ s1 += mag[1][j]; s2 += mag[2][j]; s3 += mag[3][j]; }
if(s1==s2 || s1==s3) suma=s1;
else suma=s2;
i=0;
do { i++; s=0;
for(j=1; j<=n; j++)s+=mag[i][j];
}
while(s==suma);
iv=i;
j=0;
do {j++; s=0; for(i=1; i<=n; i++)s+=mag[i][j];} while(s==suma);
ik=j;
printf("Greska je u vrsti %d i koloni %d\n",iv,ik);
printf("Pogresna vrednost je %d\n",mag[iv][ik]);
printf("Pravilna vrednost je %d\n",mag[iv][ik]+suma-s);
mag[iv][ik]=mag[iv][ik]+suma-s;
printf("Pravilni magicni kvadrat je:\n");
for(i=1; i<=n; i++)
{ for(j=1; j<=n; j++) printf("%4d",mag[i][j]);
printf("\n");
}

Predrag S. Stanimirovi

153

Programski jezici

Primer. Napisati program koji najefikasnijim postupkom izraunava n-ti stepen matrice A. n-ti
stepen se moe izraunati rekurzivno sa najmanjim brojem matrinih mnoenja na sledei
nain:
An =
(Ak)2,
A(Ak)2

A,
n=1
n=2k
, n=2k+1

#include<stdio.h>
void mnozi(int n, int a[10][10], int b[10][10], int c[10][10])
{ int i,j,k;
int s;
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{ s=0;
for(k=0; k<n; k++) s+=a[i][k]*b[k][j];
c[i][j]=s;
}
}
void kopi(int n, int a[10][10], int b[10][10])
{ int i,j;
for(i=0; i<n; i++)
for(j=0; j<n; j++) b[i][j]=a[i][j];
}
void citaj(int n, int a[10][10])
{ int i,j;
printf("Unesi %d*%d elemenata matrice\n", n,n);
for(i=0; i<n; i++)
for(j=0; j<n; j++) scanf("%d",&a[i][j]);
}
void pisi(int n, int a[10][10])
{ int i,j;
for(i=0; i<n; i++)
{ for(j=0; j<n; j++) printf("%d ",a[i][j]);
printf("\n");
}
}
void stepen(int m, int n, int a[10][10], int b[10][10])
{ int c[10][10], p[10][10];
if(m==1) kopi(n,a,b);
else { stepen(m/2,n,a,c);
mnozi(n,c,c,p);
if(m%2==1)mnozi(n,p,a,b);
else kopi(n,p,b);
}
}
void main()
{ int n,m;
int a[10][10], b[10][10];
printf("Red kvadratne matrice = "); scanf("%d", &n);
citaj(n,a);

154

printf("Stepen = "); scanf("%d", &m);


stepen(m,n,a,b); pisi(n,b);

Primer. Invertovanje elemenata niza.


#include<stdio.h>
void ucitaj(int k, float x[])
{ int i;
for(i=0;i<k;i++) scanf("%f",&x[i]);
}
void stampaj(int k, float x[])
{ int i;
for(i=0; i<k; i++) printf("%.6f ",x[i]);
printf("\n");
}
void promeni(int k, float x[])
{ int i;
float pom;
for(i=0;i<k/2;i++)
{ pom=x[i]; x[i]=x[k-i-1]; x[k-i-1]=pom; }
}
void main()
{ void stampaj(int k, float[]);
void ucitaj(int k, float x[]);
void promeni(int k, float x[]);
int n;
float a[50];
printf("Koliko elemenata?\t"); scanf("%d", &n);
printf("Elementi?\n");
ucitaj(n,a);
stampaj(n,a);
promeni(n,a);
}

stampaj(n,a);

#include<stdio.h>
void ucitaj(int k, float *x)
{ int i;
for(i=0;i<k;i++) scanf("%f",x+i);
}
void stampaj(int k, float *x)
{ int i;
for(i=0; i<k; i++) printf("%.6f ",*(x+i));
printf("\n");
}
void promeni(int k, float *x)
{ int i;
float pom;
for(i=0;i<k/2;i++)
{ pom=*(x+i); *(x+i)=*(x+k-i-1); *(x+k-i-1)=pom; }
}
void main()
{ void stampaj(int k, float *x);
void ucitaj(int k, float *x);
void promeni(int k, float *x);

Predrag S. Stanimirovi

155

Programski jezici

int n;
float a[50];
printf("Koliko elemenata? "); scanf("%d", &n);
printf("Elementi?\n");
ucitaj(n,a); stampaj(n,a);
promeni(n,a); stampaj(n,a);
}

Primer. Proizvod dve matrice.


program proizvodmatrica;
const
max = 20;
type
matrica = array[1..max]of array[1..max] of real;
var
a, b, c: matrica;
n, m, p: integer;
procedure ucitavanje(var x:matrica; n, m:integer);
var
i, j:integer;
begin
for i := 1 to n do
for j := 1 to m do read(x[i,j])
end;
procedure mnozenje(a,b:matrica; m,k,l:integer; var c:matrica);
var
i,j,r:integer;
begin
writeln('m = ',m,'k = ',k, 'l = ',l);
for i := 1 to m do
for j := 1 to l do
begin
c[i,j] := 0;
for r:=1 to k do c[i,j]:=c[i,j]+a[i,r]*b[r,j];
end
end;
procedure ispis(x:matrica; m, n:integer);
var
i,j:integer;
begin
for i := 1 to m do
begin for j := 1 to n do
write(' ', x[i][j]);
writeln
end
end;
begin {program}
(* ucitavanje dimenzija matrica *)
write('n = ? '); readln(n);
write('m = ? '); readln(m);
write('p = ? '); readln(p);
(* ucitavanje matrica *)
writeln('Zadajte matricu a');
ucitavanje(a, n, m);

156
writeln('Zadajte matricu b');

ucitavanje(b, m, p);

(* izracunavanje proizvoda ucitanih matrica *)


mnozenje(a,b, n, m, p, c);
writeln(' Proizvod unetih matrica je matrica : ');
writeln;
ispis(c, n, p);
end.

Primer. Napisati program kojim se razmenjuju vrsta koja sadri element najvee vrednosti i
vrsta koja sadri element najmanje vrednosti.
program razmenavrsta;
type opseg=1..10;
niz = array[opseg] of integer;
matrica=array[opseg] of niz;
var m,n,l,s:opseg;
a:matrica;
c:niz;
procedure citaj(m,n:opseg; var x:matrica);
var i,j:opseg;
begin
for i:=1 to m do
begin
for j:=1 to n do read(x[i][j]);
readln;
end
end;
procedure pisi(m,n:opseg; x:matrica);
var i,j:opseg;
begin
for i:=1 to m do
begin
for j:=1 to n do write(x[i][j],' ');
writeln;
end
end;
procedure razmenivrste(var a,b:niz);
var p:niz;
begin
p:=a; a:=b; b:=p;
end;
function indminmax(m,n,p:integer; a:matrica):integer;
var i,j,k:integer;
minmax:real;
begin
k:=1; minmax:=a[1][1];
for i:=1 to m do
for j:=1 to n do
if p*a[i][j]<p*minmax then
begin
minmax:=a[i][j]; k:=i;
end;
indminmax:=k;
end;
begin
writeln;

Predrag S. Stanimirovi

157

Programski jezici

readln(m,n); citaj(m,n,a);
l:=indminmax(m,n,1,a); s:=indminmax(m,n,-1,a);
if l<>s then razmenivrste(a[l],a[s]);
pisi(m,n,a);
end.

Primer. Napisati program koji formira magini kvadrat reda n (n je neparan broj). Magini
kvadrat se sastoji od prirodnih brojeva rasporeenih u tabelu koja ima isti broj vrsta i kolona.
Broj vrsta (odnosno kolona) predstavlja red kvadrata. Brojevi su rasporeeni tako da je njihov
zbir u svakoj vrsti, koloni i svakoj dijagonali jednak.
Na primer, magini kvadrat reda 3 izgleda ovako:
6 1 8
7 5 3
2 9 4.
program magic;
uses crt;
type mat=array[1..39,1..39] of integer;
var mag : mat;
i,j,k,n:integer;
begin
writeln(' Unesite dimenzije '); readln(n);
for i:=1 to n do
for j:=1 to n do mag[i,j]:=0;
i:=1; j:= (n+1) div 2; k:=1;
while k<= n*n do
begin
mag[i,j]:=k;
k:=k+1;
if (i=1) and (j=1) then i:=i+1
else if i=1 then
begin
i:=n; j:=j-1
end
else if j=1 then
begin
j:=n; i:= i-1
end
else if mag[i-1,j-1]<>0 then i:=i+1
else begin
i:=i-1; j:=j-1
end
end;
writeln; clrscr;
for i:=1 to n do
begin
for j:= 1 to n do write(mag[i,j]:4); writeln
end
end.

Primer. Data je matrica A dimenzija nn. Napisati program kojim se formira niz d[1],d[2], ,
d[n], u kome je d[1] suma elemenata na glavnoj dijagonali matrice, d[2] suma elemenata na
prvoj dijagonalnoj paraleli donjeg trougla matrice, d[3] suma elemenata na drugoj dijagonalnoj
paraleli, itd.
program paralele;
type opseg=1..10;
niz=array[opseg] of real;
matrica=array[opseg,opseg] of real;
var i,n:opseg;
a:matrica;
d:niz;
procedure ucitaj(n:opseg; var x:matrica);
var i,j:opseg;

158
begin
for i:=1 to n do
begin
writeln('Elementi ',i,' te vrste?');
for j:=1 to n do read(a[i,j]);
readln;
end;
end;
procedure paral(n:opseg; x:matrica; var d:niz);
var i,j:opseg;
begin
for i:=1 to n do
begin
d[i]:=0;
for j:= i to n do d[i]:=d[i]+a[j,j-i+1];
end;
end;
begin
write(' Dimenzije? '); readln(n);
ucitaj(n,a);
writeln;
paral(n,a,d);
for i:=1 to n do
writeln(' suma elemenata na ',i-1,'. dijagonalnoj paraleli je',
d[i]:0:6);
end.

Primer. Svaki element matrice koji predstavlja maksimum svoje vrste i minimum svoje kolone
naziva se sedlasta taka. Pronai sve sedlatse take u zadatoj matrici.
#define MAXX 100
#define MAXY 100
#include<stdio.h>
#include<conio.h>
#include<limits.h>
#include<stdlib.h>
int a[MAXX][MAXY], mini[MAXX], maxi[MAXY],m,n;
void main()
{ int i,j;
clrscr();
printf("Dimenzije matrice? "); scanf("%d%d",&m,&n);
printf("Elementi?\n");
for(i=0;i<m;i++)
for(j=0;j<n;j++) scanf("%d", &a[i][j]);
for(i=0;i<m;i++)maxi[i]=maximum(i);
for(j=0;j<n;j++)mini[j]=minimum(j);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
if(maxi[i]==a[i][j] && mini[j]==a[i][j])
printf("a[%d]
[%d]=%d ",i,j,a[i][j]);
}
int minimum(int kol)
{ int i,rez=INT_MAX;
for(i=0;i<m;i++) rez=min(rez,a[i][kol]);
return(rez);
}
int maximum(int vrs)
{ int j,rez=INT_MIN;

Predrag S. Stanimirovi

159

Programski jezici

for(j=0;j<n;j++) rez=max(rez,a[vrs][j]);
return(rez);

Primer. Data je matrica Amn celih brojeva. Element a[i,j] je vrh, ako je vei od svojih susednih
elemenata koji su iznad, ispod, sa leve i sa desne strane. Visina vrha je razlika izmeu elementa
i njegovog najvieg suseda. Napisati program koji e formirati niz vrhova sortiran u nerastui
redosled po visini.
#include<stdio.h>
int vrh(int i, int j, int m, int n, int a[10][10])
{ if(i==0 && j==0)
return(a[i][j]>a[i][j+1] && a[i][j]>a[i+1][j]);
else if(i==m-1 && j==n-1)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1]);
else if(i==0 && j==n-1)
return(a[i][j]>a[i][j-1] && a[i][j]>a[i+1][j]);
else if(i==m-1 && j==0)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j+1]);
else if(i==0)
return(a[i][j]>a[i][j-1] &&
a[i][j]>a[i+1][j] && a[i][j]>a[i][j+1]);
else if(j==0)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j+1]&&
a[i][j]>a[i+1][j]);
else if(i==m-1)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1] &&
a[i][j]>a[i][j+1]);
else if(j==n-1)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1] &&
a[i][j]>a[i+1][j]);
else return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1] &&
a[i][j]>a[i+1][j] && a[i][j]>a[i][j+1]);
}
int min2(int x, int y)
{if(x<y) return(x); else return(y); }
int min3(int x, int y, int z)
{ int min;
min=x;
if(y<min) min=y;
if(z<min) min=z;
return(min);
}
int min4(int x, int y, int z, int w)
{ int min;
min=x;
if(y<min) min=y;
if(z<min) min=z;
if(w<min)min=w;
return(min);
}
int visina(int i, int j, int m, int n, int a[10][10])
{ int min2(int,int);
int min3(int,int,int);

160
int min4(int,int,int,int);
if(i==0 && j==0)
return(min2(a[i][j]-a[i][j+1],a[i][j]-a[i+1][j]));
else if(i==m-1 && j==n-1)
return(min2(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1]));
else if(i==0 && j==n-1)
return(min2(a[i][j]-a[i][j-1],a[i][j]-a[i+1][j]));
else if(i==m-1 && j==0)
return(min2(a[i][j]-a[i-1][j],a[i][j]-a[i][j+1]));
else if(i==0)
return(min3(a[i][j]-a[i][j-1],a[i][j]-a[i+1][j],
a[i][j]-a[i][j+1]));
else if(j==0)
return(min3(a[i][j]-a[i-1][j],a[i][j]-a[i][j+1],
a[i][j]-a[i+1][j]));
else if(i==m-1)
return(min3(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1],
a[i][j]-a[i][j+1]));
else if(j==n-1)
return(min3(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1],
a[i][j]-a[i+1][j]));
else return(min4(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1],
a[i][j]-a[i+1][j],a[i][j]-a[i][j+1]));
}
void main()
{ int vrh(int i, int j, int m, int n, int a[10][10]);
int visina(int i, int j, int m, int n, int a[10][10]);
int i,j,a[10][10], vrhovi[25],visine[25], pom,k=0,m,n;
scanf("%d%d", &m,&n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
if(vrh(i,j,m,n,a))
{ vrhovi[k]=a[i][j]; visine[k]=visina(i,j,m,n,a); k++;}
for(i=0;i<k-1;i++)
for(j=i+1;j<k;j++)
if(visine[i]<visine[j])
{ pom=visine[i]; visine[i]=visine[j]; visine[j]=pom;
pom=vrhovi[i]; vrhovi[i]=vrhovi[j]; vrhovi[j]=pom;
}
printf("\nNiz vrhova i visina:\n");
for(i=0;i<k;i++)
printf("Vrh: %d visina: %d\n",vrhovi[i], visine[i]);
}

8.5.2. Pokazivai i viedimenzionalni nizovi u C


Dvodimenzionalni nizovi (matrice) se u memoriji registruju po vrstama, koristei uzastopne
memorijske lokacije. Na primer, dvodimenzionalni niz int a[3][2] se u memoriji rasporeuje u
sledeem poretku:
a[0][0], a[0][1], a[1][0], a[1][1], a[2][0], a[2][1] .
Ako se deklarie pokaziva p pomou
int *p

Predrag S. Stanimirovi

161

Programski jezici

posle dodele p=a pointer p uzima za svoju vrednost adresu elementa koji lei u nultoj vrsti i
nultoj koloni matrice a (tj. adresu prvog elementa matrice a). Takoe, vae sledee pointerske
jednakosti:
p=&a[0][0], p+1=&a[0][1], p+2=&a[1][0],p+3 =&a[1][1], p+4=&a[2][0], p+5=&a[2][1].
Dvodimenzionalni nizovi jesu jednodimenzionalni nizovi jednodimenzionalnih nizova. Na
primer, ako je r ime dvodimenzionalnog niza, tada je r[i] jednodimenzionalni niz koji sadri
elemente i-te vrste matrice r.
U naem sluaju, vrste matrice a date su izrazima a[0], a[1] i a[2]. S obzirom na poznata
svojstva jednodimenzionalnih nizova, vae sledee jednakosti:
a[0]=&a[0][0], a[1]=&a[1][0], a[2]=&a[2][0] .
Takoe je
a[j][k]=*(a+j*duzina_vrste +k).

8.6. Zapisi
Zapisi (slogovi) su strukture podataka koje se, za razliku od polja, sastoje od komponenti
(segmenata) razliitog tipa. Zapisi se u programu definiu preko eksplicitnih definicija
odgovarajuih strukturnih tipova podataka ili preko anonimnih opisa tipova. Sledei primer
ilustruje eksplicitne definicije strukturnog tipa podataka koji obuhvata zapise:
type datum is record
mesec : (j a n , f e b , m a r , a p r , m a j ,jun,jul, a v g , s e p , o k t , n o v , d e c ) ;
dan : integer range 1 . . 3 1 ;
godina : integer range 1 9 0 0 . . 2 1 0 0 ;
end record;

U ovom primeru definisan je strukturni tip DATUM koji moe da se koristi za definisanje
konkretnih zapisa u programu, npr:
d a n a s , sutra : D A T U M ;

Pojedinim komponentama ovako definisanih struktura podataka moe se pristupati preko


selektora koji se formira od imena same strukture (ne strukturnog tipa), take i imena
komponete. Npr:
danas.mesec := dec;
sutra. dan := 1 4 ;
danas.dan := sutra.dan;

U svim jezicima u kojima se mogu definisati zapisi, obino postoji i mogunost da se dodeli
vrednost odjednom celom zapisu. Na primer
danas := (dec, 1 3 , 1 9 9 4 ) ;
-- O va ko je u mnogim je z i ci ma
danas := DATUM(dec, 13, 1 9 9 4 ) ;
-- Ovako je u jeziku Pascal
danas := (mesec => dec, god => 1 9 9 4 , dan => 1 3 ) ;
-- U Adi

Jednom definisani strukturni tipovi mogu da se koriste za definisanje novih strukturnih


tipova. Npr. moe se definisati strukturni tip koji obuhvata polja zapisa:
type p r a z n i k is array ( 1 . . 1 0 ) of DATUM;
Raspust : PRAZNIK;
Ra sp us t( 1) := ( 2 3 , dec, 1 9 1 4 ) ;

Takoe se preko ve definisanih zapisa mogu definisati novi zapisi:

162
type OSOBA is
record
Ime : String(1.. 1 0 ) ;
Prezime : String(1..1 5 ) ;
Dan_rodj : DATUM;
end record;
Student, Ja, Ti : OSOBA;
Student := ("Ana", "Petrovic", ( 1 4 , m a j , 1 9 7 0 ) ) ;
Ja.Dan_rodj .godina := 1 9 5 3 ;

Primer . Zapis sa varijantama.


type
VrstaInstrumenta = (zicani,duvacki);
TipInstrumenta = (u da rn i, gudacki);
TipMaterijala = ( m e t a l , d r v o ) ;
Instrument =
record
case Vrsta:VrstaInstrumenta of
zicani:
(case T i p : TipInstrumenta of
udarni :
(case k l a v i j a t u r a : Boolean of
false : (dijapazon : r e a l ) ;
true : (dirki : 1..100);
);
gudacki :
(
raspon : ( k b a s , c e l o , v i o l a , v i o l i n a )
);
duvacki:
(
case Materijal : TipMaterijala of
metal : (nacinsv : ( k l a v , pokret));
drvo : (pisak : (jednodelni, dvodelni)
);
end;

Primer. Osnovne operacije sa kompleksnim brojevima.


program kracun;
type
complex = record
re, im:real;
end;
var
a, b, c, d, e, f, g, h, i:complex;
rl:real;
procedure sabiranje (x, y:complex; var z:complex);
begin
z.re := x.re + y.re;
z.im := x.im + y.im;
end;
procedure oduzimanje(x,y:complex; var z:complex);
begin
z.re := x.re - y.re;
z.im := x.im - y.im;
end;
procedure mnozenje(x,y:complex; var z:complex);
begin
z.re := x.re*y.re - x.im*y.im;
z.im := x.re*y.im + x.im*y.re;

Predrag S. Stanimirovi

163

Programski jezici

end;
procedure conjug(x:complex; var y:complex);
begin
y.re := x.re; y.im := -x.im;
end;
function moduo(c:complex):real;
begin
moduo := sqrt( sqr(c.re) + sqr(c.im) );
end;
procedure deljenje(x,y:complex; var z:complex);
var
c:complex;
r:real;
begin
conjug(y, c);
mnozenje(x, c, z);
r := sqr(y.re) + sqr(y.im);
z.re := z.re/r;
z.im := z.im/r;
end;
procedure ucitaj(var c:complex);
begin
write(' Realni deo = ? '); read(c.re);
write(' Imainarni deo = ? '); readln(c.im);
end;
procedure stampaj(c:complex);
begin
write(' (', c.re, '.', c.im, ' ) ');
end;
begin
ucitaj(a); ucitaj(b); ucitaj(c);
sabiranje(a, b, d); oduzimanje(a, c, e);
sabiranje(b, c, f); deljenje(d, e, g);
mnozenje(g, f, h); writeln; writeln;
write(' (a+b)/(a-c)*(b+c) = '); stampaj(h); writeln; writeln;
rl:= moduo(d);
e.re := e.re*rl; e.im := e.im*rl;
write(' |a+b|*(a-c) = '); stampaj(e); writeln; writeln;
end.

Primer. Definisan je tip


const max=50;
type polinom = record
red:0..max;
koef:array[0..max] of real;
end;
koji predstavlja unutranju formu polinoma. Napisati procedure za uitavanje, ispis polinoma,
kao i procedure za zbir, razliku i proizvod dva polinoma. U glavnom programu testirati napisane
procedure.
program polinomi;
const
max = 50;
type
polinom = record
red : 0..max;

164

var

koef : array[0..max] of real;


end;
a, b, c, d:polinom;

procedure ucitavanje(var x:polinom);


var
i : integer;
begin
write('red = ? '); read(x.red);
write('Koeficijenti = ? ');
for i := 0 to x.red do read(x.koef[i]);
end;
procedure zbir(a,b:polinom; var c:polinom);
var
i : integer;
begin
if a.red > b.red then
begin
c.red := a.red;
for i := 0 to b.red do
c.koef[i] := a.koef[i] + b.koef[i];
for i := b.red+1 to a.red do
c.koef[i] := a.koef[i];
end
else begin
c.red := b.red;
for i := 0 to a.red do
c.koef[i] := a.koef[i] + b.koef[i];
for i := b.red+1 to a.red do
c.koef[i] := b.koef[i];
end;
end;
procedure proizvod(a, b:polinom; var c:polinom);
var
i,j:integer;
begin
c.red := a.red + b.red;
for i := 0 to c.red do c.koef[i] := 0;
for i := 0 to a.red do
for j := 0 to b.red do
c.koef[i+j] := c.koef[i+j] + a.koef[i]*b.koef[j];
end;
procedure stampanje(x:polinom);
var
i : integer;
begin
write(x.koef[x.red]:8:2, '*x**', x.red);
for i := x.red-1 downto 1 do
write('+',x.koef[i]:8:2, '*x**', i);
write(x.koef[0]:8:2);
end;
begin
writeln('Zadati prvi polinom '); ucitavanje(a);
writeln('Zadati drugi polinom '); ucitavanje(b);

Predrag S. Stanimirovi

165

Programski jezici

zbir(a, b, c);
proizvod(a, b, d);
writeln;
writeln(' Zbir unetih polinoma je : '); stampanje(c);
writeln;
writeln(' Proizvod unetih polinoma je : '); stampanje(d);
writeln; writeln;
end.

Primer. Napisati program za ureivanje uenika jednog odeljenja prema proseku ocena. Ako
vie uenika ima isti prosek urediti ih alfabetski.
program ucenici;
const
numpred = 6;
numuc = 3;
type
ucenik = record
ime : string[30];
uspeh :array[1..numpred] of 1..5;
end;
var
razred :array[1..numuc] of ucenik;
procedure citanje;
var
i,j : integer;
begin
writeln(' Uneti ', numuc, ' imena i ocene iz ', numpred,'
predmeta ');
for i := 1 to numuc do
begin
readln(razred[i].ime);
for j := 1 to numpred do read(razred[i].uspeh[j]);
readln;
end;
end;
procedure pisanje;
var
i,j:integer;
begin
writeln;
for i := 1 to numuc do
begin
write(razred[i].ime,' ');
for j := 1 to numpred do write(razred[i].uspeh[j] :3);
writeln;
end;
end;
function prosek(i:integer):real;
var
j : integer;
r : real;
begin
r := 0;
for j := 1 to numpred do
r := r + razred[i].uspeh[j];

166
r := r/numpred;
prosek := r;
end;
function inverzija(i,j:integer):boolean;
begin
inverzija := (prosek(i) < prosek(j) ) or
(prosek(i) = prosek(j) ) and (razred[i].ime >
razred[j].ime);
end;
procedure ureenje;
var
i,j:integer;
pomuc:ucenik;
begin
for i := 1 to numuc-1 do
for j := i+1 to numuc do
if inverzija(i,j) then
begin
pomuc:=razred[i]; razred[i]:=razred[j];
razred[j]:= pomuc;
end;
end;
begin
citanje;
end.

ureenje;

pisanje;

Primer. Data je realna matrica X dimenzije mn i celi brojevi Ip i Jp, (1=Ip<= m,1<= Jp<= n).
Svakom elementu matrice pridruuje se jedno polje na tano odreen nain. Polje je odreeno
sa tri elementa: koordinatama (i,j) i realnim brojem koji predstavlja njegovu visinu. Broj X[i,j]
odreuje visinu polja sa koordinatama (i,j). U polju sa koordinatama (I p, Jp) nalazi se loptica.
Loptica prelazi sa polja A na polje B ako vae sledei uslovi:
- polja A i B su susedna, to znai da imaju zajedniku strinicu;
- visina polja B je strogo manja od visine polja A, i
- polje B ima najmanju visinu u odnosu na sva polja koja su sesedna u
odnosu na A.
Loptica se zaustavlja u polju u odnosu na koje ne postoji polje na koje moe da pree. Takvo
polje se naziva zvrno. Odrediti polje na kome e se loptica zaustaviti kao i put od poetnog
polja (Ip, Jp) do zavrnog.
program loptica;
uses crt;
type matrica = array[1..50,1..50] of real;
koordinate =1..50;
polje=record
i,j:koordinate;
visina:real;
end;
var x:matrica;
a,b:polje;
i,j,m,n:koordinate;
kraj:boolean;
procedure najnize_susedno(p:polje; mat:matrica; var najnize:polje);

Predrag S. Stanimirovi

167

Programski jezici

begin
najnize:=p;
if(p.i-1 in [1..m]) and (p.j in [1..n]) and
(mat[p.i-1,p.j]<najnize.visina) then
begin
najnize.visina:=mat[p.i-1,p.j];
najnize.i:=p.i-1;
najnize.j:=p.j;
end;
if(p.i+1 in [1..m]) and (p.j in [1..n]) and
(mat[p.i+1,p.j]<najnize.visina) then
begin
najnize.visina:=mat[p.i+1,p.j];
najnize.i:=p.i+1;
najnize.j:=p.j;
end;
if(p.i in [1..m]) and (p.j-1 in [1..n]) and
(mat[p.i,p.j-1]<najnize.visina) then
begin
najnize.visina:=mat[p.i,p.j-1];
najnize.i:=p.i; najnize.j:=p.j-1;
end;
if(p.i in [1..m]) and (p.j+1 in [1..n]) and
(mat[p.i,p.j+1]<najnize.visina) then
begin
najnize.visina:=mat[p.i,p.j+1];
najnize.i:=p.i;
najnize.j:=p.j+1;
end;
end;
begin
clrscr;
write('m = ? '); readln(m);
write('n = ? '); readln(n);
for i:=1 to m do
begin
for j:=1 to n do read(x[i,j]);
readln;
end;
writeln('Unesi koordinate loptice ');
write('Ip = ? '); readln(a.i);
write('Jp = ? '); readln(a.j);
a.visina:=x[a.i,a.j];
writeln; writeln('Loptica prelazi sledeci put:');
kraj:=false;
repeat
najnize_susedno(a,x,b);
if b.visina<a.visina then
begin
writeln(' polje sa koordinatama [',a.i,',',a.j,']', ' i
visinom ',x[a.i,a.j]:10:5,';');
a:=b;
end
else begin
writeln('i zaustavlja se u polju sa koordinatama
[',a.i,',',a.j,'] i visinom '
,x[a.i,a.j]:10:5,';');
kraj:=true;
end;
until kraj;
repeat until keypressed;
end.

168
Primer. Ako su dati kompleksan broj z i realan broj e>0 napisati program koji sa zadatom
tanou izraunava vrednost kompleksne funkcije
z z2
zn
ez=1+
...
...
1!
2!
n!
{$N+}
program kracun;
type
complex = record
re, im:double;
end;
var
z,rez:complex;
eps:double;
procedure sabiranje (x, y:complex; var z:complex);
begin
z.re := x.re + y.re;
z.im := x.im + y.im;
end;
procedure mnozenje(x,y:complex; var z:complex);
begin
z.re := x.re*y.re - x.im*y.im;
z.im := x.re*y.im + x.im*y.re;
end;
function moduo(c:complex):double;
begin
moduo := sqrt( sqr(c.re) + sqr(c.im) );
end;
procedure ucitaj(var c:complex);
begin
writeln;
write(' Realni deo = ? '); read(c.re);
write(' Imainarni deo = ? '); readln(c.im);
end;
procedure stampaj(c:complex);
begin
write(' (', c.re:22:14, '.', c.im:22:14, ' ) ');
end;
procedure compexp(z:complex; eps:double; var ez:complex);
var n:integer;
clan:complex;
begin
clan.re:=1; clan.im:=0; ez:=clan;
n:=0;
while moduo(clan)>=eps do
begin
n:=n+1;
z.re:=z.re/n; z.im:=z.im/n;
mnozenje(clan,z,clan);
sabiranje(ez,clan,ez);
end;
end;
begin
ucitaj(z); write(' Tacnost= '); readln(eps);
compexp(z,eps,rez); stampaj(rez);

Predrag S. Stanimirovi

169

Programski jezici

end.

8.7. Strukture i nabrojivi tipovi u c


8.7.1. lanovi strukture
Strukture dozvoljavaju da se razliite komponente ujedine u pojedinanu strukturu.
Komponente strukture su takoe imenovane i nazivaju se lanovi (odnosno elementi ili polja).
Elementi struktura su razliitih tipova generalno, i mogu se prilagoavati problemu. Strukture se
definiu pomou kljune rei struct. U najoptijem obliku, strukture se opisuju na sledei nain:
struct [oznaka]
{ tip ime_elementa1;
tip ime_elementa2;

};
Rezervisana re struct slui kao informacija kompajleru da neposredno iza nje sledi opis neke
strukture. Zatim sledi neobavezni identifikator oznaka, koji predstavlja ime strukture. Ime
dodeljeno strukturi se moe kasnije koristiti pri deklaraciji promenljivih strukturnog tipa. Iza
imena strukture, izmeu velikih zagrada, deklariu se pojedini delovi strukture. Elementi
strukture mogu biti proizvoljnih tipova, pa i nove strukture. Iza poslednje zagrade pie se znak
';'.
Primer. Sledeom strukturom opisani su osnovni podaci o studentu:
ime, broj indeksa i upisana godina.
struct student { char *ime;
int indeks;
int godina;
} s1,s2,s3;
Ovim se s1,s2,s3 deklariu kao promenljive koje mogu da sadre konkretne vrednosti
saglasno tipu student, tj. podatke o studentima. Svaki slog o studentu sadri tri komponente:
ime, indeks i godina studija.
Struktura moe da se koristi kao ablon za deklaraciju tipova podataka. Na primer, neka je
deklarisana struktura student na sledei nain:
struct student { char *ime;
int indeks;
int godina;
};
Sada se mogu deklarisati strukturne promenljive strukturnog tipa struct student. Na primer,
moemo pisati
struct student pom, razred[100];
Tek posle ovakvih deklaracija se alocira memorija za promenljivu pom i niz razred.
Objedinjavanje opisa strukture ije je ime izostavljeno sa deklaracijama promenljivih koristi
se kada se ablon strukture ne koristi na drugim mestima u programu. Na primer, moemo pisati
struct

170
{ char *ime;
int indeks;
int godina;
} s1,s2,s3;
Strukturna promenljiva se moe inicijalizovati na mestu svoje deklaracije:
static struct student pom= { "Milan", 1799, 3 };
lanovima strukture se direktno pristupa pomou operatora '.'.
Na primer, vrednosti lanovima strukture student mogu se dodeljivati na sledei nain:
pom.ime= "Milan";
pom.indeks= 1799;
pom.godina= 3;
String "milan" se moe dodeliti kao vrednost polja pom.ime i na sledei nain:
strcpy(pom.ime, "Milan");
Takoe, lanovima strukture se mogu zadati eljene vrednosti pomou funkcija scanf() i gets():
gets(pom.ime);
scanf("%d",&pom.indeks);
scanf("%d",&pom.godina); }
Ako se opis strukture navede van svih funkcija, ta struktura se moe koristiti u svim funkcijama
koje su definisane posle opisa strukture. Uobiajeno je da se definicija strukture navede na
poetku izvornog programa, pre opisa promenljivih i funkcija. U velikim programima opisi
struktura se obino piu u posebnom fajlu.
Primer. Prebrojati studente tree godine.
Moe se prvo napisati fajl cl.h:
#define N 10
struct student { char *ime;
int indeks;
int godina;
};

Ovaj header fajl moe se koristiti kao informacija u modulima koje ine program.
#include "cl.h"
main()
{ struct student s[10];
int i;
for(i=0; i<N; i++)
{ printf("%d ti student : ",i);
scanf("%s", s[i].ime); scanf("%d", &s[i].indeks);
scanf("%d", &s[i].godina);
}
printf(" Studenata trece godine ima %d\n", fail(s));
}
fail(struct student class[])
{ int i, cnt=0;
for (i=0; i<N; ++i)
cnt +=class[i].godina==3;
return(cnt);

Predrag S. Stanimirovi

171

Programski jezici

Primer. Deklaracija strukture datum i inicijalizacija strukturne (i statike) promenljive danas.


static struct datum
{ int dan;
int mesec;
int godina;
} danas={9, 4, 1996};
Primer. Program za korekciju tekueg vremena.
void main( )
{ struct vreme
{ int sat;
int minut;
int sekund;
} tekuce,naredno;
printf("Unesi tekuce vreme [cc:mm:ss]:");
scanf("%d%d%d",&tekuce.sat,&tekuce.minut,&tekuce.sekund);
naredno=tekuce;
if (++naredno.sekund==60)
{ naredno.sekund=0;
if(++naredno.minut==60)
{ naredno.minut=0;
if(++naredno.sat==24) naredno.sat=0;
}
}
printf("Naredno vreme: %d:%d:%d\n", naredno.sat,
naredno.minut, naredno.sekund);
}

8.7.2 Strukturni tipovi podataka i pokazivai


Mogu se definisati pokazivake promenljive koje e pokazivati na strukturne promenljive.
Vrednosti ovakvih pokazivakih promenljivih jesu adrese strukturnih promenljivih na koje
pokazuju.
Na primer, za definisani strukturni tip podataka student moe se definisati pokazivaka
promenljiva pstudent:
struct student *pstudent;

Sada se elementima strukture student moe pristupiti koristei operator indirekcije '*' i
operator '.':
(*pstudent).ime
(*pstudent).indeks
(*pstudent).godina

U cilju pristupa elementima strukturne promenljive pomou pokazivaa na tu promenljivu


uveden je operator ``strelica u desno'' ->. Generalno pravilo je sledee:
Ako je pokazivakoj promenljivoj pointer_strukture dodeljena adresa neke strukture, tada je
izraz
pointer_strukture ->ime_lana

ekvivalentan izrazu
(*pointer_strukture).ime_lana

172
U poslednjem izrazu zagrade nisu neophodne.
Operatori -> i '.' imaju asocijativnost sleva udesno.
Na primer elementima strukture pstudent pristupa se na sledei nain:
pstudent->ime
pstudent->indeks
pstudent->godina

Sve eksterne i statike promenljive, ukljuujui strukturne promenljive, koje nisu eksplicitno
inicijalizovane, automatski se inicijalizuju na vrednost nula.
Strukture se mogu inicijalizovati od strane programera na mestu svoje deklaracije.
Primer. Primeri inicijalizacije struktura.
struct datum={11, 4, 1996};
struct karta={12, 'f'};
static struct complex
{ double real;
double imag;
} m[3][3]=
{ { {1.0,-0.5}, {2.5,1.0}, {0.7,0.7} },
{ {7.0,-6.5}, {-0.5,1.0}, {45.7,8.0} },
};

Primer. Neka je definisana struktura licnost:


struct licnost
{ char ime[30];
char adresa[50];
unsigned starost;
}

Takoe, neka je definisana pokazivaka promenljiva osoba:


struct licnost *osoba;
Elementima strukture linost, na koju ukazuje promenljiva osoba, moe se pristupiti pomou
operatora indirekcije '*' i operatora '.':
(*osoba).ime
(*osoba).adresa
(*osoba).starost

Takoe, elementima strukturne promenljive na koju ukazuje pointer osoba, moe se pristupiti i
na sledei nain:
osoba->ime
osoba->adresa
osoba->starost

Formalni parametar funkcije moe biti strukturna promenljiva kao i pokaziva na strukturnu
promenljivu. Ukoliko je formalni parametar strukturna promenljiva, tada se kao stvarni
parametar navodi strukturna promenljiva. U pozivu te funkcije, kao stvarni parametar, predaje
se kopija vrednosti te strukturne promenljive. Na taj nain, ne menja se vrednost strukturne
promenljive koja je predata kao stvarni parametar. U sluaju kada je formalni parametar
funkcije pointer na strukturu, tada se kao stvarni parametar predaje adresa strukturne

Predrag S. Stanimirovi

173

Programski jezici

promenljive. Time je omogueno ne samo korienje vrednosti pokazivake promenljive


(pomou operatora indirekcije), ve i promena tih vrednosti.
Takoe, strukture se mogu koristiti kao elementi nizova. Nizovi struktura se deklariu
analogno ostalim nizovima. Na primer, za definisane strukture licnost i student mogu se koristiti
nizovi
struct licnost osobe[20]
struct student studenti[50]

Ovakvim deklaracijama opisan je niz struktura osobe od najvie 20 elemenata, kao i niz
struktura studenti sa najvie 50 elemenata. Svaki element niza osobe predstavlja jednu
strukturnu promenljivu tipa licnost.
Elementi strukture mogu biti nove strukture. Struktura koja sadri bar jedan element
strukturnog tipa naziva se hijerarhijska struktura.
Primer. Definisana je struktura licnost koja sadri element datumroena strukturnog tipa
datum:
struct datum
{ unsigned dan;
unsigned mesec;
unsigned godina;
}
struct licnost
{ char *ime;
datum datumroenja;
}

Strukturna promenljiva danas moe se definisati pomou izraza


struct datum danas;
Pointer p na ovu strukturu deklarie se iskazom
struct datum *p;
Postavljanje pointera p na adresu strukturne promenljive danas ostvaruje se naredbom
p=&danas;

Sada se strukturnoj promenljivoj danas moe pristupiti indirektno, pomou pointera p na jedan
od sledea dva ekvivalentna naina:
(*p).godina=1996; p->godina=1996;
p->mesec=4;
(*p).mesec=4;
p->dan=11;
(*p).dan=11;
Takoe, pointeri mogu biti lanovi strukture.
Primer. Izraz
struct pointeri
{ int *n1;
int *n2;
};

174
definie strukturu pointeri sa dva ukazatelja n1 i n2 na tip int. Sada se moe deklarisati
strukturna promenljiva ukaz:
struct pointeri ukaz;
void main()
{ int i1, i2;
struct { int *n1;
int *n2;
}ukaz;
ukaz.n1=&i1; ukaz.n2=&i2;
*ukaz.n1=111; *ukaz.n2=222;
/* indirektno dodeljivanje vrednosti promenljivim i1, i2 */
printf("i1=%d *ukaz.n1=%d\n", i1, *ukaz.n1);
printf("i2=%d *ukaz.n2=%d\n", i2, *ukaz.n2);
}

8.7.3. Upotreba typedef iskaza u C


Kljuna re typedef dozvoljava dodeljivanje alternativnih imena postojeim tipovima
podataka, kao i definisanje novih tipova podataka.
Primer. Iskazom
typedef int celi;

definie se ime celi kao ekvivalentno kljunoj rei int. Sada se moe pisati
celi i, j, n;

Izraz
typedef double vektor[20];

definie tip vektor kao niz od 20 elemenata tipa double.


Analogno, tip matrica kao dvodimenzionalni niz elemenata tipa double moe se definisati na
sledei nain:
typedef double matrica[10][10];

Nakon ovih definicija tipova se imena vektor i matrica mogu koristiti kao tipovi podataka.
Takoe, mogu se uvesti i strukturni tipovi podataka.
typedef struct
{ int dan;
int mesec;
int godina;
} datum;

Sada se identifikator datum moe koristiti kao samostalan tip podataka. Na primer, iskazom
datum roendan[10];

deklarie se vektor roendan kao jednodimenzionalni vektor sa elementima tipa datum.


Primer. Program za mnoenje matrica.
void main()
{int i, j, k;
typedef double mat[3][3];
static mat
m1={{1.0,2.0,3.0},{4.0,5.0,6.0},{7.0,8.0,9.0,
m2=9.0,8.0,7.0},{6.0,5.0,4.0},{3.0,2.0,1.0}};
mat m3;

Predrag S. Stanimirovi

175

Programski jezici

for (i=0; i<3; ++i)


for (j=0; j<3; ++j)
for (m3[i][j]=0, k=0; k<3; ++k)
m3[i][j]+=m1[i][k]*m2[k][j];
printf("\nProizvod matrica\n");
for (i=0; i<3; ++i)
for (j=0; j<3; ++j)
printf("%15.2f%c",
m3[i][j], (j==2) ? '\n' : ' ');
}

Primer. Ime string kao tip za pokazivae na tip char uvodi se pomou operatora typedef na
sledei nain:
typedef char *string;
Sada je
string str1, str2;
ekvivalentno sa
char *str1, *str2;
Primer. Implementacija osnovnih aritmetikih operacija s kompleksnim brojevima.
#include <stdio.h>
#include <math.h>
/* UVEDENI TIPOVI
*/
struct kom
{
float prvi,drugi;
};
/* NAJAVE FUNKCIJA
*/
void upis(struct kom *p);
void ispis(struct kom p);
struct kom zbir(struct kom p,struct kom q);
struct kom proiz(struct kom p,struct kom q);
void main()
{
struct kom a,b,c;
upis(&a);upis(&b);
c=zbir(a,b);
printf("Njihov zbir je ");ispis(c);
c=proiz(a,b);
printf("Njihov proizvod je ");ispis(c);
}
void upis(struct kom *p) /* Da bi upisani kompleksan broj bio
zapamcen
koriste se pointeri. Prema tome, koriste se oznake
(*p).prvi=p->prvi, (*p).drugi=p->drugi
*/
{
float x,y;
printf(" Daj dva broja :\n");
scanf("%f%f",&x,&y);
p->prvi=x;p->drugi=y;
}
void ispis(struct kom p)
{ printf("\n %f *i+ %f\n",p.prvi,p.drugi); }
struct kom zbir(struct kom p,struct kom q)
/* U C-jeziku vrednost funkcije MOZE DA BUDE struct tipa */
{ struct kom priv;
priv.prvi=p.prvi+q.prvi;priv.drugi=p.drugi+q.drugi;

176
return(priv);
}
struct kom proiz(struct kom p,struct kom q)
{ struct kom priv;
priv.prvi=p.prvi*q.prvi-p.drugi*q.drugi;
priv.drugi=p.prvi*q.drugi+p.drugi*q.prvi;
return(priv);
}
/* Nastavak prethodnog,uz koriscenje typedef
%
Znaci, opet kom. brojevi
*/
#include <stdio.h>
#include <math.h>
typedef struct
{
float prvi,drugi; } kompl;
void upis(kompl *p);
void ispis(kompl p);
kompl zbir(kompl p,kompl q);
kompl proiz(kompl p,kompl q);
void main()
{ kompl a,b,c;
upis(&a); upis(&b); c=zbir(a,b); ispis(c);
c=proiz(a,b); ispis(c);
}
void upis(kompl *p)
{ float x,y;
printf(" Daj dva broja
scanf("%f%f",&x,&y);
p->prvi=x;p->drugi=y;
}

:\n");

void ispis(kompl p)
{ printf("\n %f *i+ %f\n",p.prvi,p.drugi); }
kompl zbir(kompl p,kompl q)
{ kompl priv;
priv.prvi=p.prvi+q.prvi;priv.drugi=p.drugi+q.drugi;
return(priv);
}
kompl proiz(kompl p,kompl q)
{ kompl priv;
priv.prvi=p.prvi*q.prvi-p.drugi*q.drugi;
priv.drugi=p.prvi*q.drugi+p.drugi*q.prvi;
return(priv);
}

8.7.4. Unije
Unija je tip podataka koji moe da sadri (u raznim situacijama) objekte razliitih tipova.
Unije odreuju nain manipulisanja razliitim tipovima podataka u istoj memorijskoj oblasti.
Svrha njihovog postojanja je uteda memorije. One su analogne slogovima promenljivog tipa u
Pascal-u, a sintaksa im je zasnovana na strukturama jezika C. Svrha unije je da postoji samo
jedna promenljiva koja moe da sadri bilo koju od vrednosti razliitih tipova. Unije se
razlikuju od struktura po tome to elementi unije koriste isti memorijski prostor, i to se u
svakom trenutku koristi samo jedan element unije.

Predrag S. Stanimirovi

177

Programski jezici

Primer. Pretpostavimo da u tabeli simbola nekog kompajlera, konstanta moe da bude int, float
ili char. Najvea uteda memorije se postie ako je vrednost ma kog elementa tabele
memorisana na istom mestu, bez obzira na tip. U naem sluaju je potrebna sledea deklaracija
union tag
{ int ival;
float fval;
char *sval;
};
union tag u;

Ekvivalentna deklaracija je data kako sledi:


union tag
{ int ival;
float fval;
char *sval;
} u;

Promenljivoj koja je deklarisana kao unija prevodilac dodeljuje memorijski prostor dovoljan za
memorisanje najveeg od specificiranih lanova unije. Programer mora davodi rauna o tome
koji tip se trenutno memorie u uniji, jer je vaei tip onaj koji je najskorije memorisan.
lanovi unije se selektuju identino lanovima strukture:
unija.clan ili pointer_unije->clan.
Ako je int tip tekueg lana unije u, njegova vrednost se prikazuje izrazom
printf("%d\n",u.ival);
ako je aktivni lan tipa float piemo
printf("%f\n",u.fval);
a ako je tipa char
printf("%s\n",u.sval);
Elementima strukturne promenljive u vrednosti se mogu dodeliti, na primer, iskazima
u.ival=189; ili u.fval=0.3756; ili u.sval="string";
Primer.
void main()
{ union { int i;
float f;
} x;
x.i=123;
printf("x.i=%d x.f=%f\n",x.i,x.f);
x.f=12.803;
printf("x.i=%d x.f=%f\n;x.i,x.f);
}

Unije mogu da se pojavljuju u strukturama i nizovima. Kombinacijom strukture i unije grade se


promenljive strukture.
Primer. Tablica simbola
struct { char*name;
int flags;
int utype;

178
union { int ival;
float fval;
char *sval;
} u;
} symtab[100];

Sada moemo pristupiti lanu ival i-tog elementa tablice simbola pomou izraza
symtab[i].u.ival;

Prvi znak stringa sval i-tog elementa tablice simbola se dobija jednim od sledea dva
ekvivalentna izraza:
*symtab[i].u.sval;
symtab[i].u.sval[0];

Unija se moe inicijalizovati samo pomou vrednosti koja odgovara tipu njenog prvog lana.
Stoga se unija opisana u prethodnom primeru moe inicijalizovati samo pomou celobrojne
vrednosti.
Primer. Osnovne geometrijske figure se mogu okarakterisati sledeom strukturom:
struct figura
{ float povrsina, obim; /* Zajednicki elementi */
int tip;
/* Oznaka aktivnog elementa */
union
{ float r;
/* Poluprecnik kruga */
float a[2];
/* Duzine strana pravougaonika */
float b[3];
/* Duzine strana trougla */
} geom_fig;
} fig;

8.8. Nabrojivi tip podataka u c


Kljunom reju enum deklariu se nabrojivi (enumerisani) tipovi podataka. Promenljive
nabrojivog tipa mogu da imaju samo konaan skup vrednosti. Na primer iskazom
enum flag{true,false};
definisan je nabrojivi tip enum flag. Promenljive ovog tipa mogu da imaju samo vrednosti true
ili false. Kljuna re enum oznaava da se radi o nabrojivom tipu podataka, a identifikator flag
predstavlja ime definisanog nabrojivog tipa. Izmeu zagrada se nalazi lista vrednosti.
Deklaracija promenljivih nabrojivog tipa se sastoji od kljune rei enum, imena enumerisanog
tipa, eventualno liste dozvoljenih vrednosti i liste enumerisanih promenljivih koje se deklariu.
Na primer, mogu se deklarisati sledee promenljive
enum flag file_end, input_end;

ime nabrojivog tipa se moe izostaviti, ime se dobija neimenovani nabrojivni tip. Na primer,
sledea deklaracija je analogna prethodnoj:
enum {true,false} file_end, input_end;

Dodeljivanje vrednosti enumerisanoj promenljivoj je analogno dodeljivanju vrednosti


promenljivima ostalih tipova. Sledei iskazi su legalni:
file_end=false;

Predrag S. Stanimirovi

179

Programski jezici

if(input_end = = true)

U sledeem primeru se definie nabrojivi tip enum dani:


enum dani {pon,uto,sre,cet,pet,sub,ned};

Vrednosti nabrojivog tipa se tretiraju kao celobrojne konstante. Preciznije, C kompajler


dodeljuje sekvencijalne celobrojne vrednosti elementima liste vrednosti, startujui od prvog
elementa liste, kome se dodeljuje vrednost 0. Na primer, izrazom
ovaj_dan=sreda;
dodeljena je vrednost 2 (ne ime ``sreda'')

promenljivoj ovaj_dan (tipa enum dani).


Sekvencijalni nain dodeljivanja celobrojnih vrednosti elementima iz liste imena moe se
promeniti eksplicitnim dodeljivanjem eljene celobrojne vrednosti nekom elementu iz liste
imena. Na primer, moemo pisati
enum dani{pon,uto,sre=10,cet,pet,sub=100,ned} ;

Sada je
pon=0, uto=1, sre=10, cet=11, pet=12, sub=100, ned=101.

Ako se eli eksplicitno dodeljivanje celobrojne vrednosti nabrojivog promenljivoj, mora da se


koristi kast operator.
Na primer, izraz
ovaj_dan=pon

ekvivalentan je sa
ovaj dan=(enum dani)0;

Pri tome se mogu koristiti i negativni celi brojevi.


Primer. Program odreivanje sledeeg dana u nedelji
void main()
{ int k;
enum dani{pon,uto,sre,cet,pet,sub,ned} sledeci;
printf("unesite danasnji dan:\n");
scanf("%d",&k);
k+=1; k%=7;
sledeci=(enum dani)k;
printf("\nsledeci dan je %d.dan u nedelji\n", (int)sledeci);
}

Ista konstanta se ne moe koristiti u deklaracijama razliitih nabrojivih tipova podataka. Na


primer, definicije tipova
enum radnidani {pon,uto,sre,cet,pet};
enum vikend {pet,sub,ned};

su nekorektne, jer se konstanta pet pojavljuje u definiciji oba tipa. Nabrojivi tip se moe
definisati koristei operatore typedef i enum. Na primer, sledeim definicijama su uvedena dva
nabrojiva tipa, samoglasnik i dani:
typedef enum {A,E,I,O,U} samoglasnik;
typedef enum {pon,uto,sre,cet,pet,sub,ned} dani;

180
Posle definicije ovih tipova mogu se deklarisati promenljive uvedenih tipova:
samoglasnik slovo;
dani d1,d2;

Promenljivoj nabrojivog tipa se moe dodeliti bilo koja vrednost koja je sadrana u definiciji
nabrojivog tipa:
slovo=U;
d1=sre;

Ako se vrednosti promenljivih nabrojivog tipa ispisuju pomou funkcije printf(), ispisuju se
celobrojne vrednosti koje su dobile na osnovu definicije nabrojivog tipa.
Za razliku od PASCALa, promenljive nabrojivog tipa se ne mogu koristiti kao brojake
promenljive u operatorima FOR ciklusa.

8.9. Zapisi sa varijantama


U nekim programskim jezicima (Pascal, Ada) postoji mogunost da se definiu zapisi sa
segmentima koji se ukljuuju u strukturu zapisa u zavisnosti od odreene vrednosti nekog
drugog segmenta zapisa. Razmotrimo primer koji predstavlja definiciju strukturnog tipa
I n s t r u me n t kojim se opisuje zapis sa atributima muzikih instrumenata, prilagoen razliitim
tipovima instrumenata. U tabeli su prikazane komponente koje postoje u sluaju promenljive A
tipa Instrument.
Komponente promenljive A tipa Instrument

A:Instrument
A.Vrsta:=
icani
A.tip :=

viola

elo

false
true
A.dijapazon:
A.broj: 1..100
real

gudacki
A.raspon :=
kontrabas

udarni
A.klavijatura :=

duvaki
A.Materijal :=
metal
drvo
A.nain :=
A.pisak :=
klavir pokrtetni jednodelni dvodelni

Primer. Program za izraunavanje rastojanja u razliitim koordinatnim sistemima.


program Rastojanje;
type Koordinate =
record
case Kord : (Dekartove, Polarne) of
Dekartove : (x,y:real);
Polarne
: (r:real; fi:real)
end;
var
A,B:koordinate;
d : real;
begin
case A.Kord Dekartove : case b.Kord Dekartove Polarne
Dekartove :
case B.Kord of

Predrag S. Stanimirovi

181

Programski jezici

Dekartove : d:= sqrt(sqr(A.x-B.x) + sqr(A.y-B.y));


Polarne :
d:= sqrt(sqr(A.x-B.r*cos(B.fi)) +
sqr(A.y-B.r*sin(fi)) )
end;
Polarne :
case B.Kord of
Dekartove : d:= sqrt(sqr(A.r*sin(A.fi)-B.x) +
sqr(A.r*cos(A.fi)-B.y) );
Polarne :
d:= sqrt(sqr(A.r)+sqr(B.r)2*A*B.r*cos(A.fi-B.fi))
end;
end;
end.

Ovaj primer je program za izraunavanje rastojanja izmeu dve take u ravni, pri emu
postoji mogunost da svaka od taaka bude definisana u Dekartovom ili polarnom
koordinatnom sistemu. Obuhvaeni su svi sluajevi: kada su obe take zadate Dekartovim
koordinatama, jedna od tacaka Dekartovim, a druga polarnim koordinatama i sluaj kada su obe
take definisane polarnim koordinatama. Primer je dat u jeziku Pascal.

8.9.1. Naredba w i th u Pascal-u


U programskom jeziku Pascal postoji posebna naredba wi th prilagodena radu sa zapisima.
Smisao ove naredbe ilustruje sledei primer:
Student : OSOBA;
with Student do
with Dan_rodj do
begin
mesec := maj; dan := 14; godina := 1963
end;

ili
with Student, Dan_rodj do
begin
mesec := maj; dan := 14;
end;

godina := 1963

Sledei primer ilustruje prednosti upotrebe naredbe w i t h . Dat je program u kome se


pomou zapisa sa varijantama definie struktura koja obuhvata geometrijske figure trougao,
pravougaonik i krug i izraunavaju povrine ovih figura. Program je najpre napisan bez naredbe
with, a zatim sa naredbom with . Oigledno je da se tekst programa skrauje i postaje pregledniji.
Primer. Napisati program koji za izabranu vrstu geometrijskog tela zadatog na sledei nain
type tip=(kvadar,kocka,lopta);
telo=record
case fig:tip of
kvadar:(duzina,sirina,visina:real);
kocka:(ivica:real);
lopta:(poluprecnik:real);
end

izraunava povrinu i zapreminu odabranog geometrijskog tela.


program figure;
const pi=3.14159;
type tip=(kvadar,kocka,lopta);
telo=record

182
case fig:tip of
kvadar:(duzina,sirina,visina:real);
kocka:(ivica:real);
lopta:(poluprecnik:real);
end;
var o,p:real;
tp:string;
fig:telo;
begin
writeln('Tip figure? '); readln(tp);
if tp='kvadar' then
with fig do
begin
readln(duzina,sirina,visina);
o:=2*(duzina*sirina+duzina*visina+sirina*visina);
p:=duzina*sirina*visina;
end
else if tp='kocka' then
with fig do
begin
readln(ivica);
o:=6*sqr(ivica); p:=sqr(ivica)*ivica;
end
else if tp='lopta' then
with fig do
begin
readln(poluprecnik);
o:=4*sqr(poluprecnik)*pi;
p:=4*sqr(poluprecnik)*poluprecnik*pi/3;
end;
writeln; writeln('Obim = ',o,' Povrsina = ',p);
end.

Primer. Dati su podaci o stambenom stanju radnika iji je broj unapred poznat. Ulazni podaci
su slogovi sledee sadrine:
- ime radnika;
- stambeno stanje:
0 - ako je radnik bez stana,
1 - ako je radnik ima stan,
2 - ako je radnik ima kuu;
Ako radnik ima kuu ili stan navode se jo dva podatka: broj lanova porodice i kvadratura
stambenog objekta. Smatra se da je radnik stambeno ugroen ako ima manje od 17m 2 po lanu
domainstva. Ako radnik ima kuu, za kvadraturu uzeti 90% od uitane kvadrature kue.
Na izlazu tampati imena radnika koji nemaju ni stan ni kuu, a zatim imena radnika koji
imaju manje od 17m2 po lanu porodice.
program stanovi;
uses crt;
const
max = 50;
type
naziv=string[30];
tipstanja=0..2;
stambstanje =
record
ime:naziv;

Predrag S. Stanimirovi

Programski jezici

183

case stanje:tipstanja of
1,2:(brojclanova:1..10; kvadratura : real);
0 : ();
end;
var
brojradnika, brojugrozenih, i:integer;
ss:array[1..max] of stambstanje;
j:1..max;
k:1..30;
kvadraturapoclanu:real;
(* procedura za stampanje rednog broja i imena *)
procedure stampanje( var br:integer; a:naziv);
var
j:1..30;
begin
br := br+1;
write(br, '. ',a,'
');
end;
begin
clrscr;
readln(brojradnika);
brojugrozenih := 0;
for j := 1 to brojradnika do
begin
write('Ime? '); readln(ss[j].ime);
write('stanje=? '); readln(ss[j].stanje);
case ss[j].stanje of
0: ;
1,2:begin
writeln('Broj clanova i kvadratura? ');
readln(ss[j].brojclanova, ss[j].kvadratura);
end;
end {case};
end; {for}
writeln(' SPISAK STAMBENO UGROZENIH ');

writeln;

for j := 1 to brojradnika do
begin
if ss[j].stanje = 0 then
begin
stampanje(brojugrozenih, ss[j].ime);
writeln('
BEZ STANA ')
end
else
begin
if ss[j].stanje = 2 then
ss[j].kvadratura := 0.9*ss[j].kvadratura;
kvadraturapoclanu:= ss[j].kvadratura/ss[j].brojclanova;
if kvadraturapoclanu < 17. then
begin
stampanje(brojugrozenih, ss[j].ime);
writeln(kvadraturapoclanu:7:2);
end {if};
end {else }
end {for};

184
end.

8.10. Skupovi
U matematici skup ini vie elemenata objedinjenih nekim zajednickim svojstvom. U nekim
programskim jezicima (Pascal) postoji mogunost definisanja skupova kao struktura podataka i
odgovarajuih strukturnih tipova podataka, meutim ovaj pojam u programskim jezicima je
neto ui u odnosu na matematiki pojam.
Primer koji sledi ilustruje definisanje strukturnih tipova za rad sa skupovima i njihovo
korienje.
program skupovi;
type
OsnovneBoje = (crvena, oranz, zuta, plava, violet);
Boje = Set of OsnovneBoje;
var
Sboja, Sboja1, Sboja2 : Boje;
Jednaboja : OsnovneBoje;
B : Boolean;
begin
Sboja1 := [crvena, zuta, violet];
Sboja2 := [];
Sboja1 := [crvena, zuta, violet, oranz, zelena, plava];
Sboja2 := [plava];
end.

U datom primeru ne bi bila dozvoljena dodeljivanja:


Sbojal := [cr na ] ;
Sboja2 := [bela];
jer boje c r n a i b e l a ne postoje u tipu podataka O s n o v n e B o j e nad kojim je definisan
strukturni tip Boje.
Nad skupovima u programskom jeziku Pascal mogu se izvravati sve operacije koje postoje i
u teoriji skupova u matematici.

Unija skupova
Unija dva skupa predstavlja se znakom +. Na primer, korektni su sledei izrazi.
Sbojal := [ crve n a , zuta, vio le t ] ;
Sboja2 := [ p la va , zelena];
Sboja := Sbojal + S b o j a 2 ;

Posle zadnje naredbe dodeljivanja, promenljiva Sboja dobija vrednost [cr ve na, z u t a ,
v i o l e t , p l a v a , zelena]. Isto dodeljivanje moe da se postigne i sa:
Sboja := [crvena, zuta, violet] + [plava, zelena];

Presek skupova
Presek dva skupa predstavlja se znakom *.
Sbojal := [crvena, zuta, violet];
Sboja2 := [plava, zelena. zuta];
Sboja := Sbojal * Sboja2;

Promenljivoj Sboja dodeljena je vrednost skupa [z uta]. Meutim u sledeem sluaju


Sboja1 := Ccrvena, zuta, violet];
Sboja := Sbojal * [zelena];

Predrag S. Stanimirovi

185

Programski jezici

promenljiva Sboja dobija vrednost praznog skupa.

Razlika skupova
Razlika dva skupa predstavlja se znakom -.
Sboja1 := [crvena, zuta, violet];
Sboja := Sbojal - [zuta, violet];

Promenljivoj S b o j a dodeljuje se vrednost koja je dopuna skupa [ z u t a , violet] do skupa


[crvena, zuta, violet], a to je skup [crvena].

Jednakost i nejednakost skupova


Dva skupa su jednaka samo ako sadre iste elemente, a nejednaki su ako se razlikuju bar po
jednom elementu.
Sboja1 := [crvena, zuta, violet];
Sboja2 := [crvena, zuta, violet];
Sboja := [crvena, zuta, violet, zelena];
B := Sbojal = Sboja2;
B := Sbojal <> Sboja;

U oba navedena dodeljivanja, logika promenljiva B dobija vrednost TRUE. Odnosno, obe
navedene relacije izmeu skupova su istinite.

Podskupovi
Sboja1 := [crvena, zuta];
Sboja2 := [crvena, zuta, violet];
B := Sboja1 <= Sboja2;
B := Sboja2 >= Sboja1;

U ovom primeru, promenljiva B takoe dobija vrednost T R U E jer je skup dodeljen


promenljivoj S b o j a l podskup skupa koji je dodeljen promenljivoj Sboja2. Meutim, ako se
relacija postavi obrnuto:
B := Sboja2 <= Sboja1;
B := Sboja1 >- Sboja2;

promenljiva B dobija vrednost FALSE.

Pripadnost skupu
Ovo je operacija koja omoguava da se ispita pripadnost odreenog elementa zadatom skupu
elemenata:
Sboja1 := [crvena, zuta];
Sboja2 := [crvena, zuta, violet];
Jednaboja := violet;
B := Jednaboja in Sboja1;
B := Jednaboja in Sboja2;

U prvom dodeljivanju B dobija vrednost FALSE jer boja viol et ne pripada skupu Sboja1, a u
drugom TRUE jer violet pripada skupu Sboja2.

Primeri.
Primer. Napisati program za formiranje simetrine razlike skupova a i b korienjem sledeeg
tipa:
type alfabet = set of 'a'..'z;
Napisati funkciju card(s)koja vraa broj elemenata skupa s tipa alfabet.

186
Testirati napisane potprograme.
Napisati program koji uitava dva stringa i ispisuje sve znakove koji se pojavljuju u jednom a
ne pojavljuju u drugom.
program leskup3;
type slova = set of 'a'..'z';
var s1,s2:string;
skup:slova;
i,l1,l2:integer;
ch:'a'..'z';
begin
write('Prvi string = ? '); readln(s1);
write('Drugi string = ? '); readln(s2);
skup:=[];
l1:=length(s1); l2:=length(s2);
for i:=1 to l1 do
if pos(s1[i],s2)=0 then skup:=skup+[s1[i]];
for i:=1 to l2 do
if pos(s2[i],s1)=0 then skup:=skup+[s2[i]];
writeln('To su znaci:');
for ch:='a' to 'z' do
if ch in skup then write(ch,' ');
end.

Primer. Data je deklaracija


type prirodan=1..maxint;
Napisati:
a) funkciju brojcifara(n) koja izraunava broj razliitih cifara u dekadnom zapisu broja n;
b) proceduru vanbroja(n); koja tampa u rastuem redosledu sve cifre koje ne ulaze u sastav
dekadnog prirodnog broja n.
program leskup4;
type prirodan=1..maxint;
skup=set of 0..9;
var n:prirodan;
function card(s:skup):integer;
var i:0..9;
k:integer;
begin
k:=0;
for i:=0 to 9 do if i in s then k:=k+1;
card:=k;
end;
function brojcifara(n:prirodan):prirodan;
var skupcifara:skup;
c:0..9;
begin
skupcifara:=[];
repeat
c:=n mod 10; n:=n div 10;
skupcifara:=skupcifara+[c];
until n=0;
brojcifara:=card(skupcifara);
end;

Predrag S. Stanimirovi

187

Programski jezici

procedure vanbroja(n:prirodan);
var skupcifara:skup;
c:0..9;
begin
skupcifara:=[];
repeat
c:=n mod 10; n:=n div 10;
skupcifara:=skupcifara+[c];
until n=0;
writeln('U sastav broja ne ulaze sledece cifre:');
for c:=0 to 9 do
if not(c in skupcifara) then write(c:3);
end;
begin
write('Zadati broj '); readln(n);
writeln('Zadati broj ima ',brojcifara(n),'
razlicitih cifara');
vanbroja(n);
end.

Primer. Napisati program koji odreuje skup delitelja za sve brojeve od 1 do 100. Rezultat
smestiti u niz skupova.
program leskup5;
type skupdel=set of 0..9;
nizskupdel = array[1..100] of skupdel;
var nizdel:nizskupdel;
i,j:1..100;
begin
for i:=1 to 100 do
begin
nizdel[i]:=[];
for j:=1 to trunc(sqrt(i)) do
if i mod j =0 then
nizdel[i]:=nizdel[i]+[j]+[i div j];
end;
writeln('Delitelji su: ');
for i:=1 to 100 do
begin
writeln('Za ',i:4);
for j:=1 to i do
if j in nizdel[i] then write(j,' ');
writeln;
readln;
end;
end.

Primer. Ako su date deklaracije


const n=10;
type
opseg=1..n;
matrica=array[opseg,opseg] of real;
skupbrojeva=set of opseg;

188
Primer. Napisati program koji zamenjuje sve samoglasnike u redu unetog teksta znakom * i
tampa abecedno sortirane suglasnike koji se pojavljuju u tekstu.
program leskup7;
type skupslova=set of 'a'..'z';
var ch:char;
slova,samoglasnici,suglasnici,pojave:skupslova;
s:string;
begin
writeln('Uneti jedan red znakova');
s:='';
pojave:=[];
samoglasnici:=['a','e','i','o','u'];
slova:=['a'..'z']; suglasnici:=slova-samoglasnici;
while not eoln do
begin
read(ch);
if ch in samoglasnici then s:=s+'*'
else if ch in suglasnici then
begin
pojave:=pojave+[ch]; s:=s+ch;
end
else s:=s+ch;
end;
writeln; writeln('Transformisani red= ',s);
writeln('Suglasnici su:');
for ch:='a' to 'z' do
if ch in pojave then write(ch,' ');
writeln;
end.

Primer. Od dva zadata niza celih brojeva A i B sa elementima izmeu 1 i 200 formirati niz C
tako da se njegovi elementi pojavljuju samo jednom. Odtampati elemente niza C u opadajuem
redosledu. Ukoliko je mogue, iz niza C izbaciti jedan element tako da je zbir preostalih
elemenata maksimalan deljiv sa 3.
program nizovi;
const max = 400;
type
opseg = 1..200;
niz = array[1..max] of opseg;
skup = set of opseg;
var
a, b, c:niz;
n, m:integer;
s:skup;
i, j:integer;
procedure ucitavanje;
var
k : integer;
begin
writeln('Zadati broj elemenata prvog niza ');
readln(n);
writeln('Zadati elemente prvog niza ');
for k := 1 to n do read(a[k]);
readln;

Predrag S. Stanimirovi

189

Programski jezici

writeln('Zadati broj elemenata drugog niza ');


readln(m);
for k := 1 to m do read(b[k]);
readln;
end;
procedure formiranje;
var i:integer;
begin
s := [];
for i := 1 to n do s :=
for i := 1 to m do s :=
j := 0;
for i := 1 to 200 do
if i in s then begin
j :=
c[j]
end;
end;

s+[a[i]];
s+[b[i]];

procedure ispis;
var i:integer;
begin
writeln;
for i:= 200 downto 1 do
if i in s then write('
writeln;
end;

j+1;
:= i;

',i);

procedure izbaci;
var l,k:integer;
suma:longint;
begin
suma:=0;
for k:=1 to j do suma:=suma+c[k];
if (suma mod 3) = 1 then
begin
k:=1;
while ((k mod 3 <>1) or not (k in s)) and (k<=200) do
k:=k+1;
if k>200 then writeln('Ne moze se izbaciti')
else begin
s:=s-[k];
j := 0;
for l := 1 to 200 do
if l in s then
begin
j := j+1;
c[j]:= l;
end;
end;
end;
if (suma mod 3) = 2 then
begin
k:=1;
while((k mod 3 <>2) or not (k in s)) and (k<=200) do
k:=k+1;
if k>200 then writeln('Ne moze se izbaciti')
else begin
s:=s-[k]; j := 0;
for l := 1 to 200 do

190

end;

if l in s then
begin
j := j+1;
end;

c[j]:= l;

end;

end;

begin
ucitavanje; formiranje; ispis;
izbaci;
for i:= 1 to j do write(' ',c[i]);
writeln;
end.

Primer. Ispisati sve razliite cifre koje se nalaze u zpisu celog pozitivnog broja n kao i one cifre
koje ne pripadaju broju n.
program cifre;
type
natur = 1..maxint;
cifra = 0..9;
skupcifara = set of cifra;
var
s:skupcifara;
c:cifra;
n:natur;
procedure razcifre(n:natur; var sk:skupcifara);
var
cif:cifra;
begin
sk := [];
while n <> 0 do
begin
cif := n mod 10; n := n div 10; sk := sk + [cif];
end;
end;
procedure print(n:natur; sk:skupcifara);
var
cif :cifra;
broj : integer;
begin
writeln(' Cifre sadrzane u broju ');
writeln;
broj := 0;
for cif := 0 to 9 do
begin
if cif in sk then
begin
write(cif :5);
broj := broj + 1;
end;
end;
writeln;
writeln(' Broj sadrzi ', broj, ' razlicitih cifara ');
end;
procedure nprint(n:natur; sk:skupcifara);
var
cif:cifra;

Predrag S. Stanimirovi

191

Programski jezici

spom:skupcifara;
begin
writeln;
writeln(' Cifre koje nisu sadrzane u broju ');
spom := [0..9] - sk;
for cif := 0 to 9 do
if cif in spom then
write(cif:5);
writeln;
end;
begin {program}
write(' Zadati ceo broj : '); readln(n);
writeln;
razcifre(n, s);
print(n, s);
writeln;
nprint(n, s);
end.

Nai sve proste brojeva manje ili jednake datom prirodnom broju max primenom Eratostenovog
sita.
program eratosten;
const
max = 250;
type
skup = set of 2..max;
var
sito, prosti :skup;
next, m : integer;
begin
{ zadavanje pocetnih podataka }
prosti := [];
sito := [2..max];
next := 2;
{glavni algoritam }
while sito <> [] do
begin
m := next;
while m <= max do
begin
sito := sito - [m];
m := m + next;
end;
prosti := prosti + [next];
repeat
next := next + 1;
until (next in sito) or (next > max);
end;
{stampanje prostih brojeva }
for m := 1 to max do
if m in prosti then write(m:5);
writeln;
end.

Skupovi se esto koriste za skraeno predstavljanje sloenih uslova. Na primer, u sledeem


primeru imamo niz uslova koji se jednostavno zamenjuju jednim uslovom definisanim nad
skupom podataka:

192
if (I = 215) or (I = 220) or ... or (I = 275) or (I = 280) then ...

Isti uslov moe se predstaviti preko skupova na sledei nain:


If I in [215, 220, 225, .... 280] then ...

Naredni primeri i ilustruju mogunost korienja skupova za reavanje nekih problema koji
se obino reavaju drugim tipovima podataka.
U poslednjem primeru odreduju se sve prosti brojevi u skupu prvih sto celih brojeva.
U narednom primeru dat je program kojim se prepoznaju identifikatori pri emu su to
proizvoljni nizovi slova i cifara koji obavezno zapoinju slovom. Podrazumeva se da su
identifikatori medusobno odvojeni prazninom i da se niz identifikatora zavrava takom.
Primer. Prepoztiavanje identifikatora.
program Sintaksa
var
CH : char;
greka : Boolean;
begin
read(CH); write(CH);
repeat
if not (CH 1n ['A' .. 'Z'])
then greka := true;
read(CH); write(CH);
while CH < > ' ' do
begin
if not (CH In [A' . . Z', '0' . . '9' ]
then greka := true;
read(CH); write(CH): :
end;
-'writeln;
1f greka then writeln('GREKA');
read(CH): write(CH);
until CH = ' . '
end.

8.11. DATOTEKE
Kao strukturni tipovi podataka mogu se definisati i tipovi koji obuhvataju datoteke kao
sekvencijalne strukture jednorodnih zapisa. Ovakvi strukturni tipovi opisuju se sa file i postali su
standardni u programskim jezicima posle pojave ovog koncepta u jeziku Pascal. Zbog toga emo
njegove osnovne karakteristike opisati na primeru ovog jezika.
Datoteke su jednorodne strukture podataka, slino poljima ali za razliku od polja, broj
elemenata datoteke se ne definie unapred i podrazumeva se da one fiziki postoje van programa na
nekom od spoljanjih memorijskih medijuma (disku, traci, disketi itd.). Evo nekoliko primera
opisa razliitih tipova datoteka:
const Limit = 10;
type
Opseg
= 1 .. Limit;
Skup
= set of Opseg;
Vektor
= array [Opseg] of real;

Predrag S. Stanimirovi

Complex
Intdat
Redat
Chdat
Skupdat
Vekdat
Komdat

Programski jezici

193

= record Re. Im : integer;


= file of integer;
= file of real;
= file of char;
= file of Skup;
= file of Vektor;
= file of Complex;

end {record};

Promenljive tipa datoteka opisuju se sa:


var

F : Tipdat;

gde je
Ti pdat tip datoteke, ili anonimno sa:
var

F : file of Tipslog;

gde je Ti psl og tip elemenata datoteke.


Prilikom opisa svake promenljive tipa datoteke automatski se generie jedna baferska
promenljiva koja po tipu odgovara tipu elemenata datoteke. U sluaju kada se radi o promenljivoj
F baferska promenljiva se oznacava sa F^. Preko ove baferske promenljive ostvaruje se svaka
veza sa konkretnom datotekom, kako upis tako i itanje slogova iz datoteke. Kada baferska
promenljiva F^ dostigne kraj datoteke standardna funkcija E O F ( F ) dobija vrednost true, dok u
suprotnom ima vrednost false.
Za rad sa datotekama mogu se koristiti sledee procedure:
RESET(F) - Pozicioniramo se na poetak datoteke F da bi je obraivali od prvog sloga. Ako
je datoteka F prazna vai:
EOF(F) = true i F^ je nedefinisano
inae je
EOF( F) = false i F^ dobija vrednost prvog sloga datoteke.
REWRITE(F) - Brisu se svi slogovi datoteke F. Pri tome EOF(F) dobija vrednost true i
postoji mogunost ponovnog kreiranja datoteke sa istim imenom.
GET(F) - Prelaz na sledei slog datoteke F. Baferska promenljiva F^ dobija vrednost
sledeeg sloga datoteke ako on postoji. Ako je kraj datoteke i nema vie slogova (nema
sledeeg sloga) vai:
EOF(F) = true i F^ je nedefinisano.
Dejstvo ove procedure je nedefinisano ako je pre njenog poziva bilo
EOF(F) = true.
PUT(F) - Tekua vrednost baferske promenljive F^ upisuje se u datoteku F, postaje aktivan
sledei element datoteke i vai:
EOF(F) = true i F^ nedefinisano.
Pre upotrebe ove procedure mora da se pozicionira na kraj datoteke, odnosno treba da vai:
EOF(F) = true.
Primer. Program kojim se sudraj datoteke A preslikava u datoteku B.
program Datoteke;
type Dat = file of integer;
var A,B : Dat;
begin
reset(A); rewrite(B);
while not EOF(A) do
begin

194

end.

B^ := A^ ;
GET(A); PUT(B)

Napomena: Obino se kod implementacije jezika Pascal procedure reset i rewrite koriste za
povezivanje stvarnih datoteka sa logikim programskim datotekama. Na primer:
RESET(I N P U T, 'PODACI '); - Datoteka kreirana na disku pod imenom PODACI'
povezuje se sa standardnom datotekom INPUT.
R E W R I T E ( O U T P U T. ' I Z L A Z 1 ); - Kao izlazna datoteka na disku e biti kreirana
datoteka sa imenom ' IZ LAZ'.
U principu sve operacije nad datotekama mogu se izvravati preko etiri navedene
procedure. Meutim, zbog prakticnosti i jednostavnijeg definisanja osnovnih aktivnosti nad
datotekama postoje i procedure read i wr i te.
READ(F,X) ekvivalentno sa X := F^; GET(F);
WRITE(F.X) ekvivalentno sa F^ := X; PUT(F);
Procedure read i write se mogu koristiti i sa vie argumenata pri emu je:
READ(F, XI, X2, .... XK);
ekvivalentno sa:
READ(F, XI);
READ(F, X2);

READ(F, XK);

WRITE(F, XI, X2, .... XK);


ekvivalentno sa:
WRITE(F, XI);
WRITE(F. X2);

WRITE(F, XK);

Nad datotekama se obino mogu izvravati dve osnovne operacije i to itanje slogova
datoteke i upis slogova u datoteku, koje se mogu opisati na sledei nain:
(1) itanje slogova iz datoteke:
RESET(F);
while not EOF(F) do
begin
READ(F. Komp);
X := Komp;
end;

RESET(F);
repeat
READ(F, Komp);
X := Komp;
until EOFCF);

(2) Upis slogova u datoteku, kreiranje datoteke:


REWRITE(F);
while UPIS do
begin
Komp := X;
WRITE(F,Kopm);
end;

REWRITECF);
repeat
Komp := X;
WRITE(F,Komp);
until not UPIS;

Promenljiva U P I S logikog tipa ovde sluzi da se preko nje regulie kraj upisa u datoteku.
Slogovi se upisuju kada je U P I S = true.

Primeri.
Primer. Napisati:
a) funkciju koja utvruje da li postoji datoteka sa zadatim imenom;
b) proceduru koja ponavlja zahtev za unos imena datoteke koja se otvara za uitanje sve dok se
ne unese ime postojee datoteke;

Predrag S. Stanimirovi

195

Programski jezici

c) proceduru kojom se proverava da li postoji datoteka sa zadatim imenom, sve dok se ne unese
ime datoteke koja nije oformljena. Kada je uneto ime datoteke koja nije oformljena, otvara se za
upis datoteka sa takvim imenom.
program datoteke;
uses crt;
type ime=string[50];
var imefajla:ime;
f:text;
dobro:boolean;
function postoji(imedat:ime):boolean;
var f:text;
begin
assign(f,imedat);
{$I-} reset(f); {$I+}
if (IOresult=0) then
writeln('Datoteka sa imenom ',imedat,' postoji')
else writeln('Datoteka sa imenom ',imedat,' ne postoji');
postoji:=(IOresult=0);
end;
procedure sigurnocitanje;
var imedat:ime;
f:text;
otvori:boolean;
begin
repeat
write('Ime datoteke za citanje? ');
readln(imedat); assign(f,imedat);
{$I-} reset(f); {$I+}
otvori:=(IOresult=0);
if not otvori then
writeln('Datoteka sa imenom ',imedat,' ne postoji')
else
writeln('Datoteka sa imenom ',imedat,
' je otvorena za citanje')
until otvori
end;
procedure siguranupis;
var imedat:ime;
f:text;
otvori:boolean;
begin
repeat
write('Ime datoteke za upis? ');
readln(imedat); assign(f,imedat);
{$I-} reset(f); {$I+}
otvori:=(IOresult=0);
if otvori then
writeln('Datoteka sa imenom ',imedat,' vec postoji')
else rewrite(f);
until not otvori
end;
begin
clrscr;
write('Ime datoteke za citanje? '); readln(imefajla);

196
dobro:=postoji(imefajla); sigurnocitanje;
end.

siguranupis;

Primer. U fajlu f se nalazi jedna reenica bez znakova interpukcije. Ona je sastavljena od rei
koje su razdvojene blanko znacima. Na ekranu prikazati jednu ispod druge sve rei iz te
reenice, ureene po abecedi.
program ureenje;
var
n,k,i,j:integer;
f:file of char;
priv, rec:string[40];
reci:array[1..20] of string[40];
ch : char;
begin
assign(f,'f'); reset(f);
k := 0;
rec := '';
while not eof(f) do
begin
repeat
read(f,ch);
rec := rec + ch;
until (ch = ' ') or eof(f);
k := k + 1;
reci[k] := rec;
while(ch = ' ') do read(f,ch);
rec := ch;
end;
writeln;
writeln;
for i := 1 to k - 1 do
for j := i + 1 to k do
begin
if(reci[i] > reci[j]) then
begin
priv := reci[i]; reci[i] := reci[j];
reci[j] := priv;
end;
end ;
for n := 1 to k do writeln(reci[n]);
close(f);
writeln;
end.

Primer. U fajlu c:\tp\zadaci\f.txt nalaze se sledei podaci o kandidatima za poslanike:


- ime i prezime;
- adresa;
- zanimanje;
- ime stranke koja ga kandiduje.
U fajl c:\tp\zadaci\g.txt upisati sve kandidate ureene po imenu stranke (abecedno), a u okviru
stranke po imenu kandidata.
program stranke;
type slog = record
imeip : string[20];
adresa : string[10];
zanimanje : string[8];
imes : string[10];
end;
niz=array[1..20] of slog;

Predrag S. Stanimirovi

197

Programski jezici

var
g,f : file of slog;
procedure upis;
var ch:char;
priv:slog;
begin
assign(f,'c:\tp\zadaci\f.txt'); rewrite(f);
repeat
with priv do
begin
write('Ime i prezime? '); readln(imeip);
write('Adresa? '); readln(adresa);
write('Zanimanje? '); readln(zanimanje);
write('Ime stranke? '); readln(imes);
end;
write(f,priv);
write('Jos slogova? '); readln(ch);
until not (ch in ['d','D']);
close(f);
end;
procedure citajisortiraj;
var i,j,k:integer;
a:niz;
priv:slog;
begin
assign(f,'c:\tp\zadaci\f.txt'); reset(f);
i:= 0;
while not eof(f) do begin
i:=i+1; read(f,a[i]);
end;
for j := 1 to i-1 do
for k := j+1 to i do
if(a[j].imes > a[k].imes) or
((a[j].imes = a[k].imes) and
(a[j].imeip > a[k].imeip))
then begin
priv := a[j]; a[j] := a[k]; a[k] := priv;
end;
assign(g,'c:\tp\zadaci\g.txt'); rewrite(g);
for j:=1 to i do write(g,a[j]);
close(f); close(g);
end;
procedure citanje;
var priv:slog;
begin
assign(g,'c:\tp\zadaci\g.txt'); reset(g);
while not eof(g) do
begin
read(g,priv);
with priv do
begin
writeln(imeip); writeln(adresa);
writeln(zanimanje); writeln(imes);
end;
end;
close(g);

198
end;
begin
writeln; writeln('Oformljena je sledeca datoteka');
upis; citajisortiraj; citanje;
end.

Primer. Napisati program koji formira sekvencijalnu datoteku koja se sastoji od n realnih
brojeva. Zatim oformiti novu datoteku koja sadri sve realne brojeve iz datoteke, pomnoene sa
2. Imena datoteka zadati preko tastature.
program dvostruki(input,output);
type
realdat = file of real;
var
f, fnew:realdat;
x:real;
imedat, newimedat:string[15];
begin
writeln('Unesi ime datoteke: '); readln(imedat); assign(f,imedat);
{$I-}
reset(f);
{$I+}
if IOResult <> 0 then
begin
writeln('Datoteka "',imedat, '" nije oformljena ');
halt;
end;
writeln('Unesi ime nove datoteke: '); readln(newimedat);
assign(fnew, newimedat);
rewrite(fnew);
while not eof(f) do
begin
read(f, x);
if not eof(f) then
begin
x:=2*x;
write(fnew, x)
end;
end;
close(f);
close(fnew);
end.

Primer. Napisati program koji e od celih brojeva koji se uitavaju iz postojee datoteke upisati
u novu datoteku sve one koji predstavljaju potpun kvadrat.
program dat7;
type
intdat = file of integer;
var
f,g: intdat;
x:integer;
imedat, newimedat:string[50];
begin
writeln('Unesi ime datoteke iz koje se cita: '); readln(imedat);
assign(f,imedat);
{$I-}
reset(f);
{$I+}
if IOResult <> 0 then

Predrag S. Stanimirovi

199

Programski jezici

begin
writeln('Datoteka "',imedat, '" nije oformljena ');
halt;
end;
writeln('Unesi ime nove datoteke: '); readln(newimedat);
assign(g, newimedat);
rewrite(g);
while not eof(f) do
begin
read(f, x);
if trunc(sqrt(x))=sqrt(x) then
write(g, x)
end;
close(f);close(g);
writeln('Sadrzaj nove datoteke je:');
assign(g,newimedat); reset(g);
while not eof(g) do
begin
read(g,x); write(x,' ');
end;
close(g);
end.

Primer. Ulazna datoteka DAT.TXT sadri sekvence binarnih brojeva razdvojenih prazninom.
Jedna sekvenca ima najvie 40 karaktera, sastoji se od 0 i 1, pri emu mogu postojati vodee
nule, dok duina sekvence nije fiksna. Napisati program koji uitava sve binarne brojeve iz
datoteke u niz, pri emu sve parne brojeve umanjuje za 1, a neparne uveava za 1, i tako
formirani niz sortira u rastuem poretku. Zatim tako sortirane brojeve ispisuje u izlaznu
datoteku OUT.TXT. Pretpostavka je da su svi brojevi vei od 0.
program pmfjn992;
(* Jun '99 2. na PMF *)
uses crt;
type binniz=array[1..50] of string[41];
var bn:binniz;
f,g: text;
ch:char;
b,p:string[41];
(* Eventualni prenos *)
l,k,i,j:integer;
function UvecajZa1(b:string):string;
var j:integer;
begin
j:=length(b);
while (b[j]='1') and (j>0) do
begin
b[j]:='0'; j:=j-1;
end; (*Vodece jedinice u nule *)
if j>0 then
begin
b[j]:='1'; UvecajZa1:=b;
(* Prva nula u jedinicu *)
end
else UvecajZa1:='1'+b;
(* Eventualna nova pozicija *)
end;
function UmanjiZa1(b:string):string;
var j,l:integer;
begin
j:=length(b); l:=j;

200
while (b[j]='0') and (j>0) do
begin b[j]:='1'; j:=j-1; end; (*Vodece nule u jedinice*)
b[j]:='0';
(* Prva jedinica u nulu *)
if b[1]='0'
then b:=copy(b,2,l-1); (*Izbacivanje vodece nule *)
UmanjiZa1:=b;
end;
procedure quicksort(n:integer; var niz:binniz);
function manji(s1,s2:string):boolean;
begin
manji:= (length(s1)<length(s2)) or
((length(s1)=length(s2)) and (s1<s2))
end;
procedure sort(l,d:integer; var s:binniz);
var i,j:integer;
pom,x:string[41];
begin
i:=l; j:=d; x:=s[(i+j) div 2];
repeat
while manji(s[i],x) and (i<d) do i:=i+1;
while manji(x,s[j]) and (j>l) do j:=j-1;
if i<=j then
begin
pom:=s[i]; s[i]:=s[j]; s[j]:=pom;
i:=i+1; j:=j-1;
end;
until i>j;
if j>l then sort(l,j,s); if i<d then sort(i,d,s);
end;
begin
sort(1,n,niz);
end;
begin
clrscr; assign(f,'c:\tp\zadaci\dat.txt'); reset(f);
assign(g,'c:\tp\zadaci\out.txt'); rewrite(g);
l:=0;
while not eof(f) do
begin
b:='';
read(f,ch);
while (ch='0') and (ch=' ') and not eof(f) do
read(f,ch);
while (ch <> ' ') and not eof(f) and (ch <> \#13) do
begin
b:=b+ch; read(f,ch);
end;
l:=l+1;
if b[length(b)]='1' then bn[l]:=UvecajZa1(b)
else bn[l]:=UmanjiZa1(b);
end;
quicksort(l,bn);
for i:=1 to l do writeln(bn[i]);
for i:=1 to l do writeln(g,bn[i]);
close(f); close(g);
end.

Primer. Napisati:

Predrag S. Stanimirovi

201

Programski jezici

a) funkciju koja utvruje da li postoji datoteka sa zadatim imenom;


b) proceduru koja ponavlja zahtev za unos imena datoteke koja se otvara za itanje sve dok se
ne unese ime postojee datoteke;
c) proceduru kojom se proverava da li postoji datoteka sa zadatim imenom, sve dok se ne unese
ime datoteke koja nije oformljena. Kada je uneto ime datoteke koja nije oformljena, otvara se za
upis datoteka sa takvim imenom.
program datoteke;
uses crt;
type ime=string[50];
var imefajla:ime;
f:text;
dobro:boolean;
function postoji(imedat:ime):boolean;
var f:text;
begin
assign(f,imedat);
{$I-} reset(f); {$I+}
if (IOresult=0) then
writeln('Datoteka sa imenom ',imedat,' postoji')
else writeln('Datoteka sa imenom ',imedat,' ne postoji');
postoji:=(IOresult=0);
end;
procedure sigurnocitanje;
var imedat:ime;
f:text;
otvori:boolean;
begin
repeat
write('Ime datoteke za citanje? ');
readln(imedat); assign(f,imedat);
{$I-} reset(f); {$I+}
otvori:=(IOresult=0);
if not otvori then
writeln('Datoteka sa imenom ',imedat,' ne postoji')
else writeln('Datoteka sa imenom ',imedat,
' je otvorena za citanje')
until otvori
end;
procedure siguranupis;
var imedat:ime;
f:text;
otvori:boolean;
begin
repeat
write('Ime datoteke za upis? ');
readln(imedat); assign(f,imedat); {$I-} reset(f); {$I+}
otvori:=(IOresult=0);
if otvori
then writeln('Datoteka sa imenom ',imedat,
' vec postoji')
else rewrite(f);
until not otvori
end;

202
begin
clrscr;
write('Ime datoteke za citanje? '); readln(imefajla);
dobro:=postoji(imefajla); sigurnocitanje;
siguranupis;
end.

Primer. Napisati procedure i glavni program kojima se:


a) formira datoteka sa imenima i prezimena vlasnika telefona i brojevima telefona.
Unos podataka se zavrava kada se umesto imena unese re "kraj".
Ako datotreka ve postoji tampati odgovarajuu poruku.
b) proverava da li postoji datoteka formirana prethodnom procedurom, i ako postoji ispisuje
njen celokupni sadraj.
c) ispisuje broj telefona na osnovu zadatog imena osobe, Ukoliko u datoteci ne postoji polje sa
zadatim imenom tampati odgovarajuu poruku.
program imenik;
type podatak = record
prezime:string[20];
telefon:string[10];
end;
datoteka = file of podatak;
ime=string;
var imedat,imeosobe:ime;
f:datoteka;
osoba:podatak;
procedure kreiranje(var f:datoteka);
begin
writeln('Ime datoteke koja se kreira? ');
readln(imedat); assign(f,imedat); {$I-} reset(f); {$I+}
if IOresult=0
then writeln('Takva datoteka postoji')
else begin
rewrite(f);
writeln('Unesi prezime ili "kraj" za prekid
upisa');
readln(osoba.prezime);
while osoba.prezime<>'kraj' do
begin
write('Telefon? ');
readln(osoba.telefon);
write(f,osoba);
writeln('Prezime i ime? ');
readln(osoba.prezime);
end;
end
end;
procedure ispis(var f:datoteka);
begin
writeln('Ime datoteke za citanje? ');
readln(imedat); assign(f,imedat);
{$I-} reset(f); {$I+}
if IOresult <> 0
then writeln('Takva datoteke ne postoji ')
else begin
while not eof(f) do
begin
read(f,osoba);
with osoba do writeln(prezime,' ',telefon)
end

Predrag S. Stanimirovi

Programski jezici

203

end;
end;
procedure nadjii(var f:datoteka);
var ima:boolean;
begin
write('Unesi ime osobe '); readln(imeosobe);
writeln('Ime datoteke za citanje? ');
readln(imedat); assign(f,imedat); {$I-} reset(f); {$I+}
if IOresult <> 0
then writeln('Takva datoteke ne postoji ')
else begin
ima:=false;
while (not ima) and (not eof(f)) do
begin
read(f,osoba);
with osoba do
if prezime=imeosobe then
begin
writeln(prezime,' ',telefon);
ima:=true;
end
end;
if (not ima) then
writeln('Osoba ',imeosobe,' nema telefon');
end
end;
begin
kreiranje(f); ispis(f); nadjii(f);
end.

close(f)

8.11.1. Tekstualne datoteke


Datoteke iji su elementi znaci kodirani standardnim kodom (ASCII) nazivaju se tekstualnim.
Odreene su sledeim opisom:
type Text = file of char:

U sutini tip podataka text je standardni tip podataka u jeziku Pascal kao to su to npr.
Integer, Real, Cha r i Boolean. Moe se smatrati da su tekstualne datoteke nizovi znakova koji
se mogu tampati. Za rad sa tekstualnim datotekama mogu se koristiti sledee procedure:
WRITELN(X) - zavretak tekuceg reda tekstualne datoteke X;
READLN(X) - prelaz na pocetak sledeeg reda tekstualne datoteke X (X^ pokazuje na prvi
znak sledeeg reda);
EOLN(X) - logicka funkcija koja pokazuje da li je dostignut kraj tekueg reda tekstualne
datoteke X (ako EOLN(X) = true tada X^ pokazuje na razdelnik redova).
Takoe se mogu koristiti i procedure read i write, u onom smislu u kome su ve opisane. Ako
je F tekstualna datoteka i CH promenljiva tipa char, vai:
write(F,CH); ekvivalentno je sa:
read(F.CH); ekvivalentno je sa:

F^ :=CH; PUT(F);
CH := F^; GET(F);

Procedure readln i writeln mogu se koristiti samo u sluaju tekstualnih datoteka. Slino
procedurama read i write i ove procedure se mogu koristiti sa vie argumenata i pri tome je:
READLN(F,CH1,CH2,...,CHK);

204
ekvivalentno sa:
READ(F, CH1);
...
READ(F, CHK);
READLN(F);

Za rad sa tekstualnim datotekama mogu se koristiti sledee opte procedure.


(1) itanje tekstualne datoteke F:
program Citextdl( );
var F: text; Pom, CH: char;
begin
reset(F);
...
w h i l e not EOF(F) do
begin
while not E O L N ( F ) do
begin
read(F,CH); Pom := CH ;
end;
readln(F);
end;
end.

ill
program Citextd2 ( );
var F: text; Pom, CH : char;
begin
reset(F);
...
repeat
repeat
r e a d ( F , C H ) ; Pom := C H ;
until E O L N ( F ) ;
readln(F);
until E O F ( F ) ;
end.

(2) Kreiranje tekstualne datoteke F:


program Krtextdl();
var
F: text;
CH, Pom :char;
Daljedat, Daljered :Boolean;
begin
rewrite(F);
...
while Daljedat do
begin
while Daljered do
begin
CH := Pom; write(F,CH);
end;
writeln(F);
end;
...

Predrag S. Stanimirovi

205

Programski jezici

end.

ili
program Krtextd2 ( );
var
F : text;
C H , Pom : char;
Daljedat, Daljered : Boolean;
begin
rewrit e ( F ) ;
...
repeat
repeat
CH := Pom; write(F,CH);
until not Daljered;
writeln ( F ) ;
until not Daljedat;
end.

Sledei primer je jedan od klasinih problema koji se reavaju pomou tekstualnih datoteka.
Primer. Program kojim se preslikava datoteka X u datoteku Y i pri tome se svaki niz uzastopnih
praznina zamenjuje jednom.
program Preslikati (X,Y);
var
CH : char; X,Y : text;
begin
RESET(X); REWRITE(Y);
while not EOF(X) do begin
while not EOLN(X) do begin
READ(X,CH);
WRITE(Y,CH);
if CH = '
' then
repeat
READ(X,CH)
until CH <>'';
end;
READLN(X); WRITELN(Y);
end
end.

Primeri.
Primer. Data su dva fajla
var f,g:text;
Ispitati da li su isti. Ako su isti odtampati tekst 'isti su'. Ako nisu istu odtampati koja opisuje
prvu pronaenu razliku.
program poreenje;
var
f,g:text;
radi:boolean;
i : integer;
ch1,ch2:char;
begin
assign(f,'f.pas'); assign(g,'g.pas');
reset(f); reset(g);
i:=1;
radi := true;
while not eof(f) and not eof(g) and radi do

206
begin
read(f,ch1); read(g,ch2);
if ch1 = ch2 then i:= i+1
else radi := false;
end;
if not radi then
writeln('Fajlovi se razlikuju u ',i,' -toj
komponenti')
else if eof(f) and not eof(g)
then
writeln('Datoteka g je duza')
else if not eof(f) and eof(g) then
writeln('Datoteka f je duza')
else writeln('Isti su')
end.

Primer. Napisati program kojim se itaju dva tekstua;na fajla tekst1 i tekst2, i tampaju jedan
pored drugog, na sledei nain:
tekst1
tekst2
----------------------------------------------------Ne sme se menjati struktura redova u fajlovima.
program tekstovi;
var
tekst1, tekst2 : text;
ch : char;
i,j : integer;
begin
writeln;writeln;
write('
tekst1
');
write('
tekst2 ');
writeln;writeln;
assign(tekst1, 'tekst1.pas'); assign(tekst2,'tekst2.pas');
reset(tekst1); reset(tekst2);
i := 0;
repeat
if eof(tekst1) then
begin write(' EOF '); i:=8
end
else while not eoln(tekst1) do
begin
read(tekst1,ch);
i := i+1;
write(ch)
end;
readln(tekst1);
for j := i to 38 do write(' ');
i:=0;
if eof(tekst2) then write(' EOF
')
else while not eoln(tekst2) do
begin
read(tekst2,ch); write(ch)
end;
readln(tekst2);
writeln
until eof(tekst1) and eof(tekst2)
end.

Primer. Izraunati broj praznih redova u tekstualnom fajlu.


program prazniredovi;

Predrag S. Stanimirovi

Programski jezici

207

uses crt;
var tx:text;
ime:string;
l:longint;
function empty(var t:text):longint;
var k,d:integer;
ch:char;
begin
reset(t);
k:=0;
while not eof(t) do { ciklus po redovima }
begin
d:=0;
{ d je duzina tekuceg reda }
read(t,ch);
while not eoln(t) do
begin
d:=d+1;
read(t,ch)
end;
if d=0 then k:=k+1;
read(t,ch); { propustanje kraja reda }
end;
empty:=k;
end;
begin
clrscr;
write('Unesi ime datoteke '); readln(ime);
assign(tx,ime);
l:=empty(tx);
writeln('Praznih redova u datoteci ',ime,' ima ',l);
close(tx);
end.

8.11.2. Standardne datoteke INPUT i OUTPUT


U programskom jeziku Pascal za oznaavanje standardnih ulazno-izlaznih ureaja (tastatura,
ekran i slino) koriste se tekstualne datoteke I NP UT i OUTPUT. Kada se predvia rad sa ovim
standardnim uredajima imena ovih datoteka se navode u zaglavlju programa. U torn sluaju
procedure za rad sa datotekama mogu da se koriste bez argumenta kojim se ukazuje na datoteku,
kada se podrazumeva da se ulazne procedure odnose na datoteku INPUT, a izlazne na datoteku
OUTPUT. Po dogovoru vae sledee relacije:
WRITE(CH)
READ(CH)
WRITELN
READLN
EOF
EOLN

ekvivalentno sa
ekvivalentno sa
ekvivalentno sa
ekvivalentno sa
ekvivalentno sa
ekvivalentno sa

WRITE(OUTPUT, CH)
READ(CH)
WRITELN(OUTPUT)
READLN(INPUT)
EOF(INPUT)
EOLN(INPUT)

Napomena: Obino se kod implementacije jezika Pascal procedure reset i r e wri t e koriste za
povezivanje stvarnih datoteka sa logikim (programskim) datotekama. Na primer:
R E S E T ( I N P U T, ' PODACI ' ) ;
- Datoteka kreirana na disku pod imenom
PODACI ' povezuje se sa standardnom datotekom I NPUT.

208
REWRITE(OUTPUT,' IZLAZ');
datoteka sa imenom ' I ZLAZ '.

- Kao izlazna datoteka na disku e biti kreirana

8.11.3. PRISTUP DATOTEKAMA U C


Datoteke omoguavaju da se ulazne veliine i rezultati obrade podataka trajno sauvaju na
disku. Datoteka se tretira kao sekvencijalni niz karaktera. Datotekama se pristupa korienjem
ukazatelja na strukturu FILE, koja je definisana u biblioteci stdio.h. U stdio.h su definisane i
konstante EOF i NULL. konstanta EOF oznaava kraj datoteke i ima vrednost -1. Konstanta
NULL ima vrednost 0 i vraa se kao rezultat neuspenog poziva nekih funkcija za upravljanje
datotekama.

Otvaranje i zatvaranje datoteka


Datoteka mora da bude otvorena pre bilo kakvog procesiranja. Prilikom otvaranja datoteke
mora se specificirati njeno ime i tip eljene ulazno-izlazne operacije. Moe se koristiti reim
itanja (read mode), reim upisa (write mode), odnosno reim dodavanja (append mode). Za
otvaranje datoteka koristi se funkcija fopen iz C biblioteke. Njeno zaglavlje je oblika
FILE *fopen(char *file_name, char *file_mode)
Funkcija fopen() ima dva argumenta: file_name i file_mode, tipa ukazatelj na char, a vraa
ukazatelj na strukturu FILE. Pomou specifikacije "r" datoteka se otvara za itanje; za reim
upisa u datoteku koristi se specifikacija "w", dok se za reim dodavanja na kraj datoteke koristi
"a".
Ako je otvaranje neuspeno, tj. ako fopen() ne moe da pronae eljenu datoteku, ona vraa
vrednost NULL.
Primer. Niz iskaza
#include<stdlib.h>
FILE *infile,*fopen();
infile=fopen("file","r"); }
otvara datoteku pod imenom file u reimu itanja.
Funckija fopen() vraa ukazatelj na strukturu FILE, koja se dodeljuje promenljivoj infile istog
tipa.
Neuspeno otvaranje datoteke infile se moe ispitati izrazom oblika
if(infile==NULL)
printf("datoteka file ne moze se otvoriti\n");
Poziv funkcije fopen() i ispitivanje vraenog rezultata se moe ujediniti
if((infile=fopen("file","r"))==NULL)
printf("datoteka file ne moze biti otvorena\n");
Funkcijom fclose() zatvara se datoteka otvorena za itanje ili upis. Zatvorenoj datoteci se ne
moe pristupiti pre ponovnog otvaranja. Zaglavlje ove funkcije je
int fclose(FILE *file_pointer);
gde je file_pointer ukazatelj kojim se identifikuje datoteka.
Funkcija

Predrag S. Stanimirovi

209

Programski jezici

fclose(file_pointer)
vraa vrednost EOF ako ukazatelj file_pointer nije povezan sa nekom datotekom.
Na primer, otvorena datoteka infile zatvara se izrazom
fclose(infile);

Funkcije getc()i putc()


Funkcija getc() uitava jedan po jedan karakter iz specificirane datoteke. Slina je funkciji
getchar(). Ulazni argument funkcije getc() je ukazatelj na strukturu FILE, a rezultat je vrednost
tipa int. Zaglavlje ove funkcije je oblika:
int getc(FILE *infile)
Pretpostavimo da promenljiva infile dobija vrednost pomou funkcije fopen(), koristei opciju
"r". Ako je c promenljiva tipa int, tada se iskazom
c=getc(infile);
uitava jedan znak datoteke koja je povezana sa pointerom infile.
Ako je dostignut kraj datoteke, funkcija getc() vraa vrednost EOF.
Funkcija putc() upisuje karakter u specificiranu datoteku. Poziva se izrazom oblika
int putc(char c, FILE *outfile)
Primer. Izrazima
FILE *outfile;
outfile=fopen("file","w");
putc('z', outfile);
u datoteku outfile upisuje se znak 'z'.
Primer. Napisati program kojim se sadraj datoteke "ulaz" (formiran od velikih slova azbuke)
ifrira i upisuje u datoteku "izlaz". ifriranje se sastoji u tome da se svaki znak razliit od 'Z'
zamenjuje sledeim { ASCII} znakom, dok se znak 'Z' zamenjuje znakom 'A'.
#include<stdio.h>
void main()
{ FILE *infile, *outfile;
int c;
infile = fopen("ulaz","r");
outfile= fopen("izlaz","w");
while((c=getc(infile)) != EOF)
{ if('A'<=c && c< 'Z')c++;
else c='A';
putc(c,outfile);
}
fclose(infile);
fclose(outfile);
}

Primer. Kopiranje sadraja ulazne datoteke u izlaznu datoteku. Imena datoteka data su kao
parametri funkcije main().
#include<stdio.h>
void main(argc,argv);
int argc;
char *argv[];
{ int c;
FILE *infile,*outfile,*fopen();
if((infile=fopen(argv[1],"r"))==NULL)

210

printf("datoteka %s ne moze biti otvorena\n",argv[1]);


else
if((outfile=fopen(argv[2],"w"))==NULL)
printf('datoteka %s ne moze biti otvorena\n",argv[2])
else
{ while((c=getc(infile))!=EOF) putc(c,outfile);
printf("\n");
}
fclose(infile);
fclose(outfile);

Funkcije fprintf() i fscanf()


Ove funkcije obavljaju analogne operacije kao i funkcije printf() i scanf(), s tim to zahtevaju
dodatni argument za identifikaciju datoteke u koju se upisuju ili iz koje se itaju podaci.
Zaglavlje ovih funkcija je sledeeg oblika:
fprintf(file_pointer,konverzioni_niz,lista_argumenata)
fscanf(file_pointer,konverzioni_niz,lista_argumenata)

pri emu je:


file_pointer ukazatelj na tip FILE,

konverzioni_niz je lista formata po kojima se upisuju ili itaju podaci,


dok je lista_argumenata lista vrednosti koje se upisuju u datoteku, odnosno itaju iz datoteke
koja je identifikovana pointerom file_pointer.
Funkcije fprintf() i fscanf() imaju promenljivi broj argumenata, zavisno od broja vrednosti
koje se upisuju u datoteku, odnosno itaju iz datoteke.
Na primer, izrazom
fprintf(outfile,"string u datoteku\n");

upisuje se string "string u datoteku\n" u datoteku koja je identifikovana pomou pointera outfile.
Takoe, u istu datoteku se moe upisati i sledei sadraj:
fprintf(outfile,"string sadrzaja %s u datoteku\n",x);
Primer. Izrazom oblika
fscanf(infile,"%f",&x);

iz datoteke koja je identifikovana sa infile uitava se vrednost u formatu %f i dodeljuje


promenljivoj x.
Primer. Procedure za uitavanje celog broja iz datoteke "zad2.dat" i upis istog broja u datoteku
"zad2.res".
#include<stdio.h>
void citaj(long *n)
{ FILE *f;
f=fopen("zad2.dat","r");
}
void upis(long n)
{ FILE *f;
f=fopen("zad2.res","w");
fclose(f);
}

fscanf(f,"%ld",n);

fprintf(f,"%ld",n);

fclose(f);

Predrag S. Stanimirovi

void main()
{ void citaj(long *);
long n;
citaj(&n); upis(n);
}

211

Programski jezici

void upis(long);

Primer. Iz prvog reda datoteke uitati broj timova. U svakom od sledeih redova datoteke
zadati sledee podatke za svaki tim:
- broj pobeda,
- broj nereenih rezultata, i
- broj poraza.
Sortirati tabelu prema broju osvojenih bodova. Ako dva tima imaju isti broj osvojenih bodova,
sortirati ih prema broju pobeda.
#include<stdio.h>
#include<string.h>
#define broj 10
struct klub
{ char naziv[20];
int izgubljene;
int neresene;
int dobijene;
} tabela[broj];
void strswap(char str1[broj], char str2[broj])
{ char str[broj];
strcpy(str,str1); strcpy(str1,str2); strcpy(str2,str);
}
void swap(int *p, int*q)
{ int pom;
pom=*p; *p=*q; *q=pom;
}
void ucitaj(int *n, struct klub a[broj])
{ int i;
char s[20];
FILE *f;
f=fopen("klubovi.dat","r");
fscanf(f,"%d",n);
for(i=0; i<*n; i++)
{ fscanf(f,"%s",a[i].naziv);
fscanf(f,"%d%d
%d",&a[i].dobijene,&a[i].neresene,&a[i].izgubljene);
}
close(f);
}
void ispis(int n, struct klub a[broj])
{ int i;
printf("\n");
for(i=0; i<n; i++)
{ printf("%s %d %d %d",a[i].naziv, a[i].dobijene,
a[i].neresene,a[i].izgubljene);
printf("\n");
}
}
void main()
{ int i,j,n, bodovi[broj];
ucitaj(&n,tabela);

212

for(i=0;i<n;i++)
bodovi[i]=tabela[i].neresene+3*tabela[i].dobijene;
for(i=0; i<n-1;i++)
for(j=i+1;j<n;j++)
if((bodovi[i]<bodovi[j])||
((bodovi[i]==bodovi[j]) &&
(tabela[i].dobijene<tabela[j].dobijene))
)
{ strswap(tabela[i].naziv, tabela[j].naziv);
swap(&tabela[i].izgubljene,
&tabela[j].izgubljene);
swap(&tabela[i].neresene, &tabela[j].neresene);
swap(&tabela[i].dobijene, &tabela[j].dobijene);
}
ispis(n,tabela);

Funkcija feof()
Ova funkcija ispituje da li je dostignut broj datoteke. Njen opti oblik je
int feof(FILE *file pointer)

Funkcija feof() vraa nenultu vrednost ako je dostignut kraj datoteke.


Primer. Funkcija feof se koristi za ispitivanje kraja datoteke.
if(feof(infile)) printf("kraj datoteke\n");

Funkcije fgets() i fputs()


Funkcija fgets() ima sledee zaglavlje:
char *fgets(char *string, int maxl, FILE *infile);

Ovom funkcijom se, iz datoteke na koju ukazuje pointer infile, uitava string koji se zavrava
relazom u novi red ili sadri maxl-1 znakova. Prema tome, drugi argument, oznaen sa maxl,
predstavlja maksimalnu duinu uitanog stringa. Na kraj uitanog stringa postavlja se znak '\0'.
U sluaju da linija iz koje se uitava sadri vie od maxl karaktera, linija se ne ignorie, ve se
preostali znakovi uitavaju sledeim pozivom funkcije fgets().
Razlika izmeu funkcija gets() i fgets() je u tome da gets() zamenjuje znak za prelaz u novi
red null karakterom '\0', dok fgets() ostavlja znak za prelaz u novi red, pa tek onda postavlja
znak '\0'.
Funkcija fgets() vraa vrednost NULL kada naie na znak EOF.
Funkcija fputs() poziva se izrazom
int fputs(char *string, FILE *outfile);

Pozivom ove funkcije upisuje se niz karaktera, sadrani u vrednosti parametra string, u
datoteku na koju ukazuje pointer outfile. U sluaju I/O greke ova funkcija vraa rezultat EOF.
Funkcije puts() i fputs() ne dopisuju karakter '\0' na kraj upisanog stringa. Za razliku od
funkcije puts(), funkcija fputs() ne dopisuje znak za prelaz u novi red na kraj stringa koji se
upisuje.

8.12. Strukturni tipovi podataka u MATHEMATICA

Predrag S. Stanimirovi

213

Programski jezici

Strukturni tipovi podataka, kakvi su nizovi, slogovi, skupovi i datoteke, poznat je u viim
programskim jezicima. U jeziku MATHEMATICA dominantan strukturni tip podataka su liste i
izrazi. Liste obuhvataju nizove, skupove i slogove kao strukturne tipove podataka. Takoe, svi
strukturni tipovi podataka imaju jedinstvenu strukturu.

8.12.1. Indeksirani objekti


U mnogim vrstama izraunavanja koriste se indeksirani objekti (arrays) koji sadre sekvence
izraza, od kojih je svaki specificiran odreenim indeksom. Jedan nain da se definiu sekvence
u MATHEMATICA jesu liste. Na primer, moe se definisati lista oblika a= {x,y,z,}.
Elementima takve liste se moe pristupati koriste}i izraze a[[i].Tako|e, elementi ove liste se
mogu modifikovati izrazima oblika a[[i]]=value.Ovakav pristup ima nedostatak {to
zahteva da se zadaju svi elementi kada se prvi put kreira lista. esto je mnogo praktinije da se
koriste indeksirani objekti u kojima se mogu zadati samo oni elementi koji su potrebni u
odreenom trenutku. Definicije indeksiranih objekata su oblika a[i].

Definicija vrednosti a[1]:


a[1] = 9

i vrednosti a[2]:
a[2] = 7

@
D
@
D

Sve do sada definisane vrednosti koje su povezane sa a mogu se pregledati izrazom


?a

Global`a
a 1 =9
a 2

=7

Moe se definisati vrednost za a[5] iako nisu definisane vrednosti a[3] i a[4].
a[5] = 0

Lista vrednosti indeksiranih objekata a[i] se moe definisati na sledei nain:

8@
D@
D<

Table[a[i], {i, 5}]

9, 7, a 3 , a 4 , 0

Izraz oblika a[i] se moe posmatrati kao indeksirana promenljiva. Manipulacija


indeksiranim objektima opisana je u sledeoj tabeli
a[i]=value
a[i]
a[i]=.
Clear[a]
Table[a[i]], {i,1,n}]
Array[a,n]

definisati ili predefinisati vrednost


pristup vrednosti
uklanjanje vrednosti
brisanje svih definicija vezanih za a
konstrukcija indeksiranih objekata

U izrazu oblika a[i] nije obavezno da indeks i bude broj. U stvari, indeks moe da bude
proizvoljni izraz. Upotreba simbola za indekse omoguava da se definiu jednostavne baze
podataka.
Definicija objekta area sa indeksom square sa vredno{}u 1:
area[square] = 1

214

Sledeim izrazom se dodaje novi rezultat za bazu area:


area[triangle] = 1/2

1
2

Veliine koje odgovaraju bazi area mogu se pregledati na sledei nain:

@D
@D
@D

?area

Global`area
area square

=1

area triangle

= 1
2

Ovakve definicije se mogu koristiti u proizvoljnim izrazima.


4 area[square] + area[pentagon]

4 + area pentagon

8.12.2. Vektori i matrice


Vektori se predstavljaju listama iji su elementi atomi, dok se matrice predstavljaju listama
iji su elementi liste.
{a,b,c}
{{a,b},{c,d}}

vektor {a,b,c}
matrica ija je prva vrsta vektor {a,b}a druga vektor {c,d}

8
8<
8<
<
8<

Definicija matrice m:

m = {{a, b}, {c, d}}

a, b , c, d

Prvi element matrice m:


m[[1]]

a, b

Element matrice m u prvoj vrsti i drugoj koloni:


m[[1,2]]

8<
8 <
8
<
b

Vektor v ima dve komponente:


v = {x,y}
x, y

Objekti p i q se tretiraju kao skalari:


p v + q

q + p x, q + p y

Vektori se sabiraju po koordinatama:

v + {xp, yp} + {xpp, ypp}

x + xp + xpp, y + yp + ypp

Simbol taka oznaava skalarni proizvod dva vektora:


{x, y} . {xp, yp}

x xp + y yp

Predrag S. Stanimirovi

215

Programski jezici

8 <
8
8 <
8 <
<
H LH L

Mogu se mnoiti matrice i vektori odgovarajuih dimenzija.


m . v

a x + b y, c x + d y

Mogu se mno`iti i dve matrice.


m . m

a2 + b c, a b + b d , a c + c d, b c + d2

Pomou operacija nad vektorima mogu se dobiti sklalarne veliine.


v . m . v

x a x+ c y

+y

b x +d y

Kako se liste koriste za reprezentaciju vektora i matrica, ne moe se uoiti razlika izmeu
vektora koji predstavljaju vrste i vektora koji prestavljaju kolone matrica.

5.3. Datoteke
MATHEMATICA koristi tekstualne datoteke. One se mogu obraivati pomou editora teksta.
Tako pripremljene lako se prenose u druge aplikacije. Postojee datoteke se mogu otvoriti
pomou menija File>Open, a zapisati pomo}u File>Save As, a tekstualne
pomo}u File>Save AsSpecial>Text.
U aktivni notebook, mogu se dozvati naredbom <<ime datoteke, ~ime se
pozivaju na izvr{enje. Isto dejstvo ima izraz Get["datoteka"].
Upisivanje nekog izraza u datoteku uz brisanje prethodnog sadr`aja
datoteke, posti`e se naredbom
izraz >> datoteka
ili
Put["datoteka"].
Izraz se dodaje na kraj datoteke uz ~uvanje prethodnog sadr`aja pomo}u
naredbe
izraz >>> datoteka
ili
PutAppend["datoteka"].
Direktni pristup podacima u datoteci ostvaruje se pomo}u kanala (channel).
MATHEMATICA podr`ava kanale za ~itanje i pisanje podataka.
(1) Otvaranje kanala i uspostavljanje veze sa odre|enom datotekom:
k=OpenRead["dat"]
k=OpenWrite["dat"]
k=OpenAppend["dat"]

otvaranje kanala k za ~itanje datoteke


dat
otvaranje kanala k za upisivanje u
datoteku dat pri ~emu se bri{e prethodni
sadr`aj
otvaranje kanala k za upisivanje u
datoteku dat pri ~emu se novi podaci
dodaju prethodnom sadr`aju datoteke

(2) ~itanje ili upisivanje podataka predstavljeno je slede}om tabelom:


Read[k]
Read[k,tip]
Write[k,izraz1,izraz2,...]

~itanje jednog podatka sa kanala k


~itanje podataka datog tipa sa kanala k
upisivanje niza izraza u kanal k posle

216
~ega se prelazi u novi red
(3) Zatvaranje kanala posti~ze se naredbom Close[k].
Kada datoteka sadr`i ve}i broj podataka razdvojenih prazninama ili
zarezima, ovom naredbom u~itavaju se svi podaci iz datoteke i prevode u
listu.
u~itavanje liste podataka iz
datoteke
u~itavanje liste podataka odre|
enog tipa iz datoteke
u~itavanje liste podataka iz
datoteke pri ~emu se svaki red
sme{ta u posebnu podlistu.

ReadList["dat"]
ReadList["dat",tip]
ReadList["dat",RecordList-> True]

Primer.
Neka je "ulaz" datoteka u kojoj se nalaze brojevi 1, 2, 3, 4. Posle izraza
a=ReadList["ulaz",{Real,Real}];
Print[a];
Det[a]
Prikazuje se matrica {{1.,2.},{3.,4.}} i vrednost njene determinante -2.

8.12.4. Izrazi
MATHEMATICA manipuli{e sa objektima razli~itih tipova: matemati~kim
formulama, listama, graficima. Iako oni izgledaju razli~ito, MATHEMATICA ih
predstavlja na univerzalan na~in: svi su oni izrazi. Prototip izraza u je oblika
f[x,y,... ]. Ime funkcije je f, a argumenti su x,y, ... Izrazi se ne moraju uvek
pisati u obliku f[x,y,... ]. Na primer, x+y je tako|e izraz. MATHEMATICA
konvertuje taj izraz u standardni oblik Plus[x+y]. Isti princip va`i za sve ostale
operatore. U stvari, svaka naredba u MATHEMATICAse tretira kao izraz.
Objekat f u izrazu f[x,y, ...] naziva se glava (head) tog izraza. On se moe izdvojiti
koristei izraz Head[f[x,y, ]]. Uop{te, glava izraza expr mo`e se izdvojiti pomo}u
Head[expr]. U toku pisanja programa esto puta je potrebno da se testira glava nekog izraza da
bi se odredila vrsta izraza.
Primer. U slede}oj tabeli su prikazane reprezentacije nekih izraza.
x+y+z
xyz
x^n
{a,b,c}
a->b
a=b

@
@D
D
@D
@
8<
D

Unutra{nja forma
FullForm[expr].

Head f x, y, z
f
Head a + b + c
Plus
Head a, b, c

bilo

kog

Plus[x,y,z]
Times[x,y,z]
Power[x,n]
List[a,b,c]
Rule[a,b]
Set[a,b].
izraza

mo`e

se

dobiti

pomo}u

izraza

Predrag S. Stanimirovi

217

Programski jezici

@D
@D
@
D
@
DD
@
@
@
D
DD
@
@
@
D
@
D
D
@
H
L
D
@@
D@@
DD
D

List
Head 123344
Integer
Head 123344.229
Real
FullForm x + y + z
Plus x, y, z
FullForm x + y + y
Plus x, Times 2, y
FullForm x + y + y + z^2
Plus x, Times 2, y , Power z, 2
FullForm x + y + y + z + q ^ 2
Plus x, Times 2, y , Power Plus q, z , 2

Izrazi se mogu iskoristiti za kreiranje korisnikih struktura. Na primer, take u


trodimenzinalnom prostoru se mogu predstaviti izrazom point[x, y, z]. "Funkcija" point ne
izvrava operacije, ve omoguava da se tri koordinate objedine, a da se rezultujui objekat
oznai sa point.

9. DINAMIKE STRUKTURE PODATAKA

9.1. Statike i dinamike strukture podataka


Strukturni tipovi podataka opisani u prethodnom poglavlju mogu se koristiti za reavanje
iroke klase problema. U svim razmatranim sluajevima radi se o statikim strukturama podataka,
odnosno o strukturama koje se generiu u fazi prevoenja programa, bez mogunosti da se
struktura memorijskog prostora koji zauzimaju menja u toku izvravanja programa. Meutim,
postoji jedna klasa problema kod koje je potrebno strukturu podataka generisati dinamiki, u
toku izvravanja programa, bilo da je to zbog toga to se radi o strukturama koje su po prirodi
beskonane ili zbog toga to je broj potencijalnih elemenata strukture unapred nepoznat.
Osnovne dinamike strukture su liste i one su osnova za definisanje linearnih struktura podataka
tipa magacina, redova, razliitih tablica sa unapred nepoznatim brojem elemenata, kao i nelinearnih
struktura kao to su stabla, grafovi i mree.
Kao primer gde je prirodnije korienje dinamike strukture podataka umesto statike
uzmimo retku ili slabo popunjenu matricu u kojoj vei broj elemenata ima vrednost nula, a samo
su neki elementi definisani vrednostima razliitim od nule. Umesto statikog pamenja cele

218
ovakve matrice, pri cemu se za svaki od elemenata (bez obzira da li su u pitanju nule ili ne)
rezervie odgovarajui memorijski prostor, racionalnije je ovakvu matricu memorisati tako to
se pamte samo vrednosti elementa razliitih od nule sa podacima o njihovoj lokaciji u matrici. U
ovom sluaju nije potrebno da se unapred zna broj elemenata matrice, jer je on odreen svakom
konkretnom strukturom.
Dinamike strukture podataka imaju prednosti u odnosu na statike i u pogledu njihovog
menjanja, o cemu ce biti rei neto kasnije kroz primere koji se odnose na konkretne strukture
podataka.

9.2. Pokazivai
U mnogim programskim jezicima (Pascal, Modula, C, Ada) postoji mogunost definisanja
tipova podataka koji se sastoje od neogranienog skupa pokazivaa na vrednosti odreenog tipa
podataka. Nad pokazivaima su definisane jedino operacije poredenja u smislu jednakosti i
nejednakosti. Svakom tipu pokazivaa pripada i vrednost N I L (ili N U L L ) (prazan pokaziva)
koja ne pokazuje ni na jedan element strukture. U programskim jezicima se koriste razliite
oznake za predstavljanje pokazivaa, ali je sintaksa naredbi za njihovo definisanje slina:
tip_pokaziva a = ^Ide nt if i kator_tipa
Tip pokazivaa se obino povezuje sa nekim tipom podataka. Najee je to neki strukturni
tip podataka kojim se definiu slogovi koji se povezuju u dinamiku strukturu podataka. U
ovakvim sluajevima obino je potrebno da se kao sastavni deo sloga pojavi jedan ili vie
pokazivaa istog tipa preko kojih se slogovi povezuju u odreenu strukturu podataka. Ovde se
javlja potreba za odstupanjem od jednog od osnovnih pravila koje se striktno potuje u
programskim jezicima. To pravilo se sastoji u tome da svi objekti (moemo to posmatrati i kao i
sva imena) koji se koriste u programu moraju prethodno biti definisani. U sluaju kada
definiemo tipove pokazivaa dogaa se da moramo da upotrebimo ime tipa podataka na koji
definiemo pokazivae a da taj tip jo nismo definisali. Naime povezivanje tipa pokazivaa sa
tipom podataka odgovarajue strukture postize se po jednom od sledeih modela:
type Pokaziva =T; T = record ... ;
var

P : Pokaziva;

ili
type T = record ... ;
var

P :

T;

9.3. Korienje pokazivaa


Pokazivai se obino koriste za definisanje struktura podataka tipa listi. Razmotriemo neke
od ovih struktura podataka koje imaju najiru primenu.
U narednom primeru je definisan i generisan magacin kao dinamika struktura podataka.
Magacin je kreiran kao niz meusobno povezanih slogova od kojih svaki sadri informativni
deo Info i pokaziva na sledei slog strukture. itanje i upis novih elemenata mogu je samo na
vrhu magacina.
program magacin;
type
L1= ^Slog;
Slog = record
Info : char;
Link : L1;
end;

TOP

Info
Link

Predrag S. Stanimirovi

Programski jezici

219

var
TOP,K : L1;
CH : char;
begin
TOP := NIL;
while not EOF do
begin
read(CH); new(K);
K^.Link := TOP;
K^.Info := CH;
TOP := K
end;
end.

Info
Link

Info
Link
NIL

U radu sa magacinom koriste se dve osnovne operacije od kojih jedna za upis novih slogova
u strukturu, a druga za izbacivanje slogova iz magacina. Sa datim opisom magacina ove
operacije se mogu definisati na sledei nain.
(1) Upis slogova u magacin:
var Novislog : L1;

read(CH); new(Novislog);
Novislog^.Link := TOP;
Novislog^.Info := CH;
TOP := Novislog;

(2) Izbacivanje sloga iz magacina (postie se jednom naredbom):


TOP := TOP^.Link;

Sledei primer ilustruje definisanje i generisanje reda kao dinamike strukture podataka.
Primer. Kreiranje reda kao strukture podataka.

var L, R, K : L1;

CH : char;

read(CH); new(K);
K^.Info := CH;
K^.Link := NIL;
R := K;
L := K;
while not EOF do
begin
read(CH); new(k);
K^.Info := CH;
K^.Link := L;
L := K;
end;

end.

Info
Link

220
R

Info
Link
NIL

Redu se mogu dodavati novi slogovi korienjem pokazivaa R:


var Novislog: L1;

r e a d ( C H ) ; ne w ( N o v i s l o g ) ;
R^.Link := Novislog:
Novisl og^ .Link := NIL;
Novislog^.Info := CH;
R := N o v i s l o g ;

Za izbacivanje sloga iz reda koristi se pokaziva L, a postize se samo jednom naredbom:


L

:= L^.Link;

Primeri.
Primer. Svaki element liste deklarisan je sledeim tipovima:
type pokazivac=^ slog;
slog=record
prezime:string[20];
adresa:string[30];
sledeci:pokazivac;
end;
a) Napisati proceduru za dodavanje elementa na pocetak liste.
b) Napisati procedure za formiranje liste i ispis u inverznom poretku.
c) Napisati funkciju koja ispituje da li postoji slog u listi ije je polje prezime jednako vrednosti
neke string promenljive.
d) Napisati proceduru za brisanje prvog sloga liste, pri emu se oslobaa zauzeti memorijski
prostor.
program dinam5;
type pokazivac=^ slog;
slog=record
prezime:string[20];
adresa:string[30];
sledeci:pokazivac;
end;
var pocetakliste:pokazivac;
s:string[20];
procedure citajslog(var tslog:slog);
begin
with tslog do
begin
write('Unesi ime i prezime: '); readln(prezime);
write('Unesi adresu '); readln(adresa);
end;
end;
procedure pisislog(tslog:slog);
begin
writeln;
with tslog do
begin

Predrag S. Stanimirovi

221

Programski jezici

writeln(prezime); writeln(adresa);
end;

end;

procedure dodajnapocetak(var pocetak:pokazivac);


var novi:pokazivac;
begin
new(novi);
citajslog(novi^ );
novi^ .sledeci:=pocetak; pocetak:=novi;
end;
procedure formiraj(var pocetak:pokazivac);
var tslog:pokazivac; ch:char;
begin
pocetak:=nil;
repeat
dodajnapocetak(pocetak); write('Zelite jos? ');
readln(ch);
until not (ch in ['d','D']);
end;
procedure ispisliste(pocetak:pokazivac);
var tslog:pokazivac;
begin
tslog:=pocetak;
while tslog<>nil do
begin
write('Pritisni <ENTER> za ispis sledeceg sloga');
readln;
pisislog(tslog^ ); tslog:=tslog^ .sledeci;
end;
end;
procedure izbaciprvi(var pocetak:pokazivac);
var pom:pokazivac;
begin
if pocetak<>nil then
begin
pom:=pocetak;
pocetak:=pocetak^ .sledeci;
dispose(pom);
end;
end;
function postoji(kod:string; pocetak:pokazivac):boolean;
var tslog:pokazivac;
begin
if pocetak=nil then postoji:=false
else begin
tslog:=pocetak;
while (tslog^ .prezime<>kod) and (tslog<>nil) do
tslog:=tslog^ .sledeci;
if tslog=nil then postoji:=false
else postoji:=true;
end;
end;
begin
formiraj(pocetakliste);
writeln('Formirana je sledeca struktura');

222
ispisliste(pocetakliste);
write('Ime koje trazite? '); readln(s);
if postoji(s,pocetakliste) then
writeln('Takvo ime postoji')
else writeln('Takvo ime ne postoji');
writeln('Lista bez prvog elementa:');
izbaciprvi(pocetakliste);
ispisliste(pocetakliste);
readln;
end.

Primer. Svaki element liste deklarisan je sledeim tipovima:


type pokazivac=^ slog;
slog=record
info:integer;
sledeci:pokazivac;
end;
Napisati proceduru za nadovezivanje dve liste.
program dinam6;
type pokazivac=^ slog;
slog=record
info:integer;
sledeci:pokazivac;
end;
var poc1,poc2,poc:pokazivac;
procedure formiraj(var pocetak:pokazivac);
var novi:pokazivac; ch:char;
begin
pocetak:=nil;
repeat
new(novi);
readln(novi^.info); novi^.sledeci:=pocetak;
pocetak:=novi;
write('Zelite jos? '); readln(ch);
until not (ch in ['d','D']);
end;
procedure ispisliste(pocetak:pokazivac);
var tslog:pokazivac;
begin
tslog:=pocetak;
while tslog<>nil do
begin
write(tslog^.info,' '); tslog:=tslog^ .sledeci;
end;
writeln;
end;
procedure nadovezi(p1,p2:pokazivac; var p:pokazivac);
var pom:pokazivac;
begin
if p1=nil then p:=p2
else begin
p:=p1;
if p2<>nil then

Predrag S. Stanimirovi

223

Programski jezici

begin
pom:=p1;
while pom^ .sledeci <> nil do
pom:=pom^.sledeci;
pom^ .sledeci:=p2;
end;
end;
end;
begin
writeln('Prva lista'); formiraj(poc1);
writeln('Druga lista'); formiraj(poc2);
writeln('Formirane su sledece strukture');
writeln('Prva lista'); ispisliste(poc1);
writeln('Druga lista'); ispisliste(poc2);
writeln('Liste posle nadovezivanja');
nadovezi(poc1,poc2,poc); ispisliste(poc);
readln;
end.

Primer. Svaki element liste deklarisan je sledecim tipovima:


type pokazivac=^ slog;
slog=record
info:integer;
sledeci:pokazivac;
end;
a) Napisati proceduru za formiranje liste sa strukturom reda.
b) Napisati funkciju koja odreuje aritmetiku sredinu elemenata neprazne liste.
c) Napisati proceduru koja u listi zamenjuje svako pojavljivanje broja i1 brojem i2.
d) Napisati proceduru koja zamenjuje prvi i poslednji element neprazne liste.
program dinam7;
type pokazivac=^ slog;
slog=record
info:integer;
sledeci:pokazivac;
end;
var poc:pokazivac;
i1,i2:integer;
procedure formiraj(var pocetak:pokazivac);
var novi,kraj:pokazivac; ch:char;
begin
pocetak:=nil;
new(novi);
readln(novi^ .info); novi^ .sledeci:=nil;
pocetak:=novi;
kraj:=pocetak;
write('Zelite jos? '); readln(ch);
while ch in ['d','D'] do
begin
new(novi); readln(novi^.info);
novi^ .sledeci:=nil;
kraj^ .sledeci:=novi; kraj:=kraj^ .sledeci;
write('Zelite jos? '); readln(ch);
end;
end;

224
procedure ispisliste(pocetak:pokazivac);
var tslog:pokazivac;
begin
tslog:=pocetak;
while tslog<>nil do
begin
write(tslog^ .info,' '); tslog:=tslog^ .sledeci;
end;
writeln;
end;
function sredina(poc:pokazivac):real;
var n,s:integer;
p:pokazivac;
begin
s:=0; n:=0;
p:=poc;
while p<>nil do
begin
s:=s+p^ .info; p:=p^ .sledeci; n:=n+1;
end;
sredina:=s/n;
end;
procedure zameni(i1,i2:integer; var poc:pokazivac);
var pom:pokazivac;
begin
if poc<>nil then
begin
pom:=poc;
while pom<>nil do
begin
if pom^ .info=i1 then pom^ .info:=i2;
pom:=pom^ .sledeci;
end;
end;
end;
procedure zameniprvizadnji(var poc:pokazivac);
var pom:pokazivac;
pm:integer;
begin
pom:=poc;
while pom^ .sledeci<>nil do pom:=pom^ .sledeci;
pm:=pom^ .info; pom^ .info:=poc^ .info;
poc^ .info:=pm;
end;
begin
formiraj(poc);
writeln('Formirana je sledeca struktura');
ispisliste(poc);
writeln('Aritmeticka sredina elemenata u listi je
',sredina(poc));
write('Koji element da zamenim? '); readln(i1);
write('Kojim elementom da zamenim? '); readln(i2);
zameni(i1,i2,poc);
write('Posle zamene je dobijena struktura ');
ispisliste(poc);
zameniprvizadnji(poc);

Predrag S. Stanimirovi

Programski jezici

225

write('Posle zamene prvog i poslednjeg elementa


dobijamo: ');
ispisliste(poc);
readln;
end.

Primer. Ako je data deklaracija


type stek=^ slog;
slog=record
info:char;
sledeci:stek;
end;
var vrh:stek;
napisati:
a) proceduru za postavljanje ("push") elementa u stek;
b) proceduru za uzimanje ("pop") elementa iz nepraznog steka;
c) proceduru kojom se formira stek od niza znakova, sve do znaka '.';
d) proceduru kojom se ispisuje sadraj steka;
e) program koji koristi ove procedure.
program dinam9;
type stek=^ slog;
slog=record
info:char;
sledeci:stek;
end;
var vrh:stek;
procedure push(ch:char; var vrhsteka:stek);
var novi:stek;
begin
new(novi); novi^ .info:=ch; novi^ .sledeci:=vrhsteka;
vrhsteka:=novi;
end;
procedure pop(var ch:char; var vrhsteka:stek);
var pom:stek;
begin
ch:=vrhsteka^.info; pom:=vrhsteka;
vrhsteka:=vrhsteka^.sledeci;
dispose(pom);
end;
procedure formirajstek(var vrhsteka:stek);
var ch:char;
begin
vrh:=nil;
repeat
read(ch); push(ch,vrhsteka);
end;
procedure ispis(vrhsteka:stek);
var ch:char;
begin
while vrhsteka<>nil do
begin
pop(ch,vrhsteka); write(ch);
end;

until ch='.';

226
writeln;
end;
begin
formirajstek(vrh); ispis(vrh);
end.

Primer. Ako se sa tastature uitava bez greke izraz oblika


<izraz> ::= <cifra>|M(<izraz>,<izeaz>) | m(<izraz>,<izraz>)
<cifra> ::= 0|1|2|3|4|5|6|7|8|9
gde M oznaava maksimum, a m - minimum dva broja, izraunati vrednost unetog izraza.
Na primer, M(5,m(6,8))=6.
program dinam10;
type stekpok=^ slog;
slog=record
znak:char;
sledeci:stekpok;
end;
var x:stekpok;
procedure push(ch:char; var vrh:stekpok);
var novi:stekpok;
begin
new(novi); novi^ .znak:=ch;
novi^ .sledeci:=vrh; vrh:=novi;
end;
procedure pop(var ch:char; var vrh:stekpok);
var pom:stekpok;
begin
ch:=vrh^ .znak; pom:=vrh;
vrh:=vrh^ .sledeci; dispose(pom);
end;
function racunaj:integer;
var vrh:stekpok; c,op,x,y:char;
begin
vrh:=nil;
while not eoln do
begin
read(c);
if c in ['M','m','0'..'9'] then push(c,vrh)
else if c=')' then
{ kraj izraza oblika Op(x,y) }
begin
{na vrhu steka je trojka y x op
koja se uzima iz steka,
izvrsava se operacija op i rezultat
se ubacuje u stek }
pop(y,vrh); pop(x,vrh); pop(op,vrh);
case op of
'M': if x>y then c:=x else c:=y;
'm': if x<y then c:=x else c:=y;
end;
push(c,vrh);

Predrag S. Stanimirovi

end;
end;
pop(c,vrh);
end;

227

Programski jezici

racunaj:=ord(c)-ord('0');

begin
writeln(racunaj);
end.

Primer. Ako se sa tastature uitava bez greke izraz oblika


<izraz> ::=T|F|(<!izraz>)|(<izraz>*<izraz>)|(<izraz>+<izraz>)
gde F i T oznaavaju redom logike konstante true i false, a !, + i * redom logike operacije
negacije, disjunkcije i konjunkcije, izraunati vrednost unetog izraza.
Na primer, ((!T)+(T*F))=F.
program dinam11;
type stekpok=^ slog;
slog=record
znak:char;
sledeci:stekpok;
end;
var x:stekpok;
procedure push(ch:char; var vrh:stekpok);
var novi:stekpok;
begin
new(novi); novi^ .znak:=ch;
novi^ .sledeci:=vrh; vrh:=novi;
end;
procedure pop(var ch:char; var vrh:stekpok);
var pom:stekpok;
begin
ch:=vrh^ .znak; pom:=vrh;
vrh:=vrh^ .sledeci; dispose(pom);
end;
function konj(x,y:char):char;
begin
if(x='F') or (y='F') then konj:='F' else konj:='T'
end;
function disj(x,y:char):char;
begin
if(x='T') or (y='T') then disj:='T' else disj:='F'
end;
function neg(x:char):char;
begin
if(x='F') then neg:='T' else neg:='F'
end;
function racunaj:char;
var vrh:stekpok; c,op,x,y:char;
begin
vrh:=nil;

228
while not eoln do
begin
read(c);
if c in ['T','F','!','*','+'] then push(c,vrh)
else if c=')' then
{ kraj izraza oblika (x*y), (x+y) ili (!y) }
begin { na vrhu steka je trojka y*x ili y+x }
{ ili dvojka y ! }
{ koja se uzima iz steka, izvrsava se
operacija op}
{ i rezultat se ubacuje u stek }
pop(y,vrh); pop(op,vrh);
if op='!' then { vrh steka je y ! }
c:=neg(y)
else begin
pop(x,vrh);
if op='*' then c:=konj(x,y)
else c:=disj(x,y);
end;
push(c,vrh);
end;
end;
pop(c,vrh); { U steku je ostala vrednost izraza }
racunaj:=c;
end;
begin
writeln(racunaj);
end.

Primer. Ako je data deklaracija


type red=^ slog;
slog=record
inf:char;
sledeci:red;
end;
var prvi,poslednji:red;
napisati:
a) proceduru kojom se element postavlja na kraj reda;
b) proceduru kojom se obezbeuje izlazak elementa iz reda;
c) proceduru za formiranje reda koji se sastoji iz niza znakova zavrenih takom.
d) proceduru kojom se ispisuje sadraj steka;
e) program koji koristi prethodne procedure.
program dinam12;
type red=^ slog;
slog=record
inf:char;
sledeci:red;
end;
var prvi,poslednji:red;
procedure ured(ch:char; var prvi,poslednji:red);
var novi:red;
begin
new(novi); novi^ .inf:=ch; novi^ .sledeci:=nil;

Predrag S. Stanimirovi

Programski jezici

229

if prvi=nil then
begin
prvi:=novi; poslednji:=novi;
end
else begin
poslednji^ .sledeci:=novi;
end;
end;

poslednji:=novi

procedure izreda(var ch:char; var prvi:red);


var pom:red;
begin
ch:=prvi^ .inf; pom:=prvi;
prvi:=prvi^ .sledeci; dispose(pom);
end;
procedure formiranjereda(var prvi,poslednji:red);
var ch:char;
begin
prvi:=nil;
repeat
read(ch); ured(ch,prvi,poslednji);
until ch='.'
end;
procedure ispisreda(prvi:red);
var ch:char;
begin
while prvi<>nil do
begin
izreda(ch,prvi); write(ch);
end;
writeln;
end;
begin
writeln('Unos karaktera zavrsite sa . ');
formiranjereda(prvi,poslednji);
writeln('Formiran je red sledeceg sadrzaja:');
end.

ispisreda(prvi);

Primer. Polinom obika x8+5x6-7x5+6x+1 se moe reprezentovati parovima


(1,8),(5,6),(-7,5),(6,1),(1,0)
koji se mogu registrovati odgovarajuim redom. Napisati program koji omoguava registrovanje
polinoma pomou reda i njegovo dekodiranje na osnovu zadatog reda.
program dinam13;
type pokazivac=^ slog;
slog=record
koef,eksp:real;
sledeci:pokazivac;
end;
var prvi:pokazivac;
procedure citajmonom(var tekuci:slog);
begin
with tekuci do

230
begin
write('koeficient? '); readln(koef);
write('Eksponent? '); readln(eksp);
sledeci:=nil;
end;
end;
procedure ispissloga(tekuci:slog);
begin
with tekuci do
if koef>0 then write('+',koef:4:2,'x^ ',eksp:4:2)
else write(koef:4:2,'x^ ',eksp:4:2)
end;
procedure formiranje(var prvi:pokazivac);
var ch:char; novi,kraj:pokazivac;
begin
prvi:=nil;
repeat
new(novi); citajmonom(novi^ );
if prvi=nil then prvi:=novi
else begin
kraj:=prvi;
while kraj^ .sledeci <> nil
do kraj:=kraj^ .sledeci;
kraj^ .sledeci:=novi;
end;
write('Jos? '); readln(ch)
until not(ch in ['y','Y']);
end;
procedure ispis(prvi:pokazivac);
var tekuci:pokazivac;
begin
tekuci:=prvi;
while tekuci<>nil do
begin
ispissloga(tekuci^ ); tekuci:=tekuci^ .sledeci;
end;
writeln;
end;
begin
formiranje(prvi); writeln('Formiran je sledeci polinom:');
ispis(prvi);
end.

Primer. Napisati program za sortiranje niza realnih brojeva koristei strukturu ureene liste
program SortList;
uses crt;
type list=^ slog;
slog=record
x:real;
s:list;
end;
var l:list;
izbor:char;
r:real;

Predrag S. Stanimirovi

231

Programski jezici

procedure ubaci(r:real; var a:list);


var p1, iza,ispred:list;
begin
iza:=a;
while (iza<>nil) and (r>iza^ .x) do
begin
ispred:=iza; iza:=iza^ .s;
end;
new(p1); p1^ .x:=r; p1^ .s:=iza;
if iza=a then
a:=p1
(* ubaciti na pocetak *)
else ispred^ .s:=p1; (* povezati prethodni sa novim *)
end;
procedure formiraj(var a:list);
var i,n:integer;
r:real;
begin
write('Koliko elemenata? '); read(n);
a:=nil;
for i:=1 to n do
begin
read(r); ubaci(r,a);
end;
end;
procedure ispis(a:list);
begin
while a<>nil do
begin
write(a^ .x:8:3,' '); a:=a^ .s;
end;
writeln;
end;
procedure brisi(var a:list);
var r:real;
p:list;
iza, ispred:list;
begin
write('Koji element? '); readln(r);
iza:=a;
while (iza<>nil) and (r<>iza^ .x) do
begin
ispred:=iza; iza:=iza^ .s;
end;
if iza=a then a:=a^ .s
else if iza=nil then
writeln('Takav element ne postoji')
else
begin
p:=ispred^.s; ispred^.s:=ispred^.s^.s;
end;
end;
begin
writeln; l:=nil;
repeat
izbor:=readkey;
case izbor of

dispose(p);

232
'f','F': begin formiraj(l); ispis(l); end;
'i','I': ispis(l);
'b','B': if l=nil then writeln('Lista je prazna ')
else brisi(l);
'u','U': begin
write('Element? '); read(r); ubaci(r,l);
end;
end;
until izbor in['k','K'];
end.

Razmotriemo problem traenja odreenog elementa u opisanoj strukturi tipa reda. Npr.
treba pronai slog ija je vrednost znak ' N'. Za pretraivanje reda moe se koristiti sledea
procedura:
var Point : L1;
...
Point := L;
A := True;
while (Point <> NIL) and A do
if Point^.Info = 'N'
then A:= False
else Point := Point^.Link;

Ako slog sa znakom ' N' postoji u redu tada e pokaziva Poi nt pokazivati na taj slog reda, u
suprotnom Point e pokazivati na NIL.
Gore data procedura moe se dopuniti, tako da se slogu dodaje novi slog iza ve pronaenog
sloga sa odreenom sadrinom. U nasem primeru iza sloga sa znakom ' N' moe se dodati slog
sa znakom M', pomou sledee sekvence naredbi:
var Novislog : L1;
...
New(Novislog);
Novislog^.Info := M;
Novislog^.Link := Point^.Link;
Point^.Link := Novislog;
Dodavanjem samo jedne naredbe gore dati program se moe transformisati u program za
generisanje ciklinog reda:
R^.Link := L;

Slika 9.1 Ciklini red


Za generisanje dvostruko spregnutog reda moe se koristiti sledea sekvenca naredbi
var
K, Levo, Desno. Q : L1;
CH : char;
...
read(CH);
new(K);
K^.Info := CH;
K^.Dlink := NIL;
K^.Llink := NIL;
Desno := K;

Predrag S. Stanimirovi

233

Programski jezici

Q := K;
while not EOF do
begin
read(CH); new(K);
K^.Info := CH; K^.Dlink := Q; K^.Link := K;
Q := K;
end;
Q^.Link := NIL; Levo := Q;
...

Pokazivai i tipovi pokazivaa mogu se efikasno koristiti za definisanje i generisanje i


sloenih struktura podataka kakva je struktura dvostruko povezanog reda prikazana na slici 9.2.
U ovom sluaju potrebno nam je da u okviru svakog sloga imamo po dva pokazivaa, pa je zato
tip podataka Slog definisan na sledei nain:
type L1 = ^Slog;
Slog = record
Info : char;
LLink : L1;
DLink : L1;
end;

Slika
9.2 Generisanje dvostruko spregnutog reda
Izbacivanje iz reda sloga koji je susedni u odnosu na slog na koji pokazuje pokaziva Point
(slika 9.3) moe se postii primenom sledeih naredbi:
Point^.Dlink := Point^.Dlink^.Dlink;
Point^.Dlink^.LIink := Point;

Sli
ka 9.3 Izbacivanje elementa iz dvostruko spregnutog reda
Dodavanje novog sloga redu (slika 9.4) susednog u odnosu na slog P o i n t na koji se
pozicioniramo mogue je pomou sledeih naredbi:
var N o v i s l o g : L1;
...
r e a d ( C H ) ; n e w ( N o v i s l og) ;
Novislog^.Info := CH;
Novisl o g ^ . D l ink := Point^.Dlink;
Novisio g ^ .Llink := Point;
Po in t^ .D l i n k ^ . Llink := N o v i s l o g ;
Point^.Dlink := N o v i s l o g ;
...

234

Slika 9.4 Ubacivanje elementa u dvostruko spregnuti red

Primeri.
Primer. a) Napisati proceduru kojom se dvostruko povezanoj listi dodaje element sa leve
strane.
b) Napisati proceduru kojom se dvostruko povezanoj listi dodaje element sa desne strane.
c) Napisati proceduru za formiranje dvostruko povezane liste koja se sastoji iz niza znakova koji
se zavrava takom.
d) Napisati proceduru kojom se ispisuje sadraj dvostruko povezane liste.
program dvolist1;
type pokazivac=^ slog;
slog=record
x:char;
prethodni,sledeci:pokazivac;
end;
var levi,desni:pokazivac;
izbor:char;
procedure UbaciLevo(ch:char; var levi,desni:pokazivac);
(* postavlja karakter sleva u dvostruko povezanu listu *)
var p1:pokazivac;
begin
new(p1); p1^ .x:=ch;
if levi=nil then
begin
p1^ .prethodni:=nil; p1^ .sledeci:=nil;
levi:=p1; desni:=p1;
end
else
begin
p1^ .sledeci:=levi; p1^ .prethodni:=nil;
levi^ .prethodni:=p1; levi:=p1;
end;
end;
procedure FormiranjeSleva(var levi,desni:pokazivac);
var ch:char;
begin
levi:=nil; desni:=nil;
repeat
read(ch); UbaciLevo(ch,levi,desni);
until ch='.';
end;
procedure UbaciDesno(ch:char; var levi,desni:pokazivac);
(* postavlja karakter sleva u dvostruko povezanu listu *)
var p1:pokazivac;

Predrag S. Stanimirovi

Programski jezici

235

begin
new(p1); p1^ .x:=ch;
if desni=nil then
begin
p1^ .prethodni:=nil; p1^ .sledeci:=nil; levi:=p1; desni:=p1;
end
else
begin
p1^ .prethodni:=desni; p1^ .sledeci:=nil;
desni^ .sledeci:=p1; desni:=p1;
end;
end;
procedure FormiranjeSdesna(var levi,desni:pokazivac);
var ch:char;
begin
levi:=nil; desni:=nil;
repeat
read(ch); UbaciDesno(ch,levi,desni);
until ch='.';
end;
procedure IspisNaDesno(a:pokazivac);
begin
while a<>nil do
begin
write(a^ .x); a:=a^ .sledeci;
end;
writeln;
end;
procedure IspisNaLevo(a:pokazivac);
begin
while a<>nil do
begin
write(a^ .x); a:=a^ .prethodni;
writeln;
end;

end;

begin
writeln('Dodavanje s leve strane');
FormiranjeSleva(levi,desni);
writeln('Ispis na desno:'); IspisNaDesno(levi);
writeln('Ispis na levo:'); IspisNaLevo(desni);
writeln('Dodavanje s desne strane');
FormiranjeSdesna(levi,desni);
writeln('Ispis na desno:'); IspisNaDesno(levi);
writeln('Ispis na levo:'); IspisNaLevo(desni);
end.

Primer. U krugu se nalazi n osoba. Poevi od m-te osobe vri se izlazak iz kruga po sledeem
pravilu: osoba koja izlazi iz kruga govori vrednost sledeeg koraka (ceo broj razliit od 0), tj.
koliko se treba kretati unazad (ukoliko je korak negativan) ili unapred (ako je korak pozitivan)
da bi se izabrala sledea osoba. Postupak traje dok svi ne napuste krug. Napisati program koji za
zadate vrednosti n, m, imena n osoba i korake koje govori svaka od njih ispisuje na standardni
izlaz redosled imena kojim se vri izlazak iz kruga. Za opisivanje kruga koristiti strukturu
krune liste.

236
program pmfapr2;
type lista=^ Tosoba;
Tosoba=record
ime:string[20];
pret,sled:lista;
end;
procedure formirajkrug(var glava:lista; br:integer);
var p,q:lista;
begin
if br>0 then
begin
new(glava);
write('Ime osobe? '); readln(glava^ .ime);
br:=br-1;
p:=glava;
while br>0 do
begin
new(q); write('Ime osobe? '); readln(q^ .ime);
p^ .sled:=q; q^ .pret:=p; p:=q;
br:=br-1;
end;
p^ .sled:=glava; glava^ .pret:=p;
end
else glava:=nil;
end;
procedure izbacivanje(glava:lista; br, pocetna:integer);
var p:lista;
i,korak:integer;
begin
korak:=pocetna;
while br>0 do
begin
for i:=1 to abs(korak)-1 do
if korak>0 then glava:=glava^ .sled
else glava:=glava^ .pret;
writeln('Izlazi osoba: ', glava^ .ime);
br:=br-1;
if br>0 then
begin
write('Sledeci korak: '); readln(korak);
end;
{ Izlazak osobe iz kruga}
glava^ .pret^ .sled:=glava^ .sled;
glava^ .sled^ .pret:=glava^ .pret;
p:=glava;
if korak>0 then glava:=glava^ .sled
else glava:=glava^ .pret;
dispose(p);
end;
end;
var n,m:integer;
glava:lista;
begin
write('Broj ljudi: '); readln(n);
write('Redni broj osobe od koje pocinje izbacivanje: ');
readln(m);

Predrag S. Stanimirovi

formirajkrug(glava,n);
end.

Programski jezici

237

writeln;

izbacivanje(glava,n,m);

Primer. Napisati proceduru kojom se slog ije informaciono polje sadri


postavlja na odgovarajue mesto binarnog stabla prema alfabetskom poretku.

jedan karakter

Napisati program za formiranje binarnog stabla i ispis pri sledeem obilasku: levo podstablo,
koren, desno podstablo. U binarno stablo ugraditi sve karaktere do znaka '.'
Napisati funkciju kojom se ispituje da li se vrednost znakovne promenljive objekat nalazi u
binarnom stablu. Vrednost funkcije je ili nil ako se ne nalazi, ili pokaziva na vor iji je
informacioni deo jednak objekat.
program stablo4;
type pokazivac=^ slog;
slog=record
znak:char;
levi,desni:pokazivac;
end;
var pok,koren:pokazivac;
c:char;
procedure novicvor(var cvor:pokazivac; c:char);
begin
new(cvor);
with cvor^ do
begin
znak:=c; levi:=nil; desni:=nil;
end;
end;
procedure umetanjeznaka(c:char; var p:pokazivac);
begin
if p=nil then novicvor(p,c)
else if c<p^ .znak then umetanjeznaka(c,p^ .levi)
else umetanjeznaka(c,p^ .desni);
end;
procedure inorder(p:pokazivac);
begin
if p<>nil then
begin
inorder(p^.levi);write(p^.znak:2);inorder(p^.desni);
end;
end;
function bintrag(p:pokazivac; objekat:char):pokazivac;
begin
if p=nil then bintrag:=nil
else if p^ .znak=objekat then bintrag:=p
else if p^ .znak>objekat
then bintrag:=bintrag(p^ .levi,objekat)
else bintrag:=bintrag(p^ .desni,objekat)
end;
begin
koren:=nil;
repeat

238
read(c); umetanjeznaka(c,koren);
until c='.';
readln;
inorder(koren); writeln; write('Simbol? '); readln(c);
pok:=bintrag(koren,c);
if pok=nil then writeln(c,' se ne sadrzi u stablu')
else writeln(c,' se sadrzi u stablu');
end.

Primer. Ako vor stabla osim informacionog polja sadri i polje u kome se registruje broj
pojavljivanja njegove vrednosti:
type pokazivac=^ slog;
slog=record
znak:char;
br:integer;
levi,desni:pokazivac;
end;
napisati proceduru kojom se znak ubacuje u ureeno binarno stablo. Napisati program za
formiranje binarnog stabla i ispis pri sledeem obilasku: levo podstablo, koren, desno podstablo.
U binarno stablo ugraditi sve karaktere do znaka '.'
program stablo5;
type pokazivac=^ slog;
slog=record
znak:char;
br:0..maxint;
levi,desni:pokazivac;
end;
var pok,koren:pokazivac;
c:char;
procedure umetanjeznaka(c:char; var p:pokazivac);
begin
if p=nil then
begin
new(p); p^.znak:=c; p^.br:=1; p^.levi:=nil;
p^.desni:=nil;
end
else if p^.znak=c then
p^ .br:=p^ .br+1
else if c<p^.znak then
umetanjeznaka(c,p^ .levi)
else umetanjeznaka(c,p^ .desni);
end;
procedure inorder(p:pokazivac);
begin
if p<>nil then
begin
inorder(p^ .levi);
writeln(p^.znak:2,' ',p^.br,' ');
inorder(p^ .desni);
end;
end;
begin
koren:=nil;

Predrag S. Stanimirovi

repeat
read(c);
c='.';
inorder(koren); writeln;
end.

239

Programski jezici

umetanjeznaka(c,koren);

until

9.4. Dinamike strukture podataka u c


Za razliku od vektora i skalarnih promenljivih, kojima se implicitno dodeljuje memorija
prilikom njihovog stvaranja i oslobaa prilikom brisanja, nezavisno od volje programera,
dinamike strukture zahtevaju eksplicitno dodeljivanje i oslobaanje memorije.
U bibliotekama alloc.h (stdlib.h) nalaze se definicije funkcija malloc, calloc, free i realloc,
kojima se moe eksplicitno upravljati memorijom. Definicija i semantika ovih funkcija je
sledea:
1. char *malloc(size)

rezervie memorijski blok veliine size bajtova, tj. rezervie size uzastopnih bajtova.
Rezervisani memorijski prostor se inicijalizuje vrednou 0. Argument size je tipa unsigned. U
sluaju da uspe rezervacija memorije, ova funkcija vraa pointer na tip char, koji ukazuje na
rezervisani memorijski blok, a inae vraa 0. Ova funkcija ne menja sadraj memorije koja je
izdvojena.
2. char *calloc(n, size)

rezervie memorijski blok dovoljan za smetanje n elemenata veliine size bajtova, tj. rezervie
n*size uzastopnih bajtova. Rezervisani memorijski prostor se inicijalizuje na 0. Ako je
rezervacija uspena, rezultat je pointer na char, koji ukazuje na rezervisani memorijski blok, a
inae 0.
3. void free(point)

oslobaa memorijski prostor koji je rezervisan funkcijama calloc ili malloc. Argument point je
pointer na char, koji ukazuje na memorijski prostor koji se oslobaa. Ova funkcija ne vraa
vrednost. Pokaziva point mora da ima vrednost koja je dobijena primenom funkcija malloc() i
calloc().
4. char *realloc(point, size)

oslobaa rezervisani memorijski blok i rezervie novi, veliine size bajtova. Argument point je
pointer na char i ukazuje na memorijski blok koji se realocira. Argument size je tipa unsigned i
odreuje veliinu realociranog memorijskog prostora. Na ovaj nain se mogu izgraditi razliite
strukture podataka, kao to su stekovi, redovi, liste, binarno stablo.
Primer. Naredbama
int *pint;
pint = (int*)malloc(400);
izdvaja se 400 uzastopnih bajtova.
Takoe, vrednost izraza
pint = (int*)malloc(400);
je pokaziva na tip int, koji se dobija konverzijom pokazivaa na char pomou kast operatora.
Ako tip int zauzima 4 bajta, tada pint+1 uveava pokaziva za 4 bajta, i predstavlja adresu
sledeeg celog broja. Na taj nain, 400 bajotva se koristi za smetanje 100 celih brojeva.
Ako elimo da izdvojimo onoliko memorije koliko je potrebno za za uvanje vrednosti izraza ili
podataka odreenog tipa, koristi se operator sizeof na jedan od sledea dva naina:

240
sizeof(izraz); - vraa memorijski prostor koji je dovoljan za smetanje izraza izraz;
sizeof(T); - vraa memorijski prostor koji je dovoljan za uvanje vrednosti tipa T.
Primer. Pomou operatora
pint = (int *)malloc(sizeof(int));
izdvaja se memorijski prostor za celobrojnu vrednost. Adresa te oblasti se dodeljuje
promenljivoj pint.
Noviji C prevodioci ne zahtevaju promenu tipa pokazivaa koji vraa funkcija malloc(), jer je
njen rezultat tzv. generiki pokaziva oblika { void *}, koji pokazuje na objekat bilo kog tipa.
Primer. Operatorima
long *plong;
plong = (long*)calloc(100, sizeof(long));
izdvaja se (i inicijalizuje na 0) memorijski prostor dovoljan za smetanje 100 vrednosti tipa long
(400 uzastopnih bajtova).

Jednostruko povezane liste


Jedan oblik dinamikih struktura podataka jesu jednostruko povezane liste. Ovakve strukture
podataka su organizovane iz skupa vorova koji su povezani pokazivaima u jednom smeru.
Svaki vor je strukturna promenljiva koja ima najmanje dva elementa: jedan za registrovanje
informacija, a drugi za smetaj pokazivaa koji ukazuje na sledei element liste. Zavisno od
prirode informacija koje se uvaju, informacioni deo vora moe da sadri vei broj elemenata.
Jednostruko povezane liste se mogu oformiti pomou pokazivaa sledeeg oblika:
typedef char TIP;
typedef struct cvor
{ TIP inf;
struct cvor *sledeci;
} LCVOR;
LCVOR *pocetak;

Pokazivaka promenljiva pocetak ukazuje na pocetak liste. Poslednji vor u listi u elementu
sledeci sadri vrednost NULL.
Da bi se oformila jednostruko povezana lista, u poetku se inicijalizuje na praznu listu
naredbom
pocetak=NULL;
Da bi se dinamiki kreirao bilo koji vor potrebno je da mu se dodeli odgovarajui memorijski
prostor izrazom oblika
novi=(LCVOR *)malloc(sizeof(LCVOR)); }
Ve je napomenuto da se kast operator (LCVOR*) moe izostaviti. Podrazumeva se deklaracija
oblika
LCVOR *novi;
Vrednosti elemenata u novom dinamikom objektu (voru liste) novi mogu se definisati na
sledei nain:
novi->inf='A';
novi->sledeci=pocetak; /* tj. NULL */

Predrag S. Stanimirovi

Programski jezici

241

Da bi pokazivaka promenljiva pocetak ukazivala na poetak liste potrebna je sledea dodela


vrednosti:
pocetak=novi;
Proizvoljan broj novih elemenata moe se dodavati u listu koristei gore opisani postupak. Na
primer, moemo pisati
novi=(LCVOR *)malloc(sizeof(LCVOR));
novi->inf='B';
novi->sledeci=pocetak;
pocetak=novi;
Opisani postupak je korien u sledeem programu:
#include <alloc.h>
#include <stdio.h>
typedef char TIP;
typedef struct cvor
{ TIP inf;
struct cvor *sledeci;
} LCVOR;
void pisi(LCVOR *tekuci)
{ while(tekuci!=NULL)
{ printf("->%c",tekuci->inf);
}

tekuci=tekuci->sledeci;

void main()
{ LCVOR *pocetak, *novi;
char ch;
pocetak=NULL;
printf("Unesi sadrzaj liste:\n");
while((ch=getchar())!='\n')
{ novi=(LCVOR *)malloc(sizeof(LCVOR));
novi->inf=ch;
novi->sledeci=pocetak;
}
printf("Sadrzaj liste:\n"); pisi(pocetak);
}

pocetak=novi;

Stekovi
Stek je takva struktura podataka iz koje se prvi uzima vor koji je poslednji ugraen. To znai
da se sa stekom manipulie prema LIFO principu (Last In First Out). Svaki vor mora da sadri
najmanje dva elementa: jedan element za uvanje informacija, i jedan pokaziva na sledei vor
steka. Odgovarajua struktura je data sledeim deklaracijama:
typedef struct cvor
{ TIP inf;
struct cvor *sledeci;
}
SCVOR *vrh;
Pokaziva vrh pokazuje na vrh steka, u kome se nalazi vor koji je poslednji ugraen u stek, tj.
vor koji se prvi uzima iz steka. Naredbom
vrh=NULL;
konstruie se prazan stek.

242

Funkcija kojom se postavlja novi vor u steku (push) je oblika


void push(char ch, SCVOR **pvrh)
{ SCVOR *novi;
novi = (SCVOR *)malloc(sizeof(SCVOR));
/* rezervise memoriju */
novi->inf=ch;
/* postavlja karakter u polju inf */
novi->sledeci=*pvrh;
/* pokazivac cvora je stari vrh */
*pvrh=novi;
/* vrh steka postaje novi cvor */
}
Funkcija kojom se uzima vor (iz vrha) steka (pop) moe se napisati na sledei nain:
void pop(char *ch, SCVOR **pvrh)
{ SCVOR *pomocni;
*ch=(*pvrh)->inf; pomocni=*pvrh;
}

*pvrh=(*pvrh)->sledeci;

free(pomocni);

Primer. Napisati program koji koji koristi funckije push i pop i manipulie stekom u ijim su
vorovima sadrani karakteri.
#include <alloc.h>
#include <stdio.h>
typedef char TIP;
typedef struct cvor
{ TIP inf;
struct cvor *sledeci;
} SCVOR;
void push(char ch, SCVOR **pvrh)
{ SCVOR *novi;
novi = (SCVOR *)malloc(sizeof(SCVOR));
/* rezervise
memoriju */
novi->inf=ch;
/* postavlja karakter u polju inf */
novi->sledeci=*pvrh; /* pokazivac cvora je stari vrh*/
*pvrh=novi;
/* vrh steka postaje novi cvor */
}
void pop(char *ch, SCVOR **pvrh)
{ SCVOR *pomocni;
*ch=(*pvrh)->inf;
pomocni=*pvrh; *pvrh=(*pvrh)->sledeci; free(pomocni);
}
void pisi(SCVOR **pvrh)
{ char ch;
while(*pvrh!=NULL)
{ pop(&ch,pvrh); putchar(ch); }
}
void main()
{ SCVOR *vrh;
char ch;
vrh=NULL;
printf("\nUnesi sadrzaj steka\n");
while((ch=getchar())!='\n')
push(ch, &vrh);
printf("Sadrzaj steka je:\n");
pisi(&vrh);
}

Primer. Izgraditi strukturu steka.

Predrag S. Stanimirovi

243

Programski jezici

#include <stdio.h>
#include <alloc.h>
struct stog
{ int glava; struct stog *rep; };
#define novi(x) x=(struct stog *)malloc(sizeof(struct stog))
void upis(struct stog **p);
void ispis(struct stog *p);
int duz(struct stog *p);
void main()
{ struct stog *a,*b;
novi(a); upis(&a);
printf("\n EVO ISPISA :\n"); ispis(a);
printf("Duzina joj je %d\n",duz(a));
novi(b); upis(&b);
printf("DA
"); ispis(b);
}
void upis(struct stog **p)
{ int x;struct stog *rez,*priv;
rez=NULL;
printf("\n Po zelji daj clanove:\n");
while((scanf("%d",&x))==1)
{ novi(priv); priv->glava=x; priv->rep=rez;rez=priv;}
*p=rez;printf("Kraj\n");
}
void ispis(struct stog *p)
{ if (p==NULL) {printf("P R A Z A N ");return; }
while(p!=NULL)
{ printf("EVO %d\n",p->glava); p=p->rep; }
}
int duz(struct stog *p)
{ int br=0;
if (p==NULL) return(0);
while(p!=NULL){ ++br;p=p->rep;}
return(br);
}
Odgovarajua rekurzivna funkcija duz je definisana na sledei nain:
int duz(struct stog *p)
{ int br=0;
if(p==NULL) return(0);
else return(1+duz(p->rep));
}

Primeri.
#include <stdio.h>
#include <alloc.h>
struct stog {int glava; struct stog *rep; };
#define novi(x) x=(struct stog *)malloc(sizeof(struct stog))
void upis(struct stog **p);
void ispis(struct stog *p);
int duz(struct stog *p);
struct stog *okret(struct stog *p);
struct stog * dodaj(int x,struct stog *p);
void main()

244
{ struct stog *a;
novi(a);
upis(&a);
printf("\n\nEVO ISPISA :\n");
ispis(a);
printf("Duzina joj je %d\n",duz(a));
a=okret(a);
ispis(a);
}
void upis(struct stog **p)
{ int x;struct stog *rez,*priv;
rez=NULL;
printf("\n Za prekid dati ne-broj :\n");
while((scanf("%d",&x))==1)
{ novi(priv); priv->glava=x;
priv->rep=rez; rez=priv;
}
*p=rez;
}
void ispis(struct stog *p)
{ while(p!=NULL)
{ printf("%d\n",p->glava);p=p->rep;}
}
int duz(struct stog *p)
{ int br=0;
while(p!=NULL){ ++br;p=p->rep; }
return(br);
}
struct stog * dodaj(int x, struct stog *p)
{ struct stog * rez;
novi(rez); rez->glava=x; rez->rep=p; return(rez);
}
struct stog *okret(struct stog *p)
{ struct stog *rez,*priv;
priv=NULL;
while(p!=NULL)
{ novi(rez); rez=dodaj(p->glava,priv); p=p->rep;
priv=rez;
}
return(rez);
}
/* cprim45.c */
#include <stdio.h>
#include <alloc.h>
struct stog
{ int glava;
struct stog *rep;
};
#define novi(x) x=(struct stog *) malloc(sizeof(struct stog))
void upis(struct stog **p);
void ispis(struct stog *p);
int duz(struct stog *p);
struct stog *okret(struct stog *p);
struct stog * dodaj(int x,struct stog *p);
char elem(int x,struct stog *p);
char je_skup(struct stog *p);

Predrag S. Stanimirovi

245

Programski jezici

struct stog *oskup(struct stog *p);


main()
{ struct stog *a;
novi(a);
upis(&a);
printf("\n\nEVO ISPISA :\n");
ispis(a);
printf("Duzina joj je %d\n",duz(a));
a=okret(a);
ispis(a);
printf("11 je elem : %d\n",elem(11,a));
printf("Skup je %d\n",je_skup(a));
a=oskup(a);
printf("Njegov 'oskup' je \n ");
ispis(a);
}
void upis(struct stog **p)
{ int x;struct stog *rez,*priv;
rez=NULL;
printf("\n Po zelji daj clanove,za prekid dati ne
broj:\n");
while((scanf("%d",&x))==1)
{ novi(priv);priv->glava=x;priv->rep=rez;rez=priv;}
*p=rez;
}
void ispis(struct stog *p)
{ if (p==NULL) {printf("P R A Z A N \n");return;}
while(p!=NULL)
{printf("%d\n",p->glava); p=p->rep;}
}
int duz(struct stog *p)
{ int br=0;
while(p!=NULL){ ++br;p=p->rep;}
return(br);
}
struct stog * dodaj(int x,struct stog *p)
{ struct stog * rez;
novi(rez);rez->glava=x;rez->rep=p;return(rez);
}
struct stog *okret(struct stog *p)
{ struct stog *rez,*priv;
if(p==NULL) return(NULL);
priv=NULL;
while(p!=NULL)
{ novi(rez);rez=dodaj(p->glava,priv);
p=p->rep;priv=rez;
}
return(rez);
}
char elem(int x,struct stog *p)
{ if (p==NULL) return(0);
while(p!=NULL)
{ if (x==p->glava) return(1);
p=p->rep;
}
return(0);
}

246

char je_skup(struct stog *p)


{ if(p==NULL) return(1);
else if (elem(p->glava,p->rep)) return(0);
else return(je_skup(p->rep));
}
struct stog *oskup(struct stog *p)
{ if (p==NULL) return(NULL);
else if(elem(p->glava,p->rep)) return(oskup(p->rep));
else return(dodaj(p->glava,oskup(p->rep)));
}
/* cprim46.c STOGOVI sa stringovima */
#include <stdio.h>
#include <alloc.h>
struct stog { char *glava;
struct stog *rep;
} ;
#define novi(x) x=(struct stog *) malloc(sizeof(struct stog))
void upis(struct stog **p);
void ispis(struct stog *p);
int duz(struct stog *p);
main()
{ struct stog *a,*b;
novi(a);upis(&a);
printf("\n\nEVO ISPISA :\n");
ispis(a);
printf("Duzina mu je %d\n",duz(a));
}
void upis(struct stog **p)
{ char w[50];struct stog *rez,*priv;
rez=NULL;
printf("\n Za prekid kucati znak @:\n");
while(scanf("%s",&w)==1 && w[0]!='@')
{ novi(priv);strcpy(priv->glava,w);
priv->rep=rez;rez=priv;
}
*p=rez;
}
void ispis(struct stog *p)
{ if (p==NULL) {printf("P R A Z A N ");return;}
while(p!=NULL)
{printf("EVO %s\n",p->glava);p=p->rep;}
}
int duz(struct stog *p)
{ int br=0;
if (p==NULL) return(0);
while(p!=NULL){ ++br;p=p->rep;}
return(br);
}
struct stog *spoj(struct stog *p,struct stog *q)
{ struct stog *pomoc;pomoc=p;
while((pomoc->rep)!=NULL) pomoc=pomoc->rep;
pomoc->rep=q;

Predrag S. Stanimirovi

247

Programski jezici

return(p);
}

Ureene povezane liste


Ponekad je potrebno da se vorovi liste urede u alfabetskom poretku na osnovu sadraja u
informacionim vorovima. Jedan od naina za reenje ovog problema jeste upotreba funkcije
kojom se sortiraju vorovi strukture pre ispisa njihovog sadraja. Bolji nain za dobijanje
generisanje sortirane liste je da se svaki vor postavi na odgovarajue mesto u toku formiranja
liste. Za prvi vor postoji samo jedna mogunost - moe se postaviti samo na poetak liste.
Svaki od preostalih vorova se postavlja na osnovu poreenja sadraja informacuionih delova u
vorovima. Pri postavljanju vora u listu neophodno je samo da se promeni sadraj elemenata
za povezivanje sa susednim vorovima. Umetanje vora na odgovarajue mesto moe se
realizovati rekurzivnom funkcijom umetni.
#include<alloc.h>
#include<stdio.h>
typedef char TIP;
typedef struct cvor
{ TIP inf;
struct cvor *sledeci;
} LCVOR;
void pisi(LCVOR *tekuci)
{ if(tekuci!=NULL)
{ printf("->%c",tekuci->inf);
pisi(tekuci->sledeci);
}
printf("\n");
}
void umetni(LCVOR *novi, LCVOR **lista)
/* Rezultat je pokazivac na pocetak liste */
/* tj. pokazivac na LCVOR */
{ if(*lista==NULL)
{ novi->sledeci=NULL;
*lista=novi;
}
else if(novi->inf<=(*lista)->inf)
{ novi->sledeci=*lista;
*lista=novi;
}
else umetni(novi, &(*lista)->sledeci);
}
void brisi(LCVOR **lista)
{ if(*lista!=NULL)
{ brisi(&(*lista)->sledeci);
free(*lista);
}
}
void main()
{ LCVOR *pocetak, *novi;
char c;
pocetak=NULL;
printf("\nUnesi niz znakova koji obrazuju listu, pa ENTER.\n");
while((c=getchar())!='\n')
{ novi=(LCVOR *)malloc(sizeof(LCVOR));

248
novi->inf =c;
umetni(novi, &pocetak);

}
printf("Sadrzaj liste:\n");
pisi(pocetak);
brisi(&pocetak);

Vanija svojstva pokazivaa


Ponekad se promenom vrenosti jednog pointera posredno menja vrednost drugog pointera.

Primer.

/* cprim41.c
U vezi pointerske tehnike
*/
#include <stdio.h>
#include <alloc.h>
struct stog { int glava;
struct stog *rep;
};
#define novi(x) x=(struct stog *)malloc(sizeof(struct stog))
void main()
{ struct stog *a,*b,*c;
novi(a);
a->glava=5; a->rep=NULL;
novi(b); b->glava=7; b->rep=NULL;
novi(c); c->glava=123; c->rep=NULL;
printf("Glave su a %d b %d c %d \n",
a->glava,b->glava,c->glava);
a->rep=b;
b->rep=c;
printf("\n SADA JE a POVEZANO SA b, A b SA c\n");
printf("Glava od a je %d\n",a->glava);
printf("Glava od a-ovog repa je %d\n", a->rep->glava);
printf("Poslednja glava od a je %d \n",
a->rep->rep->glava);
}

Neka su q i p pointeri, i neka je postavljeno q=p. Izraz oblika


q->rep=<neki_pointer>
menja p, dok izraz oblika
q=q->rep
ne menja p. Ova osobina je ilustrovana sledeim primerom.
Primer. Ilustracija neka vanih svojstava pointerske jednakosti.
#include <stdlib.h>
#include <alloc.h>
struct stog{ int glava;
struct stog *rep;
};
#define novi(x) x=(stmctstog *) malloc(sizeof(struct stog))
void ispis(struct stog *p);
main()
{struct stog *a,*b,*c,*d,*e;
novi(a); novi(b); novi(c); novi(d); novi(e);

Predrag S. Stanimirovi

249

Programski jezici

a->glava=111; a->rep=NULL;
b->glava=222; b->rep=a;
c->glava=333; c->rep=b;
e->glava=777; e->rep=NULL;
printf("prvo c=\n"); ispis (c);
d=c;
d->rep=a;
printf("drugo c=\n"); ispis(c);
d=d->rep;
printf("trece c= \n"); ispis(c);
d->rep=e;
printf("cetvrto c=\n"); ispisi(c); /* 333 111 777 */
}
void ispisi(stunt stog p)
{ if(p=NULL) return;
while(p!=NULL)
{printf("%d ",p->glava); p=p->rep; } }

Binarno stablo
U binarnom stablu svaki vor sadri dva pokazivaa. Poetni vor binarnog stabla se naziva
koren. Jedan pokaziva defini\v se levo podstablo, dok drugi pokaziva definie desno
podstablo. Ovakva struktura omoguava efikasno lociranje, brisanje i umetanje vorova.
Najjednostavnija binarna stabla se mogu reprezentovati sledeom strukturom:
typedef char TIP;
typedef struct cvor
{ TIP inf;
struct cvor *levi;
struct cvor *desni
} BCVOR;
BCVOR *koren;
Pokaziva levi pokazuje na levo podstablo; analogno, pokaziva desni pokazuje na desno
podstablo. Kraj binarnog stabla je vor ije je i levo i desno podstablo jednako nil. Binarno
stablo se moe posmatrati kao rekurzivna struktura podataka, zato to njegov koren pokazuje
na dve analogne strukture, koje se nazivaju levo i desno podstablo.
Binarna stabla se mogu koristiti za konstrukciju ureenih struktura podataka. Jedno od
moguih ureenja je opisano u sledeem. Prvi element takve strukture se postavlja u koren
stabla. Svaki sledei element se poredi sa korenom. Ukoliko taj element prethodi korenu,
postavlja se u levo podstablo, a inae u desno podstablo. To znai da vorovi levog podstabla
prethode korenu, a svi vorovi desnog podstabla slede iza korena ili su mu jednaki.

Pointeri na funkcije u C
U jeziku C mogu se definisati pointeri na funkcije, kojima se mogu dodeljivati vrednosti i
koji se mogu smestiti u strukture, preneti u funkcije ili vratiti kao vrednosti od strane funkcija.
Primer. Uoimo sledee deklaracije:
int f();
int *f();
int (*pf)();
int* (*pf)();

250
Izraz int f() deklarie funkciju koja vraa vrednost tipa int.
Izraz int *f() deklarie funkciju f koja vraa pointer na vrednost tipa int.
Izrazom int (*pf)() deklarie pf kao ukazatelj na funkciju koja vraa vrednost tipa int.
Izraz int *(*pf)() definie ukazatelj pf kao ukazatelj na funkciju koja vraa pointer na int.
Primer. Jedna funkcija se prenosi u drugu funkciju kao argument pomou pointera.
float abs(float x)
{ return((x<0) ? -x : x); }
float fun(float x)
{ return(1./(x*x+1.)) }
float koren(float (*pf)(float), float arg)
{ float q=1.0, e=.001, x;
x=(*pf)(arg);
while(abs(q*q-x)>=e)
q=(x/q+q)/2;
return(q)
}
void main()
{static float x[]={1.1,2.2,3.3,4.4};
int i;
printf("\n");
for(i=0; i<4; ++1)
printf("Kvadratni koren fun(%.3f)=%.3f je %.3f\n",
x[i], fun(x[i]), koren(fun,x[i]));
}

Primer. Konstruisati funkciju F(h)=Q(x(k) +h s(k)) za zadatu funkciju Q(x), zadati vektor xk=x (k),
zadati pravac s=s(k) i parametar koraka h. Konstrukcija ovakve funkcije predstavlja poznat
problem ptimization along a line.
float fun1(float *x)
{ int i;
float f=0.0;
for(i=0; i<3; i++)f+=(x[i]-1.0)*(x[i]-1.0);
return(f);
}
float LineFun(float (*fun)(),float *xk,float *s,int
n,float h)
{ int j;
float xt[50],f;
for(j=0; j<n; j++)xt[j]=xk[j]+h*s[j];
f=(*fun)(xt);
return(f);
}
void main()
{ float r, x[50], s[50];
int i,n;
scanf("%d", &n);
for(i=0;i<n;i++)scanf("%f",&x[i]);
for(i=0;i<n;i++)scanf("%f",&s[i]);
r=LineFun(fun1,x,s,n,h);
printf("%f\n", r);
}

scanf("%f", &h);

Predrag S. Stanimirovi

251

Programski jezici

10. Objektno-orijentisano programiraje (oop)

10.1. Osnovni pojmovi


OOP uvodi drugaiji nain razmiljanja u prgramiranju! U OOP-u, mnogo vie vremena troi
se na projektovanje, a mnogo manje na samu implementaciju (kodovanje).
U OOP-u, razmilja se najpre o problemu, a tek naknadno o programskom reenju.
U OOP-u, razmilja se o delovima sistema (objektima) koji neto rade, a ne o tome kako se
neto radi (algoritmi). Drugim reima, OOP prvenstveno koristi objektnu dekompoziciju umesto
iskljuivo algoritamske dekompozicije.
U OOP-u, panja se prebacuje sa realizacije na meusobne veze izmeu delova. Tei se to
veoj redukciji i strogoj kontroli tih veza. Cilj OOP-a je da smanji interakciju izmeu
softverskih delova.
U osnovi objektno-orijentisanog programiranja lei ideja da se u jednoj strukturi podataka
objedine i podaci i akcije koje se sprovode nad tim podacima (to su metode u terminologiji
OOP). Kljuni pojmovi u objektno-orijentisanim programskim jezicima jesu:
- klase,
- objekti, i
- poruke.
Klasama se opisuje struktura i ponaanje pojedinanih primeraka klase. Pojedinani primerci
(instance) klase, nazivaju se objekti. Svi objekti koji pripadaju jednoj klasi imaju strukturu koja
je definisana klasom kojoj pripadaju, i nad njima se mogu izvravati samo operacije koje su
definisane tom klasom. Operacije koje su definisane nekom klasom nazivaju se metodi. Klase se
mogu posmatrati kao abloni za kreiranje novih objekata. U tom smislu je pojam klase slian
pojmu tipa. Meutim, pripadnost klasi je svojstvo objekata, dok je pripadnost tipu svojstvo
promenljivih i izraza. Svaka klasa se moe posmatrati kao celina u kojoj su pored polja u
kojima su opisani podaci (svojstva) opisana i polja koja predstavljaju funkcije i/ili procedure.
Ovakve funkcije, odnosno procedure, nazivaju se metodi klase.
Svojstva objekata menjaju se pozivom odgovarajuih metoda. Pozivi metoda nazivaju se
poruke. Objekat odgovara na poruku tako to izvrava odgovarajui metod. Sintaksa poruka
zavisi od konkretnog programskog jezika, ali je generalno slina pozivu procedura i funkcija u
proceduralnim programskim jezicima. Ovakvo jedinstvo podataka i funkcija koje dejstvuju nad
tim podacima naziva se enkapsulacija.
Program u proceduralnim programskim jezicima se moe posmatrati kao skup potprograma
(procedura i funkcija) kojima se obradjuju podaci, dok program u objektno-orijentisanim
program-skim jezicima predstavlja skup objekata koji deluju jedni na druge slanjem poruka.

252
Objektno-orijentisani programski jezici se mogu implementirati statiki i dinamiki. Dinamiku
implementaciju poseduju netipizirani jezici (kakav je na primer SMALLTALK). U ovakvim
programskim jezicima ne koristi se informacija o tipovima podataka, ve samo informacija o
pripadnosti objekta odredjenoj klasi. Informacija o pripadnosti objekta odredjenoj klasi koristi
se tek u fazi izvravanja programa. Veina objektno-orijentisanih jezika je implementirana
statiki. Kod ovakvih programskih jezika, informacija o pripadnosti objekta odredjenoj klasi
koristi se u fazi kompilovanja programa, na slian nain kao to se kod proceduralnih
programskih jezika koristi informacija o tipu promenljive.
Za razumevanje klasa i metoda veoma su vani sledei pojmovi:
- enkapsulacija,
- nasledjivanje, i
- polimorfizam.
Enkapsulacija je kombinovanje podataka sa procedurama i funkcijama koje manipuliu tim
podacima.
Nasleivanje je mogunost korienja ve definisanih klasa za graenje hijerarhije klasa. Svaki
naslednik nasleuje opise podataka praroditelja kao i metode njihove obrade.
Polimorfizam predstavlja mogunost definisanja jedinstvenog po imenu metoda (procedure ili
funkcije), koji je primenljiv istovremeno na svim klasama hijerarhije nasleivanja, pri emu
svaka klasa hijerarhije moe naznaiti specifinosti realizacije kada se metod primenjuje nad
njom samom.

10.1.1. Nasleivanje
Nove klase mogu biti definisane tako da naslede sva svojstva odreene klase (roditeljska klasa),
ali i da se tim svojstvima pridodaju nova.
Neka je definisana klasa C pomou strukture koja je definisana promenljivom x i metodom m1.
Neka su C1 i C2 dva objekta klase C. Iz klase C izvedena je nasleivanjem klasa N. Neka su N1
i N2 objekti klase N. Objekti N1 i N2 imaju sve elemente koji su neohodni za definiciju klase C.
U ovom sluaju to znai da objekti N1 i N2 jesu strukture koje imaju promenljivu x i metod m1.
Meutim, u definiciji klase N mogu se definisati jo neki elementi. Na primer, neka u definiciji
klase N uestvuju i promenljiva y kao i metod m2. To znai da objekti N1 i N2, kao primerci
klase N, poseduju strukturu koja je definisana pomou dve promenljive x i y kao i dva metoda
m1 i m2.

10.1.2. Polimorfizam
Objekti mesobno utiu jedni na druge pomou poruka. Meutim, normalno je da razliiti
objekti ne reaguju na isti nain na dobijene poruke. Ovakva sposobnost razliitih objekata da
(na razliit nain) odgovore na istu poruku naziva se polimorfizam.
Neka su dati objekti a, b, c koji su razliitog tipa. Neka se za prikazivanje ovih objekata koristi
se metod display, pomou izraza
a.dispplay, b.display, c.display.
S obzirom da su objekti a, b i c razliitih tipova, moramo raspolagati mehanizmom koji e
omoguiti da se metod display u svakom sluaju prilagodi strukturi objekta koji se prikazuje. U
tom sluaju, objekti a, b i c e razliio reagovati na istu poruku koja je dobijena pozivom
procedure display. Objektno-orijentisani programski jezici raspolau takvim mehanizmom.
Meutim, jasno je da ovakav mehanizam funkcionie samo kada se informacija o pripadnosti
objekta odredjenom tipu koristi tek u fazi izvravanja programa. Meutim, ovakav koncept nije
karakteristian za statiku implementaciju objektnih programskih jezika. tavie, statika
implementacija je ea, i koristi se kod svih jezika a jakom tipizacijom. Pravi "polimorfizam"
zahteva dinamiku implementaciju jezika. Zbog toga se polimorfizam u statiki
implementiranim programskim jezicima implementira pomou virtuelnih metoda za koje vai

Predrag S. Stanimirovi

253

Programski jezici

dinamika implementacija. Takav je sluaj sa programskim jezicima C++ i DELPHI.


Napomenimo da koncept dinamike implementacije programskih jezika obino slabi nihovu
pouzdanost, posebno kada se zahteva rad u realnom vremenu (ne zna se unapred vreme
izvravanja metoda).

10.2. Objektni PASCAL


Objektni Pascal je programski jezik koji se koristi u DELPHI programskom okruenju. Vrlo je
slian Turbo Pascal-u, samo to je Borland dodao neke mogunosti. Objektni Pascal je objektno
orijentisan jezik.
Formalno posmatrajui, klase su sline slogovima u PASCAL-u. Klasa je struktura ije su
komponente uzajamno povezani podaci razliitih tipova, kao i procedure i funkcije koje koriste
te podatke. Komponente koje predstavljaju podatke nazivaju se polja ili podaci klase, dok se
kompo-nente koje predstavljaju procedure ili funkcije nazivaju metode. Za oznaavanje klasa
koristi se slubena re class. Generalno, svaka klasa poseduje sledeu strukturu:
type TimeKlase=class
PoljaPodataka;
Zaglavlja Metoda;
end;
Konkretna promenljiva koja je deklarisana tipom TimeKlase naziva se primerak (instanca) tog
tipa. U klasnom tipu se neposredno zadaju samo zaglavlja metoda (procedura ili funkcija), a
njihovi potpuni opisi se zadaju odvojeno u odeljku opisa procedura i funkcija. Potrebno je
napomenuti da se tada ime metoda formira dodavanjem ta~ke i imena procedure ili funkcije iza
imena klasnog tipa. Zaglavlja metoda pri njihovoj realizaciji ne moraju sadr`ati spisak formalnih
parametara.
Primer. U primeru je definisana klasa kojom se opisuje pojam take, kao i osnovne metode za
rad sa takama.
program obj1;
{$APPTYPE CONSOLE}
uses
SysUtils;
const Pi=3.14159;
type ttacka=class
x,y:real;
procedure
procedure
procedure
procedure
procedure
procedure
procedure
end;

Postavi(PosX,PosY:real);
Translacija(dx,dy:real);
Simetrija;
Rotacija(a:real);
zaglavlje;
Pozicija;
Izvestaj;

{ TODO -oUser -cConsole Main : Insert code here }


procedure ttacka.Postavi(Posx,PosY:real);
begin
x:=PosX; y:=PosY;
end;

254

procedure ttacka.Translacija(dx,dy:real);
begin
x:=x+dx; y:=y+dy;
end;
procedure ttacka.Simetrija;
begin
x:=-x; y:=-y;
end;
procedure ttacka.Rotacija(a:real);
var xr,yr:real;
begin
xr:=x*cos(a)-y*sin(a);
yr:=y*cos(a)+x*sin(a);
x:=xr; y:=yr;
end;
procedure ttacka.Zaglavlje;
begin
writeln('Tacka se nalazi u poziciji:');
end;
procedure ttacka.Pozicija;
begin
writeln('x= ',x:10:2,' y= ',y:10:2);
end;
procedure ttacka.Izvestaj;
begin
Zaglavlje; Pozicija
end;
var
Tacka:ttacka;
begin
Tacka:=ttacka.create;
Tacka.Postavi(5,5);
Tacka.Izvestaj;
Tacka.Translacija(2.3,3.4);
Tacka.Izvestaj;
Tacka.Rotacija(Pi/4);
Tacka.Izvestaj;
Tacka.Free;
readln;
end.

Primer. Primena objektno-orijentisanog programiranja u manipulaciji sa kompleksnim


brojevima.
program Obj3;
{$APPTYPE CONSOLE}
uses
SysUtils;

Predrag S. Stanimirovi

255

Programski jezici

type Tkompleks =class


Re,Im:real;
function Realni:real;
function Imaginarni:real;
procedure Kompleksni(R,I:real);
procedure Zbir(A,B:Tkompleks);
procedure Razlika(A,B:Tkompleks);
procedure Proizvod(A,B:Tkompleks);
procedure Kolicnik(A,B:Tkompleks);
procedure ispis;
end;
procedure Tkompleks.Kompleksni(R,I:real);
begin
Re:=R; Im:=I;
end;
function Tkompleks.Realni:real;
begin
Result:=Re;
end;
function Tkompleks.Imaginarni:real;
begin
Result:=Im;
end;
procedure Tkompleks.Zbir(A,B:Tkompleks);
begin
Re:=A.Re+B.Re; Im:=A.Im+B.Im;
end;
procedure Tkompleks.Razlika(A,B:Tkompleks);
begin
Re:=A.Re-B.Re; Im:=A.Im-B.Im;
end;
procedure Tkompleks.Proizvod(A,B:Tkompleks);
begin
Re:=A.Re*B.Re-A.Im*B.Im;
Im:=A.Im*B.Re+A.Re*B.Im;
end;
procedure Tkompleks.Kolicnik(A,B:Tkompleks);
var D:real;
begin
D:=B.Re*B.Re+B.Im*B.Im;
Re:=(A.Re*B.Re+A.Im*B.Im)/D;
Im:=(A.Im*B.Re-A.Re*B.Im)/D;
end;
procedure Tkompleks.ispis;
begin
writeln(Realni,'+I*',Imaginarni);
end;
procedure testiraj(C1,C2,C:Tkompleks; X1,Y1, X2,Y2:real);
var ch:char;
begin

256
C1.Kompleksni(X1,Y1); C2.Kompleksni(X2,Y2);
writeln('Odredjeni su kompleksni brojevi:');
C1.ispis; C2.ispis;
writeln('Pritisni + za sabiranje');
writeln('
- za oduzimanje');
writeln('
* za mnozenje');
writeln('
/ za deljenje');
readln(ch);
if ch in ['+','-','*','/'] then
begin
case ch of
'+':begin
C.Zbir(C1,C2); C.ispis;
end;
'-': begin
C.Razlika(C1,C2); C.ispis;
end;
'*': begin
C.Proizvod(C1,C2); C.ispis;
end;
'/': begin
C.Kolicnik(C1,C2); C.ispis;
end;
end;
writeln;
end;
end;
var
Z1,Z2,Z:Tkompleks;
X1,Y1,X2,Y2:real;
begin
{ TODO -oUser -cConsole Main : Insert code here }
Z:=Tkompleks.Create; Z1:=Tkompleks.Create; Z2:=Tkompleks.Create;
writeln('Koordinate prve tacke:'); readln(X1,Y1);
writeln('Koordinate druge tacke:'); readln(X2,Y2);
testiraj(Z1,Z2,Z,X1,Y1,X2,Y2);
Z1.Free; Z2.Free; Z.Free;
readln;
end.

10.2.1. Oblast dejstva polja objekata i parametar self


Domen podataka implicitno se prostire na tela procedura i funkcija kojim se realizuju metode
tog objekta. Na primer, u prethodnom programu metod Postavi koristi polja x, y objekta Tacka,
bez navo|enja imena objekta. Moe se rei da unutar metoda objekta deluje implicitno naredba
With. Svaki put kada se pozove metod nekog objekta osim stvarnih parametara predaje se i
nevidljivi parametar Self (svoj) pokazivakog tipa koji sadr`i adresu teku}eg objekta, kojim se
moe implicitno definisati pripadnost objektu. Tako na primer, metod Postavi se od strane
kompajlera tretira kao da je napisan na sledei nain:
procedure ttacka.Postavi(Posx,PosY:real);
begin
Self.x:=PosX; Self.y:=PosY;
end;
Kompajler automatski ukljuuje parametar Self tako da se ne mora koristiti eksplicitno.

Predrag S. Stanimirovi

257

Programski jezici

Izuzetak je kada identifikatori izazivaju konflikt u granicama metoda.


Primer. U sledeem primeru je pokazano kako se pomou parametra Self reava konflikt meu
poljima samog objekta i formalnog parametra, koji imaju ista imena.
program obj4;
{$APPTYPE CONSOLE}
uses
SysUtils;
type tslog=record
x,y:real;
end;
ttacka=class
x,y:real;
procedure Postavi(Pos:tslog);
procedure Pozicija;
end;
{ TODO -oUser -cConsole Main : Insert code here }
procedure ttacka.Postavi(Pos:tslog);
begin
with Pos do
begin
Self.x:=x; Self.y:=y;
end;
end;
procedure ttacka.Pozicija;
begin
writeln('x= ',x:10:2,' y= ',y:10:2);
end;
procedure testiraj(obj:ttacka; startX,startY:real);
var ch:char;
sl:tslog;
begin
with sl do
begin
x:=StartX; y:=StartY;
end;
obj.Postavi(sl);
writeln('Objekat je na startnoj poziciji:');
obj.Pozicija;
end;
var
Tacka:ttacka;
begin
Tacka:=ttacka.create;
testiraj(tacka,10.2,8.3);
Tacka.Free;
readln;
end.

258
Primer. Odrediti sutranji datum.
program obj5;
{$APPTYPE CONSOLE}
uses
SysUtils;
type

Tdan=0..31;
Tmesec=1..12;
Tgodina=1900..2100;
datm = record
dan:Tdan;
mesec:Tmesec;
godina:Tgodina;
end;
TDatum=class
dan:Tdan;
mesec:Tmesec;
godina:Tgodina;
procedure Postavi(D:Tdan;M:Tmesec;G:Tgodina);
procedure Datum;
procedure sutrasnji(Dtm:TDatum);
end;

{ TODO -oUser -cConsole Main : Insert code here }


procedure Tdatum.Postavi(D:Tdan;M:Tmesec;G:Tgodina);
begin
dan:=D; mesec:=M; godina:=G;
end;
procedure Tdatum.Datum;
begin
writeln('Dan: ',dan:3,' mesec: ',mesec:3,'
godina: ',godina);
end;
procedure testiraj(obj:TDatum; D:Tdan; M:Tmesec;
G:Tgodina);
begin
obj.Postavi(D,M,G);
writeln('Datum je:'); obj.Datum;
end;
function krajmeseca(dat:datm):boolean;
function prestupna(god:Tgodina):boolean;
begin
prestupna := god mod 4 = 0
end;
begin
with dat do
case mesec of
1,3,5,7,8,10,12:krajmeseca := dan = 31;
2: if prestupna(godina) then

Predrag S. Stanimirovi

end;

259

Programski jezici

krajmeseca := dan = 29
else krajmeseca := dan = 28;
4,6,9,11:krajmeseca := dan = 30;
end (*case *);

function krajgodine(mesec:Tmesec):boolean;
begin
krajgodine := mesec = 12;
end;
procedure Tdatum.sutrasnji(Dtm:TDatum);
var D:Tdan; M:Tmesec; G:Tgodina; dat:datm;
begin
D:=Dtm.dan; M:=Dtm.mesec; G:=Dtm.godina;
with dat do
begin
dan:=D; mesec:=M; godina:=G;
end;
if krajmeseca(dat) then
begin
self.dan := 1;
if krajgodine(M) then
begin
self.mesec := 1;
self.godina := G+1;
end
else self.mesec := M+1;
end
else self.dan := D+1;
end;
var
Dat:TDatum;
begin
Dat:=TDatum.create;
testiraj(Dat,24,3,2002);
Dat.sutrasnji(Dat);
writeln('Sutrasnji datum je:');
Dat.datum;
Dat.Free;
readln;
end.

10.2.2. Nasleivanje
Nove klase mogu biti definisane tako da naslede sva svojstva odreene klase (roditeljska klasa),
ali i da se tim svojstvima pridodaju nova.
Neka je definisana klasa C pomou strukture koja je definisana promenljivom x i metodom
m1. Neka su C1 i C2 dva objekta klase C. Iz klase C izvedena je nasledjivanjem klasa N. Neka
su N1 i N2 objekti klase N. Objekti N1 i N2 imaju sve elemente koji su neophodni za definiciju
klase C. U ovom sluaju to znai da objekti N1 i N2 jesu strukture koje imaju promenljivu x i
metod m1. Medjutim, u definiciji klase N mogu se definisati jo neki elementi. Na primer, neka
u definiciji klase N uestvuju i promenljiva y kao i metod m2. To znai da objekti N1 i N2, kao
primerci klase N poseduju strukturu koja je definisana pomou dve promenljive x i y kao i dva
metoda m1 i m2.

260

Nasleivanje u objektno-orijentisanom programiranju je bitno i ono tedi vreme, jer ne mora


da se reprogramiraju cele komponente - objekti, ve samo naslede postojei objekti i dodaju
nove osobine i metode (funkcije i procedure). Objektni koncept je preuzet jo iz doba vladavine
Turbo Pascal-a. Sve komponente sa kojima se susreemo u DELPHI-ju su klase (class).
Primer. Neka je potrebno da se kreira klasni tip za krug. Oigledno je da se za definiciju
poloaja centra moe iskoristiti klasa kojom se definie taka. Pored toga, potrebno je da se
doda polje koje predstavlja poluprenik kruga.
program obj6;
{$APPTYPE CONSOLE}
uses
SysUtils;
const Pi=3.14159;
type ttacka=class
x,y:real;
procedure
procedure
procedure
procedure
procedure
procedure
procedure
end;

Postavi(PosX,PosY:real);
Translacija(dx,dy:real);
Simetrija;
Rotacija(a:real);
zaglavlje;
Pozicija;
Izvestaj;

tkrug=class(ttacka)
r:real;
procedure Postavi(PosX,PosY,AR:real);
procedure zaglavlje;
procedure Izvestaj;
end;
{ TODO -oUser -cConsole Main : Insert code here }
procedure ttacka.Postavi(Posx,PosY:real);
begin
x:=PosX; y:=PosY;
end;
procedure ttacka.Translacija(dx,dy:real);
begin
x:=x+dx; y:=y+dy;
end;
procedure ttacka.Simetrija;
begin
x:=-x; y:=-y;
end;
procedure ttacka.Rotacija(a:real);
var xr,yr:real;
begin
xr:=x*cos(a)-y*sin(a);
yr:=y*cos(a)+x*sin(a);

Predrag S. Stanimirovi

261

Programski jezici

x:=xr; y:=yr;
end;
procedure ttacka.Zaglavlje;
begin
writeln('Tacka se nalazi u poziciji:');
end;
procedure ttacka.Pozicija;
begin
writeln('x= ',x:10:2,' y= ',y:10:2);
end;
procedure ttacka.Izvestaj;
begin
Zaglavlje; Pozicija
end;
procedure tkrug.postavi(PosX,PosY,AR:real);
begin
x:=PosX; y:=PosY; r:=AR;
end;
procedure tkrug.zaglavlje;
begin
writeln('Poluprecnik kruga je ',r:10:2);
writeln('a nalazi se na poziciji:');
end;
procedure tkrug.izvestaj;
begin
zaglavlje; pozicija;
end;
procedure Testiraj(obj:ttacka; startX,startY,dx,dy,ugao:real);
var ch:char;
begin
obj.Postavi(startX,startY);
writeln('Objekat je na startnoj poziciji:');
obj.Izvestaj;
writeln('Pritisni T za translaciju za '
,dx:0:2,',',dy:0:2);
writeln('
S za simetriju');
writeln('
R za rotaciju za ugao ',ugao:0:2);
writeln('
K za kraj');
repeat
with obj do
begin
readln(ch);
if Upcase(ch) in ['T','R','S'] then
begin
case upcase(ch) of
'T':translacija(dx,dy);
'R':rotacija(ugao);
'S':simetrija;
end;
izvestaj;
end;
end;

262
until Upcase(ch)='K';
end;
procedure TestirajKrug(obj:tkrug; startX,startY,dx,dy,ugao:real);
var ch:char;
begin
writeln('Objekat je na startnoj poziciji:');
obj.Izvestaj;
writeln('Pritisni T za translaciju za ',
dx:0:2,',',dy:0:2);
writeln('
S za simetriju');
writeln('
R za rotaciju za ugao ',ugao:0:2);
writeln('
K za kraj');
repeat
with obj do
begin
readln(ch);
if Upcase(ch) in ['T','R','S'] then
begin
case upcase(ch) of
'T':translacija(dx,dy);
'R':rotacija(ugao);
'S':simetrija;
end;
izvestaj;
end;
end;
until Upcase(ch)='K';
end;
var
Tacka:ttacka;
Krug:tkrug;
begin
Tacka:=ttacka.create; Krug:=tkrug.Create;
Testiraj(Tacka,0,0,10,10,Pi/2);
Krug.postavi(2.3,3.4,8.9);
Krug.Izvestaj;
TestirajKrug(Krug,0,0,5,5,Pi/4);
Tacka.Free; Krug.Free;
readln;
end.

Primetimo da se mogu preklapati samo metodi. Polja roditeljskog tipa bezuslovno se nasleuju
od strane tipova-potomaka i ne mogu se preklapati (to znai da imena polja potomaka ne mogu
biti ista kao i imena polja tipa-pretka).

10.2.3. Virtuelni metodi


U prethodnim primerima korieni su objektni tipovi Ttacka i Tkrug koji osim to su povezani
relacijom nasleivanja sadre i istoimene metode Zaglavlje i Izvestaj. Procedura zaglavlje
obezbeuje ispis zaglavlja za taku i krug. Jasno je da se ova dva zaglavlja razlikuju. Zbog toga
je opravdano uvoenje u klasi Tkrug metoda Zaglavlje koja preklapa istoimeni metod u klasi
TTtacka. Meutim, metod Izvestaj kod obe klase je isti:
procedure ttacka.izvestaj;
begin
zaglavlje; pozicija;

procedure tkrug.izvestaj;
begin
zaglavlje; pozicija;

Predrag S. Stanimirovi

end;

Programski jezici

263

end;

Stoga je poeljno da se u objektnom tipu TTacka definie metod Izvestaj koji e biti nasleen
u tipu Tkrug, a ne predefinisan. Da bi obezbedili da jedan metod Izvestaj koriste razni klasni
tipovi neophodno je da se prvo raskine statika veza sa metodom Ttacka.Zaglavlje koja je
uspostavljena u toku kompilacije, a zatim da se omogui da procedura Izvestaj poziva metod
Ttacka.Zaglavlje ili metod Tkrug.Zaglavlje, zavisno od klasnog tipa promenljive koja poziva
proceduru Izvestaj. Mehanizam kojim se ovo moe obezbediti naziva se dinamiko ili kasno
vezivanje (late binding). Za razliku od statikog ili ranog vezivanja (early binding), koje se
ostvaruje jo u fazi kompilacije, dinamiko vezivanje se ostvaruje u fazi izvravanja programa.
Mehanizam kasnog vezivanja se ostvaruje uvoenjem virtuelnih ili dinamikih metoda. Da bi se
metod definisao kao virtuelni ili dinamiki neophodno je da se iza njegovog zaglavlja u
objektnom tipu navede re virtual ili dynamic. Ne postoji logika, ve samo tehnika
razlika izmeu virtuelnih i dinamikih metoda. Rad sa virtuelnim metodima je bri, ali troi vie
memorije. Ako je u nekom tipu-pretku metod opisan kao virtuelni, to kod svih potomaka
njegove klase koji nasleuju taj metod mora da se iza zaglavlja metoda navede direktiva
override. Svi potomci moraju imati isti skup formalnih parametara kao i virtuelni metod
klase-pretka.
Primer. Sada tipovi Ttacka i Tkrug mogu da se definiu na sledei nain:
program obj8;
{$APPTYPE CONSOLE}
uses
SysUtils;
const Pi=3.14159;
type ttacka=class
x,y:real;
procedure Postavi(PosX,PosY:real);
procedure Translacija(dx,dy:real);
procedure Simetrija;
procedure Rotacija(a:real);
procedure zaglavlje; virtual;
procedure Pozicija;
procedure Izvestaj;
end;
tkrug=class(ttacka)
r:real;
procedure Postavi(PosX,PosY,AR:real);
procedure zaglavlje; override;
{procedure Izvestaj; }
end;
procedure ttacka.Postavi(Posx,PosY:real);
begin
x:=PosX; y:=PosY;
end;
procedure ttacka.Translacija(dx,dy:real);
begin
x:=x+dx; y:=y+dy;
end;
procedure ttacka.Simetrija;
begin
x:=-x; y:=-y;

264
end;
procedure ttacka.Rotacija(a:real);
var xr,yr:real;
begin
xr:=x*cos(a)-y*sin(a);
yr:=y*cos(a)+x*sin(a);
x:=xr; y:=yr;
end;
procedure ttacka.Zaglavlje;
begin
writeln('Tacka se nalazi u poziciji:');
end;
procedure ttacka.Pozicija;
begin
writeln('x= ',x:10:2,' y= ',y:10:2);
end;
procedure ttacka.Izvestaj;
begin
Zaglavlje; Pozicija
end;
procedure tkrug.postavi(PosX,PosY,AR:real);
begin
inherited Postavi(PosX,PosY);
r:=AR;
end;
procedure tkrug.zaglavlje;
begin
writeln('Poluprecnik kruga je ',r:10:2);
writeln('a nalazi se na poziciji:');
end;
{ procedure tkrug.izvestaj;
begin
zaglavlje; pozicija;
end; }
procedure Testiraj(obj:ttacka;
startX,startY,dx,dy,ugao:real);
var ch:char;
begin
obj.Postavi(startX,startY);
writeln('Objekat je na startnoj poziciji:');
obj.Izvestaj;
writeln('Pritisni T za translaciju za ',
dx:0:2,',',dy:0:2);
writeln('
S za simetriju');
writeln('
R za rotaciju za ugao ',ugao:0:2);
writeln('
K za kraj');
repeat
with obj do
begin
readln(ch);
if Upcase(ch) in ['T','R','S'] then
begin
case upcase(ch) of
'T':translacija(dx,dy);

Predrag S. Stanimirovi

265

Programski jezici

'R':rotacija(ugao);
'S':simetrija;
end;
izvestaj;
end;
end;
until Upcase(ch)='K';
end;
procedure TestirajKrug(obj:tkrug;
startX,startY,dx,dy,ugao:real);
var ch:char;
begin
writeln('Objekat je na startnoj poziciji:');
obj.Izvestaj;
writeln('Pritisni T za translaciju za ',
dx:0:2,',',dy:0:2);
writeln('
S za simetriju');
writeln('
R za rotaciju za ugao ',ugao:0:2);
writeln('
K za kraj');
repeat
with obj do
begin
readln(ch);
if Upcase(ch) in ['T','R','S'] then
begin
case upcase(ch) of
'T':translacija(dx,dy);
'R':rotacija(ugao);
'S':simetrija;
end;
izvestaj;
end;
end;
until Upcase(ch)='K';
end;
var
Tacka:ttacka;

Krug:tkrug;

begin
Tacka:=ttacka.create; Krug:=tkrug.Create;
Testiraj(Tacka,0,0,10,10,Pi/2);
Krug.postavi(2.3,3.4,8.9);
Krug.Izvestaj;
TestirajKrug(Krug,0,0,5,5,Pi/4);
Tacka.Free; Krug.Free;
readln;
end.

10.2.4. Konstruktori i destruktori


Konstruktor je metod koji se koristi za kreiranje objekta (odnosno primerka klase). Definie se
korienjem rezervisane rei constructor.
program obj9;
{$APPTYPE CONSOLE}
uses
SysUtils;

266

const Pi=3.14159;
type ttacka=class
x,y:real;
constructor Postavi(PosX,PosY:real);
procedure Translacija(dx,dy:real);
procedure Simetrija;
procedure Rotacija(a:real);
procedure zaglavlje; virtual;
procedure Pozicija;
procedure Izvestaj;
end;
tkrug=class(ttacka)
r:real;
constructor Postavi(PosX,PosY,AR:real);
procedure zaglavlje; override;
end;
constructor ttacka.Postavi(Posx,PosY:real);
begin
x:=PosX; y:=PosY;
end;
procedure ttacka.Translacija(dx,dy:real);
begin
x:=x+dx; y:=y+dy;
end;
procedure ttacka.Simetrija;
begin
x:=-x; y:=-y;
end;
procedure ttacka.Rotacija(a:real);
var xr,yr:real;
begin
xr:=x*cos(a)-y*sin(a);
yr:=y*cos(a)+x*sin(a);
x:=xr; y:=yr;
end;
procedure ttacka.Zaglavlje;
begin
writeln('Tacka se nalazi u poziciji:');
end;
procedure ttacka.Pozicija;
begin
writeln('x= ',x:10:2,' y= ',y:10:2);
end;

Predrag S. Stanimirovi

267

Programski jezici

procedure ttacka.Izvestaj;
begin
Zaglavlje; Pozicija
end;
constructor tkrug.postavi(PosX,PosY,AR:real);
begin
inherited Postavi(PosX,PosY);
r:=AR;
end;
procedure tkrug.zaglavlje;
begin
writeln('Poluprecnik kruga je ',r:10:2);
writeln('a nalazi se na poziciji:');
end;
procedure Testiraj(obj:ttacka;
startX,startY,dx,dy,ugao:real);
var ch:char;
begin
writeln('Objekat je na startnoj poziciji:');
obj.Izvestaj;
writeln('Pritisni T za translaciju za
',dx:0:2,',',dy:0:2);
writeln('
S za simetriju');
writeln('
R za rotaciju za ugao ',ugao:0:2);
writeln('
K za kraj');
repeat
with obj do
begin
readln(ch);
if Upcase(ch) in ['T','R','S'] then
begin
case upcase(ch) of
'T':translacija(dx,dy);
'R':rotacija(ugao);
'S':simetrija;
end;
izvestaj;
end;
end;
until Upcase(ch)='K';
end;
procedure TestirajKrug(obj:tkrug; startX,startY,dx,dy,ugao:real);
var ch:char;
begin
writeln('Objekat je na startnoj poziciji:');
obj.Izvestaj;

268

writeln('Pritisni T za translaciju za
',
dx:0:2,',',dy:0:2);
writeln('
S za simetriju');
writeln('
R za rotaciju za ugao ',ugao:0:2);
writeln('
K za kraj');
repeat
with obj do
begin
readln(ch);
if Upcase(ch) in ['T','R','S'] then
begin
case upcase(ch) of
'T':translacija(dx,dy);
'R':rotacija(ugao);
'S':simetrija;
end;
izvestaj;
end;
end;
until Upcase(ch)='K';
end;
var
Tacka:ttacka;

Krug:tkrug;

begin
Tacka:=ttacka.Postavi(0,0); Tacka.Izvestaj;
Krug:=tkrug.Postavi(2,2,3); Krug.Izvestaj;
Testiraj(Tacka,0,0,10,10,Pi/2);
Krug.postavi(2.3,3.4,8.9);
Krug.Izvestaj;
TestirajKrug(Krug,0,0,5,5,Pi/4);
Tacka.Free; Krug.Free;
readln;
end.

10.2.5. Pristup lanovima klase


lanovi klase s obzirom na nivo zatite od pristupanja mogu biti:
Javni (public) - mogu da se koriste iz svih programskih modula. Specifikator
Public oznaava da su samo lanovi klase koji se nalaze iza njega dostupni spolja.
Privatni (private) - mogu da se koriste unutar klase u kojoj su definisani kao i unutar
prijateljskih klasa (koje se nalaze u istom modulu).
Publikovani (published) - to su lanovi ije poetne vrednosti mogu da se postave u
prozoru Object Inspector-a.
U tom smislu, postoje jo i sledee sekcije u klasama: private, protected, public, i
published.
Primer.
type
TMojaKlasa = class

Predrag S. Stanimirovi

269

Programski jezici

private
Password: String;
procedure ModifikujPassword;
protected
Username: String;
public
BrTelefona: String;
end;
Varijabla password ne}e biti vidljiva za spoljne objekte (ovo zna~i da pristup imaju samo
metode datog objekta). Ali, varijable u private deklaraciji nisu potpuno privatne. Unutar unit-a
gde je deklarisana data klasa, mogu} je pristup ovim varijablama.
Varijable u protected deklaraciji su pristupa~nije od varijabli u private. ^lanovi protected-a su
vidljivi za sve u klasi.
Public varijable i metode su i zapravo javne - njima se moe pristupiti sa svakog mesta
u kodu (pod uslovom da je sama klasa vidljiva).
Published varijable i metode su sline public lanovima. Razlika je u tome to njima
mogu da pristupaju i druge spoljne aplikacije. To znai da informacije koje generie na kod u
runtime-u mogu da preuzmu strane aplikacije.

10.2.6. Objekti i organizacija memorije


Menadment memorije je vrlo bitno kako u optem programiranju, tako i u razvoju aplikacija u
Delphi okruenju. Dva osnovna pravila kojih se uvek treba drati u vezi sa memorijom su:
moramo osloboditi resurse koji su bili zauzeti kreiranjem bilo kog objekta, i moramo ih
osloboditi "samo jednom". Inae, Delphi podrava tri tipa organizacije memorije za dinamike
elemente (elementi koji nisu u steku i globalnom podruju memorije):
o
o

Svaki put kada kreiramo neki objekat, potrebno je da ga "unitimo" (oslobodimo zauzete
resurse). Ako ne uradimo tako, memorija koja je zauzeta ovim objektom nee biti dostupna
za druge objekte, i to sve dok se sam program ne okona.
Kada kreiramo komponentu, moemo odrediti posednika komponente prosleivanjem
posednika konstruktoru komponente. Posednik komponente (najee forma) je zatim
odgovoran za destrukciju svih objekata (forma za sve komponente na formi) koje poseduje.
Pa tako, ako kreiramo komponentu i dodelimo joj posednika, zatim je treba osloboditi.
Kada alociramo memoriju za stringove, dinamike nizove, i objekte referencirane interfejs
varijablama, Delphi automatski oslobaa zauzetu memoriju kada reference izlaze iz
podruja definisanosti. Nema potrebe da oslobaamo stringove; kada postanu nedostupni,
memorija se automatski oslobaa.
Druga vrsta problema moe da se javi ako pozovemo dva puta destruktor za isti objekat vratie se greka. Destruktor predstavlja metod koja slui dealociranju memorijskog
prostora. Mi sami moemo napisati programski kod za destruktor, i time preduhitriti
podrazumevani Destroy destruktor, u sluaju potrebe da izvrimo neki kod pre same
destrukcije.
Naravno, u naem programskom kodu ne moramo runo upravljati dealokacijom memorije ovo je neto to e Delphi uraditi za nas. Destroy metoda predstavlja virtuelni destruktor
klase TObject. Najvei broj klasa koje zahtevaju "ienje" koda kada se objekti
destruktuiraju, zaobilaze ovu virtuelnu metodu. Razlog zbog kojeg nikada ne bi trebalo da
definiemo novi destruktor jeste to to se objekti najee ponitavaju pozivom Free
metode, a ova metoda umesto vas poziva Destroy virtuelnog destruktora. Free metoda je
metoda koja pripada TObject klasi, a nasleuju je sve ostale klase.

270

10.3. C++ kao objektna nadgradnja jezika C


C++ je trenutno najpopularniji objektno orijentisani programski jezik. Jezik C++ nije isti
objektno orijentisani programski jezik (engl. Object-Oriented Programming Language, OOPL)
koji bi korisnika naterao da ga koristi na objektno orijentisani nain. C++ moe da se koristi i
kao malo bolji C, ali se time nita ne dobija. C++ treba koristiti kao sredstvo za OOP i kao
smernicu za razmiljanje. C++ ne spreava pisanje loih programa, ve samo omoguava
pisanje mnogo boljih programa.
Primeri koji se koriste u ovom odeljku samo su pokazni, nisu pravljeni da budu upotrebljivi.
Iz realizacije primera izbaeno je sve to bi smanjivalo preglednost osnovnih ideja. Zato su
primeri esto i nekompletni.

10.3.1. Klase
Klasa (engl. class) je osnovna organizaciona jedinica programa u OOP jezicima, pa i u jeziku
C++. Klasa predstavlja strukturu u koju su grupisani podaci i funkcije. Definicija klase se sastoji
u navoenju svih lanova klase. Klasa se definie opisom class iji je opti oblik:
class Identifikator {
lan lan ...
public lan lan ...
private lan lan ...
};

Primer. Data je definicija klase kojom se opisuje taka u dvodimenzionalnom prostoru.


enum Boolean {false, true};
class Point
{
float X,Y;
Boolean Vidljivost;
public:
float GetX() {return X;}
float GetY() {return Y;}
}

// podaci
// metodi

Pored podataka X,Y i Vidljivost koji su karakteristini za strukture, lanovi klase


Point jesu i dve funkcije GetX() i GetY(), kojima se moe pristupati objektima klase
Point. Funkcije GetX() i GetY() predstavljaju metode klase Point. Podacima X
i Y kod objekata koji pripadaju klasi Point moe se pristupiti metoda GetX() i
GetY().
Tela pridruenih funkcija (metoda) mogu da budu definisana i izvan definicije klase. Tada se
u toj klasi navode samo zaglavlja metoda. U tom sluaju se moe izvriti eksplicitno
pridruivanje odreene funkcije klasi, to je neophodno u sluaju kada se razliitim klasama
pridruuju istoimeni metodi sa jednakim brojem istoimenih parametara.
Funkcija se pridruuje odreenoj klasi prema sledeoj sintaksi:
tip ime_klase :: ime_pridruene_funkcije (lista argumenata)
telo_pridruene_funkcije

Klasa Point je mogla da bude definisana i na sledei nain:


class Point
{
float X,Y;
Boolean Vidljivost;

Predrag S. Stanimirovi

Programski jezici

271

public:
float GetX()
float GetY()
}

Tada se pridruene funkcije definiu odvojeno:


float Point :: GetX()
{return X;}
float Point :: GetY()
{return Y;}

Ovako definisana klasa se koristi slino definisanim tipovima. Objekti tipa Point se mogu
definisati kao i promenljive strukturnog tipa:
Point Centar;
Point Vrsta[80]

// Niz tacaka

Primer. Deklaracija klase osoba.


class Osoba {
public:
void koSi();
private:
char *ime;
int
god;
};

/* metod */
/* podatak: ime i prezime */
/* podatak: koliko ima godina */

Svaka funkcija iz klase se mora i definisati.


void Osoba::koSi()
{
cout<<Ja sam <<ime<<i imam
}

<<god<<godina.\n;

Klasom se definie novi, korisniki tip za koji se mogu formirati instance (primerci,
promenljive). Klasa moe da predstavlja realizaciju apstrakcije iz domena problema. Klasa
predsatvlja ablon za generisanje objekata, a objekti se nazivaju primerci (instance) klase.
Instance klase nazivaju se objekti (engl.objects). Svaki objekat ima sopstvene elemente
koji su navedeni u deklaraciji klase. Ovi elementi klase nazivaju se lanovi klase (engl. class
members). lanovima se pristupa pomou operatora . (taka):
Primer. Korienje klase Osoba. Negde u programu se definiu objekti tipa Osoba.
Osoba Pera, mojOtac, direktor;

Zatim se ti objekti mogu koristiti:


Pera.koSi();
mojOtac.koSi();
direktor.koSi();

/* poziv funkcije koSi objekta Pera */


/* poziv funkcije koSi objekta mojOtac */
/* poziv funkcije koSi objekta direktor */

Ako pretpostavimo da su ranije, na neki nain, postavljne vrednosti lanova svakog od


navedenih objekata, ovaj segment programa moe da proizvede:
Ja sam Petar Markovic i imam 25 godina.
Ja sam Slobodan Milicev i imam 58 godina.
Ja sam Aleksandar Simic i imam 40 godina.
Specifikator Public: govori prevodiocu da su samo lanovi koji se nalaze iza njega
dostupni spolja. Ovi lanovi se nazivaju javnim. lanovi iza specifikatora private: su
nedostupni korisnicima klase (ali ne i lanovima klase) i nazivaju se privatnim:

272
Pera.ime=Petar Markovic; /* nedozvoljeno */
mojOtac.god=55;
/* takoe nedozvoljeno*/

Pojam i deklaracija klase


Podaci koji su deo klase nazivaju se podaci lanovi klase (engl. data members). Funkcije koje
su deo klase nazivaju se funkcije lanice klase (engl. member functions).
lanovi (podaci ili funkcije) klase iza kljune rei private: zatieni su od pristupa
spolja. Ovim lanovima mogu pristupati samo funkcije lanice klase. Ovi lanovi nazivaju se
privatnim lanovima klase (engl. private class members).
lanovi iza kljune rei public: dostupni su spolja i nazivaju se javnim lanovima klase
(engl. public class members).
lanovi iza kljune rei protected: dostupni su funkcijama lanicama date klase, kao i
klasa izvedenih iz te klase, ali ne i korisnicima spolja, i nazivaju se zatienim lanovima klasa
(engl. protected class members).
Redosled sekcija public, protected i private proizvoljan je, ali se preporuuje ba navedeni
redosled. Podrazumeva se da su lanovi privatni (ako se ne navede specifikator ispred).
Objekat klase ima unutranje stanje, predstavljeno vrednostima atributa, koje menja pomou
operacija. Funkcije lanice nazivaju se jo i metodima klase, a poziv ovih funkcija- upuivanje
poruke objektu klase. Objekat klase menja svoje stanje kada se pozove njegov metod, odnosno
kada mu se uputi poruka.
Objekat unutar svoje funkcije lanice moe pozivati funkciju lanicu neke druge ili iste klase,
odnosno moe uputiti poruku drugom objektu. Objekat koji alje poruku (poziva funkciju)
naziva se objekat-klijent, a onaj koji je prima je objekat-server.
Preporuuje se da se klase projektuju bez javnih podataka lanova. Podaci lanovi treba da
budu privatni, osim ukoliko postoje jaki razlozi za suprotnu odluku. Javne treba da budu samo
funkcije lanice koje predstavljaju operacije date apstrakcije koje su na raspolaganju
korisnicima klase. Zatiene su obino jednostavne operacije klase koje ne predstavljaju
operacije interfejsa date klase, nego su ili proste funkcije za pristup do podataka lanova, ili
pomone funkcije koje slue za implementaciju javnih operacija jer se koriste na vie mesta.
Ovakve jednostavnije operacije su pomone (engl. helper functions) i esto su potrebne i
izvedenim klasama, pa su zbog toga zatiene.
Unutar funkcije lanice klase, lanovima objekta ija je funkcija pozvana pristupa se
direktno, samo navoenjem njihovog imena.
Mogue je preklopiti (engl. overload) funkcije lanice, ukljuujui i konstruktore.
Deklaracijom klase smatra se deo kojim se navodi ono to korisnici klase treba da vide. To su
uvek javni lanovi. Meutim, da bi prevodilac korektno zauzimao prostor za objekte klase,
mora da zna njegovu veliinu, pa u deklaraciju klase ulaze i deklaracije privatnih podataka
lanova.
Primer. Data je deklaracija klase kojom se opisuju kompleksni brojevi.
// deklaracija klase complex:
class complex {
public:
void cAdd(complex);
void cSub(complex);
float cRe();
float cIm();
//...

Predrag S. Stanimirovi

};

273

Programski jezici

private:
float real, imag;

Gore navedena deklaracija je, zapravo, definicija klase, ali se iz istorijskih razloga naziva
deklaracijom.
Pravu deklaraciju klase predstavlja samo deklaracija class S;. Pre potpune deklaracije
mogu samo da se definiu pokazivai i reference na tu klasu, ali ne i objekti te klase, jer se
njihova veliina ne zna.

10.3.2. Konstruktori i destruktori


Da bi se omoguila inicijalizacija objekta, u klasi se definie posebna funkcija koja se
implicitno (automatski) poziva kada objekat nastaje. Ova funkcija se naziva konstruktor
(engl. constructor) i nosi isto ime kao i klasa.
class Osoba
{ public:
Osoba(char *ime, int godine); /* konstruktor*/
void koSi();
/* funkcija: predstavi se! */
private:
char *ime;
/* podatak: ime i prezime */
int god;
/* podatak: koliko ima godina */
}; /* Svaka funkcija se mora i definisati: */
void Osoba::koSi()
{cout<<Ja sam <<ime<< i imam <<god<< godina.\n ;
}
Osoba::Osoba (char *i, int g)
{ ime=i;
/* dodeli ime */
god=((g>=0 && g<=100) ? g:0); /*proveri godine*/
}

Korienje klase Osoba:


Osoba Pera (Petar Markovic, 25); /* poziv konstruktora Osoba */
mojOtac (Slobodan Milicev, 58);
Pera.koSi ();
mojOtac.koSi ();

Ovakav deo programa moe dati ranije navedene rezultate.


Mogue je definisati funkciju koja se poziva uvek kada objekat prestaje da ivi. Ova
funkcija se naziva destruktor.

Pojam konstruktora
Funkcija lanica koja nosi isto ime kao i klasa naziva se konstruktor. Ova funkcija se uvek
poziva prilikom formiranja objekta te klase.
Konstruktor nema tip koji vraa. On moe da ima argumente proizvoljnog tipa. Unutar
konstruktora, lanovima objekta pristupa se kao i u bilo kojoj funkciji lanici.
Konstruktor se uvek implicitno poziva pri nastanku objekta klase.
Konstruktor, kao i svaka funkcija lanica, moe biti preklopljen. Konstruktor koji se moe
pozvati bez stvarnih argumenata naziva se podrazumevanim konstruktorom.
Ukoliko u klasi nije eksplicitno deklarisan nijedan konstruktor, prevodilac implicitno
generie podrazumevani konstruktor koji je javni i koji vri podrazumevanu inicijalizaciju

274
podobjekta osnovne klase i objekata-lanova pozivima njihovih podrazumevanih konstruktora,
ako ih ima. Ako takvih konstruktora nema javlja se greka.
Primer. U sluaju ranije definisane klase Point, atributi objekta Centar tipa point mogu se
definisati na sledei nain:
Point centar;
Centar.X=17; Centar.Y:=42; Centar.Vidljivost=false;

U ovom sluajuje je pristup podacima koji ine objekat izvren kao i u sluaju bilo koje druge
strukture podataka. Pomou konstruktora i destruktora eksplicitno se stvara, odnosno unitava
odredjeni objekat. U konkretnom slu\v caju se moe koristiti sledei kod:
class point {
float X,Y;
Boolean Vidljivost;
public: // ovim funkcijama je dozvoljen pristup spolja
point(float NewX=0, float NewY=0);
// konstruktor sa podrazumevanim argumentima
~Point()
// destruktor
{ cout << memorija je oslobodjena\n; }
// Ostale funkcije (metodi)
float GetX() { return X; }
float GetY() { return Y; }
}
Point::Point(float NewX, float NewY) {
X=NewX; Y=NewY; Vidljivost=false;
cout<<"Koordinate su prihvacene ";
}
void main()
{
float n,m;
Point Tacka(5,6);
//poziv konstruktira sa zadatim argumentima
n=Tacka.GetX();
cout << "n dobija vrednost koordinae X,\n";
m=Tacka.GetY();
cout << "m dobija vrednost koordinae Y,\n";
}

Program proizvodi sledei ispis:


Koordinate su prihvacene n dobija vrednost koordinate X,
m dobija vrednost koordinate Y,
memorija je oslobodjena

Konstruktorom klase automatski se aktivira kod deklaracije objekta klase koja odgovara
konstruktoru. Destruktorom se unitava objekat na koji se primenjuje.

Kada se poziva konstruktor?

Konstruktor je funkcija koja pretvara presne memorijske lokacije koje je sistem


odvojio za novi objekat u pravi objekat koji ima svoje lanove i koji moe da prima
poruke.
Konstruktor se poziva uvek kada objekat klase nastaje, tj. kada se:
1. izvrava definicija statikog objekta;
2. izvrava definicija automatskog objekta unutar bloka; formalni argumenti, pri
pozivu funkcije, nastaju kao lokalni automatski objekti;

Predrag S. Stanimirovi

275

Programski jezici

3. inicijalizuje objekat, pozivaju se konstruktori njegovih podataka lanova;


4. stvara dinamiki objekat operatorom new;
5. stvara privremeni objekat, pri povratku iz funkcije, koji se inicijalizuje
vraenom vrednou funkcije

Naini pozivanja konstruktora


Konstruktor se poziva kada nastaje objekat klase. Na tom mestu je mogue navesti
inicijalizatore, tj. stvarne argumente pozivom konstruktora. Poziva se onaj konstruktor koji se
najbolje slae po broju i tipovima argumenata:
class X {
public:
X ();
X (double);
X (char *);
//...
};
void main () {
double d=3.4;
char *p=Niz znakova;
X a(d),
b(p),
c;
//...
}

//poziva se X(double)
//poziva se X(char *)
//poziva se X()

Pri definisanju objekta c sa zahtevom da se poziva podrazumevani konstruktor klase X, ne


treba navesti X c(),ve samo X c;
Pre izvravanja samog tela konstruktora klase, pozivaju se konstruktori lanova. Argumenti
ovih poziva mogu da se navedu iza zaglavlja definicije konstruktora klase, iza znaka :
(dvotaka):
class YY
{ public: YY (int j) {...}
//...
};
class XX
{ public:
XX (int);
private:
YY y;
int i;
};
XX::XX (int k) : y (k+1) , i(k-1) {
//y je inicijalizovan sa k+1, a i sa k-1
//... ostatak konstruktora
}

Prvo se pozivaju konstruktori lanova, po redosledu deklarisanja u deklaraciji klase, pa se


onda izvrava telo konstruktora klase.
Ovaj nain ne samo da je mogu, ve je i jedino ispravan: navoenje inicijalizatora u
zaglavlju konstruktora predstavlja specifikaciju inicijalizacije lanova, to je razliito od
operacije dodele koja se moe vriti unutar tela konstruktora

276
Konstruktor se moe pozvati i eksplicitno u nekom izrazu. Tada nastaje privremeni objekat
klase pozivom odgovarajueg konstruktora sa navedenim argumentima. Isto se deava ako se u
inicijalizatoru eksplicitno navede poziv konstruktora:
void main () {
complex c1(1,2.4);
// poziv konstruktora sa zadatim vrednostima
complex c2;
// poziv konstruktora sa podrazumevanim vrednostima
c2=c1+complex(3.4,-1.5);
// privremeni objekat
complex c3=complex(0.1,5);
// opet privremeni objekat koji se kopira u c3
}

Kada se pravi niz objekata neke klase, poziva se podrazumevani konstruktor za svaku
komponentu niza ponaosob, po rastuem redosledu.

Destruktor
Funkcija lanica ima isto ime kao klasa, uz znak ~ ispred imena, naziva se destruktor. Ova
funkcija poziva se automatski, pri prestanku ivota objekta klase, za sve navedene sluajeve:
class X {
public:
~X () {cout<< poziv destruktora klase X!\n;}
}
void main() {
X x ;
//...
}
// ovde se poziva destruktor objekta x

Destruktor nema tip koji vraa i ne moe imati argumente. Unutar destruktora, lanovima se
pristupa kao i u bilo kojoj drugoj funkciji lanici. Svaka klasa moe da ima najvie jedan
destruktor.
Destruktor se implicitno poziva i pri unitavanju dinamikih objekta pomou operatora
delete. Za niz, destruktor se poziva za svaki element ponaosob. Redosled poziva destruktora je,
u svakom sluaju obratan od redosleda poziva konstruktora.
Ako klasa nema eksplicitni deklarisan destruktor, prevodilac implicitno generie
podrazumevani destruktor koji je javni i koji vri destrukciju podataka lanova i podobjekta
osnovne klase pozivom njihovih destruktora.
Destruktor se skoro nikada ne poziva korektno. Destruktori se uglavnom koriste kada objekat
treba da dealocira memoriju ili neke sistemske resurse koje je konstruktor alocirao; to je
najee potrebno kada klasa sadri lanove koji su pokazivai na pridruene dinamike objekte
koji ekskluzivno pripadaju datom objektu, pa ih je potrebno unititi prilikom unitavanja tog
objekta. Destruktor se automatski poziva kada neka akcija, kao to je korienje operatora
delete, izaziva unitenje objekta.

10.4. Nasleivanje
Pretpostavimo da nam je potreban novi tip, Maloletnik. Maloletnik je jedna vrsta osobe, koja
poseduje sve to i osoba, samo ima jo neto, tj. ima staratelja. Ovakva relacija izmeu klasa
naziva se nasleivanje.
Kada nova klasa predstavlja jednu vrstu druge klase (engl. a-kind-of), kae se da je ona
izvedena iz osnovne klase.
class Maloletnik: public Osoba{

Predrag S. Stanimirovi

277

Programski jezici

public:
Maloletnik(char *ime, char *staratelj, int godine);
konstruktor */
void koJeOdgovoran();
private:
char *staratelj;
};

/*

void Maloletnik::koJeOdgovoran () {
cout<<Za mene odgovara <<staratelj<<.\n ;
}
Maloletnik::Maloletnik(char *i, char *s, int g): Osoba(i,g),
staratelj(s) {}

Izvedena klasa Maloletnik ima sve lanove kao i osnovna klasa Osoba, ali ima jo i lanove
staratelj i koJeOdgovoran. Konstruktor klase Maloletnik definie da se objekat ove klase
inicijalizuje zadavanjem imena, staratelja i godina, i to tako da se konstruktor osnovne klase
Osoba (koji inicijalizuje ime i godine) poziva se odgovarajuim argumentima. Sam konstruktor
klase Maloletnik samo inicijalizuje staratelja.
Sada se mogu koristiti nasleene osobine objekata klase Maloletnik a na raspolaganju su i
njihova posebna svojstva kojih nije bilo u klasi Osoba:
Osoba otac(Petar Petrovic, 40 );
Maloletnik dete(Milan Petrovic, Petar Petrovic, 12 );
otac.koSi ();
dete.koSi ();
dete.koJeOdgovoran();
otac.koJeOdgovoran();
/* Ovo, naravno, ne moe !*/
/* izlaz e biti:
Ja sam Petar Petrovi i imam 40 godina.
Ja sam Milan Petrovi i imam 12 godina.
Za mene odgovara Petar Petrovi.
*/

10.4.1. Kako se definiu izvedene klase u jeziku C++?


Da bi se klasa izvela iz postojee klase, nije potrebno menjati postojeu klasu, niti je ponovo
prevoditi. Izvedena klasa se deklarie navoenjem rei public i naziva osnovne klase, iza
znaka : (dvotaka):
class Base {
int i;
public:
void f();
};
class Derived : public Base {
int j;
public:
void g();
};

Objekti izvedene klase imaju sve lanove osnovne klase, i svoje posebne lanove koji su
navedeni u deklaraciji izvedene klase.
Objekti izvedene klase definiu se i koriste na uobiajen nain:
void main ()
{ Base b:

278
Derived d;
b.f();
b.g();
d.f();
d.g();

//ovo, naravno ne moe


// d ima i funkciju f,
// i funkciju g

Izvedena klasa ne nasleuje funkciju lanicu operator=.

10.4.2. Prava pristupa


Kljuna re public u zaglavlju deklaracije izvedene klase znai da su svi javni lanovi osnovne
klase ujedno i javni lanovi izvedene klase.
Privatni lanovi osnovne klase uvek to i ostaju. Funkcije lanice izvedene klase ne mogu da
pristupaju privatnim lanovima osnovne klase.
Javnim lanovima osnovne klase se iz funkcija lanica izvedene klase pristupa neposredno, kao
i sopstvenim lanovima:
class Base {
int pb;
public:
int jb;
void put (int x) {pb=x;}
};
class Derived : public Base {
int pd;
public:
void write (int a, int b, int c) {
pd=a;
jb=b;
pb=c;
//ovo ne moe
put(c);
//ovako moe
}
};

Deklaracija lana izvedene klase sakriva istoimeni lan osnovne klase. Sakrivenom lanu
osnovne klase moe da se pristupi pomou operatora : :. Na primer, Base::jb.
esto postoji potreba da nekim lanovima osnovne klase pristupaju funkcije lanice
izvedenih klasa, ali ne i korisnici klasa. To su najee funkcije lanice koje direktno pristupaju
privatnim podacima lanovima. lanovi koji su dostupni samo izvedenim klasama, ali ne i
korisnicima spolja, navode se iza kljune rei protected: i nazivaju se zatieni lanovi.
Zatieni lanovi ostaju takvi i za sledee izvedene klase pri sukcesivnom nasleivanju.
Uopte, ne moe se poveati pravo pristupa nekom lanu koji je privatan, zatien ili javni.
class Base {
int pb;
protected:
int zb;
public:
int jb;
//...
};
class Derived : public Base {
//...
public:
void write (int x) {

Predrag S. Stanimirovi

279

Programski jezici

jb=zb=x
//moe da pristupi javnom i zatienom lanu,
pb=x;
//ali ne i privatnom: greka!
};

void f() {
Base b;
b.zb=5;
//odavde ne moe da se pristupa zatienom lanu
}

Primer. U ovom header fajlu (point.h) definisane su dve klase. Klasa Lokacija opisuje X i Y
koordinate take. Klasa Point opisuje vidljivost take.
enum boolean { false, true }
class Lokacija
{
Protected: // U izvedenim klasama je dozvoljen pristup internim
podacima
int X;
int Y;
// Sve klase izvedene iz klase Lokacija imae
pristup X i Y
public:
// Ovim funkcijama je dozvoljen pristup spolja
Lokacija (int InitX, int InitY); // konstruktor
int GetX();
int GetY();
};
class Point : public Lokacija // klasa izvedena iz klase Lokacija
{
Protected:
Boolean Vidljivost;
Public:
Point(int InitX, int InitY);
// konstruktor
void Show();
void hide();
boolean Isvisible();
void MoveTo(int NewX, int NewY);
};

10.5. Privatno i zatieno izvoenje


10.5.1. ta je privatno i zatieno izvoenje?
Kljuna re public u zaglavlju deklaracije izvedene klase znai da je osnovna klasa javna,
odnosno da su svi javni lanovi osnovne klase ujedno i javni lanovi izvedene klase. Privatni
lanovi osnovne klase nisu dostupni izvedenoj klasi, a zatieni lanovi osnovne klase ostaju
zatieni i u izvedenoj klasi. Ovakvo izvoenje se u jeziku C++ naziva jo i javno izvoenje.
U zaglavlje deklaracije moe se, ispred imena osnovne klase, umesto rei public upisati re
private, to se i ne podrazumeva ako se ne navede nita drugo. U ovom sluaju javni i zatieni
lanovi osnovne klase postaju privatni lanovi izvedene klase. Ovakvo izvoenje se u jeziku C+
+ naziva privatno izvoenje.
U zaglavlje deklaracije moe se, ispred imena osnovne klase, upisati re protected. Tada
javni i zatieni lanovi osnovne klase postaju zatieni lanovi izvedene klase. Ovakvo
izvoenje u jeziku C++ naziva se zatieno izvoenje.

280
U svakom sluaju, privatni lanovi osnovne klase nisu dostupni izvedenoj klasi. Izvedena
klasa moe samo nadalje sakriti zatiene i javne lanove osnovne klase izborom naina
izvoenja.
U sluaju privatnog i zatienog izvoenja, kada izvedena klasa smanjuje nivo prava pristupa
do javnih i zatienih lanova osnovne klase, moe se ovaj nivo vratiti na poetni eksplicitnim
navoenjem deklaracije javnog ili zatienog lana osnovne klase u javnom ili zatienom delu
izvedene klase. U svakom sluaju, izvedena klasa ne moe poveati nivo prava pristupa do
lana osnovne klase.
class Base {
private:
int bpriv;
protected:
int bprot;
public:
int bpub;
};
class PrivDerived : Base {
//privatno izvoenje
protected:
Base: : bprot;
//vraanje na nivo protected
public:
PrivDerived () {
bprot=2; bpub=3;
//moe se pristupiti
}
};
class ProtDerived : protected Base {
//zatieno izvoenje
//...
};
void main () {
PrivDerived pd;
pd.bpub=0;
//greka: bpub nije javni lan
}

Pokaziva na izvedenu klasu moe se implicitno konvertovati u pokaziva na javnu osnovnu


klasu ili u pokaziva na privatnu osnovnu klasu samo unutar izvedene klase, jer se samo unutar
nje zna da je ona izvedena. Isto vai i za reference.

10.5.2. Semantika razlika izmeu privatnog i javnog izvoenja

Javno izvoenje realizuje koncept nasleivanja, koji je iskazan relacijom B je vrsta A.


Ova relacija podrazumeva da izvedena klasa ima sve to i osnovna, to znai da je sve to
je dostupno korisniku osnovne klase, dostupno i korisniku izvedene klase. U jeziku C++ to
znai da javni lanovi osnovne klase treba da budu javni i u izvedenoj klasi.

Privatno izvoenje ne oslikava ovu relaciju, jer korisnik izvedene klase ne moe da
pristupi onome emu je mogao u osnovnoj klasi. Javnim lanovima osnovne klase mogu
pristupiti samo funkcije lanice izvedene klase, to znai da objekat izvedene klase u sebi
sakriva podobjekat osnovne klase. Zato privatno izvoenje realizuje sasvim drugu relaciju,
relaciju A je deo od B. Ovo je sutinski razliito od relacije nasleivanja.

Poto privatno izvoenje realizuje relaciju A je deo od B, ono je semantiki


ekvivalentno sa implementacijom kada klasa B sadri lana koji je tipa A.

Prilikom projektovanja, treba strogo voditi rauna o tome u kojoj su od ove dve relacije
neke dve uoene klase.U zavisnosti od toga treba izabrati nain izvoenja.

Predrag S. Stanimirovi

281

Programski jezici

Ako je relacija izmeu dve klase A je deo od B, izbor izmeu privatnog izvoenja i
lanstva zavisi od manje vanih detalja: da li je potrebno redefinisati virtuelne funkcije
klase A, da li je unutar klase B potrebno konvertovati pokazivae, da li klasa B treba da
sadri jedan ili vie primeraka klase A i slino.

10.5. Polimorfizam i virtuelni metodi


Pretpostavimo da nam je potrebna nova klasa Zena koja je jedna vrsta osobe, samo to jo
ima i devojako prezime. Klasa Zena bie izvedena iz klase Osoba.
I objekti klase Zena treba da se odazivaju na funkciju koSi, ali je teko pretpostaviti da e
jedna dama otvoreno priznati svoje godine. Zato objekat klase Zena treba da ima funkciju koSi,
samo to e ona izgledati malo drugaije, svojstveno izvedenoj klasi Zena:
class Osoba{
public:
Osoba(char *ime, int godine);
/* konstruktor */
virtual void koSi();
/* virtualna funkcija */
protected:
/* dostupno naslednicima */
char *ime;
/* podatak: ime i prezime */
int god;
/* podatak: koliko ima godina */
};
void Osoba::koSi () {
cout<<Ja sam <<ime<< i imam <<god<< godina.\n;
}
Osoba::Osoba(char *i, int g) : ime(i), god(g) {}
class Zena : public Osoba {
public:
Zena(char * ime, char * devojacko, int godine);
/*konstruktor */
virtual void koSi(); /* nova verzija funkcije koSi */
private:
char *devojacko;
};
Zena::Zena(char *i, char *d, int g): Osoba(i,g),
devojacko(d) {}
void Zena::koSi () {
cout<< Ja sam <<ime<<, devojacko prezime
<<devojacko<<.\n;
}

Funkcija lanica koja e u izvedenim klasama imati nove verzije deklarie se u osnovnoj
klasi kao virtuelna funkcija (virtual). Izvedena klasa moe da da svoju definiciju virtuelne
funkcije, ali i ne mora. U izvedenoj klasi ne mora se navoditi re virtual .
Da bi lanovi osnovne klase Osoba bili dostupni izvedenoj klasi Zena, ali ne i
korisnicima spolja, oni se deklariu iza specifikatora protected: i nazivaju zatienim
lanovima.
Drugi delovi programa, ako su dobro projektovani, ne vide nikakvu promenu zbog
uvoenja izvedene klase. Oni uopte ne moraju da se menjaju:
/* Funkcija ispitaj propituje osobe i
ne mora da se menja: */
void ispitaj (Osoba *hejTi) {
hejTi->koSi();
}

282
/* U drugom delu programa koristimo novu klasu Zena: */
Osoba otac(Petar Pertovic, 40);
Zena majka(Milka Petrovic, Mitrovic, 35);
Maloletnik dete(Milan Petrovic, Petar Petrovic, 12);
ispitaj(&otac);
/* pozvae se osoba::koSi() */
ispitaj(&majka);
/* pozvae se Zena::koSi() */
ispitaj(&dete)
/* pozvae se Osoba::koSi() */
/* Izlaz e biti:
Ja sam Petar Petrovic i imam 40 godina.
Ja sam Milka Petrovic, devojacko prezime Mitrovic.
Ja sam Milan Petrovic i imam 12 godina.
*/

Funkcija ispitaj dobija pokaziva na tip Osoba. Kako je i ena osoba, C++ dozvoljava da se
pokaziva na tip Zena (&majka) konvertuje (pretvori) u pokaziva na tip Osoba (hejTi).
Mehanizam virtuelnih funkcija obezbeuje da funkcija ispitaj, preko pokazivaa hejti, pozove
pravu verziju funkcije koSi. Zato e se za argument &majka pozivati funkcija Zena::koSi, a
za argument &otac funkcija Osoba::koSi. Za argument &dete takoe e se pozvati funkcija
Osoba::koSi, jer klasa Maloletnik nije redefinisala virtuelnu funkciju koSi.
Navedeno svojstvo da se odaziva prava verzija funkcije klase iji su naslednici dali nove
verzije naziva se polimorfizam (engl. polymorphism).
Primer. Pretpostavimo da smo projektovali klasu geometrijskih figura sa namerom da sve
figure imaju funkciju crtaj() kao lanicu. Iz ove klase izveli smo klase kruga, kvadrata, trougla
itd. Naravno, svaka izvedena klasa treba da realizuje funkciju crtanja na sebi svojstven nain.
Sada nam je potrebno da u nekom delu programa iscrtamo sve figure koje se nalaze na naem
crteu. Ovim figurama pristupamo preko niza pokazivaa tipa Figura*. C++ omoguava da
figure iscrtamo prostim navoenjem:
void crtanje () {
for (int i=0; i<brojFigura; i++)
nizFigura[i]->crtaj ();
}

Iako se u ovom nizu mogu nai razliite figure, mi im pristupamo kao figurama, jer sve vrste
figura imaju zajedniku osobinu da mogu da se nacrtaju. Ipak, svaka od figura svoj zadatak
ispunie onako kako joj to i prilii, odnosno svaki objekat e prepoznati kojoj izvedenoj klasi
pripada, bez obzira na to to mu se obraamo uopteno, kao objektu osnovne klase. To je
posledica nae pretpostavke da su i krug i kvadrat i trougao vrste figura.

Svojstvo da svaki objekat izvedene klase, ak i kada mu se pristupa kao objektu


osnovne klase, izvrava metod tano onako kako je to definisano u njegovoj izvedenoj
klasi, naziva se polimorfizam.

10.5.1. Virtuelne funkcije


Jezik C++ je statiki implementiran. To znai da u fazi prevoenja programa kompilator koristi
opise klasa objekata na slian nain kao i opise tipova podataka. Pripadnost objekta klasi je
analogna pripadnosti promenljive odreenom tipu. Ve u fazi prevoenja programa odluuje se
koji e se metod izvriti. To vai i u sluaju kada u hijerarhiji nasleivanja postoje funkcije sa
istim imenom. Pri tome se koriste tri mehanizma kojima se odluuje koja e funkcija biti
pozvana:

Na osnovu razlike u spisku argumenata. Na primer, funkcije show(int,char) i


show(char,float) su dve razliite funkcije iako imaju isto ime.

Predrag S. Stanimirovi

Programski jezici

283

Drugi mehanizam je operator pridruivanja funkcije klasi. Operatorom Circle::Show()


funkcija Show pridruuje se klasi Circle i predstavlja razliitu funkciju u odnosu na
funkciju Show koja se operatorom Point::Show() pridruuje klasi Point.

Trei mehanizam se zasniva na pripadnosti klasi onog objekta na koji se deluje


odreenom funkcijom. Na primer, neka objekat Krug pripada klasi Circle, a objekat
Tacka pripada klasi Point. Porukom Tacka.Show poziva se funkcija Show iz klase Point,
a porukom Krug.Show poziva se funkcija Show iz klase Circle.

Funkcije lanice osnovne klase koje se u izvedenim klasama mogu realizovati specifino za
svaku izvedenu klasu, nazivaju se virtuelne funkcije.
Virtuelna funkcija se u osnovnoj klasi deklarie pomou kljune rei virtual na poetku
deklaracije. Prilikom definisanja virtuelnih funkcija u izvedenim klasama ne mora se stavljati
re virtual ali se to preporuuje radi poveanja itljivosti i razumljivosti programa.
Prilikom poziva odaziva se ona funkcija koja pripada klasi kojoj i objekat koji prima poziv.
class ClanBiblioteke {
public:
virual void platiClanarinu ()
{ r-=clanarina; }
//...
private:
Racun r;
//...
};

//virtuelna funkcija

class PocasniClan : public ClanBiblioteke {


public:
virtual void platiClanarinu () {}
//...
};
void main () {
ClanBiblioteke *clanovi[100];
//...
for (int i=0; i<brojClanova; i++)
clanovi[i]->platiClanarinu();
//...
}

Virtuelna funkcija osnovne klase ne mora da se redefinie u svakoj izvedenoj klasi. U


izvedenoj klasi u kojoj virtuelna funkcija nije redefinisana, vai znaenje te virtuelne
funkcije iz osnovne klase.

Deklaracija neke virtuelne funkcije u svakoj izvedenoj klasi mora da se u potpinosti


slae sa deklaracijom te funkcije u osnovnoj klasi (broj i tipovi argumenata, kao i tip
rezultata).

Ako se u izvedenoj klasi deklarie neka funkcija koja ima isto ime kao i virtuelna
funkcija iz osnovne klase, ali raliit broj i/ili tipove argumenata, onda ona sakriva (a ne
redefinie) sve ostale istoimene funkcije iz osnovne klase.

10.5.2. Dinamiko vezivanje

Pokaziva na objekat izvedene klase moe se implicitno konvertovati u pokaziva na


objekat osnovne klase. Isto vai i za reference. Ovo je interpretacija injenice da se
objekat izvedene klase moe smatrati i objektom osnovne klase.

284

Pokazivau na objekat izvedene klase moe se dodeliti pokaiva na objekat osnovne


klase samo uz eksplicitnu konverziju. Ovo je interpretacija injenice da objekat osnovne
klase nema sve osobine izvedene klase.

Objekat osnovne klase moe se inicijalizovati objektom izvedene klase, i objektu


osnovne klase moe se dodeliti objekat izvedene klase bez eksplicitne konverzije. To se
obavlja odsecanjem lanova izvedene klase koji nisu i lanovi osnovne klase.

Virtuelni mehanizam se aktivira ako se objektu pristupa preko reference ili pokazivaa:
class Base {
public:
virtual void f();
//...
};
class Derived : public Base {
public:
virtual void f();
};
void g1(Base b) {
b.f();
}
void g2(Base *pb) {
pb->f();
}
void g3(Base &rb) {
rb.f();
}
void main () {
Derived d;
g1(d);
g2(&d);
g3(d);
Base *pb=new Derived;
pb->f();
Derived &rd=d;
rd.f();
Base b=d;
b.f();
delete pb;
pb=&b;
pb->f()
}

//poziva se Base::f
//poziva se Derived::f
//poziva se Derived::f
//poziva se Derived::f
//poziva se Derived::f
//poziva se Base::f
//poziva se Base::f

Postupak koji obezbeuje da se funkcija koja se poziva odreuje u vreme izvravanja, a


ne prevoenja naziva se dinamiko vezivanje.

Primer. U ovom primeru se razmatraju efekti statike implementacije klasa u C++.


class Lokacija
{
Protected:
int X;
int Y;
// Sve klase izvedene iz klase Lokacija imae
pristup X i Y
public:
// Ovim funkcijama je dozvoljen pristup spolja
Lokacija (int InitX, int InitY); // konstruktor
int GetX();

Predrag S. Stanimirovi

285

Programski jezici

int GetY();
};
// klasa Point se izvodi iz klase Lokacija
class Point : public Lokacija
{
Protected:
Boolean Vidljivost;
// X i Y se nasleuju kao protected
Public:
Point(int InitX, int InitY);
// konstruktor
void Show();
void hide();
boolean IsVisible();
void MoveTo(int NewX, int NewY);
};
// pridruene funkcije klase Lokacija
// prvo konstruktor klase Lokacija
Lokacija::Lokacija(int InitX, int InitY)
{X=InitX; Y=InitY; }
// zatim i ostale
int Lokacija::GetX() {return X; }
int Lokacija::GetY() {return Y; }
// pridruene funkcije klase Point
// prvo konstruktor klase Point
Point::Point(int InitX, int InitY) : Lokacija(InitX, InitY)
{ Visible=false; }
// taka je inicijalno nevidljiva
// zatim i ostale
void Point::Show(void)
{
Visible=true;
putpixiel(X,Y, getcolor());
}
void Point::Hide(void)
{
Visible=false;
putpixiel(X,Y, getbkcolor());
// taka se iscrtava
pozadine
// na lokaciji X,Y
}
void Point::MoveTo(int NewX, int NewY)
{
Hide();
X=NewX; Y=NewY;
Show();
}
void Point::IsVisible()
{ ... }
// definicija funkcije
// klasu Circle izvodimo iz klase Point
class Circle : Point

// implicitno se podrazumeva

bojom

286
{

// mehanizam nasleivanja private


int Radius;
Public:
Circle(int InitX, int InitY, int InitR);
// konstruktor
void Show(void);
void hide(void);
void MoveTo(int NewX, int NewY);
void Expand(int Delta);
// klasa ima svoje metode Hide, Show i MoveTo, kao i novi metod
Expand
};
// pridruene funkcije klase Circle
// prvo konstruktor klase Circle
Circle::Circle(int
Point(InitX,InitY)
{ Radius=InitR; }

InitX,

int

InitY,

int

InitR)

// zatim i ostale
void Circle::Show(void)
{
Visible=true;
circle(X,Y, Radius);
}

// poziv konstruktora

void Point::Hide(void)
{
unsigned int Temp;
Temp=getcolor();
selector(getbkcolor());
Visible=false;
putpixiel(X,Y, getbkcolor());
pozadine
selector(Temp);
}

//

krug

se

iscrtava

bojom

void Circle::MoveTo(int NewX, int NewY)


{
Hide();
X=NewX; Y=NewY;
Show();
}
void Circle::Expand(int Delta)
{ ... }
// definicija funkcije
// Glavni program
void main()
{ Point Tacka;
Circle Krug;
Tacka=Point(4,5);
Tacka.MoveTo(10,20);
Krug=Circle(4,5,5);
Krug.MoveTo(10,20);
}

//
//
//
//

kreira se taka
taka se pomera
krug sa centrom
centar kruga se

na lokaciji (4,5)
na (10,20)
u (4,5) radijusa 5
pomera u (10,20)

U poruci Tacka.MoveTo(10,20) poziva se funkcija MoveTo iz klase Point kojoj pripada


objekat Tacka i u okviru ove funkcije pozivaju se funkcije Show i Hide definisane u klasi Point.

Predrag S. Stanimirovi

287

Programski jezici

Funkcije Hide i Show su predefinisane u klasi Circle jer je bilo potrebno da se za njih vee
kod koji omoguava da se prikae odnosno sakrije ceo krug, a ne samo taka. Kako se radi o
statikoj implementaciji, u klasi Circle je morala da se ponovi definicija funkcije MoveTo iako
je njen kod isti sa kodom istoimene funkcije u klasi Point koja se nasleuje. Ovo je potrebno
zbog eksplicitnog pridruivanja funkcije MoveTo klasi Circle. Da funkcija MoveTo nije
eksplicitno pridruena klasi Circle poruka Krug.MoveTo bi se izvrila, ali se u tom sluaju
poziva nasleena funkcija iz klase Point. Kako je kod ove funkcije isti i u jednoj i u drugoj
klasi, na prvi pogled se ini da nema razlike u ovim pozivima. Meutim, problem je u tome to
e funkcijom MoveTo koja je pozvana iz iz klase Point biti pozvane i funkcije Hide i Show iz te
klase. To znai da se nee izvriti kod koji je potreban za sakrivanje i prikazivanje kruga, ve
samo take. Generalno, statika implementacija ne dozvoljava da profunkcionie mehanizam
polimorfizma, i da se aktivne funkcije Show i Hide odrede na osnovu objekta koji poziva
funkciju MoveTo.
Da bismo mogli da iskoristimo polimorfizam u ovom primeru, potrebno je da se unesu
sledee izmene:
-

Funkcije Hide i Show u klasi Point definisati kao virtuelne. Ove funkcije ostaju
predefinisane u klasi Circle i za njih se automatski primenjuje atribut virtual tako
da se ne mora eksplicitno navoditi u klasi Circle.

Funkcija MoveTo u klasi Circle vie nije potrebna. Ona se nasleuje iz klase Point.

10.5.3. Nizovi i izvedene klase


Objekat izvedene klase je vrsta objekta osnovne klase. Meutim, niz objekata izvedene klase
nije vrsta niza objekata osnovne klase. Uopte neka kolekcija objekata izvedene klase nije vrsta
kolekcije objekata osnovne klase.
Na primer, iako je automobil vrsta vozila, parking za automobile nije i parking za sve vrste
vozila, jer na parking za automobile ne mogu da stanu i kamioni. Ili, ako korisnik neke funkcije
prosledi toj funkciji korpu banana ne bi valjalo da mu ta funkcija vrati korpu u kojoj je jedna
ljiva, smatrajui da je korpa banana isto to i korpa bilo kakvog voa.
Ako se rauna sa nasleivanjem, u programu ne treba koristiti nizove objekata, ve nizove
pokazivaa na objekte. Ako se formira niz objekata izvedene klase i on prenese kao niz objekata
osnovne klase (to, po prethodno reenom, semantiki nije ispravno, ali je mogue) moe doi
do greke:
class Base {
public: int bi;
};
class Derived : public Base {
public: int di;
};
void f (Base *b) { cout<<b[2].bi; }
void main () {
Derived d[5];
d[2].bi=77;
f(d);
}

//nee se ispisati 77

U prethodnom primeru, funkcija f smatra da je dobila niz objekata osnovne klase koji su
krai (nemaju sve lanove) od objekata izvedene klase. Kada joj se prosledi niz
objekata izvedene klase, funkcija nema naina da odredi da se niz sastoji samo od
objekata izvedene klase.Rezultat je, u optem sluaju, neodreen.

288

Pored navedene greke, fiziki nije mogue direktno smetati objekte izvedene klase u
niz objekata osnovne klase. Objekti izvedene klase su dui, a za svaki element niza je
odvojen samo prostor koji je dovoljan za smetanje objekata osnovne klase.

Zbog svega to je reeno, kolekcije (nizove) objekata treba realizovati kao nizove
pokazivaa na objekte:
void f(Base **b, int i) {cout<<b[i]->bi;}
void main () {
Base b1,b2;
Derived d1,d2,d3;
Base b[5];
tip Base**
b[0]=&d1; b[1]=&b1;
Base*
b[3]=&d3; b[4]=&b2;
d2.bi=77;
f(b,2);
}

//b se moe konvertovati u


b[2]=&d2;

//konverzija Derived* u

//ispisae se 77

Kako je objekat izvedene klase vrsta objekta osnovne klase, C++ dozvoljava implicitnu
konverziju pokazivaa Derived* u Base* .Zbog logikog pravila da niz objekata
izvedene klase nije vrsta niza objekata osnovne klase, a kako se nizovi ispravno
realizuju pomou nizova pokazivaa, C++ ne dozvoljava implicitnu konverziju
pokazivaa Derived** (u koji se moe konvertovati tip niza pokazivaa na objekte
izvedene klase) u Base** (u koji se moe konvertovati tip niza pokazivaa na objekte
osnovne klase). Za prthodni primer nije dozvoljeno:
void main () {
Derived d[5];
//...
f(d,2);
Base**
}

//d je tipa Derived**


//nije dozveljena konverzija Derived** u

10.5.4. Apstraktne klase


est je sluaj da neka osnovna funkcija nema nijedan konkretan primerak (objekat), ve samo
predstavlja generalizaciju izvedenih klasa
Na primer, svi izlazni znakovno orijentisani ureaji raunara imaju funkciju za ispis jednog
znaka, ali se u osnovnoj klasi izlaznog ureaja ne moe definisati nain ispisa tog znaka, ve je
to specifino za svaki ureaj posebno, ili ako iz osnovne klase osoba izvedemo dve klase
mukaraca i ena, onda klasa osoba ne moe imati primerke, jer ne postoji osoba koja nije ni
mukog ni enskog pola.
Klasa koja nema instance (objekte) ve su iz nje samo izvedene druge klase, naziva se
apstraktna klasa.
u jeziku C++, apstraktna klasa sadri bar jednu virtuelnu funkciju lanicu koja je u njoj samo
deklarisana, ali ne i definisana. Definicija te funkcije dae izvedene klase. Ovakva virtuelna
funkcija naziva se istom virtuelnom funkcijom. Njena deklaracija u osnovnoj klasi zavrava se
sa =0:
class OCharDevice {
public:
virtual int put (char) =0;
//...
};

// ista virtuelna funkcija

Predrag S. Stanimirovi

289

Programski jezici

U jeziku C++ apstraktna klasa je klasa koja sadri bar jednu istu virtuelnu funkciju. Ovakva
klasa ne moe imati instance, ve se iz nje izvode druge klase. Ako se u izvedenoj klasi ne
navede definicija neke iste virtuelne funkcije iz osnovne klase, i ova izvedena klasa je takoe
apstraktna.
Pokazivai i reference na apstraktnu klasu mogu da se definiu, ali oni ukazuju na objekte
izvedenih konkretnih (neapstraktnih) klasa.

10.6. Viestruko nasleivanje


10.6.1. ta je viestruko nasleivanje
Nekad postoji potreba da izvedena klasa ima osobine vie osnovnih klasa istovremeno. Tada
se radi o viestrukom nasleivanju.
Klasa se deklarie kao naslednik vie klasa tako to se u zaglavlju deklaracije, iza znaka : ,
navode osnovne klase razdvojene zarezom. Ispred svake osnovne klase treba da stoji re public .
Na primer
class Derived : public Base1, public Base2, public Base3 {
//...
};

Sva navedena pravila o nasleenim lanovima vae i ovde. Konstruktori svih osnovnih klasa
pozivaju se pre poziva konstruktora lanova izvedene klase i pre izvravanja tela konstruktora
izvedene klase. Konstruktori osnovnih klasa pozivaju se po redosledu deklarisanja tih klasa u
zaglavlju izvedene klase. Destruktori osnovnih klasa izvravaju se na kraju, posle izvravanja
tela destruktora izvedene klase i destruktora lanova.

10.6.2. Virtuelne osnovne klase

Posmatrajmo sledei primer:


class
class
class
class

B
X
Y
Z

{/**/};
: public B {/*...*/};
: public B {/*...*/};
: public X, public Y {/*...*/};

U ovom primeru klase X i Y nasleuju klasu B, a klasa Z klase X i Y. Klasa Z ima sve
to imaju X i Y. Kako svaka od klasa X i Y ima po jedan primerak lanova klase B, to
e klasa Z imati dva skupa lanova klase B. Njih je mogue razlikovati pomou
operatora : : (npr. z.X: :i ili z.Y: :i).

Ako ovo nije potrebno, klasu B treba deklarisati kao virtuelnu osnovnu klasu.
class
class
class
class

B
X
Y
Z

{/**/};
:virtual public B {/**/};
:virtual public B {/**/};
: public X, public Y {/**/};

Sada klasa Z ima samo jedan skup lanova klase B.

Ako neka izvedena klasa ima virtuelne i nevirtuelne osnovne klase, onda se konstruktori
vurtuelnih osnovnih klasa pozivaju pre konstruktorsa nevirtuelnih osnovnih klasa po
redosledu deklarisanja. Svi konstruktori osnovnih klasa se, naravno pozivaju pre
konstruktora lanova i konstruktora izvedena klase

10.7. Prijatelji klasa

290
esto je dobro da se klasa projektuje tako da ima povlaene korisnike, odnosno funkcije ili
druge klase koje imaju pravo pristupa njenim privatnim lanovima. Takve funkcije i klase
nazivaju se prijateljima.

10.7.1. Prijateljske funkcije


Prijateljske funkcije neke klase nisu lanice te klase, ali imaju pristup do privatnih lanova te
klase. Te funkcije mogu da budu globalne funkcije ili lanice drugih klasa.
Da bi se neka funkcija proglasila prijateljem klase, potrebno je bilo gde u deklaraciji te klase
navesti deklaraciju te funkcije sa kljunom rei friend ispred. Prijateljska funkcija se definie na
uobiajeni nain:
class X {
public:
void f(int ip)

{ i=ip;}

private:
friend void g (int, X&);
//prijateljska globalna funkcija
friend void Y::h ();
//prijateljska lanica druge klase
int i;
};

void g (int k, X &x) {


x.i=k; // prijateljska funkcija moe da pristupa
//privatnim lanovima klase
void main () {
X x;
x.f(5);
//postavljanje prko lanice
g(6,x);
//postavljanje preko prijatelja

Globalne funkcije koje predstavljaju usluge neke klase ili operacije nad tom klasom
nazivaju se klasnim uslugama.

Nema formalnih razloga da se koristi globalna funkcija umesto funkcija lanica.


Globalne funkcije su ponekad pogodnije:
1. globalnoj funkciji moe da se dostavi kao argument i objekat drugog tipa, koji
e se konvertovati u potreban tip, dok funkcija lanica mora da se pozove za
objekat date klase;
2. kada funkcija treba da pristupa lanovima vie klasa;
3. kada je notaciono pogodnije da se koriste globalne funkcije (poziv je f(x))
umesto lanica (poziv je x.f()); npr. , max(a,b) je itljivije od a.max(b);

Prijateljstvo se ne nasleuje: ako je funkcija f prijatelj klasi X, a klasa Y izvedena iz


klase X, funkcija f nije prijatelj klasi Y.

10.7.2. Prijateljske klase

Ako je potrebno da sve funkcije lanice klase Y budu prijateljske funkcije klasi X,onda
se klasa Y deklarie kao prijateljska klasa klasi X. Tada sve funkcije lanice klase Y
mogu da pristupaju privatnim lanovima klase X, ali obratno ne vai:
class X {

friend class Y;

};

//...

Predrag S. Stanimirovi

291

Programski jezici

Prijateljstvo nije ni tranzitivna relacija: ako je klasa Y prijatelj klasi X, a klasa Z nije
automatski prijatelj klasi X, ve to mora eksplicitno da se naglasi.
Prijateljske klase obino se koriste kada dve klase imaju tenje meusobne veze. Pri
tome je nepotrebno otkrivati delove neke klase da bi oni bili dostupni drugoj klasi, jer
e onda biti dostupni i ostalima. U tom sluaju se ove dve klase proglaavaju
prijateljskim. Na primer, na sledei nain moe se obezbediti da samo klasa Creator
moe da stvara objekte klase X:
class X {
public:
...
private:
friend class Creator;
X();
//konstruktor je dostupan samo klasi Creator
...

};

10.7.3. Pokaziva this


Unutar svake funkcije lanice postoji implicitni (podrazumevani, ugraeni) lokalni objekat
this. Tip ovog objekta je konstantni pokaziva na klasu u kojoj je ta funkcija lanica (ako je
klasa X, this je tipa X*const). Ovaj pokaziva ukazuje na objekat ija je funkcija lanica
pozvana:
// definicija funkcije cAdd lanice klase complex
complex complex::cAdd (complex c) }
complex temp=*this;
// u temp se prepisuje objekat koji je prozvan
temp.real+=c.real;
temp.imag+=c.imag;
return temp;
}

Pristup lanovima objekta ija je funkcija lanica povana obavlja se neposredno; implicitno
je to pristup preko pokazivaa this i operatora ->. Moe se i eksplicitno pristupati lanovima
preko ovog pokazivaa unutar funkcije lanice:
// nova definicija funkcije cAdd lanice klase complex
complex complex:: cAdd (complex c) {
complex temp;
temp.real=this->real+c.real;
temp.imag=this->imag+c.imag;
return temp;
}

Pokaziva this je, u stvari, skriveni argumenat funkcije lanice. Poziv objekat.f() prevodilac
prevodi u kod koji ima semantiku kao f (&objekat).
Pokaziva this moe da se iskoristi prilikom povezivanja dva objekta. Na primer, neka klasa
X sadri objekat klase Y, pri emu objekat klase Y treba da zna ko ga sadri. Veza se inicijalno
moe uspostaviti pomou konstruktora:
class X {
public:
X () : y(this) {...}
private:
Y y;
};

292
class Y {
public:
Y (X* theContainer) : myContainer (theContainer) {...}
private:
X* myContainer;
};

10.7.4. Primerci klase


Za svaki objekat klase formira se poseban komplet svih podataka lanova te klase.
Za svaku funkciju lanicu, postoji jedinstven skup lokalnih statikih objekata. Ovi objekti
ive od prvog nailaska programa na njihovu definiciju, do kraja programa, bez obzira na broj
objekata te klase. Lokalni statiki objekti funkcija nelanica, pa nemaju nikakve veze sa klasom
i njenim objektima.
Podrazumevano se sa objektima klase moe raditi sledee:
1. definisati primerci (objekti) te klase i nizovi objekata klase;
2. definisati pokazivai na objekte i reference na objekte;
3. dodeljivati vrednosti (opertor =) jednog objekta drugom;
4. uzimati adrese objekata (operator &) i posredno pristupati objektima preko
pokazivaa (operator *);
5. pristupiti lanovima i pozvati funkcije lanice neposredno (operator.) ili
posredno (operator ->);
6. prenositi objekti kao argumenti funkcija i to po vrednosti ili referenci, ili
prenositi pokazivai na objekte;
7. vraati objekti iz funkcija po vrednosti ili referenci, ili vraati pokazivai na
objekte.
Neke od ovih operacija korisnik moe redefinisati preklapanjem operatora. Ostale ovde
nenavedene operacije korisnik mora definisati posebno ako su potrebne (ne podrazumevaju se).

10.7.5. Konstantne funkcije lanice

Dobra programerska praksa je da se korisnicima klase najavi da li neka funkcija lanica


menja unutranje stanje objekta ili ga samo ita i vraa informaciju korisniku klase.

Funkcije lanice koje ne menjaju unutranje stanje objekta nazivaju se inspektori ili
selektori (engl. inspector,selector). Re const iza zaglavlja funkcije ukazuje korisniku
klase da je funkcija lanica inspektor. Ovakve funkcije lanice nazivaju se u jeziku C+
+konstantnim funkcijama lanicama (engl. constant member functions).

Funkcija lanica koja menja stanje objekta naziva se mutator ili modifikator (engl.
mutator, modifier) i ne oznaava se posebno:
class X {
public:
int read () const
int write (int j=0)
private:
int i;
};

{ return i; }
{ int temp=i; i=j return temp; }

Deklarisanje funkcije lanice kao inspektora samo je notaciona pogodnost i stvar lepog
ponaanja prema korisniku. To je obeanje projektanata klase da funkcija ne menja
stanje objekta koje je projektant definisao. Prevodilac nema naina da u potpunosti
proveri da li inspektor posredno menja neke podatke lanova klase.

Predrag S. Stanimirovi

Programski jezici

293

Inspektor moe da menja podatke lanove pomou eksplicitne konverzije, koje probija
kontrolu konstantnosti. To je ponekad sluaj kada inspektor treba da izrauna podatak
koji vraa, pa ga onda sauva u nekom lanu da bi sledei put bre vratio odgovor.

U konstantnoj funkciji lanici tip pokazivaa this je const X*const, tako da pokazuje na
konstantni objekat, pa nije mogue menjati objekat preko ovog pokazivaa (svaki
neposredni pristup lanu je implicitni pristup preko ovog pokazivaa). Takoe, za
konstantne objekte klase nije dovoljno pozivati nekonstantnu funkciju lanicu
(korektnost konstantnosti).
Za prethodni primer:
X x;
const X cx;
x.read();
objekta;
x.write();
objekta;
cx.read();
cx.write();
objekta;

//
//

u
u

redu:
redu:

konstantna

funkcija

nekostantnog

nekonstantna

funkcija

nekostantnog

// u redu: konstantna funkcija konstantnog objekta;


// greka: nekonstantna funkcija konstantnog

10.8. Ugnjeivanje klasa

Klase mogu da se deklariu i unutar deklaracije druge klase (ugnjeivanje deklaracija


klasa). Ugnjeena klasa se nalazi i u oblasti vaenja okruujue klase, pa se njenom
imenu moe pristupiti samo preko operatora razreavanja oblasti vaenja : :.
Okruujua klasa nema nikakva posebna prava pristupa lanovima okruujue klase.
Ugnjeivanje je samo stvar oblasti vaenja, a ne i kontrole pristupa lanovima.
int x,y;
class Spoljna {
public:
int x;
class Unutrasnja {
void f (int i, Spoljna *ps) {
x=i;
//greka: pristup Spoljna: :x nije
korektan!
::x=i;
//u redu: pristup globalnom x;
y=i;
//u redu: pristup globalnom y;
ps->x=i;
//u redu: pristup Spoljna: :x objekta
*ps;
}
};
};
Unutrasnja u;
vaenja!
Spoljna: :Unutrasnja u;

//greka:Unutrasnja nije u oblasti


//u redu

Unutar deklaracije klase mogu se navesti i deklaracije nabrajanja (enum) i typedef


deklaracije.Ugnjeivanje se koristi kada neki tip semantiki pripada samo datoj klasi, a
nije globalno vaan i za druge klase. Ovakvo korienje poveava itljivost programa i
smanjuje potrebu za globalnim tipovima.

294
Strukture

Struktura je klasa kod koje su svi lanovi podrazumevano javni. To se moe promeniti
eksplicitnim umetanjem public: i private:
struct a {

class a {
public:
//
//
private:
private:
//
//
};
};
Struktura se obino koristi za definisanje slogova podataka koji ne predstavljaju
apstrakciju, odnosno nemaju ponaanje (nemaju znaajnije operacije), nego najee
slue samo za implementaciju sloene strukture neke apstrakcije. Strukture tipino
poseduju samo konstruktore i moda destruktore kao funkcije lanice.

isto to i :

10.9. Zajedniki lanovi klasa


10.9.1. Zajedniki podaci lanovi
Pri nastanku objekata klase, za svaki objekat se pravi poseban komplet podataka lanova.
Ipak, mogue je definisati podatke lanove za koje postoji samo jedan primerak za celu klasu, tj.
za sve objekte klase.
Ovakvi lanovi se nazivaju statikim lanovima, i deklariu se pomou rei static:
class X {
public:
//...
private:
static int i;
int j;

// postoji samo jedan i za celu klasu


// svaki objekat ima svoj j
//...

Svaki pristup statikom lanu iz bilo kog objekta klase znai pristup istom zajednikom
lanu- objektu.
Statiki lan klase ima ivotni vek kao i globalni statiki objekat: nastaje na poetku
programa i traje da kraja programa. Statiki lan klase ima sva svojstva globalnog statikog
objekta, osim oblasti vaenja i kontrole pristupa.

Statiki lan mora da se inicijalizuje posebnom definicijom van deklaracije klase.


Obraanje ovakvom lanu van klase vri se preko operatora : :. Za prethodni primer:
int X: : i=5;

Statikom lanu moe se pristupiti iz funkcije lanice, ali i van funkcija lanica, ak i pre
formiranja ijednog objekta klase, naravno uz potovanje prava pristupa. Tada mu se pristupa
preko operatora : : (X : : i).
Zajedniki lanovi se uglavnom koriste kada svi primerci jedne klase treba da dele neku
zajedniku informaciju, npr. kada predstavljaju neku kolekciju, odnosno kada je potrebno imati
ih sve na okupu i pod kontrolom. Na primer svi objekti neke klase se uvezuju u listu, a glava
liste je zajedniki lan klase.

Predrag S. Stanimirovi

295

Programski jezici

Zajedniki lanovi smanjuju potrebu za globalnim objektima i tako poveavaju itljivost


programa, jer je, za razliku od globalnih objekata, mogue ograniiti pristup do njih. Zajedniki
lanovi logiki pripadaju klasi i upakovani su u nju.

10.9.2. Zajednike funkcije lanice


I funkcije lanice mogu da se deklariu kao zajednike za celu klasu, dodavanjem rei static
ispred deklaracije funkcije lanice.
Statike funkcije lanice imaju sva svojstva globalnih funkcija, osim oblasti vaenja i
kontrole pristupa. One poseduju pokaziva this i ne mogu neposredno (bez pominjanja
konkretnog objekta klase) koristiti nestatike lanove klase. Statike funkcije mogu neposredno
koristiti samo statike lanove te klase.
Statike funkcije lanice mogu se pozivati za konkretan objekat, ali i pre formiranja ijednog
objekta klase, preko operatora : :.

Primer:

class X {
static int
int
public:
static int
int
};

x;
y;

// statiki podatak lan;

f(X,X&);
g();

//statika funkcija lanica;

int X:: x=5;


int X:: f(X x1, X& x2) {
int i=x;
int j=y;

//definicija statikog podatka lana;


//definicija statike funkcije lanice;
// pristup statikom lanu X: :x;
// greka: X: :y nije statiki,
// pa mu se ne moe pristupiti

neposredno!
int k=x1.y;
return x2.x;
}
int X: : g () {
int i=x;
int j=y
return j;
}
void main () {
X xx;
int p=X: :f(xx,xx);
int q=X: :g();
xx.g();
p=xx.f(xx,xx);
}

// ovo moe;
// i ovo moe,
// ali se izraz x2 ne izraunava;
//nestatika funkcija lanica moe da
// koristi i pojedinane i zajednike
// lanove; y je ovde this->y;

//
//
//
//
//

X: :f moe neposredno, bez objekta;


greka: za X:: g mora konkretan objekat!
ovako moe;
i ovako moe,
ali se izraz xx ne izraunava;

Statike funkcije predstavljaju operacije klase, a ne svakog posebnog objekta. Pomou njih
se definiu neke opte usluge klase, npr. tipino stvaranje novih, dinamikih objekata te klase
(operator new je implicitno definisan kao statika funkcija klase). Na primer, na sledei nain
obezbeuje se da se za datu klasu mogu formirati samo dinamiki objekti:
class X{
public:
static X*create () { return new X; }
private:
X ();
//konstruktor je privatan

296
};

10.10. Preklapanje operatora


10.10.1. Pojam preklapanja operatora
Pretpostavimo da su nam u programu potrebni kompleksni brojevi i operacije nad njima.
Treba nam struktura podataka koja e, pomou osnovnih tipova, predstaviti strukturu
komleksnog broja, a takoe i funkcije koje e realizovati operacije nad kompleksnim brojevima.
Kada je potrebna struktura podataka za koju nisu bitni detalji implementacije, ve operacije
koje se nad njom vre, sve ukazuje na klasu. Klasa upravo predstavlja apstraktni tip podataka
za koji su definisani podaci.
U jeziku C++, operatori za korisnike tipove su specijalne funkcije koje nose ime operator
@ gde je @ neki operator ugraen u jezik:
class complex {
public:
complex(double re, double im);
friend complex operator+(complex, complex);
friend complex operator-(complex, complex);

/* konstruktor */
/* operator + */
/* operator - */

private:
double real, imag;
};
complex:: complex (double r, double i): real(r), imag(i) {}
complex operator+(complex c1, complex c2) {
complex temp(0,0);
/*privremena
complex*/
temp.real=c1.real+c2.real;
temp.imag=c1.imag+c2.imag;
return temp;
}

promenljiva

tipa

complex operator- (complexc1, complex c2) {


return complex(c1.real-c2.real, c1.imag-c2.imag);
}

Operatorske funkcije se mogu koristiti u izrazima kao i operatori nad ugraenim


tipovima. Izraz
t1@t2
se tumai kao t1.operator@(t2) ili
operator@(t1,t2).

10.11. Operatorske funkcije


10.11.1. Osnovna pravila

U jeziku C++, pored obinih funkcija koje se eksplicitni pozivaju navoenjem


identifikatora u zagradama, postoje i operatorske funkcije.
Operatorske funkcije su posebne vrste funkcija koje imaju posebna imena i nain
pozivanja, i one se mogu preklopiti za operande koji pripadaju korisnikim tipovima.
Ovaj princip se naziva preklapanje operatora. on omoguava da se definiu znaenja za
korisnike tipove i formiraju operacije nad objektima ovih tipova, npr. operacije nad
kompleksnim brojevima, matricama itd.
Postoje neka ogranienja u preklapanju operatora. Ne mogu se:
1. preklapati operatori .,.*,: :,?: i sizeof, dok svi ostali mogu;

Predrag S. Stanimirovi

297

Programski jezici

2. definisati znaenja operatora za ugraene tipove podataka;


3. uvoditi nive simbole za operatore;
4. manjati osobine operatora koje su ugraene u jezik: broj operanada, prioriteti i
asocijativnost
Operatorske funkcije imaju imena operator@ gde je @ znak operatora. Operatorske
funkcije mogu biti lanice ili globalne funkcije kod kojih je bar jedan argument tipa
korisnike klase.

10.11.2. Boni efekti i veze izmeu operatora

Boni efekti koji postoje kod operatora za ugraene tipove nikad se ne podrazumevaju
za definisane operatore: ++ ne mora da menja stanje objekta, niti da znai sabiranje sa
1. Ovo vai i za i sve operatore dodele (=, +=, -=, *= itd.).
Operator = (i ostali operatori dodele) ne mora da menja stanje objekta. Ipak, ovakve
upotrebe treba strogo izbegavati.
Veze koje postoje izmeu operatora za ugraene tipove ne podrazumevaju se za
redefinisane operatore. Na primer, a+=b ne mora automatski da znai a=a+b, ako je
definisan operator +, ve operator += mora posebno da se definie.
Preporuuje se da operatori koje definie korisnik imaju oekivano znaenje, radi
itljivosti programa. Na primer, ako su definisani i operator += i operator +, dobro je da
a+=b koristi isti efekat kao i a=a+b.

Operatorske funkcije kao lanice i globalne funkcije

Operatorske funkcije mogu da budu lanice klasa ili globalne funkcije. Ako je @ neki
binarni operator (npr. +), on moe da se realizuje kao funkcija lanica klase X na sledei
nain:
p operator@

(X)

ili kao prijateljska globalna funkcija na sledei nain:


p operator@ (X,X)

Unarni i binarni operatori

Mnogi operatori jezika C++ (kao i jezika C) mogu da budu i unarni i binarni.
Unarni operator ima samo jedan operand, pa se moe realizovati kao operatorska
funkcija lanica bez argumenata (prvi operand je objekat ija je funkcija lanica
pozvana):
tip operator@ ()

ili kao globalna funkcija sa jednim argumentom:


tip operator@ (X x)

Binarni operator ima dva operanda, pa se moe realizovati kao funkcija lanica sa
jednim argumentom (prvi operand je objekat ija je funkcija lanica pozvana):
tip operator@ (X xdesni)

ili kao globalna funkcija sa dva argumenta:


tip operator@ (X xlevi, X xdesni).

Primer.
class complex {
public:

298
complex (double re=0, double im=0) : real ( r), imag (i) {}
friend complex operator+ (complex, complex);
complex operaator! ()
//unarni operator!, konjugivani
broj

};

{ return complex (real, -imag);}


private:
double real, imag;

10.12. Neki posebni operatori


10.12.1. Operatori new i delete
Ponekad programer eli da preuzme kontrolu nad alokacijom dinamikih objekata neke
klase, a ne da je prepusti ugraenom alokatoru. To je zgodno npr. kada su objekti klase mali i
moe se precizno kontrolisati njihova alokacija, tako da se smanje trokovi alokacije.
Za ovakve potrebe mogu se preklopiti operatori new i delete za neku klasu. Operatorske
funkcije new i delete moraju biti statike funkcije lanice, jer se one pozivaju pre nego to je
objekat stvarno inicijalizovan, odnosno poto je uniten.
Ako je korisnik definisao ove operatorske funkcije za neku klasu, one e se pozivati kad god
nastaje dinamiki objekat te klase operatorom new, odnosno kada se takav objekat dealocira
operatorom delete.
Unutar tela ovih operatorskih funkcija na treba splicitno pozivati konstruktor, odnosno
destruktor. Konstruktor se implicitno poziva posle funkcije new, a destruktor se implicitno
poziva pre funkcije delete. Ove operatorske funkcije slue samo da obezbede prostor za
smetanje objekta i da ga posle oslobode, a ne da od presnih bitova naprave objekat, odnosno
pretvore ga u presne bitove. Operator new treba da vrati pokaziva na alocirani prostor.
Ove operatorske funkcije deklariu se na sledei nain:
void* operator new (size t veliina)
void operator delete (void* pokaziva)

Tip size t je celobrojni tip definisan u <stdlib.h> i slui za izraavanje veliina objekata.
Argument veliina daje veliinu potrebnog prostora koji treba alocirati za objekat. Argument
pokaziva je pokaziva na prostor koji treba osloboditi.
Podrazumevani (ugraeni) operatori new i delete mogu da se pozivaju unutar tela
redefinisanih operatorskih funkcija ili eksplicitno, preko operatora : :, ili implicitno, kada se
prave dinamiki objekti za koje nisu redefinisani ovi operatori.
Primer:
#include <stdlib.h>
class XX {
public:
void* operator new (size_t sz)
{ return new char [sz]; }
ugraeni new
void operator delete (void *p )
{ delete [] p; }
delete
//...
};

//koristi se za
//koristi se ugraeni

Predrag S. Stanimirovi

299

Programski jezici

10.13. Osnovni standardni ulazno/izlazni tokovi


10.13.1. Klase istream i ostream
Kao i jezik C, ni C++ ne sadri ulazno/izlazne (U/I) operacije, ve se one realizuju
standardnim bibliotekama. Ipak, C++ sadri standardne U/I biblioteke realizovane u duhu
jezika C++.
Na raspolaganju su i stare C biblioteke sa funkcijama scanf i printf, ali njihovo korienje
nije u duhu jezika C++.
Biblioteka ije se deklaracije nalaze u zaglavlju < iostream.h > sadri dve osnovne klase,
istream i ostream (ulazni i izlazni tok). Svakom primerku klasa ifstream i ofstream, koje su
redom izvedene iz navedenih klasa, moe da se pridrui jedna datoteka za ulaz/izlaz, tako da se
datotekama pristupa iskljuivo preko ovakvih objekata, odnosno funkcija lanica ili prijatelja
ovih klasa. Time je podran princip enkapsulacije.
U ovoj biblioteci definisana su i dva korisniku dostupna (globalna) statika objekta:
1. Objekat cin klase istream koji je pridruen standardnom ulaznom ureaju
(obino tastatura);
2. Objekat cout klase ostream koji je pridruen standardnom izlaznom ureaju
(obino ekran).
Klasa istream je preklopila operator >> za sve ugraene tipove, koji slui za izlaz podataka:
istream& operator >> (istream &is, tip &t);
gde je tip neki ugraeni tip objekta koji se uitava.
Klasa ostream je preklopila operator << za sve ugraene tipove, koji slui za izlaz podataka:
ostream& operator<< (ostream &os, tip x);
gde je tip neki ugraeni tip objekta koji se ispisuje.
Ove funkcije vraaju reference, tako da se moe vriti U/I u istoj naredbi. Osim toga, ovi
operatori su asocijativni sleva u desno, tako da se podaci ispisuju prirodnim redosledom.
Ove operatore treba koristiti za uobiajene, jednostavne U/I operacije:
#include <iostream.h>

//obavezno ako se eli U/I

void main () {
int i ;
cin>>i;
//uitava se i
cout
<<i=<<i<<\n;
//ispisuje se npr.: i=5 i prelazi
u novi red
}

10.13.2. Ulazno/izlazne operacije za korisnike tipove


Korisnik moe da definie znaenje operatora >> i << za svoje tipove. To se radi definisanjem
prijateljskih funkcija korisnikove klase, jer je prvi operand tipa istream& odnosno ostream&.

Primer za klasu complex:

#include < iostream.h>


class complex {
public:
//...
friend ostream& operator << (ostream&, const complex&);
//...
};
/...

300
ostream& operator << (ostream &os, const complex &c) {
return os <<( <<c.real<<;<<c.imag<<);
}
void main () {
complex c(0.5,0.1);
cout <<c=<<c<<\n;
}

//ispisuje se:c=(0.5, 0.1)

10.14. Uvod u objektno modelovanje


10.14.1. Apstraktni tipovi podataka
Apstraktni tipovi podataka predstavljaju realizacije struktura podataka sa pridruenim
protokolima (operacijama i definisanim nainom i redosledom pozivanja tih operacija). Na
primer, red je struktura elemenata koja ima operacije stavljanja i uzimanja elemenata u
strukturu, pri emu se elementi uzimaju po istom redosledu po kom su stavljeni.
Kada se realizuju strukture podataka (apsraktni tipovi podataka), najee nije bitno koji je
tip elementa strukture, vaan je samo skup operacija. Naini realizacija tih operacija ne zavise
od tipa elementa, ve samo od tipa strukture.
Za realizaciju apstraktnih tipova podataka kod kojih tip nije bitan, u jeziku C++ postoje
abloni. ablon klase predstavlja definiciju itavog skupa klasa koje se razlikuju samo po tipu
elementa, I eventualno, po dimenzijama. abloni klasa se ponekad nazivaju i generikim
klasama.
Konkretna klasa generisana iz ablona dobija se navoenjem stvarnog tipa elementa.
Formalni argumenti ablona zadaju se u zaglavlju ablona:
template <class T>
class Queue {
public:
Queue ();
}Queue ();
void put (const T&);
T
get ();
//...
};

Konkretna generisana klasa dobija se samo navoenjem imena ablona, uz definisanje


stvarnih argumenata ablona. Stvarni argumenti ablona su tipovi i, eventualno, celobrojne
dimenzije. Konkretna klasa se generie na mestu navoenja, u fazi prevoenja. Na primer, red
dogaaja moe se kreirati na sledeI nain:
class Event ;
Queue <Event*>

que;

que.put(e);
if (que.get ()->isUrgent())...

Generisanje je samo stvar automatskog generisanja parametrizovanih koda istog oblika, a


nema nikakve veze sa izvravanjem. Generisane klase nemaju nikakve posebne meusobne
veze.

Predrag S. Stanimirovi

301

Programski jezici

10.14.2. Projektovanje apstraktnih tipova podataka


Apstraktni tipovi podataka (struktura podataka) su veoma esto korieni elementi svakog
programa. Projektovanje biblioteke klasa koje se realizuju standardne strukture podataka veoma
je delikatan posao. Ovde e biti prikazana konstrukcija dve este linearne strukture podataka:
1. Kolekcija je linearna neureena struktura elemenata koja ima samo operacije
sastavljanja elemenata i izbacivanja datog elementa iz strukture. Redosled elemenata
nije bitan, a elementi se mogu i ponavljati.
2. Red je linearna ureena struktura elemenata. Elementi su ureeni po redosledu
stavljanja. Operacija uzimanja vraa element koji je prvi stavljen u strukturu.
Vaan koncept pridruen strukturama je pojam iteratora. Iterator je objekat pridruen
linearnoj strukturi koji slui za pristup redom elementima strukture. Iterator ima operacije za
postavljanje na poetak strukture, za pomeranje na sledei element strukture, za pristup do
tekueg elementa na koji ukazuje i operaciju za ispitivanje da li je doao do kraja strukture. Za
svaku strukturu moe se napraviti proizvoljno mnogo objekata-iteratora i svaki od njih pamti
svoju poziciju.
Sutina koncepta iteratora je da obezbedi sekvencijalni pristup do elemenata agregatne
strukture, bez izlaganja njene interne realizacije. S druge strane, loe je optereivati sam
interfejs date strukture operacijama koje obezbeuju takav pristup. Zato se obezbeuje posebna
klasa iteratora pridruena datoj strukturi, koja je odgovorna za obilazak strukture, poznaje njenu
internu predstavu, i za koju se onda moe napraviti proizvoljan broj instanci koje nezavisno
iteriraju. Ovakvo reenje predstavlja projektni obrazac (engl. design pattern) Iterator (ili
Cursor).
Pri realizaciji biblioteke klasa za strukture podataka, bitno je razlikovati protokol strukture
koji definie njenu semantiku, od njene implementacije.
Protokol strukture odreuje znaenje njenih operacija, potreban nain ili redosled pozivanja
itd.
Implementacija se odnosi na nain smetanja elemenata u memoriju, organizaciju njihove
veze itd. Vaan aspekt implementacije je da li je ona ograniena ili nije. Ograniena realizacija
se oslanja na fiksno dimenzionisani niz elemenata, dok se neograniena realizacija odnosi na
dinamiku strukturu (najee listu).

Na primer, protokol reda izgleda otprilike ovako:


temlate <class T>
class Queue {
public:
virtual IteratorQueue<T>* createIterator () const=0;
virtual void put
(const T&) = 0;
virtual T
get ()=0;
virtual void clear ()=0;
virtual
virtual
virtual
virtual
virtual

const
int
int
int
int

T& first () const=0;


isEmpty () const=0;
isFull () const=0;
isLength () const=0;
location (const T&) const=0;

virtual

Da bi se korisniku obezbedile obe realizacije (ograniena i neograniena), postoje dve klase


izvedene iz navedene apstraktne klase koja definie interfejs reda. Jedna od njih podrazumeva
ogranienu realizaciju, a druga neogranienu.
Na primer:

302
template <class T, int N>
class QueueB : public Queue<T>
public:
QueueB ()
QueueB (const Queue<T>&);
virtual - QueueB ()
Queue<T>& operator= (const Queue<T>&) ;
virtual Iterator Queue<T>* createIterator () = const;
virtual void put
virtual T
get
virtual void clear
virtual
virtual
virtual
virtual
virtual

const
int
int
int
int

T& first
isEmpty
isFull
isLength
location

(const T& t);


()
;
()
;
() const;
() const;
() const;
() const;
(const T&) const;

Treba obratiti panju na nain kreiranja iteratora. Korisniku je dovoljan samo opti,
zajedniki interfejs iteratora.Korisnik ne treba nita da zna o specifinostima realizacije iteratora
i njegovoj vezi sa konkretnom izvedenom klasom reda. Zato je definisana osnovna apstraktna
klasa iteratora, iz koje su izvedene klase za iteratore vezane za dve posebne realizacije reda:
template <class T>
class IteratorQueue {
public:
virtual ~IteratorQueue ( ) {}
virtual void reset () = 0;
virtual int next () = 0;
virtual int isDone () const = 0;
virtual const T* currentItem () const = 0;
};

Izvedene klase reda pravie posebne, njima specifine iteratore koji se uklapaju u zajedniki
interfejs iteratora:
Template <class T, int N>
IteratorQueue<T>* QueueB<T, N>: : createIterator ( ) const
return new IteratorQueueB<T, N> (this);
}

Sutina ovog reenja je da se korisnici ovog podsistema oslanjaju samo na apstraktne


interfejse Queue i IteratorQueue, odnosno da ne znaju za specifinosti konkretnih
implementacija. ak i samo pravljenje iteratora obavlja se preko apstraktnog interfejsa, tj.
operacije createIterator ( ), koju definiu konkretne izvedene klase QueueB i QueueU, tako to
prave konkretne specifine iteratore. Ovakav pristup znatno poveava fleksibilnost softvera.
Ovo reenje, tj operacija createIterator( ) predstavlja projektni obrazac Factory Method, koji
se sastoji u obezbeivanju interfejsa za pravljenje objekta, pri emu konkretne izvedene klase
odluuju koji konkretni objekat da naprave.
Relacije izmeu opisanih klasa prikazane su na sledeem dijagramu:

Predrag S. Stanimirovi

303

Programski jezici

Sama realizacija ograniene i neograniene strukture oslanja se na dve klase koje imaju
sledee interfejse:
template <class T>
class Unbounded
public :
Unbounded
();
Unbounded (const. Unbounded<T>&) ;
~Unbounded
();
Unbounded <T>& operator = (const Unbounded<T>&);
void
void
void
void
void

append (const T&);


insert (const T&, int at=0);
remove ( const T&);
remove (int at=0);
clear ( );

int isEmpty ( ) const;


int isFull ( ) const;
int length ( ) const;
const T& first ( ) const;
const T& last ( ) const;
const T& itemAt (int at) const;
T& itemAt (int at);
int location (const T&) const;
};
template <class T, int N>
class Bounded {
public:
Bounded ( );
Bounded (const Bounded<T,N>&);
~Bounded ( );
Bounded<T,N>& operator=(const Bounded<T,N>&);
void append

(const T&);

304
void
void
void
void

insert (const T&, int at=0);


remove ( const T&);
remove (int at=0);
clear ( );

int isEmpty ( ) const;


int isFull ( ) const;
int length ( ) const;
const T& first ( ) const;
const T& last ( ) const;
const T& itemAt (int at) const;
T& itemAt (int at);
int location (const T&) const;
};

Definisana struktura moe se koristiti kao u sledeem primeru:


class Event {
//...
};
typedef QueueB<Event*, MAXEV> EventQueue;
typedef IteratorQueue<Event*> Iterator;
//...
EventQueue que;
que.put (e);
Iterator* it=que.createIterator ();
For (; !it->isDone(); it->next () )
(*it->currentItem ())->handle ();
delete it;

Promena orijentacije na ogranieni red veoma je jednostavna. Ako se eli neogranieni red,
dovoljno je promeniti samo:
typedef

QueueU<Event*>

EvenrQueue;

10.14.3. Modelovanje strukture-klase i osnovne relacije izmeu


klasa
Klasa je osnovna jedinica strukturnog modela sistema.
Klasa je veoma retko izolovana. Ona dobija smisao samo zu druge klase sa kojima je u
relaciji. Osnovne relacije izmeu klasa su: asocijacija, zavisnost i nasleivanje.

Klasa, atributi i operacije


Klasom se modeluje apstrakcija. Klasaje opis skupa objekata koji dele iste atribute, operacije,
relacije i semantiku.
Atribut je imenovano svojstvo entiteta. Njime se opisuje opseg vrednosti koje instance tog
svojstva mogu da imaju.
Operacija je implementacija usluge koja se moe zatraiti od bilo kog objekta klase da bi se
uticalo na ponaanje.
Klasa se prikazuje pravougaonim simbolom u kome mogu postojati posebni odeljci za ime
klase, atribute i operacije:

Predrag S. Stanimirovi

Programski jezici

305

CLASSA
name: String
age: int=0
ClassA( )
setName(newName: String): void

Asocijacija
Asocijacija (pridruivanje) je relacija izmeu klasa iji su objekti na neki nain strukturno
povezani. Ta veza izmeu objekata klasa postoji odreeno due vreme, a ne samo tokom
trajanja izvravanja operacije jednog objekta koju poziva drugi objekat. Instanca operacije
naziva se vezom i postoji izmeu objekata datih klasa.
Asocijacija se predstavlja punom linijom koja povezuje dve klase. Asocijacija moe imati
ime koje opisuje njeno znaenje. Svaka strana u asocijaciji ima svoju ulogu koja se moe
naznaiti na strani date klase.
Na svakoj strani asocijacije moe se definisati kardinalnost pomou sledeih oznaka:
1
tano jedan
*
proizvoljno mnogo
1..* jedan i vie
0..1 nula ili jedan
3..7 zadati opseg i slino.
Druga posebna karakteristika svake strane asocijacije je navigabilnost: sposobnost da se sa te
strane (od objekta sa jedne strane veze) dospe do druge strane (do objekta sa druge strane veze).
Prema ovom svojstvu, asocijacija moe biti simetrina ili asimetrina.

Zavisnost
Relacija zavisnosti postoji ako klasa A na neki nain koristi usluge klase B. To moe biti npr.
odnos klijent-server (klasa A poziva funkcije klase B) ili odnos instancijalizacije (klasa A pravi
objekte klase B)
Za realizaciju ove relacije izmeu klase A i B potrebno je da interfejs ili implementacija klase
A zna za definiciju klase B. Tako je klasa A zavisna od klase B.
Oznaka :
Client

Supplier

Znaenje relacije moe da se navede kao stereotip relacije na dijagramu, npr. <<call>> ili
<<create>>.
Ako klasa Client koristi usluge klase Supplier tako to poziva operacije objekata ove klase
(odnos klijent-server), onda ona tipino vidi ove objekte kao argumente svojih operacija. U
ovom sluaju, za implementaciju na jeziku C++, interfejsu klase Client nije potrebna definicija
klase Supplier, ve samo njenoj implementaciji:
class Supplier;
class Client {
public;
//...

306
void aFunction (Supplier*);
};
// Implementacija:
void Client :: aFunction (Supplier* s)
//...
s->doSomething ( );
}
Pri implementaciji na jeziku C++, ako je potrebno dobiti notaciju prenosa po vrednosti, a
zadrati navedenu pogodnost slabije zavisnosti izmeu modula, onda se argument prenosi preko
reference na konstantu:
void Client :: aFunction (const Supplier& s)
s.doSomething();
}
Ako klasa Client instancijalizuje klasu Supplier, onda je realizacija nalik na:
Supplier* Client : : createSupplier
(/*some arguments*/)
{ return new Supplier
(/*some arguments*/);
}

Nasleivanje (generalizacija/specijalizacija)
Nasleivanje predstavlja relaciju generalizacije odnosno specijalizacije, zavisno u kom smeru se
posmatra. Oznaka :
Base

Derived

Relacija generalizacije/specijalizacije predstavlja relaciju koja ima dve vane


semantike manifestacije:
(a) Nasle|ivanje: nasle|ena klasa implicitno poseduje sve atribute, operacije I
asocijacije osnovne klase (va`I i tranzitivnost).
(b) Supstitucija: objekat (instanca) izvedene klase mo`e se na}I svugde gde se oekuje
objekat osnovne klase (vai i tranzitivnost). Za strukturni aspekt sistema ovo
pravilo ima sledeu bitnu manifestaciju: ako u nekoj asocijaciji u~estvuje osnovna
klasa, onda u nekoj vezi kao instanci te asocijacije mogu u~estvovati objekti svih
klasa izvedenih iz te klase.

Realizacija:
class Derived : public Base //

Zbog ovako definisane semantike osnovnih relacija izme|u klasa (prvenstveno


asocijacije i nasle|ivanja), softverski sistemi (aplikacije) koji su modelovani objektno
imaju jedno op{te svojstvo: njihova struktura u vreme izvr{avanja mo`e se apstraktno
posmatrati kao tipizirani graf, jer se sastoji iz objekata (instanci klasa) povezanih
vezama (instancama asocijacija). Dakle, objekti predstavljaju vorove, a veze grane
jednog grafa. Pritom, objekti kao vorovi grafa imaju svoje tipove (to su klase ije su
ovo instance), kao I veze koje su instance odgovarajuih asocijacija. Na stranama
svake veze koja je instanca neke asocijacije nalaze se instance onih klasa koje povezuje
ta asocijacija, ili klasa izvedenih iz njih (ukljuuju}i i tranzitivnost nasle|ivanja).

Predrag S. Stanimirovi

307

Programski jezici

Primeri:
1. Napisati funkciju za deljenje polja P na dva dela, pri emu u polje P1 ulaze svi elementi
polja P vei od zadatog broja k, a u polje P2, svi elementi polja P manji od k. Elementi
polja P1 i P2 treba da budu sortirani.
#include<stdio.h>
#include<iostream.h>
void main(void){
int p[20],p1[20],p2[20],n,i,j,zadati,br1,br2;
cout<<"\n Unesite dimenziju niza:";
cin>>n;
cout<<"\n Unesite elemente niza:\n";
for(i=0; i<n; i++)
cin>>p[i];
cout<<"\n Unesite zadati element:";
cin>>zadati;
br1=0;
br2=0;
for(i=0; i<n; i++){
if(p[i]>zadati){
p1[br1]=p[i];
br1++;
}
else{
p2[br2]=p[i];
br2++;
};
};
for(i=0; i<br1-1; i++){
for(j=i+1; j<=br1-1; j++){
if(p1[i]>p1[j]){
zadati=p1[i];
p1[i]=p1[j];
p1[j]=zadati;
};
};
};
for(i=0; i<br2-1; i++){
for(j=i+1; j<=br2-1; j++){
if(p2[i]>p2[j]){
zadati=p2[i];
p2[i]=p2[j];
p2[j]=zadati;
};
};
};
cout<<"\n Polje P1\n";
for(i=0; i<br1; i++)
cout<<"\n P1["<<i<<"]="<<p1[i];
cout<<"\n\n\n Polje P2\n";
for(i=0; i<br2; i++)

308
cout<<"\n P2["<<i<<"]="<<p2[i];
cout<<"\n\n";
}

2. Korienjem reprezentacije liste preko polja napisati funkciju za ure|enje listi po polju
info u rastui redosled metodom bubble-sort.
#include<stdio.h>
#include<iostream.h>
struct el_liste{
int info;
int link;
};
// int smesteni;
el_liste lista[20];
void unos(int info){
int i=0;
while(lista[i].link!=0){
i=lista[i].link;
};
lista[i].link=i+1;
lista[i+1].info=info;
lista[i+1].link=0;
};
int nadji(int k){
int j=0,i;
for(i=1; i<k; i++){
j=lista[j].link;
};
return lista[j].link;
};
void buble_sort(int n){
int i,j,promena,p,pom,pom1;
j=n;
do{
promena=0;
for(i=2; i<=j; i++){
pom=nadji(i-1);
pom1=nadji(i);
if(lista[pom].info>lista[pom1].info){
p=lista[pom].info;
lista[pom].info=lista[pom1].info;
lista[pom1].info=p;
promena=1;
};
};
j--;
} while(j>=2 || promena!=0);
};
void stampaj(){
int i=0;

Predrag S. Stanimirovi

309

Programski jezici

while(lista[i].link!=0){
i=lista[i].link;
cout<<"\n "<<lista[i].info;
};
};
void main(void){
int i,j,n,broj;
cout<<" \n Unesite broj elemenata liste:";
cin>>n;
lista[0].info=0;
lista[0].link=0;
for(i=1; i<=n; i++){
cin>>broj;
unos(broj);
};
buble_sort(n);
stampaj();
cout<<"\n\n";
}

3. Projektovati potprograme za rad sa dekom float tipa. (zpp3)


#include<stdio.h>
#include<iostream.h>
#include<float.h>
float dek[10];
int levi_slob=-1, desni_slob=10;
int pun(){
if((levi_slob<desni_slob)&& (levi_slob+1 < desni_slob))
return 1;
else return 0;
};
void upisi_levo(float broj){
if(pun()!=0){
//nije pun
levi_slob++;
dek[levi_slob]=broj;
cout<<"\nBroj: "<<broj<<" upisan sa leve strane.";
}
else{
cout<<"\n Greska!!! Dek je pun sa leve strane!!!";
};
};
void upisi_desno(float broj){
if(pun()!=0){
desni_slob--;
dek[desni_slob]=broj;
cout<<"\n Broj: "<<broj<<", upisan sa desne
strane.";
}
else{
cout<<"\n Greska!!! Dek je pun sa desne strane!!!";
};
};

310

float citaj_levo(){
float broj;
if(levi_slob < 0){
return FLT_MAX;
}
else{
broj = dek[levi_slob];
levi_slob--;
return broj;
};
};
float citaj_desno(){
float broj;
if(desni_slob > 9){
return FLT_MAX;
}
else{
broj = dek[desni_slob];
desni_slob++;
return broj;
};
};
void main(void){
float broj;
for(int i=1; i<=6; i++){
upisi_levo((float) i);
upisi_desno((float) i);
};

for(int j=1; j<=6; j++){


broj=citaj_levo();
if(broj==FLT_MAX)
cout<<"\n Greska!!! Citanje iz praznog deka sa leve
strane!!!";
else
cout<<"\n Uspesno citanje sa leve strane broja:
"<<broj;
broj=citaj_desno();
if(broj==FLT_MAX)
cout<<"\n Greska!!! Citanje iz praznog deka sa
desne strane!!!";
else
cout<<"\n Uspesno citanje sa desne strane broja:
"<<broj;
};

4. Projektovati algoritam za memorisanje retkih matrica u vidu rasute tablice. Za primarnu


transformaciju kljueva, koristiti funkciju i+j mod m, gde su i i j indeksi elemenata
matrice, a m veliina rasute tablice. Koliziju kljueva reiti linearnim traenjem mesta
za smetanje sinonima. Pretpostavimo da je retka matrica posednuta 20%. Sa ulaza
uitavati indekse i elemente matrice. tampati ulazne podatke i rasutu tablicu.
#include<stdio.h>
#include<iostream.h>
struct tablica{

Predrag S. Stanimirovi

};

int
int
int
int

311

Programski jezici

k1;
k2;
broj;
sinonim;

struct tablica tab[40];


void postavi(){
for(int i=0; i<40; i++){
tab[i].k1 = -1;
tab[i].k2 = -1;
tab[i].broj =0;
tab[i].sinonim = -1;
};
};
void stampaj_tablicu(){
cout<<"
i j broj";
for(int i=0; i<40; i++){
if(tab[i].k1 != -1){
cout<<"\n"<<i<<" "<<tab[i].k1<<" "<<tab[i].k2<<"
"<<tab[i].broj;
};
};
};
void upisi_u_tab(int i, int j, int broj){
int kljuc = (i + j) % 40;
if((tab[kljuc].k1 == -1) && (tab[kljuc].k2 == -1)){
// Nema nicega u datoj lokaciji
tab[kljuc].k1 = i;
tab[kljuc].k2 = j;
tab[kljuc].broj = broj;
}
else{
if(((tab[kljuc].k1 + tab[kljuc].k2) % 40) == kljuc){
// Postoji sinonim
int br = kljuc;
while(tab[br].k1 != -1){
br = (br + 1) % 40;
};
tab[br].k1 = i;
tab[br].k2 = j;
tab[br].broj = broj;
tab[br].sinonim = tab[kljuc].sinonim;
tab[kljuc].sinonim = br;
}
else{
// postoji nesto i treba ga premestiti
struct tablica pom;
pom.k1 = tab[kljuc].k1;
pom.k2 = tab[kljuc].k2;
pom.broj = tab[kljuc].broj;
pom.sinonim = tab[kljuc].sinonim;
tab[kljuc].k1 = i;
tab[kljuc].k2 = j;
tab[kljuc].broj = broj;

312
tab[kljuc].sinonim = -1;
int kljuc1 = (pom.k1 + pom.k2) % 40;
while(tab[kljuc1].sinonim != kljuc){
kljuc1 = tab[kljuc].sinonim;
};
int br1 = kljuc1;
while(tab[br1].k1 != -1){
br1 = (br1 +1) % 40;
};

};
};

tab[br1].k1 = pom.k1;
tab[br1].k2 = pom.k2;
tab[br1].broj = pom.broj;
tab[br1].sinonim = pom.sinonim;
tab[kljuc1].sinonim = br1;

};

void main(void){
postavi();
int i,n,prvi,drugi,broj;
cout<<"\n Unesite broj elemenata matrice:";
cin>>n;
for(i=0; i<n; i++){
cout<<"\n Unesite prvi indeks:";
cin>>prvi;
cout<<"\n Unesite drugi index:";
cin>>drugi;
cout<<"\n Unesite element matrice:";
cin>>broj;
upisi_u_tab(prvi,drugi,broj);
cout<<"\n\n";
};
cout<<"\n";
stampaj_tablicu();
}

5. Projektovati klasu koja realizuje polinom sa realnim koeficijentima i realnim


argumentom. U glavnom programu demonstrirati mogunosti klase.
//Modul pol_main.cpp
#include <iostream.h>
#include "pol.h"
void main () {
double a1[3]={2.1,3.7,1.12};
double a2[4]={-2.1,1.3,-1.12,1.5};
Polinom p1(a1,2),p2(a2,3);
cout<<p1;
cout<<p2;
int i=p1.getPower ();
cout<< i <<"\n";
double s=p2(3);

Predrag S. Stanimirovi

313

Programski jezici

cout <<"\nVrednost polinoma p2(3)=" <<s<<"\n";


Polinom q=p1+p2;
i=q.getPower();
cout<<q;
q=p1-p2;
cout<<q;

6. Projektovati klasu koja realizuje matricu proizvoljnih dimenzija. Dimenzije matrice se


zadaju pri njihovom nastanku, u vreme izvravanja programa, to znai da je matrica
dinamika. Smatrati da su elementi matrice celi brojevi.
// Modul matrix.h
#include <stdlib.h>
#include <iostream.h>
#ifndef _Matrix
#define _Matrix
class istream;
class ostream;
typedef int Type;
class Matrix {
public:
Matrix (int m, int n);
Matrix (const Matrix& mat);
~Matrix ();
Matrix& operator = (const Matrix&);
friend int operator == (const Matrix&, const Matrix&);
friend int operator != (const Matrix&, const Matrix&);
Type& operator () (int i, int j);
friend Matrix operator + (const Matrix&);
friend Matrix operator - (const Matrix&);
friend Matrix operator + (const Matrix&, const Matrix&);
friend Matrix operator - (const Matrix&, const Matrix&);
friend Matrix operator * (const Matrix&, const Matrix&);
friend Matrix operator * (const Matrix&, const Type&);
friend Matrix operator * (const Type&, const Matrix&);
friend
friend
friend
friend
friend
friend

Matrix trans (const Matrix&);


Matrix compl (const Matrix&, int i, int j);
Type det (const Matrix&);
Type cofact (const Matrix&, int i, int l);
Matrix adj (const Matrix&);
Matrix inv (const Matrix&);

Matrix& operator +=
Matrix& operator
Matrix& operator *=
Matrix& operator *=

(const Matrix&);
-= (const Matrix&);
(const Matrix&);
(const Type&);

friend istream& operator >> (istream&, Matrix&);


friend ostream& operator << (ostream&, const Matrix&);

314

protected:
void allocate ();
void release ();
void copy (const Matrix&);
private:
int cols, rows;
Type **mat;
};
#endif
//Modul matrix.cpp
//Definicija funkcija iz modula matrix.h
//#include "matrix.h"
//Alokacija dinamicke strukture za predstavljanje matrice
void Matrix::allocate () {
mat=new Type*[rows];
for (int i=0;i<=rows;i++) {
mat[i]=new Type[cols];
for (int j=0;j<=cols;j++) mat[i][j]=Type(0);
}
}
//Dealokacija dinamicke strukture za predstavljanje matrice
void Matrix::release () {
for (int i=0;i<=rows;i++) delete [] mat[i];
delete [] mat;
}
//Kopiranje matrice argumenata u strukturu objekta ciji je clan
void Matrix::copy (const Matrix& right) {
for (int i=0;i<=rows;i++)
for (int j=0;j<=cols;j++) this->mat[i][j]=right.mat[i][j];
}
//Konstruktor
Matrix::Matrix (int m, int n): rows(m), cols(n) {
allocate();
}
//Konstruktor kopije
Matrix::Matrix
(const
rows(right.rows),cols(right.cols) {
allocate();
copy(right);
}

Matrix&

//Destruktor
Matrix::~Matrix () {
release ();
}
Matrix& Matrix:: operator = (const Matrix& right) {
if (&right==this) return *this;

right):

Predrag S. Stanimirovi

315

Programski jezici

if (right.rows!=rows || right.cols!=cols) return *this;


release();
allocate();
copy(right);
return *this;
}
Type& Matrix::operator () (int i, int j) {
static Type error(0);
if (i<0 || i>rows || j<0 || j>cols) return error;
return mat[i-1][j-1];
}
int operator == (const Matrix& left, const Matrix& right) {
if (right.rows!=left.rows || right.cols!=left.cols) return 0;
for (int i=0;i<=left.rows;i++)
for (int j=0;j<=left.cols;j++)
if (left.mat[i][j]!=right.mat[i][j]) return 0;
return 1;
}
int operator != (const Matrix& left, const Matrix& right) {
return !(left==right);
}
Matrix operator + (const Matrix& m) {return m;}
Matrix operator - (const Matrix& m) {return -Type(1)*m;}
Matrix operator + (const Matrix& left, const Matrix& right) {
Matrix m=left;
return m+=right;
}
Matrix operator - (const Matrix& left, const Matrix& right) {
Matrix m=left;
return m-=right;
}
Matrix& Matrix :: operator += (const Matrix& right) {
if (rows!=right.rows || cols!=right.cols) return *this;
for (int i=0;i<rows;i++)
for (int j=0;j<cols;j++)
mat[i][j]+=right.mat[i][j];
return *this;
}
Matrix& Matrix :: operator -= (const Matrix& right) {
if (rows!=right.rows || cols!=right.cols) return *this;
for (int i=0;i<rows;i++)
for (int j=0;j<cols;j++)
mat[i][j]-=right.mat[i][j];
return *this;
}
Matrix operator * (const Matrix& left, const Matrix& right) {
Matrix m (left.rows, right.cols);
if (left.cols!=right.rows) return m;
for (int i=0;i<left.rows;i++)
for (int j=0;j<right.cols;j++)

316

return m;

for (int k=0;k<left.cols;k++)


m.mat[i][j]+=left.mat[i][k]*right.mat[k][j];

}
Matrix& Matrix :: operator *= (const Type& t) {
for (int i=0;i<rows;i++)
for (int j=o;j<cols;j++)
mat[i][j]*=t;
return *this;
}
Matrix operator * (const Matrix& left,const Type& t) {
Matrix m=left;
return m*=t;
}
Matrix operator * (const Type& t, const Matrix& right) {
return right*t;
}
Matrix& Matrix::operator *= (const Matrix& right) {
return *this=*this*right;
}
istream& operator >> (istream& is, Matrix& m) {
for (int i=0;i<m.rows;i++)
for (int j=0;j<m.cols;j++)
is>>m.mat[i][j];
return is;
}
ostream& operator << (ostream& os, const Matrix& m) {
os<<"{\n";
for (int i=0;i<m.rows;i++) {
os <<"{";
for (int j=0;j<m.cols;j++)
os << m.mat[i][j] << ((j<m.cols-1)?",":"}");
os << ((i<m.rows-1)?",\n":"\n}\n");
}
return os;
}
//Funkcija za transponovanje matrice
Matrix trans (const Matrix& m) {
Matrix temp(m.cols, m.rows);
for (int i=0;i<m.rows;i++)
for (int j=0;j<m.cols;j++)
temp.mat[j][i]=m.mat[i][j];
return temp;
}
//Vraca matricu sa izostavljenom odgovarajucom vrstom i kolonom
Matrix compl (const Matrix& m, int r, int c) {
Matrix temp(m.rows-1, m.cols-1);
if (m.cols<1 || m.rows<1) return temp;
for (int i=0,x=0;i<m.rows;i++) {
if (i==r-1) continue;
for (int j=0,y=0;j<m.cols;j++) {

Predrag S. Stanimirovi

317

Programski jezici

if (j==c-1) continue;
temp.mat[x][y]=m.mat[i][j];
y++;
}
x++;
}
return temp;
}
//Izracunava determinantu matrice
Type det (const Matrix& m) {
if (m.rows!=m.cols) return 0;
if (m.rows==1) return m.mat[0][0];
Type temp=Type(0);
for (int j=0,c=1;j<m.cols;j++,c*=-1)
temp+=(Type(c)*m.mat[0][j]*det(compl(m,1,j+1)));
return temp;
}
//Izracunava kofaktor
Type cofact (const Matrix& m, int r, int c) {
if (m.rows!=m.cols) return 0;
if ((r+c)%2!=0)
return (-det (compl(m,r,c)));
else
return (det (compl(m,r,c)));
}
//Vraca adjungovanu matricu
Matrix adj (const Matrix& m) {
Matrix temp(m.rows, m.cols);
if (m.rows!=m.cols) return temp;
for (int i=0;i<m.rows;i++)
for (int j=0;j<m.cols;j++)
temp.mat[i][j]=cofact(m,i+1,j+1);
return trans(temp);
}
//Vraca inverznu matricu
Matrix inv (const Matrix& m) {
Type temp=det(m);
if (temp!=0)
return (1/temp)*adj(m);
else
return Matrix(0,0);
}

10.15. Elementi objektno-orijentisanog programiranja u


MATHEMATICA
MATHEMATICA ima i neke elemente objektno-orijentisanog programiranja, jer
omoguava korisniku da definie svoje objekte. Pri definisanju osobina objekata prvo se navodi
ime objekta koje je odvojeno znacima /: od definicije osobine objekta.

318

@
D
@
D
@
D

@
@
D
D
@
D

@
@
D
D@
D
@
D
@
D
@
D

Primer. U ovom primeru su simbolu h dodeljene tri osobine:


h

h x_

+ h: y_

:= hplus x, y ;

P h x_ ,:x_ := hp x ;

f_ h x_ : := fh f, x ;

Ove osobine se mogu koristiti u programu:


h 2 +h 3
hplus 2, 3

Definicijama oblika f[args]=rhs ili f[args]:= rhs vri se vezivanje tih definicija sa objektom f.
Informacije o takvim definicijama se dobijaju posle izraza ?f. Za sve izraze kojima se dodeljuju
osobine simbolu f, a koji imaju f kao glavu koristi se naziv donje vrednosti (downvalues) za f.
MATHEMATICA takoe podrava definiciju gornjih vrednosti (upvalues), kojim se pridruuju
definicije simbolima koji se ne pojavljuju direktno kao glave u tim definicijama. Gornje
vrednosti se uvode koristei znakove ^:. Posmatrajmo na primer definiciju oblika Exp[g[x_]]:=
rhs. Ova definicija je vezana za simbol Exp, i moe se posmatrati kao donja vrednost za Exp.
Meutim, ovakav pristup nije najbolji, zbog toga to je Exp standardna funkcija, i to moe da
nepotrebno uspori izraunavanje izraza. bolje je da se izrazom oblika Exp[g[x_]]^:=rhs
definicija asocira za g, i da predstavlja gornju vrednost objekta g.
f[args] /:rhs
f[g[args],...]^:=rhs ili f[g,...]^:=rhs

definicija donje vrednosti


za f
definicija gornje vrednosti
za g

Donja vrednost za f se moe definisati na sledei nain:


f[g[x_]] := fg[x]

@
@
D
D@
D

Ova definicija se moe videti kada se trai informacija za f:


?f

Global`f
f g x_ := fg x

Gornja vrednost za objekat g se moe definisati na sledei nain:


Exp[g[x_]] ^:= expg[x]
Ova definicija je asocirana za g:

@
D
@
D@
D8
@
D

@
D

?g

Global`g
g x_ ^:= expg x

i nije asocirana za Exp:


??Exp

<

Exp z is the exponential function.


Attributes Exp = Listable, NumericFunction, Protected, ReadProtected

Definicija gornje vrednosti za g se koristi pri evaluaciji sledeeg izraza:


Exp[g[5]]
expg 5

Definicija za f[g[x]] bi trebalo da predstavlja gornju vrednost za g u sluajevima kada je


funkcija f poznatija (ee u upotrebi) u odnosu na funkciju f. Na primer, u sluaju izraza
Exp[g[x]], funkcija Exp je standardna funkcija, dok g verovatno predstavlja korisniku
funkciju.
Jo jedna gornja vrednost za g je definisan izrazom

Predrag S. Stanimirovi

319

Programski jezici

g/: g[x_] + g[y_] := gplus[x, y]

Sve definicije vezane za objekat g se prikazuju na sledei nain:

@
D
@
D@
D@
D
@
D
@
D

?g

Global`g
g x_

^:= expg x
g x_

+g

y_ ^:= gplus x, y

Definicija za zbir g-ova se koristi kad god je mogue:


g[5] + g[7]

gplus 5, 7

Kako je unutranji oblik izraza g[x_]+g[y_] jednak Plus[g[x_],g[y_]], prethodna


definicija se moe tretirati kao donja vrednost za Plus. U tom sluaju, kad god se definiu
izrazi oblika g[x_]+g[y_] kao donja vrednost za Plus, ove definicije se koriste kad god se
pojavi poziv funkcije Plus. Ovim se usporava evaluacija ovakvih izraza. Meutim, ako se
definicija za g[x_]+g[y_] posmatra kao gornja vrednost za g, tada se pokuava primena te
definicije samo kada se g pojavi unutar funkcije Plus. S obzirom da se g pojavljuje mnogo
manje u odnosu na funkciju Plus, ova definicija ima mnogo vie opravdanja.
Gornja vrednost se mogu upotrebiti za konstrukciju baze osobina partikularnog objekta.
Svaka definicija koja se uini kao gornja vrednost se moe asocirati sa objektom koji se
posmatra, radije nego sa osobinom koja se specificira.
Sledea definicija odreuje gornju vrednost za objekat square kojim se daje njegova povrina:
area[square] ^= 1

Sledei izraz dodaje definiciju za perimeter:


perimeter[square] ^= 4

Obadve definicije su sada asocirane sa objektom square:

@@
DD

?square

Global`square
area square ^= 1

perimeter square ^= 4

Izrazom oblika f[args] moe se definisati gornja vrednost za g, bilo direktno, bilo za neki
objekat sa glavom g koji se pojavljuje u args. Ne mogu se asocirati definicije vezane za neki
objekat g ako se on pojavljuje u suvie niskom nivou na levoj strani izraza koji se koristi za
takvu definiciju.
U sledeem izrazu g predstavlja glavu jednog argumenta, i sa njim se moe asocirati
definicija gornje vrednosti.
g/: h[w[x_], g[y_]] := hwg[x, y]

U izrazu koji sledi, g se pojavljuje isuvie duboko na levoj strani izraza koji se sa njim
povezuje, te definicija gornje vrednosti koja je asocirana sa g ne uspeva:

@
@
@
D
DD

g/: h[w[g[x_]], y_] := hw[x, y]

TagSetDelayed::tagpos :
Tag g in h w g x_ , y_

is too deep for an assigned rule to be found.

320

$Failed

Mogue pozicije simbola u definicijama date su u sledeoj tabeli:


f[...]:=rhs
f/: f[g[...]...][...]:=rhs
g/: f[...,g,...]:=rhs
g/: f[...,g[...],...]:=rhs

donja vrednost za f
donja vrednost za f
gornja vrednost za g koji prestavlja argument
gornja vrednost za g koji prestavlja glavu

U optem sluaju, moete poeleti da definiete klasu apstraktnih matematikih objekata sa


imenom quat. Ovi objekti se mogu predstaviti izrazom oblika quat[data], i mogu imati
posebne osobine u odnosu na aritmetike operacije (na primer sabiranje i mnoenje). Ove
osobine se mogu postaviti definicijama gornjih vrednosti za quat u odnosu na Plus i
Times.
Definicija gornje vrednosti objekta quat u odnosu na Plus:
quat[x_] + quat[y_] ^:= quat[x + y]

@D

Ova definicija se koristi u simplifikaciji sledeeg izraza:


quat[a] + quat[b] + quat[c]

quat a + b + c

Kada se definie gornja vrednost za quat u odnosu na neku operaciju, na primer Plus, u
stvari se proiruje domen operacije Plus na objekte quat. U definiciji sabiranja quat
objekata, moe se koristiti specijalna operacija sabiranja, na primer quatPlus, za koju se
definie odgovarajua donja vrednost. Ovakav pristup je pogodniji nego da se koristi standardna
operarcija sabiranja Plus, tako to se njeno standardno dejstvo predefinie za objekte tipa
quat.
Gornja vrednost u stvari predstavlja mogunost da se implementira jedan aspekt objektnoorijentisanog programiranja. Simbol slian quat predstavlja objekat odreenog tipa. Razliite
gornje vrednosti za quat specificiraju metode koje definiu kako se quat objekti ponaaju
pod odreenim operacijama

11. VIZUELNO PROGRAMIRANJE

Predrag S. Stanimirovi

321

Programski jezici

Okruenje za vizuelno programiranje omoguava da koristite mia i seriju specijalizovanih


softverskih alatki za brzo i jednostavno kreiranje aplikacija. Najvea prednost vizuelnog
programiranja je da omoguava poetnicima da ponu sa pisanjem pravih programa na samom
poetku. Takoe, ova tehnika je korisna i za iskusne programere jer im omogu}ava da
kompleksne programe napiu pomou samo nekoliko klika miem. Iskusni Windows
programeri znaju da takvi procesi kao to je manipulacija listama, klizaima ili grafikim
objektima uvek zahtevaju pisanje komplikovanih programa. Objektno-orijentisano
programiranje skrauje ovaj postupak uaurenjem (umotavanjem) nekih od ovih procesa u
relativno jednostavne omotae. Vizuelno programiranje itavu paradigmu pomera jedan korak
dalje, omoguavajui da kliknete na mia jednom ili dva puta, ime omoguujete da aplikacija
koja podrava vizuelno programiranje obavi te komplikovane radnje umesto vas.
DELPHI je projektovan tako da omogui pristup svojim objektima preko vizuelnih alatki,
kao to su komponente. Jo neki programski jezici su i pre DELPHI-a poeli da koriste
vizuelne alate, ali je DELPHI jedinstven u tome, jer omoguava da konvertujete bilo koji
objekat koji kreirate u vizuelnu alatku kojom se moe upravljati pomou mia ili tastature.
Drugim reima, postoji kompletna integracija DELPHI-jevih objekata i DELPHI-jevih
vizuelnih alatki.
Objektno-orijentisano programiranje je nova metodologija izrade velikih programskih
sistema, koje se pojavilo kada su programski sistemi toliko narasli da tehnike struktuiranog
programiranja vie nisu davale zadovoljavajue rezultate. Dok je u centru panje struktuiranog
programiranja struktura programa, u centru panje objektno-orijentisanog programiranja su
objekti. Objekti su inteligentni podaci koji mogu da se nalaze u odreenim stanjima. Ta stanja
mogu da se promene primenom odreenih metoda. Skup objekata sa istim osobinama ine jednu
klasu. Klase su analogne tipovima podataka, kao to su celi brojevi ili realni brojevi, ali mogu
da predstavljaju proizvoljno sloene apstraktne objekte. Pojavom personalnih raunara koji rade
pod operativnim sistemom WINDOWS, firma BORLAND je 1995 godine objavila svoje prvo
programsko okruenje DELPHI, za izradu aplikacija za rad pod operativim sistemom
WINDOWS.
Borland-ov paket DELPHI (verzije 1/2/3/4/5/6) predstavlja razvojni alat za kreiranje
WINDOWS aplikacija, a odnedavno i LINUX programa. DELPHI je sna`na alatka za kreiranje
programa sa grafikim interfejsom (GUI). DELPHI je prvi programski jezik koji premoava
granicu izme|u razvojnog okruenja visokih performansi i programiranja na niskom nivou
(mainski nivo). Kada kreirate programe u DELPHI-ju imate svu mo jednog istinskog
programskog jezika (objektni PASCAL), ugra|enog u jedno RAD (RAPID APPLICATION
DEVELOPMENT) okruenje. Svi uobiajeni elementi WINDOWS-a grafikog korisnikog
interfejsa kao to su forme, dugmii, dijalozi, ..., ukljueni su u DELPHI kao komponente.
DELPHI tako|e dozvoljava programerima da razviju sopstvene grafike kontrole i da ih
jednostavno implementiraju u svoje ili programe drugih programera.
Moe se rei da je DELPHI objektno orijentisana verzija PASCAL-a integrisana u vizuelno
razvojno okruenje. DELPHI-jeva verzija PASCAL-a je potpuno objektno-orijentisana kao npr.
i jezik C++, te je u nekim situacijama i bolje reenje od C-a. DELPHI kompajler pravi
aplikacije zapakovane u jedan kompaktni izvrni fajl, tako da pri distribuciji aplikacija nisu
potrebne raznorazne run-time biblioteke, DLL-ova i sl.

11.1. Uvod u Delphi

322
Ono to je vrlo vano za nekoga ko je programirao u proceduralnim jezicima kao to su
Pascal i C, i navikao je da "stvari dri pod kontrolom", to je, da mora da se miri sa injenicom
da u poetku, a vrlo esto ni kada iza sebe bude imao gomilu programa, neke mogunosti
Delphija nee razumeti do kraja, to mu ipak nee smetati da ih sa uspehom koristi. Delphi je
objektno-orijentisan jezik i vi dok gradite aplikaciju u njemu, eleli to ili ne, kreirae se objekti
pod kontrolom Delphija koji zamenjuju na stotine programskih linija koje bi morali napisati da
bi u nekom od proceduralnih jezika kreirali Windows aplikaciju. Nije neophodno da znate
principe objektno-orijentisanog programiranja da biste kreirali aplikaciju u Delphiju, jer e se
upotreba njegovih komponenti objanjavati kao da se radi o ovladavanju naina korienja
nekog tehnikog ureaja bez uputanja u detalje tehnike realizacije. Skoro da je sigurno da vas
raskone mogunosti Delphija, koje se ogledaju u injenici, da u nekoliko minuta moete
kreirati mone multimedijalne ili database aplikacije, koje su vam iz perspektive Pascal ili C
programera izgledale skoro nedostine, nee ostaviti ravnodunim. Da bi se zadovoljile narasle
ambicije ka produbljivanju znanja bilo bi poeljno da se upoznate i sa principima objektnoorijentisanog programiranja. Mnogi autori, zastupaju miljenje da je za poetak bitnije nauiti
kako kreirati aplikaciju kombinovanjem komponenti i korienjem njihovih svojstava, pa tek
nakon na desetine kreiranih aplikacija upoznati ta se deava iza "scene". Ono to je vano, za
poetak, to je da to potpunije upoznate mogunosti koje vam prua objekat, ili da znate kako
da u Help-u pronaete ono to vas u vezi objekta interesuje.

11.1.1. Prvi Delphi program


Kada se pokrene Delphi na ekranu e se pojaviti (slika 1): naslovna linija glavnog prozora,
meni glavnog prozora, trake za alate, paleta komponenti, objekt inspektor i forma koja je
generiki dobila ime Forml. Ova forma iako prazna poseduje osobine Windows programa: moe
se premetati, mogu joj se menjati dimenzije, moe se minimizirati, maksimizirati i zatvoriti.
Ima i svoju ikonicu koja se dodeljuje pri minimizaciji.

Inspektor objekata
Glavni prozor (main)

Prozor za formu
Paleta komponenti
Editor programskog koda

Predrag S. Stanimirovi

Programski jezici

323

slika1
U sistemu Delphi prozori budue aplikacije se pripremaju u vidu forme. Projektovanjem
forme postavljaju se optimalne dimenzije prozora, razmetaju upravljaki elementi i meni,
dodaju gotove slike, postavljaju zaglavlja, natpisi itd. Delphi, automatski kreira kostur aplikacije
koju reprezentuje prazna forma. Na vama je da sa nje kao platforme dalje razvijate aplikaciju
koja e odraditi sve to ste projektom zamilili. Praznoj formi se automatski dodeljuje i modul
koji dobija generiko ime Unit1 koji sadri definiciju forme u tipu TForm1. Ovaj modul se
nalazi u posebnom prozoru za editovanje, koji e se prikazati u prednjem planu izborom iz
podmenija View opcije Toggle Form/Unit, ili pritiskom na taster F12, ili klikom na ikonicu na
paleti alata, ili klikom na vidljivi deo prozora za editovanje, Modul Unit1 ima sledei izgled:
unit Unitl;
interface
uses Windows, Messages,
Forms,
Dialogs;

SysUtils,

type
TForml =class(TForm)
private
{Private declarations}
public
{Public declarations}
end;
var
Form 1: TForml;
implementation
{SR*.DFM}
end.

Classes,

Graphics,

Controls,

324
Klasa TForm1 (moe se i preimenovati) je namenjena vama, kako biste je proirivali
objektima i metodama koje e obezbediti realizaciju vaeg projekta. Vaa forma nasleuje
Delphijevu formu TForm. Ova forma se kreira i aktivira posredstvom projektnog fajla koji se
takoe automatski kreira, i koji u ovom momentu kada u projektu nismo nita samostalno
kreirali ima sledei izgled:
program Project 1;
uses
Forms,
Unitl in'Unitl.pas' |Forml};
{$R*.RES}
begin
Application.Initialize;
Application.CreateForm(TForml,Forml);
Application.Run;
end.

Ovaj fajl moete dobiti izborom iz podmenija View opcije Project Source. Programska linija:
Application. CreateForm(TForml,Forml);

kreira formu, koja se sledeom linijom:


Application.Run;

prikazuje na ekranu. Za sada nije neophodno da znate ta radi objekat Application, dovoljno je
da imate na umu da ima potrebnu "inteligenciju" da upravlja tokom programa za vreme
njegovog izvravanja.
Aplikacija iako prazna, eka na akciju od korisnika: pritisak dirke tastature ill dugmeta
mia, i ako pritisnete na dirku tastature ili dugme mia ona to detektuje. Aplikacija vas
"oslukuje", ali poto niste programirali ta treba da radi, samo vas "oslukuje" i ignorie.
Klju u razumevanju rada Delphi aplikacije lei u razumevanju: dogaaja i procedure za
obradu dogaaja kao reakcije na dogaaj. Kada se pritisne dugme mia, dirka tastature, ali i
"to-ta" nezavisno od aktivnosti korisnika - Delphi izaziva dogaaj. Ako aplikacija raspolae
procedurom za obradu izazvanog dogaaja ona e se izvriti kao reakcija na dogaaj.
Programiranje u Delphiju se uglavnom i sastoji u kreiranju koda aplikacije koji treba da reaguje
neposredno ill posredno, na dogaaje.

Pokretanje prve aplikacije


Kreiranu aplikaciju moete pokrenuti na vie naina:
- klikom na opciju Run podmenija Run;
- pritiskom na dugme - preicu Run ( strelica udesno);
- pritiskom na taster F9.
Delphi ovu aplikaciju prevodi i pokree prikazujui praznu formu. Ovu formu moete
premetati, menjati joj dimenzije, proiriti na ceo ekran, minimizirati ili zatvoriti pritiskom na
dugme Close.

Svojstva forme
Svaka Delphi aplikacija se sastoji iz bar jedne komponente tipa TForm - koja predstavlja
"glavni prozor" tradicionalnih Windows aplikacija. Komponenta forma, ali i ostale komponente,
imaju svojstva koja definiu njihov izgled. Postavljanje svojstava se moe realizovati u toku
dizajniraiija posredstvom prozora objekt inspektora (Object inspector) koji ima dve kartice:
svojstava (sa natpisom Properties) i dogaaja (sa natpisom Events). Ako sluajno ne vidite

Predrag S. Stanimirovi

325

Programski jezici

prozor objekt inspektora, iz menija View izaberite opciju Object Inspector ili pritisnite taster
F11.
Primer 1. U objekt inspektoru izaberite karticu Properties i dizajnirajte formu zadajui sledea
svojstva:
- Caption: Prvi program (unoenjem teksta Prvi program desno od naziva svojstva);
- Color: clRed (klikom na svojstvo Color pojavljuje se strelica na dole, klikom na
strelicu prikazuje se lista moguih vrednosti meu kojima treba izabrati clRed);
- Top: 200 (udaljenost forme od gornje ivice ekrana);
- Left: 250 (udaljenost od leve ivice ekrana);
- Width: 300 (irina forme);
- Height: 400 (visina forme);
- Borderlcons: [biSystemMenu]. Dvostrukim klikom na Borderlcons otvara se lista
podsvojstava, nasta ukazuje znak + pored imena Borderlcons. Klikom na podsvojstva
biMinimize, biMaximize, biHelp postaviti False, a biSystemMenu postaviti na True.
- Name: GlavnaForma (promena generikog imena Form1 na GlavnaForma).
Ako pokrenemo aplikaciju (izborom Run iz podmenija Run) videemo da ne radi nita pametno,
ali da je u naslovnoj liniji tekst: Prvi program, boja forme crvena, pozicija i dimenzije
izmenjene u odnosu na predanju formu, a od dugmia naslovne linije ostalo je samo Close.
Promene pozicije i dimenzija forme moe se realizovati korienjem mia.
Kakve su promene u modulu u kom je definisana forma videemo stavljanjem u prvi
plan prozora editora koda. To se moe postii na jedan od sledeih naina:
- iz menija View izborom opcije Toggle Form/Unit;
- klikom na dugme - preicu Toggle Form/Unit;
- klikom na F12;
- klikom na vidljivi deo editora programskog koda.
Primetiete da je samo klasa koja definie formu promenila ime sa TForm1 na
TGlavnaForma, a ime forme Form1 je zamenjeno na GlavnaForma. Ista promena se moe
uoiti i u ComboBoxu objekt inspektora neposredno ispod njegove naslovne linije.
Forma se moe prebaciti u prednji plan na isti nain na koji je to postignuto sa editorom
programskog koda.

uvanje aplikacije
Aplikaciju emo sauvati izborom opcije SaveAll iz podmenija File ili klikom na dugme
preice SaveAll. Kada u izabranom folderu (ili upravo kreiranom) treba kreirati ime fajla
modula forme (Delphi e ponuditi generiko ime Unitl) ne sme mu se dodeliti isto ime kao
formi, da ne bi dolo do kolizije imena. Preporuuje se da ako forme imenujemo sa
GlavnaForma, UlaznaForma, IzlaznaForma itd., modulu koji sadri formu dodeljujemo ime bez
rei Forma. Zato emo modulu nae forme dodeliti ime Glavna. Time e se kreirati fajl
Glavna.pas, a modulu (unit) Delphi automatski dodeljuje ime Glavna. Kada treba kreirati ime
projekta (Delphi e ponuditi generiko ime Project1), ako za ime projekta unesemo na primer
Prvi. Delphi automatski dodaje nastavak .dpr, tako da je ime projektnog fajla Prvi.dpr. Ako
pokrenemo program kreira se izvrni fajl sa imenom Prvi.exe. Pogledajmo koje je jo fajlove
Delphi kreirao u folderu gde smo sauvali projektni fajl Prvi.dpr i Glavna.pas. To su fajlovi sa
nastavkom:
- .~*, koji predstavljaju kopije fajlova i mogu se brisati, ako ne elimo da sauvamo
prethodne verzije programa;
- .dcu, koji predstavljaju prevedeni kod programskog modula, i mogu se brisati jer ih
Delphi ponovo pravi kad god se prevodi aplikacija;
- .pas, koji sadre izvorni kod programa i ne smeju se brisati;

326
- .res, koji sadre binarne resurse poput sistemske ikone programa i ostale bitmape, a
mogu se kreirati i menjati pomou Image Editora iz podmenija Tools;
- .dfm, koji sadri vrednosti koje predstavljaju svojstva forme, kao i svojstva svih
komponenti koje su postavljene na formu. Ovi fajlovi se ne smeju brisati, vani su kao i fajlovi
sa izvornim kodom.
Aplikacija koju smo kreirali sadri .dfm fajl koji moemo uitati u Delphijev editor koda
izborom opcije Open podmenija File. Fajl Prvi.dfm ima sledei izgled:
object GlavnaForma: TGlavnaForma
Left = 250
Top = 200
Width = 400
Height=300
Borderlcons = [biSystemMenu]
Caption = Prvi program'
Color=clRed
Font.Charset=ANSI_CHARSET
Font. Color=clWindowText
Font.Height=-13
Font.Name=Times New Roman'
Font.Style = [fsBold]
PixelsPerInch = 96
TextHeight=15
end

Ovaj tekstualni opis forme moe i runo da se prepravlja, mada se to radi retko. Nakon
prepravki, da bi se promene aktivirale na formi, fajl se mora sauvati.

Dodavanje komponenti formi


Delphi u glavnom prozoru sadri paletu komponenti (slika 2) koja ima vie kartica sa
oznakama: Standard, Additional, Data Access, Data Control, itd. Svaka nova verzija Delphija
donosi nove kartice, kao i izmene na nekim od postojeih. Da bi se komponenta postavila na
formu potrebno je pritisnuti jeziak eljene kartice iz palete komponenti, kliknuti na dugme
komponente koju elimo da postavimo, a zatim kliknuti na formu. Ako traena kartica palete
komponente nije vidljiva klikite na desno dugme u desnom gornjem uglu dok jeziak traene
kartice ne postane vidljiv.
Ako ne moete da se setite koje dugme odgovara komponenti koju traite, zadrite
kursor mia na dugmetu sekundu ili dve, pa e se pojaviti uto obojena priruna pomo sa
nazivom komponente.
Strelica za izbor
Panel
komponente

Label Edit

Button

ListBox

Slika 2.
Abecedni spisak komponenti iz koga se moe izabrati komponenta koja se postavlja na
formu moe se nai u opciji Component list menija View.

Predrag S. Stanimirovi

327

Programski jezici

Komponenta Label
Ova komponenta slui za prikazivanje teksta na formi koji se ne moe neposredno menjati u
toku izvravanja aplikacije korienjem tastature. Koristi se za prikazivanje informacija i
obeleavanje pojedinih komponenti aplikacije. Font i boja teksta joj se mogu menjati
dvostrukim klikom na svojstvo Font objekt inspektora. Svojstva joj se mogu menjati i u toku
izvravanja aplikacije to e se ilustrovati sledeim primerom.
Primer 2. Na formu postaviti komponentu Label sa kartice Standard. Komponenti Label
postaviti sledea svojstva:
- Caption: Delphi je izuzetan;
- Font: Times New Roman (irne fonta), Bold (stil), 28 (veliina);
- Hint: Ovo je Labela;
- ShowHint: True
Isprogramirati reagovanje na dogaaje, tako da:
- klik na komponentu Label menja boju komponente u crvenu;
- dvostruki klik na komponentu Label menja boju komponente u utu.

Slika 3.
Aplikaciju kreirajte postupajui na sledei nain:
1. Zaponite novu aplikaciju:
- izborom New Application iz menija File, ili;
- u meniju File izaberite opciju New, a zatim u dijalog prozoru koji se pojavljuje na
kartici New izaberite Application.
2. Kliknite levim dugmetom mia na element sa oznakom A (komponenta Label) kartice
Standard palete komponenti. Time je za korienje izabrana komponenta Label.
Premestite kursor mia na formu i ponovo kliknite levim dugmetom. Na formi e se
pojaviti komponenta Label.
3. Izabranoj komponenti postavite u svojstvo Caption tekst Delphi je izuzetan!.
4. Postavljanje fonta i njegovih svojstava zaponimo klikom na svojstvo Font. U koloni sa
desne strane e se pojaviti dugme sa tri take (...). Pritisak na ovo dugme prikazuje okvir
za dijalog u kome emo izabrati font: Times New Roman, stil: Bold i veliinu: 28. Ovo
se moglo realizovati i dvostrukim klikom na svojstvo Font, ime e se otvoriti lista
"podsvojstava" kojima moemo dodeliti navedene vrednosti. Dakle, moemo uoiti da
kod svojstava koja imaju znak plus (+) ispred imena dvostrukim klikom se otvara lista
"podsvojstava", a gde se nakon klika pojavi dugme sa tri take (...) drugim klikom se
otvara dijalog prozor.
5. U svojstvu Hint za Labelu upisati poruku: "Ovo je Labela".
6. Svojstvo ShowHint postaviti na True, ime se obezbeduje da kada se u toku izvravanja
aplikacije kursor mia nae iznad Labele pojavljuje se uti pravougaonik u kome se
ispisuje sadraj postavljen u svojstvu Hint.
7. Da bi isprogramirali da se klikom na komponentu Label promeni njena boja u crveno,
kliknite na jedinu vidljivu komponentu na formi (Label), a zatim u prozoru objekt
inspektora kliknite na jeziak kartice Events (dogaaji). Pojavie se lista dogaaja koji
se dele na tri glavne kategorije: dogaaje mia, dogaaje tastature i sistemske dogaaje
(sistemski za ovu komponentu nisu predvieni). Nakon dvostrukog klika na polje desno
od polja OnClick editor programskog koda izlazi u prednji plan, a u njemu kostur
procedure za obradu dogaaja OnClick:

328

procedure TForml.LabellClick(Sender:TObject);
begin
end;

Poev od pozicije kursora uneemo liniju kojom se svojstvo Color komponente Labell
postavlja
na clRed:
Label1.Color:=clRed;

Nakon ove promene svojstva primeujemo da se postavljanje svojstava komponenti


moe
realizovati i u toku izvravanja aplikacije, a ne samo u toku dizajniranja.
8. Da bi isprogramirali da se dvostrukim klikom na komponentu Label boja komponente
promeni u utu, treba u kartici Events objekt inspektora izabrati dogaaj OnDblClick i
kreirati proceduru:
procedure TForml.Label1DblClick(Sender.TObject);
begin
Label1.Color:=clYellow;
end;

9. Pokrenite aplikaciju sa F9 i obratite panju na promene koje izazivaju klik i dvostruki


klik na komponenti Label. Takoe, primetite da se nakon zadrke kursora nad
komponentom pojavljuje hint: "Ovo je labela".

Komponenta Edit
Ovo je standardna Windows kontrola za unos kraih jednolinijskih tekstova preko tastature.
Uneti tekst je sadran u svojstvu Text tipa string. Ova kontrola se koristi i za unos numerikih
podataka, tako to se string uitan u ovu kontrolu konvertuje u numerike podatke, korienjem
funkcija StrToInt i StrToFloat ime se priprema za numeriku obradu. Da bi se numeriki
podatak prikazao u Edit kontroli primenjuju se inverzne konverzije IntToStr i FIoatToStr.
Primer 3. Kreirati aplikaciju (slika 4.) koja sadri Edit kontrolu i dugme (Button), i koja:
- obezbeduje da se u toku kreiranja forme obrie sadraj Edit kontrole, a boja forme postavi
na uto;
- na DblClick na Edit kontrolu ispisuje u Edit kontroli poruku: Napravili ste DblClick!;
- ispisuje hint (poruku sa savetom) za Edit kontrolu: Klikni 2 puta (ShowHintTrue);
- zatvara formu klikom na dugme Button.

Slika 4.
1. Zaponite novu aplikaciju:
- izborom New Application iz menija File, ili;
- u meniju File izaberite opciju New, a zatim u dijalog prozoru koji se pojavljuje na
kartici New izaberite Application.
2. Kliknite levim dugmetom mia na element sa oznakom ab (komponenta Edit) kartice
Standard palete komponenti. Time je za korienje izabrana komponenta Edit.

Predrag S. Stanimirovi

329

Programski jezici

Premestite kursor mia na formu i ponovo kliknite levim dugmetom. Na formi e se


pojaviti komponenta Edit.
3. U svojstvu Hint za Edit kontrolu upisati poruku: Klikni 2 puta.
4. Svojstvo ShowHint Edit kontrole postaviti na True, ime se obezbeduje da kada se u
toku izvravanja aplikacije kursor mia nae iznad Edit kontrole pojavljuje se uti
pravougaonik u kome se ispisuje sadraj postavljen u svojstvu Hint.
5. Kliknite levim dugmetom mia na element sa oznakom OK (komponenta Button)
kartice Standard palete komponenti. Time je za korienje izabrana komponenta
Button. Premestite kursor mia na formu i ponovo kliknite levim dugmetom. Na formi
e se pojaviti komponenta Button. Njenim svojstvima Name i Caption dodelite
vrednost Kraj. Ova komponenta omoguava da se pritiskom na nju pokrene neka akcija
posredstvom procedure za obradu dogaaja.
6. Da bi isprogramirali da se u toku kreiranja forme obrise svojstvo Text komponente Edit,
a boja forme postavi na utu: treba selektovati formu (klikom na formu ili izborom u
ComboBoxu objekt inspektora), a zatim na kartici Events (dogaaji) objekt inspektora,
dvostrukim klikom na polje desno od polja OnCreate postaviti editor programskog koda
u prvi plan. U njemu se pojavljuje kostur procedure za obradu dogaaja OnCreate, koju
ete isprogramirati na sledei nain:
procedure TForm1.FormCreate(Sender:TObject);
begin
Edit1.Text:=";
Form1.Color:=clYellow;
end;

7. Da bi isprogramirali da se dvostrukim klikom na komponentu Edit ispie: Napravili ste


DblClick!, treba selektovati komponentu Edit, a zatim u kartici Events objekt inspektora
izabrati dogaaj OnDblClick i kreirati proceduru
procedure TForm1.Edit1DblClick(Sender:TObject);
begin
Edit1.Text:='Napravili ste DblClick!';
end;

8. Da bi isprogramirali da se dvostrukim klikom na komponentu Button prekine


izvravanje programa, selektovati komponentu Button, a zatim u kartici Events objekt
inspektora izabrati dogaaj OnClick i kreirati proceduru
procedure TForm1.KrajClick(Sender:TObject);
begin
Close;
end;

Procedura forme Close zatvara formu, a ovde i prekida izvravanje aplikacije, jer je
forma - glavna forma aplikacije.
Napomena. Ako se desi da elite da uklonite neku proceduru, koju ste grekom
postavili, najjednostavnije je da obriete telo procedure i aktivirate opciju Compile iz
podmenija Project. Time e se obrisati ne samo procedura, ve i njena najava u interfejs sekciji.
Uopte kompilacijom se sve procedure koje sadre samo kostur bez tela automatski briu.
Primer 4. Napisati aplikaciju koja obezbeuje osnovne funkcije kalkulatora. Aplikacija treba da
sadri: dve Edit kontrole za unos dva podataka (operanda), Edit kontrolu za rezultat, etiri
dugmeta tipa Button za operacije (+,-,*/) i dugme tipa Button za kraj. Kontrolisati korektnost

330
podataka pri naputanju Edit kontrola i ako je podatak nekorektan vratiti fokus na kontrolu sa
nekorektnim podatkom (slika 5).

Slika 5.
1. Zaponite novu aplikaciju.
2. Na formu postavite tri Edit kontrole. Dodelite im imena tako, da imenu koje ukazuje
na funkciju kontrole prethodi prefiks ed koji oznaava da je tip komponente Edit.
Prema tome u svojstvo Name komponenti postavite redom: edPrvi, edDrugi,
edRezultat. Ako ove komponente nisu istih dimenzija selektujte ih dok je pritisnut
taster Shift, a zatim iz podmenija Edit izaberite opciju Size. U radio-grupama Width
i Height dijaloga Size izaberite Shrink to smallist.
Ako komponente nisu verikalno poravnate prvo selektujte onu po kojoj elite da vrite
poravnanje, pa selektujte ostale, a zatim u podmeniju Edit izaberite Align i u radiogrupi Horizontal dijaloga Align kliknite na Left Sides.
3. Dok drite Shift kliknite levim dugmetom mia na element sa oznakom OK
(komponenta Button) kartice Standard palete komponenti. Time je izabrana
komponenta Button za korienje. Sada moete, zbog selekcije sa Shift, da
postavljate komponente tipa Button na formu, a da ne morate svaki put prethodno da
oznaavate dugme Button na paleti. Premestite kursor mia na formu i kliknite pet
puta na pozicijama prema slici koristei levo dugme. Na formi e se pojaviti pet
komponenti Button. Postavljanje ovih komponenti prekinite klikom na strelicu
izbora (oznaka sa leve strane) kartice Standard. Primetiete da Delphi
komponentama automatski dodeljuje imena KomponentaX - gde je Komponenta tip
oznaene komponente u ovom sluaju Button, a X redni broj postavljanja. U ovom
primeru komponente dobijaju imena Buttonl, Button2, ... , Button5. Meutim, poto
imena Button1,... , Button5 ne ukazuju na funkcije ovih komponenti u aplikaciji, to je
poeljno da im se promeni svojstvo Name u neto izraajnije. Dodelite im redom imena
btSaberi, btOduzmi, btMnozi, btDeli i btKraj, a svojstvu Caption redom: Saberi, Oduzmi,
Mnozi, Deli i Kraj.
4. Da bi isprogramirali da se klikom na dugme btSaberi sabere sadraj Edit komponenti
edPrvi i edDrugi i rezultat dodeli komponenti edRezultat treba selektovati dugme
btSaberi (klikom na dugme ili iz ComboBoxa objekt inspektora), a zatim na kartici
Events (dogaaji) objekt inspektora, dvostrukim klikom na polje desno od polja OnClick
postaviti editor programskog koda u prvi plan. U njemu se pojavljuje kostur procedure
za obradu dogaaja OnClick, koju isprogramiramo na sledei nain:
procedure TForml.btSaberiClick(Sender:TObject);
begin
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)+
StrToFloat(edDrugi.Text));
end;

Predrag S. Stanimirovi

331

Programski jezici

U proceduri se sadraji svojstva Text (tipa string) obe Edit komponente funkcijom
StrToFloat prevode u numerike vrednosti, sabiraju i dobijeni rezultat funkcijom
FloatToStr konvertuje u string da bi se dodelio svojstvu Text komponente edRezultat.
5. Postupkom kao u 4. samo nad dugmetom btOduzmi isprogramirajte:
procedure TForml.btOduzmiClick(Sender:TObject);
begin
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)StrToFloat(edDrugi.Text));
end;

6. Postupkom kao u 4. i 5. nad dugmadima btMnozi i btDeli isprogramirajte:


procedure TForml.btMnoziClick(SendenTObject);
begin
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)*
StrToFloat(edDrugi.Text));
end;
procedure TForml.btDeliClick(Scnder: TObject);
begin
if (StrToFloat(edDrugi.Text)=0) then
begin
ShowMessage('Deljenje nulom');
edDrugi.SetFocus;
edDrugi.SelectAll
end
else
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)/
StrToFloat(edDrugi.Text));
end;

U proceduri TForm1.btDeliClick ako je podatak kojim se deli jednak 0 procedurom


ShowMessage se ispisuje poruka: Deljenje nulom, i kontrola vraa komponenti
edDrugi korienjem metode SetFocus. Nakon toga sadraj Edit kontrole se
selektuje metodom Select All.
7. Kontrolu korektnosti podataka realizujete tako to kreirate proceduru kao reakciju na
dogaaj koji je nastao naputanjem Edit kontrole u kojoj je postavljen podatak koji
predstavlja operand. Da bi kontrolisali da li je podatak u Edit polju edPrvi korektno
unet, selektujte edPrvi, a na kartici Events napravite dvostruki klik na dogaaj
OnExit. U prvi plan se postavlja editor koda i u njemu kostur procedure koju
moete programirati na sledei nain:
procedure TForml.edPrviExit(Sender:TObject);
var s:string;
n:real;
er:integer;
begin
s:=edPrvi.Text;{*u string kopira sadrzaj Edit komponente*}
val(s,n,er);
{*konverzija stringa u numericki
podatak*}
if er<>0 then //ako konverzija nije uspesna,
begin
//kontrola se vraca Edit komponenti edPrvi
ShowMessage('Nekorektan podatak');
edPrvi.SetFocus;
edPrvi.SelectAll;
end

332
end;

8. Kontrolu korektnosti podatka u Edit polju edDrugi realizujte, kao u taki 7. uz


promenu imena kontrole sa edPrvi na edDrugi:
procedure TForm1.edDrugiExit(Sender:TObject);
var s:string;
n:real;
er:integer;
begin
s:=edDrugi.Text;
val(s,n,er);
if er<>O then
begin
ShowMessage('Nekorektan podatak');
edDrugi.SetFocus;
edDrugi.SelectAll;
end
end;

9. Na formu postavite komponentu Button i u njeno svojstvo Name unesite btKraj, a u


svojstvo Caption unesite Kraj. Dugme btKraj programirajte tako da zatvara formu i
aplikaciju:
procedure TForm1.btKrajClick(Sender:TObject);
begin
Close;
end;

Parametar Sender
Primetili ste da se u svim procedurama za obradu dogaaja pojavljuje parametar
Sender. Kad god se izazove dogaaj povezan sa nekom procedurom za obradu dogaaja, ta
procedura dobija informaciju koja potie od objekta koji je izazvao dogaaj. Ova informacija se
predaje posredstvom parametra Sender. U sutini, kada je procedura za obradu dogaaja
pozvana, parametar Sender "delegira" objekt koji je izazvao dogaaj. To je zbog toga to je
Sender tipa TObject, a to je predak za sve klase. Prema tome, objektu tipa TObject moe se
dodeliti bilo koji objekt.
U izvesnom smislu, Sender je kao "maska", pod kojom komponenta koja je izazvala
dogaaj ulazi u proceduru za obradu dogaaja. Proveru da li je objekat koji je izazvao dogaaj
specificiranog tipa realizuje operator is, tako to rezultat provere: Sender is TButton daje True
ako je operand sa leve strane is objekat tipa koji je oznaen desnim operandom, u protivnom je
False.
Meutim, ne smemo pisati:
Sender.Text:='Ovo je nedozvoljeno';

ak i kada je izaziva dogaaja komponenta tipa TEdit koja ima svojstvo Text. To je zato to je
Sender tipa TObject, a klasa TObject nema svojstvo Text. Ali, moe se korienjem operatora
as napisati
(Sender as TEdit).Text:='Ovo je dozvoljeno'

gde se kompajleru saopstava da operand levo od operatora as tretira kao da ima tip oznaen
drugim operandom.
Ako treba pristupiti svojstvu Hint, a dogaaj je izazvan od komponenti TEdit,
TButton, TLabel ili TPanel moe se napisati

Predrag S. Stanimirovi

333

Programski jezici

(Sender as TControl).Hint:='Ovo je dozvoljeno';

jer je svojstvo Hint obrazovano u klasi TControl odakle ga nasleuju TEdit, TButton, TLabel
i TPanel.
Primer 5. Napisati aplikaciju koja radi isto to i aplikacija iz primera 4., ali u kojoj se
korienjem parametra Sender etiri procedure u kojima se realizuje raunanje zamenjuju
jednom procedurom, i dve za kontrolu podataka takoe jednom.
1. Ponoviti korake iz prethodnog primera od 1. do 4.
2. Izaberite dugme btSaberi i napravite dvostruki klik na dogaaju OnClick kartice
Events. Otvorie se kostur procedure:
procedure TForml.btSaberiClick(Sender: TObject);
begin
end;
Poto elimo da kreiramo jednu proceduru za obradu sva etiri dogaaja: sabiranja,
oduzimanja, mnozenja i deljenja vratite se na karticu Events objekt inspektora i modifikujte
naziv btSaberiCIick uz dogaaj OnClick u naziv btRaunajClick i pritisnite Enter.
Isprogramirajte proceduru na sledei nain:
procedure TForml.btRaunajClick (Sender: TObject);
begin
if Sender=btSaberi {*ako je dogadjaj izazvan pritiskom na
dugme btSaberi *}
then edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)
+StrToFloat(edDrugi.Text))
else
if Sender=btOduzmi
{* akoje dogadjaj izazvan
pritiskom na dugme btOduzmi *}
then
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)StrToFloat(edDrugi.Text))
else
if Sender=btMnozi
{* ako je dogadjaj izazvan
pritiskom na dugme btMnozi * }
then
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)*
StrToFloat(edDrugi.Text))
else
if(StrToFloat(edDrugi.Text)=0) then
begin
ShowMessage('Deljenje nulom');
edDrugi.SetFocus;
edDrugi.SelectAll
end
else
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)/StrToFloat
(edDrugi.Text));
end;

Izaberite preostala dugmad btOduzmi, btMnozi i btDeli i za svako nakon klika na


dogaaj OnClick i klika na stelicu izaberimo btRaunajClick. Time se obezbeduje da
procedura btRaunaj Click obraduje sva etiri dogaaja. Ovde nema potrebe da se operatorom
is proverava tip koga reprezentuje Sender jer je samo dugmadima btSaberi, btOduzmi,
btMnozi i btDeli pridruena procedura btRaunajClick.

334
3. Kontrolu korektnosti podataka realizujete tako to za komponentu edPrvi posredstvom
dogaaja OnClick na kartici Events postavite kostur procedure koji povratkom na polje
OnExit preimenujete na edEditExit i nakon pritiska na Enter unesete sledei kod:
procedure TForm1.edEditExit(Sender:TObject);
var s:string;
n:real;
er:integer;
begin
s:=(Sender as TEdit).Text;
val(s,n,er);
if er<>0 then
begin
ShowMessage('Nekorektan podatak!');
(Sender as TEdit).SetFocus;
(Sender as TEdit).SelectAll;
end
end;

Za kontrolu edDrugi tipa TEdit u kartici Events dogaaju OnExit pridruite nakon
klika na strelicu proceduru: edEditExit.
4. Kliknite na dugme Run da biste preveli i pokrenuli program. Unesite vrednosti operanda,
kliknite na dugme operacije koju biste eleli da realizujete, i rezultat e se pojaviti u
Edit kontroli za rezultat.

Komponenta RadioGroup
Komponenta RadioGroup sadri vie radio-dugmadi koja predstavljaju grupu opcija od
kojih samo jedna moe biti odabrana. Obino se koristi kada treba kreirati vie nezavisnih grupa
radio-dugmadi, tako da se svakoj grupi dodeljuje posebna komponenta RadioGroup. Ova
komponenta omoguava brzo postavljanje grupe radio-dugmadi. Svojstvom Caption postavlja
se naslov grupe, a nazivi opcija se postavljaju tako to se nakon dvostrukog klika na kolonu
vrednosti svojstva Items otvori editor liste stringova u koji unosimo nazive opcija. Kada
zatvorimo ovaj editor, okvir grupe bie popunjen radio-dugmadima ije smo nazive kucali. Koje
je dugme pritisnuto (izabrano) izraava sadraj svojstva Itemlndex. Prvo dugme u grupi ima
indeks 0, drugo 1, ltd. Ako je svojstvo postavljeno na -1 nijedno dugme nije u odabranom
stanju. Svojstvo Itemlndex se moe menjati i u toku izvravanja programa.
Primer 6. Napisati aplikaciju koja obezbeuje osnovne funkcije kalkulatora. Aplikacija treba da
sadri: Edit kontrole za dva operanda, Edit kontrolu za rezultat, dugme (Button) kojim se
zadaje izraunavanje po zadatoj operaciji, Radio grupu ijim se dugmiima definiu operacije
(+,-,*,/) i dugme tipa TButton za kraj izvravanja aplikacije. Kontrolisati korektnost podataka
pri naputanju Edit kontrola i ako je podatak nekorektan vratiti fokus na kontrolu sa
nekorektnim podatkom (slika 6).

Slika 6.
1. Ponoviti korake 1. i 2. iz primera 4.

Predrag S. Stanimirovi

335

Programski jezici

2. Postavite dva dugmeta tipa TButton. Dodelite im redom svojstvu Name vrednosti:
btRaunaj i btKraj, a svojstvu Caption: Raunaj i Kraj.
3. Postavite komponentu RadioGroup sa kartice Standard palete komponenti. U
svojstvu Name unesite ime: rgOperacija, a u svojstvu Caption unesite: Izaberi
operaciju. Pronaite svojstvo Items i napravite dvostruki klik na polje vrednosti.
Prikazae se editor liste stringova. Unesite sledee vrednosti:
Saberi
Oduzmi
Mnozi
Deli
Klikom na dugme OK zatvorite editor string liste. Okvir grupe dugmadi je popunjen
dugmadima sa nazivima koje ste kucali.
4. Izaberite dugme btRaunaj i napravite dvostruki klik na dogaaju OnClick kartice
Events. Proceduru isprogramirajte na sledei nain:
procedure TForm1.btRaunajClick(Sender:TObject);
begin
case rgOperacija.Itemlndex of
0:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)+
StrToFloat(edDrugi.Text));
l:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)StrToFloat(edDrugi.Text));
2:edRezuItat.Text:=FloatToStr(StrToFloat(edPrvi.Text)*
StrToFloat(edDrugi.Text));
3:if (StrToFloat(edDrugi.Text)=0) then
begin
ShowMessage('Deljenje nulom');
edDrugi.SetFocus;
edDrugi.SelectAll;
end
else
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)/
StrToFloat(edDrugi.Text));
end
end;

Ovde se koristi vrednost svojstva Itemlndex (0 - saberi, 1 - oduzmi, 2 -mnozi, 3 deli) komponente RadioGroup da bi se odredilo koje je dugme oznaeno i na
osnovu toga izvrila odgovarajua naredba.
5. Kontrolu korektnosti podataka realizujete kao u taki 3. prethodnog primera.
6. Isprogramirajte kraj programa korienjem dugmeta btKraj kao u prethodnom
primeru.
7. Kliknite na dugme Run da biste preveli i pokrenuli program. Unesite vrednosti
operanda, kliknite na radio-dugme operacije koju biste eleli da realizujete, a zatim
zadajte izraunavanje klikom na dugme Raunaj.

Komponenta RadioButton
U prethodnom primeru smo videli kako se radio-dugmad koriste u grupi. Meutim,
radio-dugmad se mogu postavljati na formu i pojedinano korienjem komponente
RadioButton sa palete komponenti. Sva dugmad forme se tretiraju kao posebna grupa, to znai
da samo jedno dugme moe biti u stanju izabrano. Da li je konkretno dugme izabrano proverava

336
se korienjem svojstva Checked koje moe imati vrednost True (izabrano) i False (nije
izabrano).
Primer 7. Napisati aplikaciju koja obezbeuje osnovne funkcije kalkulatora. Aplikacija treba da
sadri: Edit kontrole za dva operanda, Edit kontrolu za rezultat, dugme (Button) kojim se
zadaje izraunavanje po zadatoj operaciji, etiri radio-dugmeta kojim se definiu operacije i
dugme tipa TButton za kraj izvravanja aplikacije (slika 7.). Kontrolisati korektnost podataka
pri naputanju Edit kontrola i ako je podatak nekorektan vratiti fokus na kontrolu sa
nekorektnim podatkom .

Slika 7.
1. Ponoviti korake 1. i 2. iz primera 4.
2. Postavite dva dugmeta tipa TButton. Dodelite im redom - svojstvu Name:
btRaunaj i btKraj, a svojstvu Caption: Raunaj i Kraj.
3. Postavite etiri komponente RadioButton i redom im dodelite imena (svojstvo
Name) i nazive (svojstvo Caption): (rbSaberi, Saberi), (rbOduzmi, Oduzmi),
(rbMnozi, Mnozi), (rbDeli, Deli). Postavite da podrazu-mevajua operacija bude
sabiranje tako to ete dugmetu rbSaberi u svojstvu Checked postaviti True.
4. Izaberite dugme btRaunaj i napravite dvostruki klik na dogaaj OnCIick kartice
Events. Proceduru isprogramirajte na sledei nain:
procedure TForml.btRacunajClick(Sender:TObject);
begin
if rbSaberi.Checked then
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)
+
StrToFloat(edDrugi.Text));
if rbOduzmi.Checked then
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)StrToFloat(edDrugi.Text));
if rbMnozi.Checked then
edRezultat.Text:=FIoatToStr(StrToFloat(edPrvi.Text)*
StrToFloat(edDrugi.Text));
if rbDeli.Checked then
if (StrToFloat(edDrugi.Text)=0) then
begin
ShowMessage('Deljenje nulom');
edDrugi.SetFocus;
edDrugi.SelectAll;
end
else
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)/
StrToFloat(edDrugi.Text));
end;

Predrag S. Stanimirovi

337

Programski jezici

Komponenta ListBox
Komponenta okvir sa listom sadri niz stavki i omoguava da izaberemo jednu ill vie
stavki. Stavke postavljamo posredstvom svojstva Items u toku projektovanja ili izvravanja. Da
bi u toku projektovanja postavili njegove vrednosti potrebno je da na njemu napravite dvostruki
klik ime se otvara editor stringova u kome unosite stavke. U toku izvravanja je mogue u
svojstvo Items uitati listu stavki iz tekstualnog fajla metodom LoadFromFile, na primer:
ListBoxl.Items.LoadFromFile('c:\data\stavke.txt');

Sadraj svojstva Items se moe kopirati u fajl metodom SaveToFile.


Ako je svojstvo MultiSelect postavljeno na False, to je podrazumevana vrednost,
mogue je odabrati samo jednu stavku. Redni broj odabrane stavke sadran je u svojstvu
Itemlndex tipa Integer (indeksiranje je poev od 0). Ako bi u proceduri dogaaja OnCIick za
ListBox uneli liniju koda:
Editl.Text:=ListBoxl.Items[ListBoxl.Itemlndex];

obezbedili bi da se izabrana stavka prikae u Edit kontroli. Stavke su indeksirane u granicama


od 0 do Items.Count-1. Ako treba da pristupimo stavkama, to se moe realizovati ciklusom
for:
for i:=0 to ListBox1.Items.Count-1 do
begin
s:=ListBox1.Items[i]; {* obrada stringa s *}
end;

Ako je svojstvo MultiSelect postavljeno na True mogu je odabir vie stavki. Nain
izbora zavisi od svojstva ExtendedSelect. Ako ovo svojstvo ima vrednost True, dovoljno je da
kliknete na jednu stavku, pritisnete Shift i kliknete na drugu stavku pa da budu selektovane te
dve stavke i sve izmeu njih. Ako dok drite taster Ctrl pritisnete neku stavku izabraete je, ili
ponistiti njen izbor, ne utiui na druge stavke. Ako svojstvo ExtendedSelect ima vrednost
False, svaki pritisak na neku stavku znai izbor ili ponitavanje izbora te stavke. Komponenta
ListBox u toku izvravanja raspolae svojstvom Selected tipa boolean, koja informie koje
stavke su izabrane iz okvira sa listom kod koga je MultiSelect postavljen na True. Na primer,
da bi proverili da li je izabrana stavka broj 5 moemo uneti sledecu liniju:
if ListBox1.Selected[5] then ...

Ako svojstvo Sorted ima vrednost True tada e stavke liste u svakom trenutku biti
abecedno sortirane. Podrazumevana vrednost False ukazuje da stavke nisu sortirane i da su u
poretku u kom su dodate listi.
Primer 8. Napisati aplikaciju (slika 8) koja obezbeuje osnovne funkcije kalkulatora. Aplikacija
treba da sadri: Edit kontrole za dva operanda, Edit kontrolu za rezultat i komponentu ListBox
za definisanje operacije (saberi, oduzmi, pomnozi, podeli). Predvideti da se klikom na stavku u
ListBoxu izvri odgovarajuca operacija (slika 8.). Kontrolisati korektnost podataka pri
naputanju Edit kontrola i ako je podatak nekorektan vratiti fokus na kontrolu sa nekorektnim
podatkom.

Slika 8.

338

1. Ponoviti korake 1. i 2. iz primera 4.


2. Postavite dugme tipa TButton. Svojstvu Name dodelite vrednost btKraj, a svojstvu
Caption: Kraj.
3. Postavite komponentu ListBox i dvostrukim klikom na svojstvo Items otvorite
editor liste stringova. Unesite stringove: 'Saberi', 'Oduzmi', 'Mnozi', 'Deli'. Klikom
na dugme OK zatvorite editor liste stringova. ListBox je popunjen nazivima koje ste
kucali.
4. Izaberite komponentu ListBox1 i napravite dvostruki klik na dogaaj OnClick
kartce Events. Proceduru koja se pojavljuje isprogramirajte na sledei nain:
procedure TForm1.ListBox1Click(Sender:TObject);
begin
case ListBox1.Itemlndex of
0:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)+
StrToFloat(edDrugi.Text));
l:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)StrToFloat(edDrugi.Text));
2:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)*
StrToFloat(edDrugi.Text));
3:if(StrToFloat(edDrugi.Text)=0) then
begin
ShowMessage('Deljenje nulom');
edDrugi.SetFocus;
edDrugi.SelectAll;
end
else
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)/
StrToFloat(edDrugi.Text));
end
end;

5. Kliknite na dugme Run da biste preveli i pokrenuli program. Unesite vrednosti


operanda i kliknite na stavku sa imenom operacije koju biste eleli da realizujete.
Nakon klika rezultat se pojavljuje u Edit kontroli edRezultat.
Primer 9. Kreirati aplikaciju kojom se u toku izvravanja formiraju stavke komponente
ListBox koje su kvadratni koreni brojeva od 1 do 100 (slika 9).

Slika 9.

Predrag S. Stanimirovi

339

Programski jezici

1. Postavite na formu komponente tipa ListBox i Button.


2. Komponenta ListBox ne dobija stavke u toku izrade aplikacije ve u toku
izvravanja. Za formu izradite proceduru kao reakciju na dogaaj OnCreate koja
popunjava svojstvo Items komponente ListBox:
procedure TForml.FormCreate(Sender:TObject);
var i:integer;
r:real;
RealStr,IntStr:string;
begin
for i:=l to 100 do
begin
r:=sqrt(i);
str(r:14:9,RealStr);
str(i:5,IntStr);
ListBoxl.Items.Add(IntStr+':'+RealStr);
end;
end;

3. Programirajte zatvaranje forme i prekid izvravanja klikom na dugme Buttonl, kome


je u svojstvu Caption uneta vrednost: Kraj.
procedure TForm1.Button1Click(Sender: TObject);
begin
Close
end;

Komponenta ComboBox
Komponenta ComboBox kombinuje Edit kontrolu sa komponentom ListBox. Ova
komponenta omoguava izbor jedne od stavki sa liste, ili unoenje linije teksta preko tastature
kao kod Edit kontrola. Izabrana stavka iz liste se postavlja u Edit kontrolu. Postoje tri vrste
komponenti tipa ComboBox koje se definiu svojstvom Style:
- Simple (StyIe=csSimple). Simple ComboBox izgleda kao lista sa Edit kontrolom u
zaglavlju. Korisnik moe da odabere element sa liste (koji e se prikazati u zaglavlju) ili da
unese novi tekst u polje za tekst (Edit kontrolu). Ovaj tip nije est poto on ne daje osnovnu
prednost komponente ComboBox - manji prostor koji zauzima na formi.
- Drop-Down (Style=csDropDown). Ova vrsta ComboBoxa dri listu "urolanu" i
skrivenu od pogleda, sve dok se ne klikne na dugme sa strelicom nadole koje se nalazi sa desne
strane Edit kontrole. Tada lista pada i korisnik moe da izabere stavku sa liste koja e se
prikazati u polju za tekst (Edit kontroli).
- Drop-Down-List (Style=csDropDownList). I ovaj tip ComboBox-a dri listu
"urolanu", koja se otvara na klik na strelicu nadole. Klikom na neku od stavki, ona se prikazuje
u polju za tekst. Ali, ovaj stil ne dozvoljava da se bilo ta unese u polje za tekst, ono je
predvieno "samo za itanje".
Poto je ComboBox kombinacija Edit kontrole i komponente ListBox, to on sadri
mnoga njihova zajednika svojstva i dogaaje. Njegovo svojstvo Text se koristi kao istoimeno
svojstvo Edit kontrole. Svojstva Items i Sorted imaju iste osobine kao odgovarajua svojstva
komponente ListBox.
Primer 10. Kreirati aplikaciju koja sadri ComboBox tipa Simple ili DropDown kome e se u
toku projektovanja u svojstvo Items postaviti lista od nekoliko naziva programskih jezika (npr.
ALGOL, FORTRAN, COBOL, ...). Obezbediti da se uneti tekst u polje za tekst ComboBoxa
nakon pritiska na Enter (iji je kod 13) doda listi. Lista treba da bude u svakom trenutku
sortirana (slika 10.).

340

Slika 10.

1. Postavite na formu komponentu ComboBox i svojstvo Style na Simple ili


DropDown, a svojstvo Sorted na True. Ako izaberete Simple razvuite
komponentu po vertikali.
2. Aktivirajte svojstvo Items komponente ComboBox i u njen editor stringova unesite
nekoliko naziva programskih jezika.
3. Preite na karticu Events i napravite dvostruki klik na OnKeyPress, i unesite sledei
programski kod:
procedure TForm1.ComboBox1KeyPress(Sender:TObject; var Key:
Char);
begin
if Key=#13 then //ako je pritisnuto Enter
begin
ComboBoxl.Items.Add(ComboBoxl.Text); // dodaje sadrzaj
polja za
// tekst kao stavku
ComboBoxu
ComboBoxl.Text:="; //brise polje za tekst
Key:=#0
end;
end;

Dogaaj OnKeyPress alje proceduri pritisnuti znak posredstvom parametra Key tipa
Char. Procedura prima svaki uneti znak u polju za tekst komponente ComboBox i kada se
pritisne Enter sadraj polja za unos dodaje kao stavku liste. Procedura brie sadraj polja za
unos i dodelom Key:=#0 onesposobljava bilo kakvu akciju poto znak #0 nema nikakvo
znaenje.
Primer 11. Napisati aplikaciju koja obezbeuje osnovne funkcije kalkulatora. Aplikacija treba
da sadri: Edit kontrole za dva operanda, Edit kontrolu za rezultat i komponentu ComboBox za
definisanje operacije (saberi, oduzmi, mnozi, podeli). Predvideti da se klikom na stavku u
ComboBox-u izvri odgovarajua operacija (slika 11.). Kontrolisati korektnost podataka pri
naputanju Edit kontrola i ako je podatak nekorektan vratiti fokus na kontrolu sa nekorektnim
podatkom .

Slika 11.
Postupak kreiranja aplikacije je kao kod komponente ListBox.

Predrag S. Stanimirovi

341

Programski jezici

1. Ponoviti korake 1. i 2. iz primera 4.


2. Postavite dugme tipa TButton. Svojstvu Name dodelite vrednost btKraj, a svojstvu
Caption: Kraj.
3. Postavite komponentu ComboBox i dvostrukim klikom na svojstvo Items otvorite
editor liste stringova. Unesite stringove: 'Saberi', 'Oduzmi', 'Mnozi', 'Deli'. Klikom
na dugme OK zatvorite editor liste stringova. ComboBox je popunjen nazivima koje
ste kucali.
4. Komponenti ComboBox za svojstvo Style izaberite csDropDown. a u svojstvo Text
upiite: Biraj operaciju.
5. Izaberite komponentu ComboBox1 i napravite dvostruki klik na dogaaj , OnClick
kartce Events. Proceduru koja se pojavljuje isprogramirajte na sledei nain:
procedure TForm1.ComboBox1Click(Sender:TObject);
begin
case ComboBox1.Itemlndex of
0:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)+
StrToFloat(edDrugi.Text));
l:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)StrToFloat(edDrugi.Text));
2:edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)*
StrToFloat(edDrugi.Text));
3:if(StrToFloat(edDrugi.Text)=0) then
begin
ShowMessage('Deljenje nulom');
edDrugi.SetFocus;
edDrugi.SelectAll;
end
else
edRezultat.Text:=FloatToStr(StrToFloat(edPrvi.Text)/
StrToFloat(edDrugi.Text));
end
end;

Isti efekat bi se postigao da se umesto dogaaja OnClick za izbor operacije koristio


dogaaj OnChange, uz isti programski kod u proceduri.
6. Kliknite na dugme Run da biste preveli i pokrenuli program. Unesite vrednosti
operanda, kliknite na strelicu ComboBox-a, a zatim izaberite stavku sa imenom
operacije koju biste eleli da realizujete. Nakon klika rezultat se pojavljuje u Edit
kontroli edRezultat.

Komponenta PopupMenu
Komponenta PopupMenu omoguava kreiranje iskaueg menija koji se pojavljuje
kada se klikne desnim dugmetom mia iznad vizuelne komponente kojoj je pridruena. Uslov
je, da je svojstvu komponente PopupMenu prethodno pridruen konkretan iskaui meni koji
je prethodno kreiran.
Kada se na formu postavi komponenta iskaueg menija sa imenom na primer
PopupMenu1, i u objekt inspektoru za formu postavi svojstvo PopupMenu na PopupMenu1,
time se definie da se klikom na formu aktivira iskaui meni. To znai da se aktivira klikom
bilo gde na formi, pa i na njenim komponentama. Ali ako ovo svojstvo aktiviranja iskaueg
menija ukinemo za formu, a dodelimo za neku komponentu, npr. Edit kontrolu tada se ovaj
meni aktivira samo klikom na tu Edit kontrolu.

342
Pozicija pojavljivanja menija zavisi od vrednosti svojstva Alignment. Gornja ivica
menija e biti na visini kursora, a u zavisnost od toga da li je vrednost za Alignment paLeft,
paCenter ili paRight na poziciji kursora e mu biti leva ivica, centar gornje ivice ili desna ivica.
Ako svojstvo AutoPopup iskaueg menija ima podrazumevajuu vrednost True, to
obezbeuje da se meni automatski prikazuje kada se klikne desnim dugmetom mia na
komponentu koja je vezana za taj meni. Ako svojstvo AutoPopup ima vrednost False, iskaui
meni se nee prikazivati klikom na desno dugme mia, ali se moe programirati korienjem
metode Popup (to se retko koristi u praksi).
Stavke menija se postavljaju dvostrukim klikom na svojstvo Items komponente
PopupMenu ili na samu komponentu, ime se otvara dijalog dizajnera menija. Stavke menija
su tipa TMenuItem. U dijalogu dizajnera menija se u svojstvu Caption unose nazivi stavki.
Nakon pritiska Enter posle unosa naziva stavke svojstvo Name dobija generiko ime koje se
moe promeniti.
Stavke menija imaju svojstvo Enabled kojim se definie da li e stavka biti omoguena
(True) ili onemoguena (False) i svojstvo Visible koje definie da li e stavka biti vidljiva
(True) ili nevidljiva (False).
Primer 12a. Napisati aplikaciju koja obezbeuje osnovne funkcije kalkulatora. Aplikacija treba
da sadri: Edit kontrole za dva operanda. Edit kontrolu za rezultat i komponentu PopupMenu
(iskaui meni) za definisanje operacije (saberi, oduzmi, pomnozi, podeli). Predvideti da se
nakon klika desnim dugmetom na formu pojavi iskaui meni u kome se klikom bira
odgovarajua operacija, koja se nakon klika izvrava (slika 12). Kontrolisati korektnost
podataka pri naputanju Edit kontrola i ako je podatak nekorektan vratiti fokus na kontrolu sa
nekorektnim podatkom.

Slika 12.
1. Ponoviti korake 1. i 2. iz primera 4.
2. Postavite dugme tipa TButton. Svojstvu Name dodelite btKraj, a svojstvu Caption:
Kraj.
3. Postavite komponentu PopupMenu i dvostrukim klikom na svojstvo Items ili na
samu kompo-nentu otvorite dijalog dizajnera menija. U svojstvo Caption objekt
inspektora upisite Saberi. Nakon pritiska Enter svojstvu Name se dodeljuje ime
Saberi1 i formira se nova objektna promenljiva Saberi1 tipa TMenuItem to se
moe videti u prozoru liste objekata. Istovremeno se u dijalogu dizajnera menija
otvara pravougaonik za novu stavku. Kliknite na taj pravougaonik i ponovite
prethodni postupak unosei u svojstvo Caption naziv Oduzmi. Kreirajte jo stavke
Mnozi i Deli.
4. Sada programirajte dogaaje koji reaguju na klik na neku od stavki menija na sledei
nain. Nakon klika na stavku Saberi (dok je aktivan dizajner menija) i izbora kartice
Events napraviti dvostruki klik na desno polje dogaaja OnClick. Kostur
procedure koji se otvara isprogramirajte na sledei nain:
procedure TForm1.Saberi1Click(Sender:TObject);
begin

Predrag S. Stanimirovi

343

Programski jezici

Edit3.Text:=FloatToStr(StrToFloat(Editl.Text)+
StrToFloat(Edit2.Text));
end;

Za stavke Oduzmi, Mnozi, Deli kreirati procedure:


procedure TForml.OduzmilClick(Sender:TObject);
begin
Edit3.Text:=FloatToStr(StrToFloat(Editl.Text)StrToFloat(Edit2.Text));
end;
procedure TForm1.MnozilClick(Sender:TObject);
begin
Edit3.Text:=FloatToStr(StrToFloat(Editl.Text)*
StrToFloat(Edit2.Text));
end;
procedure TForml.DelilClick(Sender:TObject);
begin
if(StrToFloat(Edit2.Text)=0) then
begin
ShowMessage('Deljenje nulom!');
Edit2.SetFocus;
Edit2.SelectAll;
end
else Edit3.Text:=FloatToStr(StrToFloat(Editl .Text)/
StrToFloat(Edit2.Text));
end;

5. Kliknite prvo na svojstvo forme PopupMenu, a zatim na strelicu na dole


ComboBoxa. Pojavie se lista sa samo jednom stavkom PopupMenu1 koju treba
izabrati. Time ste definisali da se klikom bilo gde na formi pojavi iskaui meni.
6. Kliknite na dugme Run da biste preveli i pokrenuli program. Unesite vrednosti
operanda, pa kliknite desnim dugmetom na formi, pojavie se iskaui meni.
Kliknite na stavku menija i rezultat operacije e se pojaviti u Edit kontroli
edRezultat.
Primer 12b. Prethodnu aplikaciju kreirati kompaktnije tako da samo jedna procedura
obrauje klik na neku od stavki iskaueg menija.
Kreirajte aplikaciju (ili modifikujte prethodnu) na sledei nain:
1. Ponovite korake 1., 2. i 3. dizajniranja prethodne aplikacije.
2. Svojstvu Tag objekata - stavki menija: Saberi1, Oduzmi1, Mnozi1 i Deli1 dodelite
redom vrednosti: 0,1,2, 3. Time otvarate mogunost da u jednoj proceduri za obradu
dogaaja reagujete na klik na bilo koju stavku menija korienjem: (Sender as
TMenuItem).Tag. Izaberite u dijalogu meni dizajnera stavku Saberi, zatim karticu
Events. Napravite dvostruki klik na dogaaj OnCIick. Otvorie se kostur
procedure. Vratite se na dogaaj OnCIick objekta - stavke Saberil i preimenujte
SaberilCIick u OperacijaClick. Pritisnite Enter i u editoru koda programirajte
proceduru na sledei nain:
procedure TForml.OperacijaClick(Sender: TObject);
begin
case (Sender as TMenuItem).Tag of
0:Edit3.Text:=FloatToStr(StrToFloat(Editl.Text)+
StrToFloat(Edit2.Text));
1:Edit3.Text:=FloatToStr(StrToFloat(Editl .Text)-

344
StrToFloat(Edit2.Text));
2:Edit3.Text:=FloatToStr(StrToFloat(Editl.Text)*
StrToFloat(Edit2.Text));
3:if(StrToFloat(Edit2.Text)=0) then
begin
ShowMessage('Deljenje nulom');
Edit2.SetFocus;
Edit2.SelectAll;
end
else Edit3.Text:=FloatToStr(StrToFloat(Editl.Text)/
StrToFloat(Edit2.Text));
end
end;

Za ostale stavke menija Oduzmi, Mnozi i Deli izaberite dogaaj OnCIick, i iz liste
njegovog ComboBox-a izaberite metodu OperacijaClick. Ovim smo postigli da se, kada
kliknemo na neku stavku iskaueg menija, aktivira navedena procedura koja uvek realizuje
operaciju koja odgovara pritisnutoj stavki. To je zbog toga to (Sender as TMenuItem).Tag
nosi informaciju koja je stavka pritisnuta (0 - Saberi, 1 - Oduzmi, 2 - Mnozi, 3 - Deli).

Komponenta Memo
Za razliku od komponente Edit koja moe da sadri jednu liniju teksta, ova
komponenta moe da sadri vie linija teksta. Tekst unet u Edit kontrolu moe biti samo levo
poravnat, dok u Memo okviru tekst moe biti jo centriran i desno poravnat korienjem
svojstva Alignment.
Poravnavanje Memo komponente u okviru klijentske oblasti forme korienjem
svojstva Align moe biti: du leve ivice (alLeft), duz desne ivici (alRight), duz gornje ivice (alTop), duz donje ivice (alBottom), na celoj klijentskoj oblasti
(alClient) ill bez poravnanja (alNone).
U toku projektovanja aplikacije moe se uneti tekst u Memo okvir korienjem svojstva
Lines. Dvostrukim klikom na polje sa desne strane svojstva Lines otvara se dijalog sa editorom
stringova koji omoguava da unesete vie redova teksta. Uneti redovi e se videti u Memo
okviru u toku projektovanja i bie mu inicijalni sadraj kada se pokrene program.
Za pristup pojedinim redovima Memo okvira koristite svojstvo Lines koje je objekat
tipa TStrings. Vebe radi, na formu postavite Memo okvir i u njega unesite neki tekst. Zatim
postavite dva dugmeta tipa TButton. Otvorite proceduru koja reaguje na klik na prvo dugme, i
unesite naredbu:
ShowMessage(Memol.Lines[0]);

Otvorite proceduru koja reaguje na klik na drugo dugme, i unesite naredbu:


ShowMessage(Memo1.Text);

Pokrenite program i videete da se klikom na prvo dugme prikazuje poruka u kojoj se


nalazi samo prvi red teksta iz Memo okvira, dok se klikom na drugo dugme prikazuje ceo tekst
koji je sadran u Memo okviru.
Ovde smo za prikaz sadraja koristili svojstvo Text Memo okvira koje nije pristupano
u toku projektovanja (nije sadrano u objekt inspektoru), ve se moe koristiti samo u toku
izvravanja aplikacije.
Memo okviru se u toku izvravanja mogu dodavati redovi teksta korienjem metode
Add. Na primer, ako bi u prethodnoj aplikaciji dodali jo jedno dugme i napisali proceduru koja
reaguje na klik na to dugme sa naredbom
Memo1.Lines.Add('Ovo je novi red');

postojeem tekstu Memo okvira se dodaje novi red sa tekstom: Ovo je novi red.

Predrag S. Stanimirovi

345

Programski jezici

Broj redova Memo okvira je sadran u svojstvu Count za Lines. Obrada redova Memo
okvira moe se realizovati na sledei nain:
for i:=0 to Memo1.Lines.Count-1 do
Obrada(Memol.Lines[i]); {* ime Obrada bi se zamenilo imenom
konkretne
procedure za obradu linij e *}

Korienjem metode LoadFromFile svojstva Lines Memo okvira moe se u Memo


okvir uitati sadraj tekstualnog fajla, ali i kopirati sadraj Memo okvira na disk korienjem
metode SaveToFile. Za vebu, na formu postavite Memo okvir i dva dugmeta tipa TButton
kojima ete u svojstvo Caption upisati: Ucitaj i Sacuvaj. Svojstvu Align Memo okvira dodelite
alTop.
Otvorite proceduru koja reaguje na klik na dugme Ucitaj, i unesite naredbu:
Memol.Lines.LoadFromFile('C:\AUTOEXEC.BAT');

Otvorite proceduru koja reaguje na klik na dugme Sacuvaj, i unesite naredbu:


Memol.Lines.SaveToFile('C:\AUTOEXEC.BAK');

Poto je AUTOEXEC.BAT vaan sistemski fajl bilo bi bolje da za vebu izaberete neki
drugi tekstualni fajl koji imate na disku, da se ne bi nesmotreno pokvario sadraj ovog vanog
fajla. Dovoljno je da u naredbi druge procedure grekom umesto nastavka .BAK stavite .BAT i
da nakon promena koje moete uneti u Memo okvir i pritiska na dugme Sacuvaj izgubite
prvobitini sadraj fajla AUTOEXEC.BAT. Ova aplikacija predstavlja mali editor koda po
osobinama blizak Windowsovom Notepadu.
Poto je svojstvo Lines Memo okvira tipa TStrings, a istog tipa je i svojstvo Items
komponente tipa TListBox to se stavke objekta ListBox mogu kopirati u redove Memo okvira
naredbom:
Memo1.Lines:=ListBox1.Items;
i obrnuto stavke komponente Memo okvira mogu se kopirati u ListBox redove, naredbom:
ListBox1.Items:=Memo1.Lines;

Sadraj Memo okvira se moe isprazniti korienjem metode Clear svojstva Lines:
Memo1.Lines.Clear

ili metode Clear komponente Memo:


Memo1.Clear

Ove dve naredbe su ekvivalentne.


Memo okvir ima svojstvo ScroIlBars koje omoguava da mu dodate horizontalni kliza
(ssHorizontal), vertikalni (ssVertical), oba klizaa (ssBoth) ili nijedan (ssNone).
Ako je svojstvo WordWrap postavljeno na True tada se deo reda koji izlazi van
vidljivog dela Memo okvira automatski prenosi u sledei red. Ali, treba imati na umu da kada je
WordWrap postavljeno na True mora se iskljuiti horizontalni kliza jer su ovakva
postavljanja u koliziji. Ako je WordWrap postavljeno na False tada se deo reda koji izlazi van
vidljivog dela Memo okvira nee videti. U ovom sluaju je potrebno da imate postavljen
horizontalni kliza za Memo okvir.
Primer 13. Kreirati aplikaciju tako da na formu postavite Memo okvir (na celoj klijent oblasti) i
iskaui meni koji ima stavke Iseci (Cut), Kopiraj (Copy), Prenesi (Paste). Aplikacija treba da
ima mogunost (nakon klika desnim dugmeta) isecanja i kopiranja na Clipboard selektovanog
teksta iz Memo okvira i prenoenje sa Clipboarda u Memo okvir poev od pozicije kursora
(slika 13.).

346

Slika 13.
1. Zaponite novu aplikaciju.
2. Na formu postavite Memo okvir i njegovom svojstvu Align dodelite vrednost
alClient.
3. Postavite komponentu PopupMenu i korienjem dizajnera menija unesite stavke sa
nazivima Iseci, Kopiraj i Prenesi.
4. Objektu Memo1 (ili Form1) iz liste svojstva PopupMenu izaberite jedinu stavku
PopupMenu1.
5. Na poetku implementacione sekcije unesite: uses Clipbrd;
6. Programirajte brisanje sadraja Memo okvira pri kreiranju forme:
procedure TForml.FormCreate(Sender: TObject);
begin
Memol.Clear;
end;

7. Izaberite stavku iskaueg menija Iseci i programirajte kao reakciju na klik:


procedure TForml.Iseci1Click(Sender:TObject);
begin
Memo1.CutToClipboard;
end;

8. Izaberite stavku iskaueg menija Kopiraj i programirajte kao reakciju na klik:


procedure TForm1.Kopiraj1Click(Sender: TObject);
begin
Memol.CopyToClipboard;
end;

9. Izaberite stavku iskaueg menija Prenesi i programirajte kao reakciju na klik:


procedure TForml.Prenesi1Click(Sender: TObject);
begin
Memo1.PasteFromClipboard;
end;

10. Izaberite komponentu PopupMenu iz liste objekt inspektora (ili sa forme). Na


kartici Events napravite dvostruki klik na dogaaj OnPopup i programirajte
proceduru na sledei nain:
procedure TForm1.PopupMenu1Popup(Sender: TObject);
begin
Iseci1.Enabled:=Memo1.SelLength>0;
Kopiraj1.Enabled:=Iseci1.Enabled;
Prenesi1.Enabled:=Clipboard.HasFormat(CF_TEXT);
end;

Prva linija koda omoguava korienje dugmeta Iseci samo ako je deo teksta u Memo
okviru selektovan, to se proverava iz vrednosti svojstva SelLength koje predstavlja broj
selektovanih znakova. Ako u Memo okviru nema selektovanog teksta svojstvo Enabled dobija
vrednost False pa je stavka onemoguena. Druga linija koda ima istu funkciju samo za stavku
Kopiraj. Treom linijom se omoguava stavka Prenesi samo ako clipboard sadri podatke
zahtevanog formata (u ovom primeru tekst), upotrebom objekta Clipboard i njegovog metoda

Predrag S. Stanimirovi

347

Programski jezici

HasFormat. Ova metoda proverava pet razliitih formata, korienjem parametara: CF_TEXT,
CF_PICTURES, CF_BITMAP i CF_METAFILE.
11. Pokrenite aplikaciju, unesite neki tekst i testirajte operacije selektovanja, isecanja,
kopiranja i prenosenja teksta.

Komponenta CheckBox
Ova komponenta se koristi za ukljuivanje ili iskljuivanje neke opcije. Kada stavite
komponentu tipa CheckBox na formu videete da ima dva dela: polje za potvrdu i pored njega
natpis koji blie objanjava njegovu namenu. Trenutno stanje, odnosno proveru da li je
CheckBox ukljuen ili nije moete realizovati proverom vrednosti svojstva Checked (True,
False), na primer:
if CheckBox1.Checked
then {*programski kod koji obradjuje stanje ukljuceno *}
else {*programski kod koji obradjuje stanje iskljuceno *}

Komponenta CheckBox moe imati i tree stanje koje se vizuelno prikazuje kao sivo.
Da bi se omoguilo i tree stanje CheckBoxa potrebno je svojstvu AlowGrayed postaviti
vrednost na True. Ali tada se provera stanja realizuje korienjem svojstva State koje moe
imati tri vrednosti: cbChecked, cbUnchecked i cbGrayed. Na primer, ako na formu postavite
komponente tipa CheckBox i Label, svojstvo AlowGrayed postavite na True i kreirate
proceduru kao reakciju na klik na CheckBox:
procedure TForm1.CheckBox1Click(Sender:TObject);
begin
if CheckBox1.State=cbGrayed then
Labell.Caption:='Grayed'
else if CheckBox1.State=cbChecked then
Label1.Caption:='Checked'
Label1.Caption:='UnChecked' end;

else

videete da se korienjem komponente Label klikom na CheckBox ispisuju tri mogua stanja.
Slino bi se u aplikaciji programirala obrada moguih stanja objekta tipa CheckBox.
Kada elite da koristite samo dva stanja CheckBoxa postavite AllowGrayed na False i
za proveru stanja koristite svojstvo Checked.
Komponente CheckedBox i RadioButton se koriste za kreiranje upitnika i testova.

Komponenta GroupBox
Ova komponenta se koristi za grupisanje komponenti tipa CheckBox, RadioButton i
drugih kontrola u logike celine. Komponenta GroupBox poseduje natpis koji se zadaje
svojstvom Caption. Kada se komponenta GroupBox postavi na formu, na ovu komponentu se
mogu dodavati druge komponente prostim klikom u granicama komponente GroupBox. Ona
time postaje "roditelj" nove komponente, koja se unutar nje moe samo pomerati korienjem
mia, ali se ne moe odvui van njenih granica. Komponenta "dete" moe da preuzme vrednosti
svojstava Font i Color od "roditelja" postavljanjem svojstava ParentFont i ParentColor na
True. Premetanje komponente iz jedne grupe u drugu mogue je samo operacijom Cut/Paste.
Primer 14. Kreirati mini-test iz matematike prema slici 14. Obezbediti da se klikom na dugme:
Rezultat testa ispie broj osvojenih poena, ako se za svaki taan odgovor dobija 1 poen, a
netaan -1 poen.

348

Slika 14.

1. Na formu postavite komponentu Label i u svojstvo Caption upisite formulaciju


zadatka (ako je formulacija zadatka vielinijska koristiti Memo okvir i svojstvo
Lines).
2. Postavite GroupBox i u Caption unesite: Klikni na polje sa tacnim odgovorom. Na
komponentu GroupBox postavite 6 komponenti tipa CheckBox i u svojstvo Caption
svake komponente ponuene odgovore prema slici 14.
3. Postavite komponentu Label i u svojstvo Caption unesite: Osvojili ste:.
4. Postavite Button i u njegovo svojstvo Caption unesite: Rezultat testa.
5. Kreirajte proceduru koja reaguje na klik na Button1 i koja izraunava broj osvojenih
poena i upisuje u svojstvo Caption komponente Label2:
procedure TForm1.Button1Click(Sender:TObject);
var p:integer;
begin
p:=ord(CheckBox3.Checked)+ord(CheckBox4.Checked)ord(CheckBoxl.Checked)-ord(CheckBox2.Checked)ord(CheckBox5.Checked)-ord(CheckBox6.Checked);
Label2.Caption:='Osvojili ste:' + IntToStr(p) + 'poena';
end;

Komponente Panel i Bevel


Komponenta Panel se esto koristi kao kontejnerska za paletu alatki. Takoe se koristi
za izradu statusnih panela i prikazivanje naslova korienjem svojstva Caption. Naslov
postavljen u svojstvo Caption moe biti levo i desno poravnat, i centriran unutar panela,
postavljanjem odgovarajue vrednosti u svojstvo Alignment. Sam panel se koristi slino
komponenti GroupBox. Roditelj je za sve komponente koje su postavljene na njega, tako da se
pomeranjem panela pomeraju i njegove komponente. Izgled panela se moe menjati promenom
svojstava: Bevellnner, BevelOuter, BorderStyle i BorderWidth. Panel se poravnava unutar
klijentske oblasti korienjem svojstva Align. Postavite komponentu Panel na formu i pratite
promene koje se deavaju promenom ovih svojstava.
Komponenta Bevel se nalazi na kartici Additional palete komponenti. Vizuelno je
slina komponenti Panel i koristi se kao okvir za komponente, kako bi se korisniku istaklo da
njime obuhvaene komponente predstavljaju logiku celinu. Ali, nije kontejnerska komponenta
to znai da pomeranje ove komponente ne dovodi do pomeranja njime vizuelno obuhvaenih
komponenti. Moe se koristiti ne samo za postavljanje okvira ve i za postavljanje linije za
razdvajanje grupa komponenti. Vizuelni prikaz se definie svojstvom Shape. Nema svojstvo
Caption, i ne prepoznaje nijedan dogaaj.

Predrag S. Stanimirovi

349

Programski jezici

Komponenta SpinEdit
Ova komponenta slui za uveavanje odnosno umanjivanje vrednosti u polju za tekst.
Nalazi se na kartici Samples palete komponenti. Sadri polje za tekst u kome mogu biti samo
celobrojne vrednosti i dva mala dugmeta sa strelicama nagore i nadole.
Poetna vrednost polja se zadaje korienjem svojstva Value tipa integer.
Podrazumevajua vrednost ovog svojstva je 0. Mogu se zadati najmanja vrednost (svojstvo
MinValue) i najveca vrednost (svojstvo MaxValue) koje se mogu pojaviti u polju za tekst.
Korak promene pri kliku na stelice definie se svojstvom Increment.
Primer 15. Napisati aplikaciju koja obezbeuje konverziju prirodnog broja od 0 do 31 u petocifreni
binarni broj i obratno. Neka se prirodni broj prikazuje u komponenti SpinEdit, a petocifreni binarni
sa pet komponenti tipa CheckBox.
Obezbediti da u SpinEdit kontroli svojstva MinValue i MaxValue imaju redom vrednosti 0
i 31, da je podrazumevajua vrednost 0, a korak (Increment) promene 1, i da promena vrednosti u
ovoj kontroli izaziva promenu stanja CheckBoxova koji kada su u stanju potvren redom
reprezentuju teine odgovarajuih binarnih cifara (1, 2, 4, 8, 16) binarne reprezentacije broja koji se
nalazi u SpinEdit kontroli. Obezbediti da se promenom stanja CheckBoxova menja i sadraj
SpinEdit kontrole (videti sliku 15).

Slika 15.

1. Postaviti SpinEdit i CheckBox kontrole prema slici. Svojstvu Tag CheckBox


kontrola dodelite redom vrednosti 0,1,2,3,4. U SpinEdit kontroli svojstvima
MinValue i MaxValue dodeliti redom vrednosti 0 i 31, svojstvu Value 0, a svojstvu
Increment 1.
2. U implementacionoj sekciji kreirajte funkciju koja proverava da li je u parametru
Value na poziciji zadatoj parametrom Bit vrednost 1:
function DaLiJeBit1(Value: Integer; Bit: Byte): Boolean;
begin
Result:=(Value and (1 shl Bit))<>0;
end;

Ovde se vrednost koju treba da vrati funkcija umesto da se dodeli imenu promenljive
sa istim imenom kao ime funkcije (kako je uobiajeno u Pascalu) - dodeljuje
lokalnoj promenljivoj Result koja se ne mora deklarisati.
3. U implementacionoj sekciji kreirajte funkciju koja vraa broj dobijen na osnovu
parametra Value kome na poziciji zadatoj parametrom Bit postavlja vrednost 1:
function BitNa1(Value:Integer; Bit:Byte):Integer;
begin
Result:=Value or (1 shl Bit);
end;

350
4. U implementacionoj sekciji kreirajte funkciju koja vraa broj dobijen na osnovu
parametra Value kome na poziciji zadatoj parametrom Bit postavlja vrednost 0:
function BitNa0(Value:Integer; Bit:Byte):Integer;
begin
Result:=Value and not (1 shl Bit);
end;

5. Za sve CheckBox kontrole obezbedite da se klikom na bilo koju od njih poziva


procedura koja menja vrednost u SpinEdit kontroli prema novom stanju bitova:
procedure TForml.CheckBoxClick(Sender: TObject);
var Val:Integer;
begin
Val:=SpinEdit1.Value;
with Sender as TCheckBox do
if Checked then Val:=BitNal(Val,Tag)
else Val:=BitNaO(Val,Tag);
SpinEditl.Value:=Val;
end;

6. Pri promeni vrednosti SpinEdit kontrole obezbediti i promene u CheckBox


kontrolama sledeom procedurom:
procedure TForm1.SpinEditlChange(Sender: TObject);
var i:Integer;
CheckBox: TCheckBox;
begin
for I:=l to 5 do
begin
CheckBox:=FindComponent('CheckBox'+IntToStr(I)) as
TCheckBox;
CheckBox.Checked:=DaLiJeBitl(SpinEditl.Value,CheckBox.Tag);
end;
end;

U ovoj proceduri funkcija FindComponent vraa komponentu sa imenom koje je


jednako imenu stringa koji je parametar funkcije, dalje se ova komponenta prevodi u
TCheckBox komponentu kojoj se svojstvo Checked postavlja zavisno od vrednosti (0 ili 1) na
odgovarajuoj poziciji binarne reprezentacije SpinEdit kontrole.
Primer 16. Napisati aplikaciju za odeljenjsku statistiku. Aplikacija treba da ima mogunost
izbora predmeta iz skupa svih predmeta koji se ue u koli korienjem CheckBoxova,
unoenje ocena uenika korienjem SpinEdit kontrola, izraunavanje proseka po izabranim
predmetima. Predvideti i izraunavanje ukupnog broja opravdanih i neopravdanih izostanaka.
Raspored komponenti videti na slici 16.

Predrag S. Stanimirovi

351

Programski jezici

Slika 16.
1. Zaponite novu aplikaciju.
2. Postavite komponentu GroupBox i razvucite tako da moe da primi onoliko
CheckBoxova, SpinEdit kontrola, Edit kontrola koliko kola ima predmeta,
ukljuujui kontrole za izostanke, i prosek uenika i odeljenja (prema slici).
Postaviti Caption za GroupBox prema slici 16.
3. Na GroupBox postavite CheckBox komponente stavljajui u svojstvo Caption naziv
predmeta kome su dodeljene. Svojstvu Checked dodelite true.U svojstvo Tag
postavite redom vrednosti od 201 do 221.
4. Na GroupBox postavite SpinEdit komponente. Za predmete u svojstvo MinValue
postavite za minimalnu ocenu 1, a u MaxValue postavite za maksimalnu ocenu 5. U
svojstvo Value postavite ocenu koja je po vaoj proceni najblia proseku kole (na
primer: 4). Za opravdane i neopravdane izostanke moete zadrati podrazumevajue
vrednosti. U svojstvo Tag kontrola SpinEdit unesite redom vrednosti od 1 do 23, da
bi se u toku izvravanja programa mogle prepoznati.
5. Na GroupBox postavite Edit kontrole u kojima e se prikazivati proseci po
predmetima. U svojstvo Tag postavite redom vrednosti od 101 do 123.
6. Postavite dve Labele ije je svojstvo Caption: Prosek uenika je: i Prosek odeljenja
je:. Pored ovih komponenti postavite dve Edit kontrole za prikazivanje ovih
proseka.
7. Postavite dve Bevel komponente na GroupBox prema slici za razdvajanje kolona i
proseka.
8. Iznad GroupBoxa postavite Panel i u njegovom svojstvu Caption obriite string
Panel1, a u svojstvo Align postavite alTop. Na komponentu Panel1 postavite dve
Label komponente jednu za redni broj uenika i jednu za ime uenika. Postavite
Memo okvir predvien za unos imena uenika (moe i Edit).
9. Ispod GroupBoxa postavite Panel i u njegovom svojstvu Caption obriite sadraj, a
u svojstvo Align postavite alBottom. Na komponentu Panel postavite etiri
dugmeta i to: Prethodni (za prelazak na prethodnog uenika), Sledei (za prelazak

352
na sledeeg uenika), Raunaj (za raunanje proseka uenika, odeljenja, izabranih
predmeta i zbira izostanaka) i Kraj (za kraj rada).
10. Preite u editor kod i u interfejs sekciji pod odeljkom Type unesite definiciju tabele
TTabela sa 24 vrste (21 za ocene uenika, 2 za izostanke i 1 za prosek uenika) i 50
kolona pretpostavljajui da je maksimalan broj uenika 50. Uzeti da su komponente
tabele tipa real. Unesite definiciju niza TNiz od 24 komponente tipa real, za
izraunavanje proseka po predmetima i zbira izostanaka. U odeljku za opis
promenljivih deklariite promenljivu T tipa TTable, P tipa TNiz i Ime kao niz od 50
stringova za imena uenika.
type
TTabela=array[l ..24,1 ..50] of real;
TNiz=array[l ..24] of real;
var
Forml:TForml;
T:TTabela;
P:TNiz;
Ime:array[1..50] of string;

11. U sekciji za implementaciju unesite konstantu sa inicijalnom vrednou 1 - za redni


broj uenika.
implementation
const rb:integer=l; //redni broj ucenika

12. Izabrati formu korienjem ComboBoxa ili Esc tastera, a zatim na kartici Events
napraviti dvostruki klik na dogaaj OnCreate. U proceduri koja se otvori unesite
sledei kod:
procedure TForm1.FormCreate(Sender: TObject);
var i,j:integer;
begin
for i:=1 to 23 do
//matrica ocena se
inicijalizuje sa 4
for j:=1 to 50 do
T[i,j]:=4;
btPrethodni.Enabled:=false;
// onemogueno dugme
Prethodni
// SpinEdit kontrole postavlja na 4, a Edit na prazan
string
for i:=0 to ComponentCount-l do
if Components[i] is TSpinEdit
//ako je komponenta
TSpinEdit
then (Components[i] as TSpinEdit).Value:=4
//svojstvo Value postaviti 4
else
if Components [i] is TEdit then //ako je komponenta
tipa TEdit
(Components[i] as TEdit).Text:="; //u
svojstvo Text postaviti
//prazan string
SpinEdit21.Value:=5 ; // inicijalno odlicna ocena iz
vladanja
Label5.Caption:='Redni broj ucenika:
'+IntToStr(rb);
Memo1.Text:=";
// niz imena uenika se inicij alizuj e praznim stringom
for i:=1 to 50 do Ime[i]:=";
end;

Predrag S. Stanimirovi

353

Programski jezici

Kodom je predvieno da se prolaskom preko svih komponenti koje su indeksirane


od 0 do ComponentCount-1 komponentama koje su tipa TSpinEdit dodeli 4, a
komponentama TEdit dodeli prazan string.
13. Programirajte dugme Kraj tako da obezbedi zatvaranje forme i prekid izvravanja
aplikacije.
procedure TForm1.btKrajClick(Sender: TObject);
begin
Close
end;

14. Za prvi CheckBox programirajte dogaaj OnClick tako da se prema njegovom


stanju ukljuuje/iskljuuje sa njim uparena SpinEdit kontrola. Za sve ostale
CheckBox kontrole odabrati kao reakciju na dogaaj OnClick ovaj koji je
isprogramiran za CheckBox1.
procedure TForm1.CheckBoxlClick(Sender: TObject);
var i:integer;
begin
{ukljucivanje-iskljucivanje SpinEdit kontrola ako je
kliknuto na
njemu upareno CheckBox dugme - prepoznaju
se po razlici Tag
vrednosti koja je 200 }
for i:=0 to ComponentCount- 1 do
if Components[i].Tag=(Sender as TCheckBox).Tag-200 then
TSpinEdit(Components[i]).Enabled:=(Sender as
TCheckBox).Checked;
{ukljucivanje-iskljucivanje Edit
kontrola ako je kliknuto na njemu
upareno
CheckBox dugme- prepoznaju sepo razlici Tag vrednosti
koja je 100 }
for i:=0 to ComponentCount- 1 do
if Components[i].Tag=(Sender as TCheckBox).Tag-100 then
TEdit(Components[i]).Enabled:=(Sender as
TCheckBox).Checked;
end;

Kodom se u prvom ciklusu ide preko svih komponenti i kada se naie na komponentu
koja u svojstvu Tag ima vrednost koja je za 200 manja od svojstva Tag CheckBoxa koji
je kliknut, to moe biti samo CheckBoxu uparena SpinEdit kontrola. Zato se kast
operatorom TSpinEdit komponenta Components[i] konvertuje u SpinEdit kontrolu
koju Components[i] predstavlja i svojstvu Enabled dodeljuje vrednost svojstva
Checked komponente CheckBox koja je izazvala dogaaj. Time se ukljuuje/iskljuuje
SpinEdit kontrola. Slinim postupkom se drugim ciklusom ukljuuju/iskljuuju Edit
kontrole koje su uparene sa CheckBoxom koji je izazvao dogaaj.
15. Programirati dugme Raunaj tako da odgovarajua procedura izraunava prosek
ocena, zbir izostanaka i da dobijene vrednosti upisuje u tabelu. Traena
izraunavanja realizuje sledei kod:
procedure TForml.btRacunajClick(Sender:TObject);
var i,j,s,k:integer;
Str1:string;
Pros:real;
begin
// racuna se prosek ucenika
s:=0;
//za zbir ocena
k:=0;
//broj ocena koje ulaze u prosek
for i:=0 to ComponentCount-l do

354
begin // prolaz preko omogucenih SpinEdit kontrola koje
su
// tagirane od 1 do 21, i sabiranje njihovih
vrednosti
if (Components[i] is TSpinEdit) and
TSpinEdit(Components[i]).
Enabled
and (TSpinEdit(Components[i]).Tag in [1..21]) then
begin
s:=s+TSpinEdit(Components[i]).Value; k:=k+1
end;
end;
Pros:=s/k; //prosek ucenika
T[24,rb]:=Pros;
//upis proseka tekuceg ucenika u
//poslednju vrstu tabele
str(Pros:0:2,Str1);
Edit24.Text:=Str1; //upis proseka u Edit kontrolu
for i:=0 to ComponentCount-l do //kopiranje vrednosti iz
SpinEdit
//kontrola u tabelu
if Components[i] is TspinEdit then

T[TSpinEdit(Components[i]).Tag,rb]:=TSpinEdit(Components[i]).
Value; // izracunavanje proseka po predmetima i zbira
izostanaka
for i:=l to 24 do
begin
P[i]:=0;
for j:=l to rb do P[i]:=P[i]+T[i,j];
if not (i in [22,23]) then P[i] :=P[i]/rb
end;
// upisivanje izraunatih proseka po predmetima u
// odgovarajuce komponente
for i:=0 to ComponentCount-l do
if (Components[i] is TEdit) and
(TEdit(Components[i]).Tag in
[101..
124]) and TEdit(Components[i]).Enabled then
TEdit(Components[i]).Text:=FloatToStr(
P[TEdit(Components[i]).Tag-100]);
end;

16. Programirati da se klikom na dugme Sledei uvea redni broj uenika i da se u


SpinEdit kontrole kopiraju (kao inicijalne) vrednosti iz tabele T. Reakcija na klik na
dugme Sledeci programirana je sledeom procedurom:
procedure TForml.btSledeciClick(Sender:TObject);
var i:integer;
begin
btPrethodni.Enabled:=true; // omoguceno dugme Prethodni
Ime[rb]:=Memo1.Text; // tekuce ime kopira u niz imena
rb:=rb+l; //uvecavanje na redni broj narednog ucenika
Memol.Text:=Ime[rb];
Label5.Caption:='Redni broj ucenika: '+IntToStr(rb);
// postavljanje inicijalnih vrednosti u SpinEdit i Edit
kontrole
for i:=0 to ComponentCount-1 do
if Components[i] is TSpinEdit then
//kopiranje u kontrole SpinEdit vrednosti iz Tabele
(Components[i] as TSpinEdit).Value:=
trunc(T[(Components[i] as TSpinEdit).Tag,rb])

Predrag S. Stanimirovi

355

Programski jezici

else
if Components[i] is TEdit then
(Components[i] as Tedit).Text:='';
SpinEdit21. Value:=5; // inicijalna vrednost za ocenu iz
vladanja
end;

17. Klikom na dugme Prethodni redni broj uenika se umanjuje za jedan i kopiraju
vrednosti iz tabele u SpinEdit kontrole. To realizuje sledea procedura:
procedure TForml.btPrethodniClick(Sender:TObject);
var i:integer;
begin
Ime[rb]:=Memo1.Text;
// kopira tekuce ime ucenika u niz
rb:=rb-1;
Label5.Caption:='Redni broj uenika: '+IntToStr(rb);
Memo1.Text:=Ime[rb];
if rb=1 // onemoguciti dugme Prethodni ako je redni broj 1
then btPrethodni.Enabled:=false;
for i:=0 to ComponentCount-1 do
if Components[i] is TspinEdit then
// kopira vrednosti iz tabele u SpinEdit kontrole
(Components[i] as TSpinEdit).Value:=
trunc(T[(Components[i] as TSpinEdit).Tag,rb])
else // postavlja prazne stringove u Edit kontrole
if Components[i] is TEdit then
TEdit(Components[i]).Text:="
end;

Komponenta Timer
Komponenta Timer (nalazi se na kartici System) je kao mali hronometar koji radi u
pozadini, tako to u unapred utvrenim intervalima salje poruke aplikaciji aktivirajui metodu
za obradu dogaaja OnTimer. Vi moete ukljuiti/iskljuiti Timer promenom vrednosti
svojstvu Enabled (True/False). Moete regulisati brzinu tajmera, (koja se esto meri
"tikovima"), menjajui njegovo svojstvo Interval. Ovo svojstvo definie broj milisekundi
(hiljaditih delova sekunde) izmeu dogaaja OnTimer (tikova). To znai, ako Interval ima
vrednost 1000, tajmer izaziva dogaaj OnTimer svakih 1000 milisekundi (jedanput u sekundi).
Ako elite 10 tikova tajmera u sekundi postavite Interval na 100 (1000/10=100), ili ako hoete
tikove na 2.5 sekunde postavite Interval na 2500 (2.5*1000=2500). Postavljanje intervala na 0 je isto to i njegovo iskljuivanje.

Slika 17.
Primer 17. Kreirati aplikaciju koja imitira rad elektronskog sata (slika 17).
1. Zaponite novu aplikaciju.
2. Na formu postavite komponente Label i Timer.
3. U svojstvo Interval komponente Timer unesite vrednost 1000 to je trajanje jednako
jednoj sekundi. Dvostrukim klikom na komponentu Timer otvorie se editor koda za
obradu dogaaja OnTimer koji treba isprogramirati na sledei nain:
procedure TForm1.Timer1Timer(Sender: TObject);
begin

356
Label1.Caption:=TimeToStr(Time);
end;

U ovoj proceduri tekue vreme koje vraa standardna funkcija Time pomou funkcije
TimeToStr() se transformie u string, koji se dodeljuje svojstvu Caption komponente
Label.

Zadaci za vebu
1. Kreirati aplikaciju koja obezbeuje da se klikom na formu tekui oblik kursora mia
menja na oblik koji sledi u listi svojstava Cursor za formu. Ako je tekue svojstvo poslednje iz
liste, postaviti prvo.
Uputstvo. Postavljanje kursora na sledei realizovati sa Cursor:=succ(Cursor).
2. Kreirati aplikaciju koja sadri komponente: Edit, Label i Button. Programirati da se
klikom na dugme Button ako je boja forme razliita od clPurple forma oboji crveno, Edit
kontrola zeleno i Label uto.
3. Kreirati aplikaciju koja sadri dugme tipa TButton. Programirati da se klikom na
dugme u naslovu forme ispise: Zdravo, zdravo, zdravo!. Takoe, obezbediti da dugme bude
centirano na formi nakon kreiranja, ali i nakon promene veliine.
Uputstvo. Dogaaje forme OnCreate i OnResize programirati sledeim kodom:
btZdravo.Top:=(ClientHeight-btZdravo.Height) div 2;
btZdravo.Left:=(ClientWidth-btZdravo.Width) div 2;

Programirati da reakcija na klikna dugme tipa TButton bude:


Form1.Caption:='Zdravo, zdravo, zdravo';

4. Projektovati aplikaciju u Delphiju za izraunavanje obima i povrine trougla zadatog


duinama stranica.
5. Kreirati aplikaciju koja omoguava da se zadaju dinarski kursevi dolara i marke,
iznos u dolarima ili markama, a zatim pritiskom na odgovarajuce dugme vri konverzija dolara
u marke ili obrnuto.
6. Napisati aplikaciju koja korienjem CheckBoxova kreira jelovnik i nakon izbora
narudzbine u ListBoxu ispisuje narudzbinu.
7. Napisati aplikaciju koja ima: dve Edit kontrole - jednu u koju se unosi cena artikla i
drugu u koju se unosi koliina kupljenih artikala. Postaviti i Memo okvir, jo jednu Edit
kontrolu i dugme tipa Button. Programirati da se nakon unosa cene i koliine, i klika na dugme
Button dobijeni iznos dodaje kao stavka Memo okvira, a zbir svih iznosa prikazuje u Edit
kontroli.
8. Ako je kreiran modul TestClass koji ima jedan protected (zatieni) i jedan public
(javni) podatak i metodu koja vraa podatke klase:
unit TestClass;
interface
type
TTest=class
protected
ProtectedData: Integer;
public
PublicData: Integer;
function VratiPodatke: string;
end;
implementation
uses SysUtils;
function TTest.VratiPodatke:string;
begin

Predrag S. Stanimirovi

357

Programski jezici

Result := Format ('Public: %d, Protected: %d',


[PublicData, ProtectedData]);
end;
end.

a) Da li e biti uspena kompilacija i zato, koda glavne forme koja koristi modul
TestClass i metodu ButtonlClick sa sledeim kodom:
implementation
{$R*.DFM}
uses TestClass;
procedure TForml.ButtonlClick(Sender:TObject);
var Obj:TTest;
begin
Obj:=TTest.Create;
Obj.PublicData:=10;
Obj.ProtectedData:=20;
ShowMessage(Obj.VratiPodatke);
Obj.Free;
end;

b) Ako se kreira naizgled beskorisna klasa glavne forme izvedena iz klase Ttest: type
TDete = class (TTest); da li e biti uspena kompilacija sledeeg koda:
procedure TForml.Button2Click(Sender:TObject);
var Obj: TTest;
begin
Obj:=TTest.Create;
Obj.PublicData:=10;
TDete(Obj).ProtectedData:=20;
ShowMessage(Obj.VratiPodatke);
Obj.Free;
end;

You might also like