Professional Documents
Culture Documents
Jezici
Jezici
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.
| " 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
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.
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.
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
ime
vrednost
Predrag S. Stanimirovi
Programski jezici
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
f x_ := x^2
f::usage = "f x kvadrira x"
f x kvadrira x
?? f
f x kvadrira x
f x_ := x2
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.
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>
}
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:
Predrag S. Stanimirovi
Programski jezici
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.
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 }
Predrag S. Stanimirovi
11
Programski jezici
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.
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
+
+
<
<=
>
>=
=
<>
Predrag S. Stanimirovi
Programski jezici
13
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,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
Tip
INTEGER
REAL
DOUBLE PRECISION
COMPLEX
14
Tipovi podataka u C-u
Tip
Memorija u
bajtovima
Opseg
Namena
char
0 do 255
signed
char
-128 do 127
enum
-32.768 do 32.767
unsigned
int
0 do 65.535
short int
-32.768 do 32.767
int
-32.768 do 32.767
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
double
1,7*10-308 do 1,7*10308
long
double
10
3,4*10-4932 do 3,4*104932
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;
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" */
Primeri
Primer. Unoenje karaktera preko tastature i njihovo prikazivanje na ekran.
#include <stdio.h>
main()
{ char c;
while(1)
{ c=getchar();
}
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
Predrag S. Stanimirovi
19
Programski jezici
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.
Predrag S. Stanimirovi
21
Programski jezici
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
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));
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.
sabiranje
oduzimanje
mnoenje
celobrojno deljenje
ostatak celobrojnog deljenja
DIV
MOD
MOD
MOD
2
3
3
3
= 2 (a ne 2.5)
=2
=0
=1
ROUND (X) =
TRUNC(X+0.5),
X0,
TRUNC(X-0.5),
X<0.
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
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 )
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);
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];
lista brojeva
lista je sastavljena od simboli~nih izraza
Predrag S. Stanimirovi
Complex
27
Programski jezici
Denominator
kompleksni broj iji se delovi izdvajaju pomou Re i Im
Svi strukturni tipovi podataka imaju jednoobraznu strukturu , koja ima oblik
@
D
@
D
@
D
@
D
@
D
@
D
@
D
28
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
25
34
35
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.
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.
Predrag S. Stanimirovi
31
Programski jezici
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
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 ");
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
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"
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
36
Input[ ]
Input["tekst"]
InputString[ ]
InputString["tekst"]
Print[izr1, izr2,..]
Za vreme rada korisnik moe da pristupi svim prethodno unetim izrazima, kao i dobijenim
rezultatima.
%n ili Out[n]
%...% ili Out[-n]
Predrag S. Stanimirovi
37
Programski jezici
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;
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;
38
Ovaj izraz bi trebalo pisati u obliku
if B1 and B2 then Sa;
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;
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:
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.
niz naredbi
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
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;
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.
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
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);
}
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. 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. 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);
}
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
Primeri.
Primer. Izraunati abs(x)=|x|.
void main()
{ float abs,x;
scanf("%f",&x);
abs=(x<0) ? -x : x;
printf("%f\n", abs);
}
Primer.
1. Vrednost izraza
s=
-1, x < 0,
x * x, x>=0
48
@ 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
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
@
@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]
U poslednjoj tabeli svaki od izraza value1, value2, ... predstavlja jedan izraz ili sekvencu izraza
koji su razdvojeni znakom ;.
@
D@
Na primer, izrazom:
@
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
h 2
0
Switch 17, 0, a, 1, b, _, g
g
true
false
true
false
true
Predrag S. Stanimirovi
51
Programski jezici
0, x = 0
x2,
10
20
30
40
x<0
x>0.
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.
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
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.
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);
}
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
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");
Predrag S. Stanimirovi
57
Programski jezici
moe se pisati
switch(a>b)
{ case 0: max=b; break;
case 1: max=a;
}
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, ...]
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:
@
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
h 2
0
Switch 17, 0, a, 1, b, _, g
g
Predrag S. Stanimirovi
Programski jezici
ne
uslov
da
niz naredbi
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
END DO [ime]
Predrag S. Stanimirovi
61
Programski jezici
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
62
for i := poc to kraj do naredba;
i
i 1
i
repeat
naredba_1;
naredba_2;
naredba_k
until (uslov);
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);
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; }
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);
}
5*/
5*/
4*/
#include <stdio.h>
main()
{ int x,sum=0;
while(scanf("%d",&x)==1)
sum+=x;
printf("Ukupan zbir je %d\n",sum);
}
Predrag S. Stanimirovi
Programski jezici
65
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) ;
}
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);
}
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.
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");
}
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);
}
Primeri
Primer. Uitavanje neodreenog broja prirodnih brojeva i izraunavanje njihove sume.
for(sum=0; scanf("%d", &x) ==1; )
sum +=x;
70
/* beskonacni ciklus */
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);
}
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);
}
}
72
Takoe, ekvivalentni su sledei beskonani ciklusi:
for(;;) operator
i
while(1) operator.
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
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++);
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);
}
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.
i
repeat
naredba_1;
naredba_2;
naredba_k
until (uslov);
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}
76
end {Suma2};
xk
k 0 k!
sa tanou . Sumiranje prekinuti kada bude ispunjen uslov
xn/(n!) <
k 0
xk
,
k!
i := i+ 1
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.
Predrag S. Stanimirovi
77
Programski jezici
kraj;
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
@@
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+
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
i, j
i, 4 , j, i - 1
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
@8 <
D
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]
@@
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
@
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
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.
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
@
D
@
@
@
D
D
D
@@
HL
DD
@@@
D@
D
DD
1+t
, x, 3
1
1+ 1
1+x
, 67
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
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;
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;
Predrag S. Stanimirovi
83
Programski jezici
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
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 ;
}
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.
Predrag S. Stanimirovi
Programski jezici
85
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.
Predrag S. Stanimirovi
Programski jezici
87
Glavni program
Funkcija
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);
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
Predrag S. Stanimirovi
89
Programski jezici
end;
a[k] := a[i];
a[i] := MAX;
end;
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 ) .
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)
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;
PERM(A[I], I)
(2)
PERM(I, A[I])
tanh(a n b)
tanh 2 (a 2 b 2 )
tanh 2 (a m b)
tanh(a 2 b 2 )
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.
Predrag S. Stanimirovi
Programski jezici
93
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.
za n>l
1,
za n = 0
n! =
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;
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
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
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));
#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);
}
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. 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);
}
Predrag S. Stanimirovi
101
Programski jezici
102
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
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); }
ili
return(izraz); tj return izraz;
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);
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);
return(an);
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;
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);
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
{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();
}
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
/* 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.
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);
}
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);
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; }
}
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);
}
#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);
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");
}
Predrag S. Stanimirovi
117
Programski jezici
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));
}
Predrag S. Stanimirovi
auto char c;
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 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)
Module[{promenljiva=vrednost,...}, program ]
Module[{x, y, ...}, procedura],
Module[{x=x0, y=y0,...}, procedura]
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
h = 2 * Pi n ,
i * h, N Sin i * h
i, 0, n
0, 0. ,
, 1. ,
p,
0. ,
3p
, - 1. , 2 p , 0.
2
@
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;
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;
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
Predrag S. Stanimirovi
123
@
@
D
@
@
D
D
8
<
D
Programski jezici
i, 1, 6
1
2
3
4
5
izlaz
@
D
@
D
@
8
<D
Sin n Pi
Sin n p
Block n = 1 2 , %
@
D
@
D@
@
8
<
@
D
D
D
@
D
n = 1 2 , Print f n
Print n ;
1
n
Null3
@
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
@
D
@
8
<
D
@
DL
H
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
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
t=0 ,
With
t = 1 , Print t + 1
; Print t
t = x + 1 , 2 + t^2
@
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
126
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.
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];
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);
}
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;
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 *)
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
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
naeni
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)
134
s2 sa krajem niske s1. Mora da se alocira dovoljno
memorije za s1.
char *strncat(char *s1, char *s2)
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*/ }
Predrag S. Stanimirovi
135
Programski jezici
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);
Predrag S. Stanimirovi
137
Programski jezici
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);
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;
Predrag S. Stanimirovi
139
Programski jezici
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
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.
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. 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]);
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);
}
}
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];
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.
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);
}
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)
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 */
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 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
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 ) ;
Predrag S. Stanimirovi
151
Programski jezici
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
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);
}
156
writeln('Zadajte matricu b');
ucitavanje(b, m, p);
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]);
}
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 ;
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
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 ;
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.
164
var
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.
};
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
Sada se elementima strukture student moe pristupiti koristei operator indirekcije '*' i
operator '.':
(*pstudent).ime
(*pstudent).indeks
(*pstudent).godina
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} },
};
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
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;
}
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);
}
definie se ime celi kao ekvivalentno kljunoj rei int. Sada se moe pisati
celi i, j, n;
Izraz
typedef double vektor[20];
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];
Predrag S. Stanimirovi
175
Programski jezici
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;
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);
}
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;
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;
Predrag S. Stanimirovi
179
Programski jezici
if(input_end = = true)
Sada je
pon=0, uto=1, sre=10, cet=11, pet=12, sub=100, ned=101.
ekvivalentan je sa
ovaj dan=(enum dani)0;
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.
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
Predrag S. Stanimirovi
181
Programski jezici
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.
ili
with Student, Dan_rodj do
begin
mesec := maj; dan := 14;
end;
godina := 1963
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.
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;
Predrag S. Stanimirovi
185
Programski jezici
Razlika skupova
Razlika dva skupa predstavlja se znakom -.
Sboja1 := [crvena, zuta, violet];
Sboja := Sbojal - [zuta, violet];
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;
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.
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.
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
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.
192
if (I = 215) or (I = 220) or ... or (I = 275) or (I = 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
end {record};
F : Tipdat;
gde je
Ti pdat tip datoteke, ili anonimno sa:
var
F : file of Tipslog;
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, 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);
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.
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
202
begin
clrscr;
write('Ime datoteke za citanje? '); readln(imefajla);
dobro:=postoji(imefajla); sigurnocitanje;
siguranupis;
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)
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);
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.
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.
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.
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 '.
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);
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
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);
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)
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.
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.
i vrednosti a[2]:
a[2] = 7
@
D
@
D
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
8@
D@
D<
9, 7, a 3 , a 4 , 0
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
1
2
@D
@D
@D
?area
Global`area
area square
=1
area triangle
= 1
2
4 + area pentagon
vektor {a,b,c}
matrica ija je prva vrsta vektor {a,b}a druga vektor {c,d}
8
8<
8<
<
8<
Definicija matrice m:
a, b , c, d
a, b
8<
8 <
8
<
b
q + p x, q + p y
x + xp + xpp, y + yp + ypp
x xp + y yp
Predrag S. Stanimirovi
215
Programski jezici
8 <
8
8 <
8 <
<
H LH L
a x + b y, c x + d y
a2 + b c, a b + b d , a c + c d, b c + d2
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"]
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
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;
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;
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
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 ;
:= 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;
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.
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.
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
until ch='.';
226
writeln;
end;
begin
formirajstek(vrh); ispis(vrh);
end.
Predrag S. Stanimirovi
end;
end;
pop(c,vrh);
end;
227
Programski jezici
racunaj:=ord(c)-ord('0');
begin
writeln(racunaj);
end.
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.
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
ispisreda(prvi);
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
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;
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;
...
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
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);
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
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).
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
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
*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);
}
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
246
Predrag S. Stanimirovi
247
Programski jezici
return(p);
}
248
novi->inf =c;
umetni(novi, &pocetak);
}
printf("Sadrzaj liste:\n");
pisi(pocetak);
brisi(&pocetak);
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);
}
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
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
Postavi(PosX,PosY:real);
Translacija(dx,dy:real);
Simetrija;
Rotacija(a:real);
zaglavlje;
Pozicija;
Izvestaj;
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.
Predrag S. Stanimirovi
255
Programski jezici
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.
Predrag S. Stanimirovi
257
Programski jezici
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;
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
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).
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.
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.
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.
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.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 ...
};
// podaci
// metodi
Predrag S. Stanimirovi
Programski jezici
271
public:
float GetX()
float GetY()
}
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
/* metod */
/* podatak: ime i prezime */
/* podatak: koliko ima godina */
<<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;
272
Pera.ime=Petar Markovic; /* nedozvoljeno */
mojOtac.god=55;
/* takoe nedozvoljeno*/
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.
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";
}
Konstruktorom klase automatski se aktivira kod deklaracije objekta klase koja odgovara
konstruktoru. Destruktorom se unitava objekat na koji se primenjuje.
Predrag S. Stanimirovi
275
Programski jezici
//poziva se X(double)
//poziva se X(char *)
//poziva se X()
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.
*/
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();
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);
};
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
}
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.
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.
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.
Predrag S. Stanimirovi
Programski jezici
283
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
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.
284
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
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
{
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
//
//
//
//
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)
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.
//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);
}
//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**
}
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.
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.
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 {/**/};
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
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.
{ i=ip;}
private:
friend void g (int, X&);
//prijateljska globalna funkcija
friend void Y::h ();
//prijateljska lanica druge klase
int i;
};
Globalne funkcije koje predstavljaju usluge neke klase ili operacije nad tom klasom
nazivaju se klasnim uslugama.
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
...
};
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;
};
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
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 :
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.
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
Primer:
class X {
static int
int
public:
static int
int
};
x;
y;
f(X,X&);
g();
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;
//
//
//
//
//
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
};
/* 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
Predrag S. Stanimirovi
297
Programski jezici
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 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)
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@ ()
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)
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
};
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
void main () {
int i ;
cin>>i;
//uitava se i
cout
<<i=<<i<<\n;
//ispisuje se npr.: i=5 i prelazi
u novi red
}
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;
}
que;
que.put(e);
if (que.get ()->isUrgent())...
Predrag S. Stanimirovi
301
Programski jezici
const
int
int
int
int
virtual
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
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);
}
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
(const T&);
304
void
void
void
void
Promena orijentacije na ogranieni red veoma je jednostavna. Ako se eli neogranieni red,
dovoljno je promeniti samo:
typedef
QueueU<Event*>
EvenrQueue;
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
Realizacija:
class Derived : public Base //
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";
}
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);
};
Predrag S. Stanimirovi
};
int
int
int
int
311
Programski jezici
k1;
k2;
broj;
sinonim;
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();
}
Predrag S. Stanimirovi
313
Programski jezici
Matrix& operator +=
Matrix& operator
Matrix& operator *=
Matrix& operator *=
(const Matrix&);
-= (const Matrix&);
(const Matrix&);
(const Type&);
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
316
return m;
}
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);
}
318
@
D
@
D
@
D
@
@
D
D
@
D
@
@
D
D@
D
@
D
@
D
@
D
h x_
+ h: y_
:= hplus x, y ;
P h x_ ,:x_ := hp x ;
f_ h x_ : := fh f, x ;
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
@
@
D
D@
D
Global`f
f g x_ := fg x
@
D
@
D@
D8
@
D
@
D
?g
Global`g
g x_ ^:= expg x
<
Predrag S. Stanimirovi
319
Programski jezici
@
D
@
D@
D@
D
@
D
@
D
?g
Global`g
g x_
^:= expg x
g x_
+g
y_ ^:= gplus x, y
gplus 5, 7
@@
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
TagSetDelayed::tagpos :
Tag g in h w g x_ , y_
320
$Failed
donja vrednost za f
donja vrednost za f
gornja vrednost za g koji prestavlja argument
gornja vrednost za g koji prestavlja glavu
@D
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
Predrag S. Stanimirovi
321
Programski jezici
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.
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);
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.
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.
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;
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
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;
332
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
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;
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');
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
Slika 9.
Predrag S. Stanimirovi
339
Programski jezici
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.
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
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;
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]);
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 *}
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
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;
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.
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.
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;
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;
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 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;
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;
Predrag S. Stanimirovi
357
Programski jezici
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;