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

Fakultet ekonomije i turizma

'Dr. Mijo Mirkovi' - Pula

Osnove programiranja
u programskom jeziku C++

Doc.dr.sc. Giorgio Sinkovi


Mr.sc. Igor kori

Pula, oujak, 2006.

1
Sadraj

1. Uvod 4
1.1. Kratki pregled razvoja raunala 4
1.2. Razvoj programskih jezika 8
1.3. Postupak izrade programa 11
1.4. Opis rada u okruenju Dev C++ 22
1.5. Uvod u C++ 25
2. Varijable i konstante 29
2.1. Deklaracija varijabli 31
2.2. Konstante 37
2.3. Primjeri programa s varijablama i konstantama 39
3. Operatori 40
3.1 Operator pridruivanja 40
3.2. Aritmetiki operatori 41
3.3. Kombinirani operatori 42
3.4. Poveanje i smanjenje vrijednosti varijable 42
3.5. Relacijski i logiki operatori 44
3.6.Uvjetni operator (?) 45
3.7. Konverzija podataka 45
3.8.Overflow (prekoraenje vrijednosti) 47
3.9. Zaokruivanje rezultata 48
3.10. Komunikacija preko konzole 49
4. Naredbe za kontrolu toka programa 51
4.1. Naredba if ..else 51
4.2. Naredba (petlja) while 55
4.3. Naredba dowhile 56
4.4. Naredba for 57
4.5. Naredbe break 59
4.6. Naredba continue 60
4.7. Naredba goto 61
4.8. Naredba switch 63
4.9. Generiranje sluajnih brojeva 63
5. Funkcije 68
5.1. Prijenos argumenata po vrijednosti i po referenci 72
5.2. Podrazumijevane (default) vrijednosti argumenata 73
5.3 Prenapregnute funkcije 74
5.4. Jo neka svojstva funkcija 75
5.5. Postupak izrade programa - pseudokod 76
6. Polja (tablice) 84
6.1. Jednodimenzionalna polja 84
6.2. Prijenos polja funkcijama 86
6.3. Program za sortiranje podataka (Buble sort) 87
6.4. Linerano pretraivanje polja 92
6.5. Binarno pretraivanje polja 93
6.2. Dvodimenzionalna (viedimenzionalna) polja 95

2
7. Znakovni nizovi 97
7.1. Primjer uporabe znakovnih nizova za obradu prijavnica 100
8. Pokazivai i reference 107
8.1. Operator adrese 107
8.2 . Operator dereference 110
8.3. Uporaba pokazivaa 111
8.4. Odnos pokazivaa i polja 114
8.5. Dinamiko alociranje memorije (operatori new i delete) 115
9. Ulazno/izlazni tokovi 121
9.1. Standardni razred string 121
9.2. Ulazni i izlazni tokovi 124
10. Koncept objektno orijentiranog programiranja 136
10.1. Nestrukturirano programiranje 137
10.2. Proceduralno (strukturirano) programiranje 138
10.3. Modularno programiranje 140
10.4. Objektno orijentirano programiranje 141
10.5. Razredi 142
10.6. Konstruktori i detruktori 149
10.7.Konstruktor kopije 152
10.8. Nasljeivanje 153
10.9. Polimorfizam 156
11. Predloci 158

3
1. Uvod

1.1. Kratki pregled razvoja raunala

Gledajui u povijest, moe se primijetiti da su ljudi oduvijek nastojali olakati svoj rad,
odnosno trudili su se da uz to manja osobnog napora postignu to vee uinke. S tim su
ciljem najprije uzgojili i upregnuli domae ivotinje i koristili njihovu snagu, da bi
nakon toga poeli koristiti i snagu drugih ljudi, robova. Nauili su iskoritavati i prirodne
izvore energije poput rijenog toka za nizvodni prijevoz, snagu vjetra za pokretanje
plovila itd. Kada su stvoreni uvjeti da pojedinci mogu preivjeti bez osobnog fizikog
rada, oni su dobili vie vremena za razmiljanje. Razvile su se nove, intelektualne
djelatnosti iz kojih su nastale umjetnost i znanost. Znanost je s jedne strane irila granice
ljudske spoznaje, pa s time postavljala pred ljude nove i sloenije ciljeve, a s druge strane
je razvijala sredstva, danas bi rekli tehnologiju, koja je olakavala postizane ovih ciljeva.
Navedena je tehnologija bila preteno orijentirana na svladavanje fizikih prepreka, tako
na primjer izum kotaa je omoguio prijevoz tekih predmeta uz mali utroak energije,
katapulti su dobacivali velike gromade na dodat nezamislivu udaljenost, a vodovod je na
primjer, koristio prirodni tok vode i na taj nain nije vie trebalo fiziki prenositi vodu od
njenog izvora do mjesta troenja, itd. Izum strojeva i industrijska revolucija, su ubrzale
taj proces do dotad nesluenih razmjera. Dolo je do velikog porasta broja ljudi koji se
bavi intelektualnim aktivnostima, u odnosu na one koji se bave fizikim radom. Zbog
toga je bilo za oekivati da e se ljudska tenja za prenoenje rada na strojeve, prenijeti i
na podruje intelektualnih aktivnosti. Izum elektronikog raunala predstavlja dosad
najznaajniji korak na tom planu. Iako se iz samog naziva vidi da je osnovna aktivnost
raunala bila raunanje tj. izvoenje nekih matematikih operacija, iz dosadanjeg se
razvoja vidi da raunalo zamjenjuje sve vie rutinskih i ne samo rutinskih intelektualnih
aktivnosti.
Danas se moe utvrditi da je razvoj raunala proao kroz etiri glavne faze:
1. Runa obrada abacus kojeg su koristili ve babilonci 300 godina prije Krista i koji
se u raznim oblicima zadrao skoro do dananjih dana.
2. Mehanika obrada Francuski matematiar i filozof Blaise Pascal (1623-1662)
izradio je 1642. mehaniki stroj za zbrajanje i oduzimanje. Gottfried Wilhelm Von
Leibniz (1646-1716) je pedesetak godina kasnije izradio mehaniki stroj koji je mogao
obavljati sve etiri osnovne raunske operacije.
3. Elektromehanika obrada - iako su se strojevi za mehaniko razvijanje neprekidno
razvijali, novi impuls razvoju raunala dao je izum buene kartice u drugoj polovici 19
stoljea.
4. Elektronika obrada Prvim elektronikim raunalom smatra se ENIAC
(Electronic Numerical Integrator And Computer) koje je izraeno 1946. godine. Bio je
tisuu puta bri od bilo kojeg stroja dotad, a mogao je u jednoj sekundi izvesti 5000
operacija zbrajanja1, 357 mnoenja i 38 dijeljenja. Bio je teak 30 tona i zauzimao
povrinu od 167 etvornih metara.

1
Usporedbe radi dananja osobna raunala mogu izvesti nekoliko desetaka milijuna zbrajanja u sekundi.

4
ENIAC se u slijedeih par godina usavravao i uslijedila je i izrada raunala za
komercijalne svrhe. Uslijedio je brzi razvoj u kojemu je vrijedno istaknuti slijedee
vane dogaaje:

1. generacija raunala 1946. ENIAC i sva raunala nakon toga temeljila su se na


tehnologiji elektronskih cijevi, pa je to i bio osnovni razlog za velike dimenzije
raunala i ogroman utroak elektrine energije.
2. generacija raunala 1957. izum tranzistora koji su zamijenili elektronske cijevi
utjecao je na bitno smanjenje dimenzija i poveanja brzine raunala.
3. generacija raunala 1964. uvoenje integriranih krugova i LSI (Large Scale
Integration) tehnologija
4. generacija raunala 1970. VLSI (Very Large Scale Integration) integrirani
sklopovi tzv. chip graen od silicija.
5. generacija raunala GSI (Giant Scae Integration) itavo raunalo u jednom
chip-u. Nije zaivjela zbog ergonomskih razloga

Tipina struktura dananjeg elektronikog raunala prikazana je na slici 1.1.

Slika 1.1: Tipina struktura elektronikoga raunala

Elektroniko
raunalo

Sredinja Ulazne Izlazne Vanjske


jedinica jedinice jedinice memorije

Tipkovnica
Zaslon monitor Magnetni zapis
Mi i inaice
Pisa- tampa Disk
Svjetlosna olovka Plotter -crtalo Disketa
Touch screen Projektor Vrpca
Skener Robotizirani
Digitalni fotoaparat strojevi Optiki zapis
Mikrofon CD ROM
Bar code itai DVD
itai magnetnih
kartica

Struktura sredinje jedinice je prikazana na slici 1.2.

5
Slika 1.2. Struktura sredinje (centralne) jedinice

U sredinjoj se jedinici izvode programi. Programi kao i podaci koje treba obraditi
privremeno se pohranjuju u memoriji. Programi se sastoje od pojedinanih naredbi
kojima se obrauju pojedini podaci, koji su takoer pohranjeni u pojedinim dijelovima
memorije, koje nazivamo poljima. Ti se podaci prebacuju na druge lokacije u memoriju
ili u aritmetiko- logiku jedinicu gdje se po potrebi usporeuju, zbrajaju ili se nad njima
izvode neke druge aritmetike ili logike operacije. Podaci se obino uitavaju iz neke
ulazne jedinice i nakon to su na njima izvrene odgovarajue operacije, upisuju se na
neku izlaznu jedinicu ili na vanjsku memoriju.

Za razliku od materijalnih, opipljivih dijelova raunala koji se zajedniki nazivaju


hardver, skup programa i podataka koje raunala koriste odnosno obrauju, naziva se
softver. Dakle hardver predstavlja materijalnu, a softver nematerijalnu komponentu
informacijskih sustava.

Softver se moe shvatiti kao suelje pomou kojega ovjek komunicira s raunalom.

6
Memoriju raunala je najjednostavnije zamisliti kao sae u kojem svaka elija
predstavlja osnovnu adresibilnu jedinicu- bajt. Jedan bajt se sastoji od 8 binarnih
znakova bitova i moe sadravati 28=256 razliitih znakova2.
Svaki bajt u memoriji ima svoju adresu koja poinje od 0 te se slijedea adresa
poveava za 1. Uobiajeno je da se adrese prikazuju u heksadecimalnom sustavu (s
bazom 16).

Slika 1.3: Shematski prikaz memorije raunala

0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 1819 1A 1B1C1D1E 1F 20 21 22 23

24 25 26 .

. . . . . . .

U memoriju raunala se privremeno pohranjuju naredbe i podaci. Openito uzevi ni


naredbe ni podaci ne mogu se smjestiti u samo jedan bajt, nego se mora koristiti vie
bajtova.
Skup od vie bajtova, u kojemu je smjeten jedan podatak naziva se polje (field). Polje
moe biti razliite duljine, od teoretski jednog bajta do nekoliko desetaka bajta, to ovisi
o veliini podataka . Osim pojmova polja i bajta uz memoriju se pojavljuje i pojam
rije (word). Veliina rijei u memoriji ovisi o njenim fizikim karakteristikama, pa tako
16-bitna raunala imaju rije od dva bajta, a 64- bitna raunala imaju rije od 8 bajta.

Koje je ogranienje u brzini rada raunala ?

U raunalu se sve aktivnosti odvijaju na temelju protoka elektrine struje, koja ima
brzinu svjetlosti tj. 300.000 km/sekundi.

Ako raunalo radi na frekvenciji od 3 Ghz znai da u 1 sekundi napravi 3.000.000.000


ciklusa.

300.000.000 metara
3.000.000.000

daje rezultat 1/10 metra, odnosno svjetlo u jednom ciklusu prevali 10 cm.

2
Postoje i raunala kod kojih jedan bajt nema 8 nego na primjer 6 bitova, ali su rijee u upotrebi.

7
1.2. Razvoj programskih jezika

Softver predstavlja suelje preko kojeg ovjek komunicira sa raunalom.

ovjek Softver Raunalo (hardver)

Softver se razvrstava po razliitim kriterijima, kao na primjer:

Slika 1.4. Klasifikacija softvera

Softver

Sistemski Korisniki
(Sustavni)

Operativni sustavi (Windows NT, UNIX, Linux, ...)

Pomoni programi (utilities)


Device drivers (pokretai)
Prevoditelji (language translators, compilers)
(Mreni programi)

Po mjeri korisnika (Customised


software)
Gotovi programski proizvodi (packaged
Programski jezici
application software)

Igre na raunalu (Computer games)


Softver za uenje (Educational
software)
Problemski orijentiran (Task oriented )

Obrada teksta (Word procesor) (WORD, Wordperfect, Wordstar,..)


Izrada tablica (Spreadsheet software) (EXCEL, Lotus,...)
Upravljanje bazama podataka (Database management) (Access, ORACLE, ..)
Prezentacijski softver (PowerPoint, Lotus Freelance Graphics)
Komunikacijski softver (Internet Explorer, Netscape Navigator, ...)

8
Razvoj programskih jezika tekao je usporedno s razvojem elektronikih raunala .

Prva generacija programskih jezika - stvorena je kada i prva generacija elektronikih


raunala, a temeljila se na tzv. strojnom jeziku koji se pisao u binarnom obliku tj. kao
nizovi jedinica i nula. Naredbe u strojnom jeziku su naelno imale slijedei izgled:

to treba uiniti Odakle treba uzeti Kamo staviti rezultat

Sve je bilo prikazano u u binarnom kodu, s time da su polja Odakle treba uzeti i Kamo
staviti rezultat predstavljaju adrese nekih polja u memoriji. Broj naredbi strojnog jezika
je ogranien, on ovisi o samom raunalu i danas se kree od 80-tak za RISC (Reduced
Instruction Set Computer) do oko 150 za velika CISC (Complex Instruction Set
Computer) raunala. Treba napomenuti da bez obzira na razvoj raunala i softvera,
strojni je jezik ostao jedini kojeg raunalao neposredno 'razumije'. Meutim s obzirom da
je taj jezik neprikladan za ljude, razvoj je iao prema programskim jezicima koji su bili
blii logici i nainu izraavanja koje koriste ljudi. Usporedno su se razvili programi
prevoditelji (compileri), koji takve naredbe prevode na strojni jezik.

Druga generacija programskih jezika - Umjesto binarnog strojnog jezika koji je


nepraktian za pamenje, pisanje i itanje, uvedene je tzv. mnemoniki kod. Dakle
umjesto binarnih brojeva piu se simbolike oznake koje su krae za pisanje i lake ih je
upamtiti. Programski jezik s navedenim karakteristikom zove se assembler. Iz same
definicije izlazi da je assembler jezik 1:1 tj. jedna naredba u assembleru odgovara jednoj
strojnoj naredbi.

Primjer naredbe u assembleru je :

add broj, 4

Ova bi se naredba u jeziku C++ napisala :

broj=broj + 4;

Dakle u polje koje odgovara adresi broj dodaje se 4.

Sutina naredbi se nije promijenila, samo se umjesto memorijskih adresa navode


simboliki nazivi polja.
Zanimljiv je koncept adresiranja putem relativne adrese. Reeno je da svakom polju u
memoriji, koje je ve u jezicima druge generacije prezentirano nekim nazivom (kao to
je u gornjem primjeru broj) pripada odgovarajua adresa u memoriji. Pored adrese
prevoditelj poznaje i duljinu polja koja se obino navodi prilikom definicije polja u
programu. Prilikom prevoenja programa naredbe se iz konkretnom programskog jezika
prevode u naredbe strojnog jezika, pa se umjesto naziva polja u strojnom jeziku navode
njihove adrese u memoriji. Meutim u fazi prevoenja programa nije poznato gdje e se

9
u memoriji smjestiti program u fazi njegovog izvoenja. Programi se prilikom izvoenja
naime, pune jedan iza drugog redom kako se pozivaju, pa lokacija pojedinog programa u
memoriji ovisi o sluaju. Dakle, program se kod svakog poziva moe puniti na drugu
adresu. Zbog toga polja dobivaju relativnu adresu koja pokazuje poloaj (odmak)
dotinog polja u odnosu na poetak programa. Stvarna adresa pojedinih polja (apsolutna
adresa)dobiva se kao zbroj relativne adrese i adrese punjenja programa, koja je poznata
tek neposredno prije izvoenja programa.

Trea generacija programskih jezika - Programski se jezici formalno i logiki nastoje


pribliiti ljudskom nainu izraavanja. Formalno se naredbe programskih jezika
pribliavaju govornom jeziku (engleskom). Logika konstrukcija programskih jezika
nastoji se pribliiti ljudskom nainu razmiljanja. Zbog toga jedna se naredba u takvom
jeziku (na primjer razne petlje o kojima e biti govora kasnije) moe sastojati od vie
strojnih naredbi, pa se za takve jezike kae da su 1:n.

Namee se pitanje zato se ravilo vie razliitih programskih jezika ?


Postoje najmanje dva razloga tome, od kojih je jedan objektivne, a drugi subjektivne
prirode:
1. prvi razlog za postojanje razliitih programskih jezika je bila njihova orijentacija
na podruje primjene. Dakle ako se razmiljalo o matematikim i tehnikim
proraunima, onda se nametala potreba za programskim jezikom koji 'poznaje'
matematike operacije i funkcije, moe raditi sa irokim rasponom brojeva od
onih vrlo malih, na primjer reda veliine 10-20 do onih sa nekoliko desetaka
znamenaka. Kada su u pitanju poslovne primjene, odnosno novac, raspon brojeva
nije tako velik, recimo danas od najmanje 1 lipe ili 0,01 kune, pa do nekoliko
milijardi ili bilijuna kuna. Tu je meutim bitna preciznost jer raunovodstvo na
primjer, mora biti tono ' u lipu '.
2. drugi je razlog konkurentska borba meu proizvoaima raunala na tritu i
nedostatak suradnje.

Danas se spominje broj od preko 2500 programskih jezika koji su razvijeni u pedesetak
godina3 .

Kao prvi programski jezik tree generacije uzima se FORTRAN. Njegov je razvoj
zapoeo 1954. ali se kao godina u kojoj je objavljena verzija koja slii dananjoj, uzima
1957. Naziv mu potjee od engleskog 'FORmula TRANslation' iz ega je oito da mu je
namjena bila za znanstveno-tehnike proraune.

Prvi program tree generacije za poslovne primjene bio je COBOL (COmon Business
Oriented Language) koji je objavljen 1959. godine.

U to su se vrijeme razvijeni i jezici ALGOL (ALGOrithmic Language) razvijen takoer


za znanstveno-tehnike primjene 1958. te neto kasnije (1964.) IBM je razvio jezik PL/I
3
Vidjeti na primjer http://www.oreilly.com/pub/a/oreilly/news/languageposter_0504.html

10
(Programming Language 1) koji je nastao kao spoj Fortrana i Cobola, pa je bio
univerzalno primjenljiv. Iako je jezik bio univerzalne namjene i koristio se vie od 30
godina, njega nisu prihvatili drugi proizvoai raunala, pa ga je konano istisnuo u
meuvremenu razvijeni jezik C.

Godine 1964. je objavljen i jezik BASIC (Beginer's All-purpose Sybmolic Instruction


Code), slijedili su Pascal (1970.) i C (1971.)

etvrta generacija programskih jezika (4GL) termin je uveden u ranim


osamdesetim godinama kada su se od programskih jezika 4. generacije oekivale
slijedee karakteristike:

Orijentacija na ovjeka
Osim profesionalnim programerima dostupan i krajnjem korisniku
'Izravna' komunikacija s bazama podataka
Izbjegavanje proceduralnih elemenata (ako ih ima, onda moraju biti strukturirani)
Omoguiti interakcijsku komunikaciju ovjeka i stroja
Jednostavni za uenje

Do danas je razvijeno mnogo takvih proizvoda pa postoji i njihova podjela prema


namjeni :

Za pretraivanje baza podataka (SQL, FOCUS,..)


Generatori izvjetaja ( BuildProfessional, RPG II,)
Za manipulaciju i analizu podataka (Informix, Clarion, )
Kreatori GUI (Visual Basic, Delphi,)

Primjeri razliitih programskih jezika:

C++ Source Code Assembly Language Machine Language


C++ izvorni kod Asembler Strojni jezik
IF {COUNT=10 Compare A to B Compare 3477 2883
GOTO DONE; If equal go to C If = go to 23883
ELSE Go to D Go to 23343
GOTO AGAIN;
}
Strojni kod (simulirani)
10010101001010001010100
10101010010101001001010
10100101010001010010010

Programski se jezici openito dijele na prevoditelje i interpretere. Programi


prevoditelji, kao to je ve reeno, prevode izvorni kod u strojni jezik. Program se
kasnije izvodi u strojnom jeziku. Kod interpretera programi ostaju u izvornom

11
obliku (ili meu obliku koji se naziva bytecode) u kojem ostaje i u fazi izvoenja
programa.
Ove su mogunosti prikazane na slici 5. Vidljivo je da jezik C++ kao i C i Cobol
spadaju u prevoditelje koji se u fazi izvoenja (RUN) izvode u strojnom jeziku.
Za razliku od njih JAVA i Visual Basic se prevode u tzv. bytecode oblik, dok dBase i
Basic ostaju trajno u izvornom kodu.

Koje su prednosti pojedinih rjeenja ? Program se u strojnom kodu u pravilu izvodi


bre nego u bytecodu ili izvornom obliku. Meutim troi se vie vremena na
prevoenje. S druge strane, kada se radi o strojnom jeziku, raunalo na kojemu se
izvodi program ne mora imati instaliran program prevoditelj. Drugim rijeima
program se moe prevesti na jednom raunalu i onda verziju u strojnom jeziku
prenijeti na desetak ili stotinu drugih raunala, bez da se plaa licenca za program
prevoditelj. To kod interpretera nije sluaj.

Slika 1.5: Razlike izmeu prevoditelja i interpretera

12
1.3. Postupak izrade programa

Postupak izrade programa, odvija se kroz nekoliko koraka koji su prikazani na slici 6:

Slika 1. 6: Postupak izrade programa

Definiranje problema

Definiranje algoritma

Dokumentiranje
algoritma

Pisanje programa

Testiranje programa

Program
OK?
Ne

Dokumentiranje
programa

Implementiranje
programa

Koritenje i
odravanje

Iz slike 6. se vidi da izrada programa poinje sa definiranjem problema koji se eli


rijeiti. Slijedi definicija algoritma, odnosno postupka kojim e se rijeiti program.
Ako je na primjer problem rijeiti kvadratnu jednadbu:

13
ax 2 bx c 0

Onda algoritam za rjeenje moe biti formula:

b b 2 4ac
x1, 2
2a

Slijedi korak dokumentiranja algoritma. Dokumentiranje algoritma je nuno da bi


programer, koji treba izraditi konkretni program, nedvojbeno znao to mu je initi.
Na primjer, konkretan sluaj moe biti takav da kompleksna rjeenja kvadratne
jednadbe zbog nekih razloga nisu prihvatljiva, pa ih ne treba raunati.
U dokumentaciji algoritma tada e pored ostalog pisati neto kao:

Ispitati diskriminantu (tj. b 2 4ac ) pa ako je manja od nule, program treba napisati
poruku 'Jednadba nema realnih rjeenja' i zavriti s radom.

Uz dokumentaciju algoritma treba priloiti i test podatke, tj. podatke s kojima e


programer provjeriti radi li program ono to se od njega oekuje. U konkretnom
sluaju to bi moglo biti kao to slijedi:

Test podaci:
a=1, b=4, c=4 rezultati su: x1= x2=-2
a=1, b=2, c=-3 rezultati su: x1= -3, x2=1
a=0, b=-2, c=6 rezultati su: 'Postoji samo jedan rezultat ex= 3'
a=-1, b=0, c=9 rezultati su: x1= x2=3
a=2, b=1, c=2 rezultati su: 'Jednadba nema realnih rjeenja'

Nakon to programer dobije dokumentaciju za izradu programa , koju obvezno ine


opis problema, opis algoritma i test podaci, on najprije izrauje program (kae se da
pie programski kod ili kodira) a nakon toga testira program, tj. izvodi uz razliite
uvjete, kako je navedeno u test podacima i provjerava da li dobiven oekivani
rezultat. U sluaju da ima odstupanja on korigira program i ponavlja testiranje sve
dok ne dobije oekivanje rezultate.
Kad je dovrio izradu i testirane pie dokumentaciju programa. Dokumentaciju
programa ine podaci koje je dobio (opis program, algoritma i test podaci) i njima
prikljuuje izvorni kod programa (kako ga je on napisao i testirao) te rezultate
testiranja. Po potrebi pie i druge napomene, koje su bitne za razumijevanje i
naknadno odravanje programa.

Ovako testirani i dokumentirani spreman je za implementaciju, tj. isporuku i


instalaciju kod korisnika, koji ga dalje koristi i brine o njegovom odravanju4.
Gornji primjer programa za rjeenje kvadratne jednadbe je previe jednostavan pa
su opis, problema i opis algoritma trivijalni.
Inae se za opis algoritma, najee koristi jedna od slijedeih metoda:

4
est je sluaj da o odravanju programa trajno brine onaj tko ga je isporuio.

14
Neformalni tekstualni opis
Pseudokod koji za opis algoritma koristi obini jezik uz potivanje nekih
ogranienja programskih jezika
Grafiki opisi koje koriste razliite tipove dijagrama.

Opisivanje algoritma pseudokodom pokazat e se nakon to se obrade osnovni


elementi jezika C++. U nastavku e se prikazati grafiko opisivanje na dva
jednostavna primjera .

Primjer1:
U studentskoj referadi se prikupljaju prijavnice o poloenim ispitima studenata.
Svaka prijavnica sadri slijedee podatke: matini broj studenta, ime i prezime,
naziv predmeta, ocjena na ispitu i datum polaganja. Osobe koje rade u studentskoj
referadi su za svaki ispitni rok sortirale prispjele prijavnice po matinom broju
studenata. Sada imaju dvije hrpe prijavnica, jednu kojoene prijavnice iz ljetnog
ispitnog roka i drugu u kojoj su prijavnice iz jesenskog ispitnog roka. Dakle svaka je
hrpa sortirana po matinom broju studenata. Treba izmijeati prijavnice iz te dvije
hrpe u jednu hrpu, tako da i ta nova hrpa bude sortirana po matinom broju studenta.
Navedeni primjer je klasini sluaj spajanja sortiranih datoteka koje se na engleskom
naziva merge.

Na slici 7. prikazana su dva skupa prijavnica (svaki red u tablici predstavlja jednu
prijavnicu) gdje su radi jednostavnosti isputeni ime i prezime studenta a i predmeti
su ifrirani sa P1, P2 itd.

Slika 1.7. Primjer podataka o prijavnicama

Ljetni ispitni rok - A Jesenski ispitni rok- B


MBR Predmet Ocjena
MBR Predmet Ocjena
1003 P1 3
1002 P1 3
1003 P2 4
1002 P2 4
1006 P1 2
1006 P4 2
1008 P3 4
1006 P3 4
1010 P1 5
1007 P1 5
1022 P2 3

15
Rezultat nakon spajanja te dvije tablice (hrpe) mora biti nova tablica (hrpa), kao to
je prikazano na slici 1.8.

Slika 1.8. Redoslijed prijavnica u spojenoj hrpi


MBR Predmet Ocjena

1002 P1 3

1002 P2 4

1003 P1 3

1003 P2 4

1006 P4 2

1006 P3 4

1006 P1 2

1007 P1 5

1008 P3 4

1010 P1 5

1022 P2 3

Ovdje je dobro napomenuti, da su ulazne hrpe, pa se to oekuje i od izlazne hrpe


prijavnica, sortirane po matinom broju studenata, te da je svejedno u kojem su
redoslijedu predmeti unutar toga. Zbog toga izlazno rjeenje nije jednoznano
odreeno jer bi na primjer bilo dobro i kad bi za studenta 1006, predmeti bili poredani
P1, P3, P4 ili P1, P4,P3 itd.

Postavlja se pitanje: Kako definirati postupak (algoritam) koji e uzimati jednu


za drugom prijavnice iz dvije hrpe koje su prikazane na slici 7 i slagati ih u
jednu hrpu, kao to je prikazano na slici 8?

16
Jedno rjeenje (koje je djelomino ispravno) prikazuje dijagram slici 1.9.

Slika 1.9: Postupak uzimanja i slaganja prijavnica

Ulaz
Start
1003 Izlaz
1003
Uzmi 1002
1006 A
A 1002
1008
1003
1010
Uzmi 1003
1022 B
C 1006

1006
NE 1006
DA A<B
1002 ? 1007
1002
B Sloi Sloi 1010
1006 A B
1022
1006

1007 Uzmi Uzmi


A B

to se dogaa ako se izvode naredbe kako prikazuje dijagram?

Naredbe treba poeti izvoditi od naredbe START redom prema dolje.


Uzmi A znai uzimamo prvu prijavnicu A koja nosi MBR jednak 1003.
Uzmi B znai da se uzima prijavnica iz B koja ima MBR jednak 1002.
Kada se usporede A i B (to jest polja MBR, dakle 1003 i 1002) ispada da uvjet A<B
nije zadovoljen, pa treba izvesti naredbu Sloi B, pa se prijavnica iz hrpe B (dakle
ona koja nosi MBR jednak 1002) slae kao prva u hrpu C
Slijedi naredba Uzmi B koja iz hrpe B uzima slijedei element koji je opet 1002 i
ide na usporedbu A i B

17
Uvjet A<B (1003 nije <od 1002) pa se opet izvodi naredba Sloi B koja (na drugo
mjesto, odnosno prekriva prethodnu prijavnicu u hrpi) stavlja tekuu prijavnicu
uzetu iz hrpe B, dakle opet onu koja nosi MBR jednak 1002.
Nakon toga slijedi naredba Uzmi B koja u hrpi B pronalazi slijedeu prijavnicu koja
nosi MBR jednak 1006 (prve dvije su ve uzete iz hrpe i sloene u hrpu C), te ide
na usporedbu A i B .
Uvjet A <B je sada ispunjen, pa se izvoenje logike nastavlja u drugoj grani.
Slijedi naredba sloi A, dakle na hrpu C se stavlja prijavnica iz hrpe A, to je jo
uvijek ona koja je bila prva uzeta i koja nosi MBR jednak 1003.
Slijedi naredba Uzmi A, koja opet nosi MBR jednak 1003 itd.

Nastavljajui slijediti logiku iz dijagrama, ispada da se prijavnice i dalje slau na


hrpu C redom koji je prikazan na slici 9. Logika e ipak u jednom trenutku pasti u
vodu. Kada e se to desiti ?

Sve e biti u redu do trenutka kad se iz hrpe B uzme zadnja prijavnica, koja nosi
MBR jednak 1007 i kada se ona sloi na hrpu C. (U tom trenutku e tekua
prijavnica iz hrpe A biti ona s MBR 1008 !).
Nakon naredbe Sloi B, nuno slijedi naredba Uzmi B, a hrpa B je u tom trenutku
prazna. ovjek e tada intuitivno uzeti prijavnice iz hrpe A, za koje zna da su ve
sortirane po MBR i jednu po jednu prebaciti na hrpu C.
Raunalo meutim nema intuicije, kada pokua 'uzeti prijavnicu iz hrpe ' a tamo ne
nae nita, dolazi do nenormalnog zavravanja programa koje se programerskom
govoru naziva 'pucanje programa'.

Kakvom se logikom moe premostiti ova prepreka kod raunala ?

Raunalo nikad ne moe uzimati prijavnice iz 'hrpe' nego iz neke datoteke. Kod
slaganja podataka u datoteku, radi izbjegavanja navedenog problema, na kraju se
postavlja oznaka 'kraj podataka'. Formalni sadraj oznake ovisi od raunala, odnosno
operacijskog sustava ali se prilikom svakog itanja datoteke moe ukljuiti provjera
da li je uitan 'kraj podataka' odnosno engleski 'end of file' ili skraeno EOF.

Dakle u konkretnom sluaju, uz izvoenje naredbe Uzmi B program ne bi naiao na


prazan slog nego na oznaku EOF i treba u logiku ugraditi postupak: 'Uzimaj redom
prijavnice iz hrpe A i prebacuj ih u hrpu C'.

Ovako kompletiran dijagram prikazan je na slici 1.10.

18
Slika 1.10: Cjelovita logika
slaganja prijavnica START

Uzmi
A

Uzmi
B

DA NE
A<B

Sloi Sloi
A B

Uzmi EO
Uzmi
A F B EO
A FB

EOF EOF
A B

Sloi B Sloi A

Uzmi B Uzmi A
END
EOF B
EOF A

19
Na slici 1.10. prikazano je kompletna logika rjeenja primjera 1. Vidi se da je
problem 'pucanja programa' prilikom uitavanja zadnjeg sloga izbjegnut sa
testiranjem uvjeta EOF koji se obino povezuje crtkanim linijama kako bi se
pokazalo da se ta grana izvodi samo izuzetno, tj. kada je zadovoljen navedeni uvjet.
Potrebno je skrenuti pozornost na jo dva detalja. Prvi detalj je da u grani nazvanoj
EOF B, dakle kada se prije zavrilo s uzimanjem prijavnica iz hrpe B, ponovno moe
desiti (i kad-tad mora se desiti) uvjet EOF A. Kad se taj uvjet dogodi, znai da su
iscrpljene i sve prijavnice iz hrpe A, pa program moe zavriti.

Drugi, ne manje bitan detalj, je da se uvjet EOF A mogao dogoditi i kod itanja (ili
uzimanja prijavnica) u glavnoj grani dijagrama. To bi se uostalom desilo da u
primjeru 1 podaci iz tablica A i B zamjene mjesta. Tada se, meutim ne smije zavriti
program, nego on mora ii na granu EOF A, kada mora zavriti s preslagivanjem
prijavnica iz hrpe B, pa da bi po nastanku uvjeta EOFB opet otiao na kraj programa.

Pitanja za vjebu:
1. Logika programa iz slike 1.10. ipak ima jednu 'rupu' zbog koje bi moglo doi do
pucanja programa. Moete li je identificirati ?
2. Kako bi na temelju rjeenja spajanja dvije hrpe prijavnica, rijeili program
spajanja tri hrpe prijavnica ?

Primjer2: Treba napisati program koji ispisuje redom prim brojeve od 3 do N. Prim ili
prosti brojevi su prirodni brojevi koji su djeljivi samo s 1 i samim sobom. Dakle da bi
utvrdili je li neki broj prim broj treba ga dijeliti redom s 2,3, itd. pa ako nije djeljiv ni s
jednim brojem do njega samog, on je prim broj kojeg treba ispisati.

Za razumijevanje dijagrama na slici 11. potrebna su neka pojanjenja. N je broj kojeg


treba unijeti preko konzole i na taj nain se odreuje gornja granica niza kojeg treba
ispisati.
I je broj kojeg ispituje da li je prim broj ili ne, a J je broj koji poprima vrijednosti 2, 3, itd.
s kojim dijelimo I, kako bi provjerili da li je on djeljiv s J.

Kao prvo treba primijetiti da nije potrebno da J poprima sve vrijednosti od 2 do I, jer ako
na primjer I nije djeljiv s nijednim brojem do njegove polovice, nije djeljiv ni s jednim
poslije. Ta logika dodue vrijedi i za drugi korijen od I, to je posebno pokazano u
plavom pravokutniku. SQRT(I) je standardna funkcija koju imaju mnogi programski
jezici meu kojima i C++ koja vraa drugi korijen od I (SQuare RooT).

Zato moemo tvrditi da ako broj K nije djeljiv ni s jednim brojem koji je manji od
njegovog drugog korijena, nije djeljiv ni s jednim drugim brojem osim sa samim sobom ?
Neka je Q drugi korijen od K, onda vrijedi da je K = Q*Q. Neka je K djeljiv i s nekim
drugim brojem, osim sa 1 i samim sobom, na primjer M. Dakle K nije prim broj. Onda
mora postojati i neki drugi broj N takav da vrijedi K=M*N! Ako je M<Q onda je nuno
N>Q i obratno. Dakle ne moe umnoak dva broja koji su oba vea od Q ili oba manja
od Q, biti jednak Q*Q!

20
Slika 1.11. Dijagram za ispisivanje prim brojeva od 3 do N
Start

Uitaj N Prolaz N I J K Pii I


1. 10 2 1
3 2 1 3
2. A 4 1
I=2
2 2
3.A 5 1
A 2 2
4.B 3 1 5
J=1 5.A 6 1
2 3
6.A 7 1
I>=N
DA 2 3
Kraj
? 7.B 3 2
NE 8.B 4 1 7
9.A 8 1
I=I+1 2 4
10.A 9 1
B 2 4
11.B 3 3
12.A 10 1 Kraj
J=J+1

C++ rjeenje

K=I/J
K=I%J;

If (K=0) goto A; J*K=I DA


A Bolje je J > SQRT(I)
?

NE

J>I/2 NE
B
?

DA

Pii I

A
DA

21
U zelenom pravokutniku je prikazana jedna druga varijanta logike koja se temelji na
injenici da u jeziku C++ postoji poseban operand % (modul) koji kao rezultat daje
ostatak kod dijeljenja dva cijela broja. Na primjer ako je K=11%3; (ita se K
jednako 11 modul 3) rezultat je da K poprima vrijednost 2, ili za K=18%5; rezultat je
K=3.

Za razumijevanje samog dijagrama treba napomenuti da su oznake u krugovima tzv.


prikljune toke (engleski label) . Ako se navedeni krug nalazi lijevo ili iznad
dijagrama, on predstavlja ulaz u dijagram, a kada se nalazi desno i ispod dijagrama
onda predstavlja izlaz iz dijagrama..

Tablica desno od dijagrama prikazuje to se deava za sluaj kad se zadaje N=10,


dakle kad treba ispisati sve prim brojeve koji su izmeu 3 i 10. Oznake u stupcu
'Prolaz' kao na primjer 2.A ili 4.B pokazuju kada je poela nova iteracija, i da li se
izvoenje nastavlja od prikljuka A ili B. Novom iteracijom se podrazumijeva, kada
se izvoenje jedne naredbe za drugom odozgo prema dolje prekida, te se izvoenje
naredbi vraa na neku naredbu koja je blia poetku dijagrama.

1.4. Opis rada u okruenju Dev C++

Da bi programer mogao raditi svoj posao - pisati programe nuni su mu odreeni


alati. Minimalni set alata nuan za pisanje i najjednostavnijeg programa ukljuuje:

editor (ureiva) - program u kojem programer pie svoj program i u kojem ga


sprema u obliku tekstualne datoteke
prevoditelj - program koji prevodi program napisan u nekom programskom
jeziku (pomou editora) u oblik razumljiv raunalu - strojni jezik

Osim ovih nunih alata najee se pri programiranju koristi i mnotvo drugih kao to
su:

debuger - program pomou kojeg programer pronalazi i ispravlja greke u


programu
dokumentacija - i najbolji programer ne zna sve i zato nuno u svom radu koristi
dokumentaciju o alatima i jeziku koji koristi
dodatne komponente ili biblioteke - koje donose nove funkcionalnosti i
poveavaju mogunosti razvojnih alata

Da bi se olakalo koritenje tog mnotva alata i ubrzao proces razvoja softvera svi
proizvoai razvojnih alata danas nude jedinstvene razvojne okoline (IDE - Integrated
development environment). Jedinstvene razvojne okoline (IDE) su produkti koji
objedinjavaju sve alate potrebne za razvoj softvera u homogenoj cjelini. Cjelokupan
razvoj programa obavlja se unutar jednog suelja, koje programer moe prilagoditi

22
svojim specifinim potrebama. Osim to su prilagodljivi potrebama korisnika IDE su i
proirivi dodatnim komponentama (koje moe ponuditi proizvoa IDE ili netko drugi).
Obino se IDE nudi u vie verzija (sa istom jezgrom, ali razliitim brojem dodatnih
alata) kako bi se to bolje prilagodili razliitim potrebama korisnika. Te verzije osim to
razliitih mogunosti, imaju i razliite cijene.
Da bi se nauilo programirati nije dovoljno proitati ovu knjigu (niti bilo koju
drugu knjigu), ve je nuno i pisati programe. Da bismo mogli isprobati primjere i
rijeiti zadatke iz ove knjige potrebno je imati neki razvojni alat. Na tritu je vie
kvalitetnih proizvoda razliitih proizvoaa koji mogu posluiti u tu svrhu, i ako imate
bilo koji od njih moete ih iskoristiti. Ako ne posjedujete niti jedan od komercijalnih
proizvoda i niste ih spremni nabaviti postoje naravno i alternativa - besplatni razvojni
alati. Svi primjeri navedeni u ovoj knjizi isprobani su sa dva takva alata:

Borland C++ compiler 5.5 - besplatna verzija komercijalnog prevoditelja tvrtke


Inprise (koja dolazi bez IDE)
Dev C++ - besplatni IDE koji ukljuuje MinGW prevoditelj

Dev C++ IDE je vjerojatno prihvatljivije rjeenje jer osim prevoditelja nudi i sve ostale
alate nune za rad u jedinstvenoj cjelini. Vie je razloga zato je ovaj alat pogodan za
poetnika:

"povoljna" cijena (0 kn)


kompaktnost - veliina instalacijske datoteke je samo 9MB, pa se lako moe
skinuti sa Interneta (komercijalni alati dolaze na vie CD-ova)
suelje prevedeno na hrvatski
jednostavnost - komercijalni alati nude mnotvo dodatnih alata i mogunosti koje
olakavaju i ubrzavaju razvoj aplikacije, ali mogu zbuniti poetnika, Dev C++
dolazi samo sa najosnovnijim alatima
nadogradivost - mogue je dodati gotove komponente koje nam olakavaju
razvoj (npr. mogue je dodati wx widgets koji olakavaju izradu grafikog
suelja za programe)

Bez obzira odabrali Dev C++ ili neki drugi alat veina primjera bi trebala raditi bez
ikakvih izmjena. Ako nauite bilo koji programski jezik svaki slijedei e vam biti laki, i
ako nauite koritenje bilo kojeg razvojnog alata ovladavanje slijedeim bit e lake.

Rad u Dev-C++

Da bismo mogli raditi u Dev C++ najprije ga moramo upoznati. Na slici je prikazan
uobiajen izgled suelja u Dev C++.

23
A

C B

Na slici su slovima oznaeni razliiti dijelovi suelja. Dio oznaen slovom A slian je kao
i u svim drugim Windows programima. Sastoji se od izbornika sa padajuim
podizbornicima i traka sa alatima. Na izborniku odabiremo onu opciju ili naredbu koju
elimo aktivirati. Opcije su podijeljene u grupe (npr. u grupi "Pomo" nalaze se sve
opcije vezane uz pomo korisniku). Ispod izbornika nalaze se trake sa alatima. U svakoj
traci se nalaze naredbe kojima na ovaj nain moemo pristupiti bre (klikom na gumb)
nego preko izbornika. Ovaj dio suelja se moe prilagoditi pa moemo odabrati koje
alatne trake nam trebaju, a koje ne. Na alatnim trakama se nalaze samo one naredbe koje
se esto koriste.
Najvei dio suelja zauzima editor (ureiva teksta) oznaen je slovom B. U
ovom dijelu korisnik pie program. Pri pisanju koda editor razliite dijelova koda
oznaava razliitom bojom (kljune rijei su u jednoj boji, varijable u drugoj) da bi
kod bio itljiviji. Sa lijeve strane se nalazi i traka sa numeracijom linija. Istovremeno
moe biti otvoreno vie datoteka za editiranje.
Na lijevoj strani zaslona (oznaen slovom C) nalazi se preglednik projekta i klasa. U
ovom dijelu zaslona moemo pregledavati dijelove projekta, klase koje sadri na projekt
ili ispis debugera (ovisno o tome koju karticu smo odabrali).
Dno zaslona zauzima dio u kojem moemo pregledavati razliite poruke IDE-a
preglednik izvjea (oznaen slovom D). Preglednik se sastoji od vie kartica (greke,
resursi, ispis kompajlera, debug i traenje). Ovisno o tome koju karticu odaberemo

24
vidimo odgovarajue izvjee. Ako na primjer elimo provjeriti kako je prolo
prevoenje naeg programa u izvrni kod ukljuimo karticu Ispis kompajlera i
pogledamo izvjee o prevoenju.

Da bi pribliili koritenje Dev C++ opisat emo postupak izrade jednog


jednostavnog programa.
Izrada programa poinje stvaranjem novog projekta ili datoteke. Ako radimo
jednostavni program (koji se sastoji od samo jedne datoteke i nema nikakvih dodatnih
resursa)odabrat emo opciju Nova datoteka, a ako radimo neki sloeniji program (koji
se sastoji od vie datoteka) odabrat emo opciju Novi projekt. Kad kreiramo novi
projekt stvara se posebna datoteka koja biljei to je sve ukljueno u taj projekt. Na prvi
program sastojat e se od samo jedne datoteke, pa emo odabrati opciju Nova datoteka.
Kad se kreira nova datoteka u editoru se otvori dodatna kartica u ijem vrhu pie ime te
datoteke. U toj kartici sad piemo kod naeg programa. Kod jednostavnog programa koji
samo ispisuje na zaslon poruku Dobar dan bi izgledao ovako:

#include <iostream>
Use namespace std;

int main ()
{
cout <<''Dobar dan'';
system("PAUSE");
return 0;
}

Kad smo zavrili pisanje naeg koda trebamo ga prevesti na strojni jezik i pokrenuti.
Prevoenje pokreemo ili preko izbornika ili preko gumba na alatnoj traci
(kompajliraj). Kako je proao postupak prevoenja moemo provjeriti u prozoru za
izvjee kompajlera. Ako je pri prevoenju dolo do greaka njih moemo pogledati na
dnu ekrana u pregledniku izvjea (kartica greke). U izvjeu greaka za svaku greku
pie u kojoj se liniji koda nalazi i kratki opis greke. Na osnovu ovog opisa moemo
ispraviti greke u kodu. Kad ispravimo sve greke i prevoenje proe bez njih program je
ispravno preveden i spreman za pokretanje.
Pokretanje programa obavljamo ili preko izbornika ili preko alatne trake odabirom opcije
pokreni. Poto su svi primjeri koji su napisani u ovoj knjizi programi koji se vrte u
prozoru konzole kod pokretanja takvih programa otvori s prozor konzole, program se
izvri i prozor se automatski zatvori im program doe do kraja. To u naem sluaju nije
ba prikladno jer bi na program samo ispisao poruku i prozor bi se odmah zatvorio (ne bi
stigli proitati poruku). Zato se na kraj programa stavlja naredba:

system("PAUSE");

25
Ova naredba zaustavlja izvoenje programa sve dok korisnik ne klikne bilo koju tipku na
tipkovnici. Na taj nain kad pokrenemo program, on ispie pozdravnu poruku i eka
pritisak na bilo koju tipku da zatvori prozor konzole. Ako radite programe koji se vrte u
prozoru konzole mudro je uvijek koristiti ovu naredbu.

26
1.5. Uvod u C++

Programski jezik C++ sadri 60tak kljunih rijei koje su navedene u prilogu B, na kraju
knjige. Kada bi se radilo o ljudskom jeziku, s obzirom na tako mali broj rijei bilo bi ga
jako lako nauiti. Kako se radi o programskom jeziku ono to oteava njegovo uenje
nije broj rijei, ve drugaija logika (koja odgovara raunalu)

Postoje razliite verzije programskog jezika C++ koje se u nekim detaljima mogu
razlikovati. Primjeri iz ovog teksta su raeni s prevoditeljem Bloodshed Dev-C++
4.9.9.2 i/ili s Borland C++ Compiler 5.5.

Uobiajeno je da se struktura programa u nekom programskom jeziku poinje


objanjavati primjerom kekog jednostavnog programa, pa e to i ovdje biti sluaj. U
nastavku je prikazan program koji na ekranu ispisuje Dobar dan.

Primjer 1.1.
1. // Primjer programa u C++
2. /* Ovaj program ispisuje na ekranu
3. Dobar dan */
4. #include <iostream.h>
5. int main ()
6. {
7. cout <<''Dobar dan'';
8. system("PAUSE");
9. return 0;
10. }

U nastavku slijedi opis pojedinih naredbi.


Naredbe 1.-3. su komentar, program prevoditelj (compiler) ih ignorira. To vrijedi za sve
naredbe koje poinju s dvije kose crte '//' .su Svrha komentara je da si programer stavi
biljeke koje e njemu ili nekom drugome dati odgovarajua pojanjenja.
Ako se komentar napie u vie redaka, treba svaki redak zapoeti s dvije kose crte. Drugi
nain pisanja komentara je pomou kose crte i zvjezdice kao to je uinjeno u drugom i
treem retku. Za tako pisani komentar nema ogranienja u veliini . Sve to se nalazi
izmeu '/*' koja predstavlja znak za poetak komentara i '*/' koja predstavlja znak za
kraj komentara C++ prevoditelj ignorira.

Slijedi naredba 4. #include <iostream.h>


Izrazi koji poinju sa simbolom '#' predstavljaju tzv. predprocesorske upute. One se
ukljuuju u program prije prevoenja programa. U konkretnom sluaju ova naredba
ukljuuje datoteku koja se zove iostream.h u kojoj su opisani podaci o ulazno izlaznim
operacijama. Na primjer, kako ovaj program 'zna' da 'Dobar dan' treba ispisati na ekranu
a ne na pisau ? U datoteci iostream.h se izmeu ostalog nalazi opis naredbe za pisanje
cout koja se koristi za ispisivanje na ekranu. U kasnijim e se primjerima vidjeti da
postoji i datoteka iostream koja zamjenjuje datoteku iostream.h ali tada treba dodati jo i

27
naredbu using namespace std; koja kae da se koristi standardno nazivlje. Dakle
umjesto #include <iostream.h> , moe se upisati

#include <iostream>
using namespace std;

Za naredbu 5. int main () za sada je dovoljno rei da se na taj nain oznaava toka u
kojoj poinje izvoenje programa. Ova naredba odgovara toki koja se na dijagramu
toka oznaava sa Start. Sadraj cijelog programa se nalazi unutar para vitiastih zagrada
(6. i 10.)
Obine zagrade iza izraza main su dio sintakse (pravila za pisanje) C++ koja vrijedi za
sve funkcije meu koje spada i main. Unutar tih zagrada mogu stavljati neki argumenti,
o emu e biti govora kasnije.

Naredba 7. cout <<''Dobar dan''; ispisuje na ekran 'Dobar dan'.

''Dobar dan'' se nalazi u navodnicima i na taj se nain pokazuje prevoditelju da se radi o


konstanti, tj. treba ispisati upravo taj niz znakova. Kada bi izraz bio bez navodnika
prevoditelj bi u konkretnom sluaju javio greku.

Naredba 8. system("PAUSE"); je navedena zbog razloga to kada se radi prevoditeljem


Dev-C++ , koji se koristi u primjerima iz ovog udbenika, izlaz iz programa samo bljesne
na ekranu i nestane. Ova naredba zadrava ekran s rezultatima dok se ne pritisne neka
tipka
Naredba 9. return 0; pokazuje gdje zavrava funkcija main () i vraa vrijednost koja je
navedena, u konkretnom sluaju to je 0, to se na ekranu posebno i navodi :

Press any key to continue . . .

Za razliku od nekih jezika 3. generacije C++ dozvoljava slobodan format pisanja


naredbi. Tako da bi se isti program mogao napisati i kao:

int main () { cout <<''Dobar dan''; return 0; }

Sve izvrne naredbe u C++ (one koje neto rade) moraju zavravati sa ; (toka zarez).

Primjer 1.2:
1. // Primjer programa u C++
2. /* Ovaj program ispisuje na ekran poetak
3. hrvatske himne */
4. #include <iostream.h>
5. int main()
6. {
7. cout<< "Lijepa naa domovino, "<<endl;
8. cout<< "oj junaka zemljo mila,"<<endl;

28
9. cout<< "stare slave djedovino" <<endl;
10. cout<< "da bi vazda, sretna bila."<<endl;
11. return 0;
12. }

Razlika izmeu ovog i prethodnog primjera je da se radi o ispisivanju drugaijeg teksta,


koji je opet naveden u navodnicima i da se tekst ispisuje sa 4. naredbe koje, za razliku od
prethodnog primjera, sve zavravaju sa endl; Za sada treba zapamtiti da je endl tzv.
manipulator koji pomie pisanje slijedeeg reda na poetak. Isti bi se uinak postigao
sa slijedeom naredbom:

cout<< "Lijepa naa domovino, "<<\n;

dakle, da umjesto endl moe se naredbu upisati \n .

2.Varijable i konstante

U C++ se mogu definirati dva osnovna tipa podataka: varijable i konstante. Konstante
su one veliine koje u tijeku izvoenja programa ne mijenjaju vrijednost, a mogu biti
numerike ili alfanumerike. Numerike konstante se pojavljuju u poznatom obliku kao
npr. 1, -5, 0 (kod runog je pisanja uobiajeno da se nula prekrii kako bi se razlikovala
od slova O). Ako se radi o alfanumerikim konstantama (tj. tekstu), one se kao u
prethodnim primjerima, stavljaju u navodnike.

Varijable su veline koje u pravilu u tijeku izvoenja programa mijenjaju svoju


vrijednost. Oznaavaju identifikatorima (nazivom) koji je niz alfanumerikih znakova
(dakle slova ili brojeva) te znaka za podcrtavanje '_' . Duljina niza tj. naziva varijable
nije ograniena iako neki prevoditelji uzimaju samo prvi 32 znaka, a ostale ignoriraju.
Niz kojim se oznaava varijabla (naziv varijable) ne smije zapoeti s brojem. Moe
poeti sa znakom podcrtavanja, ali se to izbjegava. U nazive varijabli ne smiju se stavljati
hrvatska slova ,,,, jer u engleskom te tipke mogu predstavljati specijalne znakove.
Postoji jo i pravilo da se naziv varijable ne smije preklapati s kljunim rijeima koje
koristi C++ kao na primjer int, float, return itd.

Dok raunalo izvrava program ono barata sa odreenim podacima (brojevi, slova,
rijei...), sve te podatke i rezultate matematikih operacija treba privremeno spremiti u
memoriju. Varijable su ustvari memorijske lokacije u koje raunalo privremeno
sprema podatke. Da bi programer lake zapamtio u koju lokaciju (varijablu) je
spremio koji podatak, svakoj varijabli (lokaciji) dodijeli naziv. Poto je koliina
memorije u raunalu ograniena, prije izvoenja programa treba rezervirati mjesto za
sve varijable u programu i to se radi pomou deklaracije varijabli. U deklaraciji se C+
navodi ime varijable (koje mora biti jedistveno) i tip varijable (jer je za razliite
+
tipove podataka potrebna razliita koliina memorije). Deklaracija za jedan
cijelobrojni podatak moe izgledati ovako: int a; kad raunalo pri izvoenju programa
doe do ove linije ono rezervira u memoriji mjesto za jedan cijeli broj (integer) i i
adresi te lokacije pridruuje naziv a. Kad se kasnije u tu varijablu (lokaciju) eli
spremiti neki podatak, to se radi pomou znaka jednakosti. Naredba a=5 sprema broj
5 u lokaciju (varijablu) koja se zove a.

29
compiler razlikuje velika i mala slova, pa e na primjer Broj1 i broj1 tretirati kao dvije
razliite varijable.

Nekoliko primjera ispravnih naziva varijabli:

x1, suma, broj_indeksa, naziv,

i nekoliko neispravnih:

3x, mi, lovac&pero,

Naziv varijable se prevoenjem programa pretvara u adresu polja u koje je smjeten


sadraj varijable. Sadraj moe biti pohranjen u polja razliite veliine tj. broja bajtova
i moe biti u razliitim oblicima ovisno o tipu varijable. Pregled tipova varijabli koje
poznaje C++ prikazan je na slici 2.1.

30
Slika 2.1. Osnovni tipovi varijabli u C++

Decimalne (floating point) Cijele (integer)

o float Logike varijable (bool)


o double Pobrojane varijable
o long double (enum)
Karakteri
o char
o unsigned char
o wchar_t
Cjelobrojne
o short
o int
o long
o unsigned short
o unsigned int
o unsigned long

Detaljniji opisi pojedinih tipova varijabli izloeni su u nastavku.

2.1.Deklaracija varijabli

Deklaracija varijabli je postupak kojim se priopuje prevoditelju, kakav tip varijable


elimo koristiti. To se ini navodei tip varijable ispred njenog naziva. Tipovi varijabli
su navedeni na slici 2.1.
Kada program prevoditelj 'prepozna'
int a;
konstantu u programu, on za nju
float broj;
automatski rezervira mjesto u memoriji. Za
varijable on to uini tek onda kada 'vidi'
Moe se deklarirati vie varijabli
njenu deklaraciju. Iz deklaracje on 'vidi'
odjednom:
koliko mjesta treba rezervirati. Zbog toga
se varijable uvijek moraju deklarirati u
int a, b, c;
programu. Deklaracije se u pravilu
stavljaju na poetak programa, kako bi
gornja deklaracija ima isti uinak kao:
prevoditelj kasnije 'prepoznao' varijable.
int a;
int b;
int c;

31
Cjelobrojne varijable (int, short, long i char) mogu biti s predznakom (signed) ili bez
(unsigned) .

2.1.1.Podrazumijevana vrijednost (by default), tj. ako se nita ne navede,


podrazumijeva se varijabla s predznakom (signed). Dakle, podatak o predznaku se treba
navesti samo kad elimo cjelobrojnu varijablu bez predznaka, na primjer:

unsigned short ocjena;

Deklariranje se moe i skratiti upotrebom rijei typedef koja je skraenica od type


definition na slijedei nain.

typedef unsigned long Prirodni;


Prirodni x;

unsigned short ocjena=5;

ili

unsigned short ocjena (5);

U oba sluaja varijabla ocjena poprima vrijednost 5.

2.1.2.Podruje vaenja naziva varijabli (scope)

U C++ se deklaracija varijabli moe nalaziti bilo gdje u programu i svaka se varijabla
mora deklarirati. U nekim jezicima postoje konvencije zbog kojih to nije uvijek
potrebno uiniti. Bitno je upamtiti da se varijabla u programu ne smije koristiti prije
nego to je deklarirana, na primjer:

broj =5;
int broj;

Prevoditelj bi u takvom sluaju javio greku, jer u trenutku kada 'vidi' naredbu broj=5; on
jo 'ne zna' kakva je varijabla broj.
Program se moe sastojati od vie zasebnih dijelova, koji su izdvojeni parom vitiastih
zagrada. U naelu, ako je varijabla deklarirana unutar jednog para vitiastih zagrada, ona
se prepoznaje samo unutar tog para vitiastih zagrada, a ne izvan njih.
S tog se stajalita varijable dijele na globalne tj. one ija deklaracija nije unutar
nijednog para vitiastih zagrada, pa im deklaracija vrijedi u cijelom programu i na
lokalne ija deklaracija vrijedi samo unutar para vitiastih zagrada u kojoj se nalazi
njihova deklaracija. Smisao ove konvencije vidi se, izmeu ostalog, kada se jedan veliki

32
program spaja iz manjih dijelova (potprograma) koje su razvijali razliiti programeri.
Svaki programer moe slobodno koristiti nazive lokalnih varijabli bez bojazni da e biti
problema, u sluaju da u nekom drugom dijelu programa postoji lokalna varijabla s
istim nazivom.

2.1.3. Osnovni tipovi varijabli

Na slici 2.1. prikazani su tipovi varijabli koje podrava C++.

Logike varijable ili u C++ notaciji bool su varijable koje mogu poprimiti samo dvije
vrijednosti 0 ili 1, Pri tome se 0 odnosi na neistinu (false), a 1 na istinu ( true).

C++ omoguava i da korisnik definira vlastite tipove podataka o emu e biti jo puno
govora kasnije. Zasad se spominje samo vrlo jednostavan tip pobrojenih varijabli
(enumerated) koji se definiraju s kljunom rijei enum.

enum godisnja_doba (proljee, ljeto, jesen, zima);

ili

enum dani (ponedjeljak, utorak, srijeda, etvrta, petak, subota, nedjelja);

kasnije se u programu moe koristiti na primjer varijable:

enum dani (ponedjeljak, utorak, srijeda, etvrta, petak, subota, nedjelja);


dani x, y;
x=nedjelja;
y=utorak;

Koritenje pobrojanih varijabli ilustrira slijedei primjer.

33
Primjer 2.1:
1. // primjer koritenja enumerated varijabli
2. #include <iostream.h>
3. enum dani {ponedjeljak, utorak, srijeda, cetvrtak, petak, subota, nedjelja};
4. int main() { Izlaz je :
5. dani d1, d2;
6. d1= utorak; Danas je 1 7
7. cout<< " Danas je "<<d1<<endl; Sutra je 2 9
8. d2 = srijeda; Press any key to continue . . .
9. cout<< " Sutra je "<<d2<<endl;
10. system("PAUSE");
11. return 0;
12. }

Izlaz iz programa e u ovom tekstu prikazivati na sivoj podlozi. On je u konkretnom


sluaju naizgled iznenaujui, no pojanjava sutinu rada pobrojanih varijabli. S obzirom
da je navedeno d1=utorak; nije jasno zbog ega se umjesto utorak, na ekranu pojavio
broj 1. Razlog je to pobrojane varijable prilikom deklaracije

enum dani {ponedjeljak, utorak, srijeda, cetvrtak, petak, subota, nedjelja};

automatski pridruuje ponedjeljak =0, utorak = 1, srijeda = 2 itd.


Da je deklaracija imala oblik:

enum dani {ponedjeljak=1, utorak, srijeda, cetvrtak, petak, subota, nedjelja};

Izlaz iz programa bi bio:


Danas je 2
Sutra je 3
Press any key to continue . . .

Da je grekom umjesto d2 = srijeda; upisano d2 = sijeda; ili bilo koji drugi pojam koji
nije naveden prilikom deklaracije enum varijable, prevoditelj bi javio greku.
U primjeru 2.1 prvi je put ispisana jedna varijabla. Vidi se da se ona ispisuje gotovo na
isti nain kao i konstanta s time da se ne navodi u navodnicima. Vidi se isto tako da se
jedna naredba cout moe koristiti za ispisivanje vie polja, s time da se za svako novo
polje navodi znak <<. Drugim rijeima, na primjer naredba:

cout<< " Danas je "<<d1<<endl;

ima isti uinak kao:

cout<< " Danas je ";


cout<< d1;
cout<< endl;

34
Varijable koje se najee koriste su brojevi i slova, odnosno znakovi. Varijable koje
sadre brojeve zovu se numerike varijable. Za njih je bitno naglasiti da postoji
nekoliko tipova cjelobrojnih varijabli i nekoliko tipova varijabli s decimalnim brojevima.
Cijeli brojevi (integer), kako im sam naziv govori, su brojevi bez decimala . Decimalni
brojevi su u C++ brojevi s kliznim zarezom (floating point, s obzirom da Amerikanci
imaju decimalnu toku). Naziv klizni zarez je zbog toga to se brojevi pamte u
eksponencijalnom obliku, za razliku od fiksnog zareza na kojeg smo navikli u
svakodnevnom pisanju. Razlika izmeu prikaza broja u fiksnom i kliznom zarezu vidi se
iz slijedeih primjera:

Fiksni zarez Klizni zarez


9,72 972*10-2
97,2 972*10-1
0,00972 972*10-5

U eksponencijalnom obliku, kao na primjer 972*10 -1, broj se sastoji od tri dijela: 972
naziva se mantisa, 10 je baza, a -1 eksponent. S obzirom da se podrazumijeva da je
baza uvijek 10, ona se ne pamti. Pamte se samo mantisa i eksponent.
Zbog toga se na primjer, broj 972*10-1 pamti u obliku koji se prikazuje kao 972e-1 (s
time da se ni e ne pamti, nego se pie kako bi itatelj mogao vidjeti gdje zavrava mantisa
i poinje eksponent). Dobro je primijetiti da tonost broja u eksponencijalnom obliku
ovisi od broja znamenki koje moe imati mantisa, dok su maksimalna, odnosno
minimalna veliina broja ovisne od broja znamenki koje moe imati eksponent.
Eksponencijalnim oblikom brojeva moe se sa manje znamenki zahvatiti puno vei
raspon brojeva. Ilustracije radi, na primjer: 5,68434*10-14 = 0,0000000000000568434 .
Ako se uzme u obzir da se baza 10 podrazumijeva i ne pamti u raunalu, kod
eksponencijalnog se oblika treba u konkretnom sluaju upamtiti 9 mjesta (6 za mantisu i
3 za eksponent s predznakom) dok se u fiksnom zarezu mora upamtiti 20 znamenki.

U tablici 2.1. prikazani su tipovi podataka koje se koriste u C++.

35
Tablica 2.1: Pregled tipova podataka
Tip Naziv Veliina Opis Granice vrijednosti
(broj bajtova) (Range)
Cijeli short 2 Integer (cjelobrojna v.) S predzn. -32768 do 32767
broj 16 bitova Bez predzn. od 0 do 65535
long 4 Integer 32 bita S predzn. -2147483648 do
2147483647
Bez predzn. od 0 do
4294967295
int * Duljina ovisi o tipu Vidjeti short, long
raunala
Realni float 4 Floating point 3,4e+/- 38 (7
(klizni zarez) znamenki)
double 8 Klizni zarez duple 1,7e+/- 308 (15
preciznosti znamenki)
long 10 Klizni zarez s 1,2e+/- 4932 (19
double poveanom duplom znamenki)
preciznosti
Znakovi char 1 8-bitni karakter S predznakom -128 do 127
Bez predzn. od 0 do 255
wchar_t 2 Wide character Wide character
(nedavno ubaeno)
Logiki bool 1 Elementi Bool-ove True ili false
algebre
* Vrijednosti ovise od tipa raunala

Vidi se da se pojedini tipovi podataka mogu pohranjivati i prikazivati u razliitim


veliinama., ovisno o potrebnoj tonosti i oekivanoj veliini brojeva. Daljnja svojstva
numerikih varijabli bit e opisana neto kasnije, kada se pojasne osnovne operacije s
njima.
Slova i posebni znakovi smjetaju se u tzv. karakter (character) varijable. Treba
naglasiti da se karakteri pamte kao integer varijable, s time da se razliito interpretiraju.
Upotreba karakter varijabli ilustriran je na primjeru 2.2.

Primjer 2.2
1. // Primjer koritenja character varijabli
2. #include <iostream.h>
3. int main() {
4. char c = 'A'; // ovako deklariran c je lokalna varijabla
5. cout<< " c = " <<c<<", a c kao cijeli broj= " << int(c) <<endl;
6. c='t';
7. cout<< " c = " <<c<<", a c kao cijeli broj= " << int(c) <<endl;
8. c='!';
9. cout<< " c = " <<c<<", a c kao cijeli broj= " << int(c) <<endl;
10. system("PAUSE");
11. return 0;
12. }

36
c = A, a c kao cijeli broj= 65 5
c = t, a c kao cijeli broj= 116 7
c = !, a c kao cijeli broj= 33 9
Press any key to continue . . .

Primjer 2.2. ilustrira da se karakter vrijednosti upisuju u navodniku, te da svaki karakter


ima neku cjelobrojnu vrijednost. Ta se vrijednost dobije uz pomo tzv. operatora
konverzije int(c) koji konvertira varijablu c u integer. U prilogu A na kraju ovog teksta
prikazana je ASCII tabela znakova iz koje se vidi veza izmeu karakter znaka i njegove
cjelobrojne vrijednosti.

2.2.Konstante

Pod konstantom se podrazumijeva svaki izraz koji ima fiksnu vrijednost. Mogu se
podijeliti na cjelobrojne (integer) , brojeve s kliznim zarezom (floating-point), karaktere i
nizove (string). Prikaz konstanti je u naelu isti kao i za varijable, samo konstante ne
mogu mijenjati svoju vrijednost.

Cjelobrojne konstante su:

1335
303
-454

Osim decimalnih brojeva C++ raspoznaje i oktalne brojeve (s bazom 8) koje prepoznaje
po prvom znaku 0 (nula) i heksadecimalne (s bazom 16) koje prepoznaje s prvim
znakovima 0x (nula iks).

75 // decimalni broj
0113 // oktalni
0x4b // heksadecimalni

Brojevi s kliznim zarezom (u Americi se koristi decimalna toka)

3.14159 // 3,14159
6.02e23 // 6,02x 1023
3.5e-12 // 3,5x 10-12

Nenumerike konstante su na primjer:

''z'' // znak
''Dobar dan'' // niz

37
prvi je primjer jednog karaktera (znak) a drugi je primjer niza karaktera (niz ili string). U
oba sluaja mora se konstanta staviti u navodnike. Oznaka z bez navodnika tretirala bi se
kao varijabla.

Kod koritenje navodnika moe doi do zabune, jer C++ koristi neke oznake s posebnim
znaenjem, kao na primjer:

'' \n'' - je oznaka za skok na novi red ili ''\t'' je tabulator. Tako na primjer ako se ispie

cout<<''jedan\ndva\ntri'';

e biti napisano u tri reda, dok e

cout<<''Lijevo \t Desno'';

biti poravnato lijevo, odnosno desno, to ilustrira slijedei primjer:

#include <iostream.h> jedan


int main() { dva
cout<<"jedan\ndva\ntri\n"; tri
cout<<"Lijevo \t Desno\n"; Lijevo Desno
system("PAUSE"); Press any key to continue . . .
return 0;
}

Konstante mogu imati svoje ime, poput varijabli. Smisao je u tome da se moe
pojednostaviti njihova upotreba. Na primjer ako je potreban broj Pi na osam decimala
Pi=3.14159265 moe biti dosadno vie puta pisati ovaj broj, a postoji i mogunost
greke. Konstantama se moe pridruiti ime na dva naina:

1. Pomou predprocesorske upute #define, kao na primjer:

#define PI 3.14159265
#define novired ''\n''

2. Na isti nain kao i varijable, na primjer:

const float PI=3.14159265;

const char tab='\t;'

U oba sluaja kasnije se u programu moe pozivati naziv PI umjesto navedenog


decimalnog broja, kao na primjer:

38
opseg = 2*PI*r;

cout <<novired;

2.3. Primjeri programa za rad s varijablama i konstantama

Slijedi primjer programa koji koristi razliite tipove varijabli

Primjer2.3.
1. /* Ovaj program prikazuje razliite mogunosti
2. koritenja varijabli i konstanti. */ duljina x u bajtovima je: 4 9
3. #include <iostream.h> duljina long u bajtovima je: 4 10
4. int main() x= 6 11
5. { c= A 12
6. int x(5); int(c) = 65 13
7. x=x+1; c= ! 15
8. char c= 'A'; int(c) = 33 16
9. cout<< ''duljina x u bajtovima je: ''<< sizeof(x)<<endl;
10. cout<< " duljina long u bajtovima je: "<< sizeof(long)<<endl;
11. cout<< "x= "<<x<<endl;
12. cout<< "c= "<<c<<endl;
13. cout<< "int(c) = " <<int(c) <<endl;
14. c='!';
15. cout<< "c= "<<c<<endl;
16. cout<< "int(c) = " <<int(c) <<endl;
17. system("PAUSE");
18. return 0;
19. }

U C++ postoji operator sizeof(varijabla) koji pokazuje koliko bajtova u memoriji


zauzima varijabla navedena u zagradi. Kao to se gornjem primjeru vidi varijabla
deklarirana s int zauzima 4 bajta i ista je kao i duljina varijable long (pri tome long nije
naziv varijable nego tip).

Primjer 2.4.
1. /* Ovaj program ispisuje maksimalne i
2. minimalne vrijednosti pojedinih varijabli */
3. #include <iostream.h>
4. #include <climits> // funkcije SHRT_MIN, itd.
5. #include <cfloat> // za float vrijednosti
6. int main()
7. {
8. cout<< "Najmanja vrijednost za short: "<<SHRT_MIN<<endl;
9. cout<< "Najvea vrijednost za short: "<<SHRT_MAX<<endl;

39
10. cout<< "Najvea vrijednost unsigned short: " <<USHRT_MAX<<endl;
11. cout<< "Najvea vrijednost int: " <<INT_MAX<<endl;
12. cout<< "Najvea vrijednost long: " <<LONG_MAX<<endl;
13. cout<< "Najvea vrijednost float: " <<FLT_MAX<<endl;
14. cout<< "Najmanja vrijednost float: " <<FLT_MIN<<endl;
15. return 0;
16. }
Izlaz je :
Najmanja vrijednost za short: -32768 8
Najveca vrijednost za short: 32767 9
Najveca vrijednost unsigned short: 65535 10
Najveca vrijednost int: 2147483647 11
Najveca vrijednost long: 2147483647 12
Najveca vrijednost float: 3.40282e+038 13
Najmanja vrijednost float: 1.17549e-038 14
Press any key to continue . . .

Iz primjera se vidi da C++ ima ugraene funkcije za izraun najveih i najmanjih


vrijednosti pojedinih tipova varijabli koje se nalaze u datoteci climits. Kao to se iz
rezultata vidi, najvea vrijednost varijable int je jednaka kao i za long, to potvruje
rezultat iz prethodnog primjera, da varijabla int zauzima 4 bajta kao i varijabla long.

Primjer 2.5:
1. // Primjer koritenja character varijabli( pr2_5)
2. #include <iostream.h>
3. int main() {
4. char a=51, b='*', c=50, d='=', e=54;
5. cout<< a<<b<<c<<d<<e<<endl;
6. cin>>a; // ova naredba moze se koristiti umjesto: system ("PAUSE")
7. return 0;
8. }

Izlaz iz programa je:


3*2=6
Pojanjene je opet u tablici s ASCII kodovima u prilogu A. dakle kada se u karakter
varijablu prebacuju vrijednosti iz ASCII tablice one se ne stavljaju u navodnike. U
naredbi 4 se varijablama dodaju vrijednosti bez da se navede toka zarez nakon svake
vrijednosti. To je zbog toga to je naredba 4. u sutini deklaracija vie varijabli istog tipa
(tj. char) kojima se zadaju poetne vrijednosti.
Naredba broj 6. ima praktiki isti uinak kao naredba system(''PAUSE'') zbog toga to je
to naredba za uitavanje pa slika ostaje na ekranu dok se ne upise neka vrijednost koju
program pridruuje varijabli a.

40
Primjer 2.6:
1. // Primjer koritenja varijabli (pr2_6)
2. #include <iostream.h>
3. int main()
4. {
5. typedef unsigned int prirodni;
6. prirodni a=5, b=2; // a i b su prirodni brojevi s pocetnim vrijednostima 5 i 2
7. float c, d;
8. cout<<"Ispisi 5/2: "<<a/b<<endl;
9. cout<<"Sada ima decimale: "<<(float)a/b<<endl; //pazi: nije float (a/b)
10. c=a/b;
11. cout<<"Ispisuje se c: "<<c<<endl;
12. c=a;
13. d=c/b;
14. cout<<"Ispisuje se d: "<<d<<endl;
15. system("PAUSE");
16. return 0;
17. }

Ispisi 5/2: 2 8.
Sada ima decimale: 2.5 9.
Ispisuje se c: 2 11.
Ispisuje se d: 2.5 14.
Press any key to continue

U ovom je primjeru u 5. retku koritena naredba typedef koja omoguuje programeru da


nekim tipovima varijabli dodijeli vlastiti naziv. U konkretnom je sluaju cjelobrojnoj
varijabli bez predznaka dodijeljen naziv prirodni. Zatim su u 6. retku varijable a i b
deklarirane kao prirodni tj. unsigned int.

Zanimljivo je ispisivanje rezultata dijeljenja dviju cjelobrojnih varijabli (to to su u


konkretnom sluaju i unsigned nema utjecaja na ova razmatranja). Ispis u naredbi 8.
nema decimala i u naredbi 9. se vidi kako ih se moe prikazati s tzv. cast operatorom
odnosno operatorom pretvorbe.
Moda iznenauje ispis varijable c u naredbi 11. Razlog zbog kojeg nema decimala je
naredba 10. Tamo se a dijeli s b ali s obzirom da su obje varijable cjelobrojne operacija
dijeljenja izvodi se s cjelobrojnom aritmetikom tj. izrauna se rezultat bez decimala pa se
nema to prebaciti u varijablu c koja moe primiti decimale jer je tipa float.
Za razliku od toga u naredbi 13. je s desne strane znaka jednakosti jedna cjelobrojna i
jedna decimalna varijabla, pa se za izraun ukljuuje decimalna aritmetika u kojoj se
izraunavaju decimale koje se prenose u varijablu d i za tim ispisuju naredbom 14.
Gornja se logika moe ilustrirati na primjer naredbama.

41
cout<<7/2;
cout<<7./2;
Prva ce naredba ispisti vrijednost 3, a druga 3,5 jer se zbog decimalne toke iza 7
ukljuuje decimalna aritmetika.

3. Operatori

Za operacije s varijablama i konstantama definirani odgovarajui operatori, operator


pridruivanja, aritmetiki operatori i njihove kombinacije

3.1. Operator pridruivanja (=)

Izmeu pridruivanja i znaka jednakosti u matematikom smislu, postoji razlika. U


matematici se znak jednakosti interpretira kao injenicu da veliine s obje strane toga
znaka imaju jednaku vrijednost.
U programiranju se znak pridruivanja interpretira tako da se vrijednost navedena na
desnoj strani , ili rezultat raunskih operacija navedenih na desnoj strani, prebacuje na
adresu polja navedenog na lijevoj strani. Zbog toga je slijedei izraz, koji u matematici
ne bi imao smisla, uobiajen u mnogim programskim jezicima:

a=a+1;

Najkraa interpretacija gornjeg izraza je : 'Poveaj a za 1'.

Ono to se u stvari deava je da program uzima sadraj koji je pohranjen na adresi a,


dodaje mu 1 i rezultat vraa na adresu polja navedenog na lijevoj strani, koje je opet a.
Tako na primjer a=5; uzrokuje 'punjenje' sadraja polja oznaenog s a sa
vrijednosti 5. Zbog toga na lijevoj strani znaka pridruivanja uvijek mora biti
varijabla, dok na desnoj strani moe biti konstanta, varijabla ili nekakva operacija,
odnosno njihova kombinacija. Pridruivanje je ilustrirano slijedeim primjerima:

int a, b; // a=? b=?


a=10; // a=10 b=?
b=4; // a=10 b=4
a=b ; // a=4 b=4
a= 2+b; // a=6 b=4
a=2+(b=5); // a=7 b=5

C++ dozvoljava i ovakve izraze:

a=b=c=5;

Uinak je da sve tri varijable a,b i c imaju vrijednost 5.

3.2.Aritmetiki operatori (+, -, *, /, %)

42
Znaenje ovih operatora je slijedee:

Operand Znaenje
+ zbrajanje
- oduzimanje
* mnoenje
/ dijeljenje
% modul

U odnosu na standardne aritmetike operacije, nova je operacija modul, o kojoj je ve


bilo rijei, a koja kao rezultat daje ostatak kod dijeljenja dva cijela broja. Na primjer:

a=11%3 ; // a=2
k=8%5 ; // k=3

Za aritmetike operatore inae vrijede uobiajena matematika pravila, kao na primjer da


mnoenje i dijeljenje ima prioritet pred zbrajanjem i oduzimanjem, odnosno da se
operacije istog prioriteta izvode s lijeva na desno.

Primjer 3.1.
1. // primjer koritenja operatora (oper1.cpp)
2. #include <iostream.h>
3. int main() {
4. int m=54;
5. int n=20;
6. cout<< " m = " <<m<<", n= " << n <<endl; m = 54, n= 20 6
7. cout<< " m+n = " <<m+n<<endl; // m+n = 74 m+n = 74 7
8. cout<< " m-n = " <<m-n<<endl; // m-n = 34 m-n = 34 8
9. cout<< " m*n = " <<m*n<<endl; // m*n = 1080 m*n = 1080 9
10. cout<< " m/n = " <<m/n<<endl; // m/n = 2 m/n = 2 10
11. cout<< " m%n = " <<m%n<<endl; // m%n = 14 m%n = 14 11
12. cout<< " m-n*2 = " <<m-n*2<<endl; // m-n*2 = 14 m-n*2 = 14 12
13. cout<< " m/2*n = " <<m/2*n<<endl; // m/2*n = 540 m/2*n = 540 13
14. system("PAUSE"); Press any key to continue . . .
15. return 0;
16. }

Iz primjera 3.1 vidi se da se aritmetiki operatori mogu izravno upisivati u naredbu cout.
U posljednje dvije naredbe za ispisivanje po rezultatu se vidi da je izraz m-n*2 izraunat
tako da je najprije izvedena operacija mnoenja, a onda zbrajanja . Isto tako u izrazu
m/2*n operacije su izvedene s lijeva na desno tj. najprije dijeljenje pa onda mnoenje.
Utvreni redoslijed operacija moe se mijenjati pomou zagrada, na isti nain kao to je
uobiajeno u matematici.

43
m
Izraz n moe se napisati kao m/2*n ili (m/2)*n . Tu zagrade nita ne
2
mijenjaju.

m
Izraz mora se pisati m/(2*n)
2n

3.3.Kombinirani operatori (+=, -=,*=, /=, %=)

Svrha je ovih operatora skratiti pisanje. Znaenje je opisano kroz slijedee primjere:

a+=5; je ekvivalentno a=a+5;


a/=b; '' a=a/b;

cijena *= kolicina+1; je ekvivalentno cijena = cijena*(kolicina+1);

3.4.Poveanje i smanjenje vrijednosti varijable

U C++ postoji jo jedna konvencija za skraenje pisanja:

a++; je istovjetno a+=1; odnosno a=a+1;


b--; je istovjetno sa b-=1; odnosno b=b-1;

Ovo se skraeno pisanje moe pisati na dva naina a++ (sufiks) ili ++a (prefiks), to
meutim nije uvijek ista stvar.

Na primjer:

b=3;
a=++b; // Rezultat e biti a=4 i b=4 (prefiks forma) jer je poveanje b izvedeno prije
prebacivanja u a.
b=3;
a=b++; // Rezultat e biti a=3 i b=4 (postfiks forma) jer je prebacivanje u a izvedeno
prije poveanja b.
Ako se u aritmetikom izrazu pojavljuje npr. b=++a, onda se taj izraz moe
interpretirati kao dvije naredbe na slijedei nain
a=a+1;
b=a;
najprije se a uvea za 1, a onda b poprimi vrijednost a. Znai moe se zamisliti da se taj
izraz ustvari sastoji on dva: prvog u kojem se a povea za 1 i drugog u kojem se koristi
takav uveani a.
Analogno, aritmetiki izraz u kojem se koristi operator a++, recimo b=a++ se moe
rastaviti na dvije naredbe:
b=a;
a=a+1;
Znai naprije b poprima vrijednost a, a zatim se a poveava za jedan. Ako se u nekom
aritmetikom izrazu koristi ++a, moe se zamisliti da se ispred tog izraza nalazi naredba
a=a+1, odnosno ako se u izrazu koristi naredna a++, moe se zamisliti da se poslije tog 44
izraza nalazi naredba a=a+1
Upotrebu kombiniranih operatora te sufiksa i prefiksa ilustrira primjer 3.2.
Primjer 3.2.
1. // primjer koritenja kombiniranih operatora
2. #include <iostream.h>
3. int main() {
4. int m, n=3; // m nema poetnu vrijednost, n=3
5. m=++n;
6. cout<< " m = " <<m<<", n= "<<n<<endl; // m=4, n=4
7. m=n++;
8. cout<< " m = " <<m<<", n= "<<n<<endl; // m=4, n=5
9. m+=9;
m = 4, n= 4 6
10. cout<< " m+=9 = " <<m<<endl; // m=13
m = 4, n= 5 8
11. n-=8;
m+=9 = 13 10
12. cout<< " n-=8 = " <<n<<endl; // n = -3 n-=8 = -3 12
13. system("PAUSE"); Press any key to continue . . .
14. return 0;
15. }

3.5.Relacijski i logiki operatori

Relacijski operatori se koriste za formiranje logikih izraza. Njihova je vrijednost = 1


istina (true) ili =0 neistina (false). Treba napomenuti da u C++ nula predstavlja neistinu,
dok se sve ostale vrijednosti interpretiraju kao istina.

Operator Znaenje
< Strogo manje
<= Manje ili jednako
> Strogo vee
>= Vee ili jednako
== Jednako
!= Razliito

Na primjer za i=1; j=2; k=4; imamo:

Izraz Istinitost Vrijednost


i<j Istinito 1
(i+j)>=k Neistinito 0
i = =2 Neistinito 0
k!=i Istinito 1

45
Posebno treba skrenuti pozornost na operator jednako = = , njega se nikako ne smije
pisati s jednim znakom = jer tada znai pridruivanje. To moe biti uzrok greke u
programu jer je recimo i= =2 bilo neistinito, a i=2 je uvijek istinito, jer se upravo
prebacilo 2 u i.

Logiki operatori su !, && i | |

Prvi operator ! predstavlja negaciju, on pretvara istinito u neistinito i obrnuto. Drugi


operator predstavlja logiki i, a trei logiki ili.

Njihovo je znaenje prikazano u slijedeoj tablici. Stupci a i b su zadani, a preostala dva


su rezultat.

Tablica 3.1. Logiki operatori


a b a && b a|| b
Istinito Istinito Istinito Istinito
Istinito Neistinito Neistinito Istinito
Neistinito Istinito Neistinito Istinito
Neistinito Neistinito Neistinito Neistinito

3.6.Uvjetni operator (?)

Opi mu je oblik

uvjet ? rezultat1:rezultat2

Ovaj operator ocjenjuje zadani uvjet i poprima vrijednost rezulata1 ili rezultat2 u
ovisnosti da li je uvjet ispunjen ili ne.
Na primjer matematiki izraz x = abs(x) (apsolutna vrijednost od x) moe se, pomou
uvjetnog operatora, napisati na slijedei nain:

x= (x<0) ? x : x; // x=abs(x)

Dakle ako je ispunjen uvjet x<0 u x se stavlja -x tj. x mijenja predznak, inae se uzima x
kakav je.

3.7. Konverzija podataka

Kada se u raunalu obavljaju operacije s varijablama razliitih tipova, onda se mora


izvriti konverzija pojedinih varijabli, kako bi izvedene operacije dale korektni rezultat.
Konverzija podataka moe biti eksplicitna i implicitna. Eksplicitna je konverzija kada se
to zahtjeva posebnom naredbom, a implicitna se izvrava bez posebnih naredbi. U
slijedeem bi se primjeru obavila implicitna konverzija podataka:

46
int n =22;
float x = 3.14159;
x +=n; // vrijednost 22 se automatski konvertira u 22,0
cout << x-2; // konstanta 2 se automatski konvertira na 2,0

Dakle, kada se operacijama mijeaju cjelobrojne i realne varijable, u raunalu se obavlja


implicitna konverzija cjelobrojnih varijabli u realne. Obrnuta konverzija, iz decimalne u
cjelobrojnu varijablu nije automatska, ali se moe izvesti eksplicitno. Pri tome vrijedi
slijedee ope pravilo:

Ako je T odreeni tip varijable, a v varijabla nekog drugog tipa, onda izraz T(v)
konvertira varijablu tipa v u tip T.
Ova se konverzija naziva cast.

int main() {
double v= 1234.56; v = 1234.56 , n = 1234
int n;
n= int(v); // isto bi bilo i bez int(v)
cout<<''v =''<<v<<'', n = ''<<n<<endl;
}

Ovaj tip konverzije podataka je C++ naslijedio od C. Isti bi rezultat bio da se umjesto
Naredbe:
n = int (v);

napie C++ naredba

n = static_cast <int>(v);

koja je naknadno uneena u jezik C++ .


ili
int main () {
char c='A'; cout<< '' char c = '<<c<<endl; char c= A
short k=c; cout<< '' short k = '<<k<<endl; short k = 65
float x=k; cout<< '' float x = '<<x<<endl; float x = 65
}

U ovim sluajevima nije bilo neophodno pisati cast operator, jer se radi o konverziji s
nieg na vii tip.
Slijedei primjer prikazuje jednu zanimljivu mogunost konverzije podataka

char z1,z2;
z2='m';
z1=z2+('A' - 'a'); M
cout<<z1;

47
Rezultat izvoenja ovih naredbi je ispis velikog slova M. Ako se pogleda ASCII tablica
Dodatak A na kraju prirunika vidi se da je 'razmak' izmeu velikog i malog slova jednak
za sva slova. Dakle ako se bilo kojem malom slovu doda navedeni 'razmak' on se
'pretvara' u veliko slovo. Automatska konverzija omoguava da se izvre aritmetike
operacije sa znakovima (char).Dakle gornje naredbe predstavljaju 'recept' kako se mala
slova prevode u velika.

Pitanje: Kako bi se velika slova prevodila u mala slova ?

Slijedi jo jedan primjer implicitne konverzije podataka:

double dbroj;
int ibroj;
unsigned long ulbroj;
dbroj = ibroj * ulbroj; // ibroj se konvertira u unsigned long;
// rezultat mnoenja se konvertira u double.

Primjer 3.3.
1. // primjer programa za ilustraciju konverzije
2. #include <iostream.h>
3. int main() {
4. int m,n, x;
5. float p;
6. m= 3/2; // oekuje se da je rezultat 1 jer nema decimala
7. p= 3/2; // oekuje se rezultat 1,5
8. cout<< " m = " <<m<<", p= "<<p<<endl; // Oba su rezultata jednaka
1?
9. m=3.0/2;
10. p=3.0/2;
11. cout<< " m = " <<m<<", p= "<<p<<endl; // Sad su rezultati oekivani
12. // slijedi ilustracija rada uvjetnog operatora
13. x=-5;
14. x= (x<0) ? -x : x; // x=abs(x) m = 1, p= 1 8
15. cout<<"x = "<<x<<endl; m = 1, p= 1.5 11
16. x=7; x=5 15
17. x= (x<0) ? -x : x; // x=abs(x) x=7 18
18. cout<<"x = "<<x<<endl; Press any key to continue . .
19. system("PAUSE");
20. return 0;
21. }

Iznenauje da je p kod prvog ispisivanja jednak 1, dakle ponaa se kao i m koji je


integer varijabla. Ovo je rezultat injenice da su s desne strane izraza p=3/2; dvije
cjelobrojne konstante. Zbog injenice da su sve veliine s desne strane cjelobrojne,
aktivira se cjelobrojna aritmetika, pa se decimale odbacuju. Prije drugog ispisivanja je u
izrazima za raunanje umjesto 3 upisano 3.0, to podrazumijeva da se radi o realnom

48
broju. Zbog injenice da su s desne strane veliine razliitog tipa (3.0 je realni broj a 2
cijeli, aktivira se aritmetika realnih brojeva u kojoj se raunaju decimale). U sluaju
cjelobrojne varijable m decimale se odbacuju, dok se u sluaju realne varijable p one
zadravaju. Treba napomenuti da bi se izrazi ponaali na isti nain, kada bi s desne strane
umjesto konstanti, bile varijable odgovarajueg tipa. U nastavku primjera je ilustrirana
upotreba uvjetnog operatora za izraun apsolutne vrijednosti broja.

3.8. Overflow (prekoraenje vrijednosti)

Overlow je tip greke koji nastaje kada se u polje eli pohraniti vrijednost koja je vea
od maksimalne vrijednosti za dotini tip podataka. Slijedei program pokazuje takav
primjer :

Primjer3.4.
1. // Primjer za ilustraciju overflow
2. #include <iostream.h>
3. int main()
4. {
5. int n=1000;
6. n*=1000;
7. cout<<n<<endl;
8. n*=1000;
9. cout<<n<<endl; 1000000 7
10. n*=1000; 1000000000 9
11. cout<<n<<endl; -727379968 11
12. n*=1000; -1530494976 13
13. cout<<n<<endl; Press any key to continue . . .
14. return 0;
15. }

Vidi se da je ve trei rezultat netoan, jer je nastao overflow. Meutim program nije
javio nikakvu greku. To pokazuje da o takvim grekama mora misliti programer. Za tu
su svrhu u C++ izraene posebne funkcije koje ispituju nastanak takvog uvjeta.

Pokuaj da se prethodni zadatak ponovi s float varijablama uz dodatak da se naredba


n*=1000; zamijeni s n*=n; radi breg rasta vrijednosti, daje slijedei rezultat5:

1e+006
1e+012
1e+024
1.#INF
Press any key to continue . . .
Dakle kod realnih varijabli rezultat upozorava da je nastao overflow.

5
Ovaj se rezultat dobije sa Dev-C++ prevoditeljem, isti program s Borland prevoditeljem nepredvieno
prekida rad ('puca').

49
3.9. Zaokruivanje rezultata

Osim greaka zbog prekoraenja vrijednosti (overflow) do greaka u raunanju moe


doi i zbog zaokruivanja, to ilustrira slijedei primjer:

Primjer3.5.
1. // Primjer programa u C++
2. /* Ovaj program pokazuje probleme u zaokruivanju */
3. #include <iostream.h>
4. int main()
5. {
6. // najprije se varijabla dijeli s ,3 a nakon toga mnoi s 3
7. int i=1000.0;
8. int j=i/3; i=1000,j=333,k=999 10
9. int k=j*3; n=1000,p=333.333,r=1000 14
10. cout<<"i="<<i<<",j="<<j<<",k="<<k<<endl; p=0.333344,r=1.00003 17
11. float n=1000.0; Press any key to continue . . .
12. float p= n/3;
13. float r= p*3;
14. cout<<"n="<<n<<",p="<<p<<",r="<<r<<endl;
15. p=p-333;
16. r=3*p; //oekuje se rezultat 1
17. cout<<"p="<<p<<",r="<<r<<endl;
18. return 0;
19. }

Kod cjelobrojnih varijabli i,j,k razlika u rezultatu je oekivana. Kod realnih varijabli
n,p,r pokazuje se da 333.333 *3 zaokruuje na 1000 pa je rezultat toan. Meutim, u
naknadnim se operacijama pojavila greka u zaokruivanju, jer 3*0,333344 nije jednako
1.
U nastavku je dana tablica s prioritetima operatora i redoslijedom njihovog izvoenja od
lijeva na desno ili obrnuto. Taj se prioritet uvijek moe mijenjati sa zagradama.

Tablica 3.2: Prioritet operatora


Operatori Opis Asocijativnost
! ++ -- * & sizeof Unarni operatori D-L
* / % Aritmetiki operatori L-D
+ - Aritmetiki operatori L-D
< <= > >= Relacijski operatori L-D
= = != Operatori jednakosti L-D
&& Logiko I L-D
|| Logiko ILI L-D
?: Uvjetni operator D-L
= += -= /= %= Operatori pridruivanja D-L

50
Asocijativnost je redoslijed izvoenja takvih operatora, L-D s lijeva na desno ili D-L s
desna na lijevo.

3.10. Komunikacije preko konzole

U dosadanjim su se primjerima koristila konzola za ispis rezultata. Nekoliko rijei o


nainu komunikacije preko konzole je neophodno radi razumijevanja primjera u
nastavku. Pod pojmom konzola podrazumijevaju se tipkovnica i ekran (zaslon) kao
standardni nain komunikacije s raunalom.

U datoteci iostream, C++ podrazumijeva da je standardni input cin s tipkovnice i


standardni output cout na ekran. Pored toga postoje i outputi cerr i clog koji su
predvieni za poruke o grekama, ali se mogu koristiti i za druge svrhe.

Output (cout)

Opi oblik je

cout << izraz;

Na primjer:

cout << '' Dobar dan'' ; // ispisuje na ekran Dobar dan


cout << 120; // ispisuje 120
cout << x ; // ispisuje sadraj varijable x

Operator << naziva se operator insertiranja s obzirom da on insertira niz znakova ili
varijable koje ga slijede u izlazni niz podataka.

Na primjer:

cout << ''Dobar dan'' << '' ja sam student, imam '' << godine<<''godine'';

pod pretpostavkom da varijabla godine sadri broj 23 , dati e slijedei izlaz:

Dobar dan ja sam student, imam 23 godine

Drugi primjer:

cout << ''Prva reenica.'';


cout << ''Druga reenica.'';

ispisat e:

Prva reenica.Druga reenica.

51
Ako se eli da se druga reenica pojavi u novom redu, treba napisati naredbu:

cout << ''Prva reenica. \n''<<''Druga reenica'';

Prebacivanje teksta na novi red uzrokuje znaka za novi red ''\n''.

Drugi nain da se prijee u novi red je:

cout << ''Prva reenica.''<<endl;


cout << ''Druga reenica.''<<endl;

Input (cin)

Naredba za uitavanje podataka cin ima oblik:

cin >> varijabla;

Vrijednost varijable se upisuje na tipkovnicu. Na primjer:

int godine;
cin >>godine;

Moe se uitati i vie varijabli na nain:

cin >>a >> b>>c;

Slijedi primjer programa, kojemu zadajemo cijeli broj a on ispisuje taj broj i njegovu
dvostruku vrijednost.

Primjer3.6. Molim upisite cijeli broj 78 6


1. // primjer ulaza/izlaza Upisali ste broj 78 8
2. #include <iostream.h> i njegova je dvostruka vrijednost 156 9
3. int main() Ukucaj neki broj za kraj 9 10
4. {
5. int i;
6. cout <<" Molim upisite cijeli broj";
7. cin >>i;
8. cout << "Upisali ste broj " << i<<endl;
9. cout <<"i njegova je dvostruka vrijednost "<<i*2;
10. cout<<endl<<"Ukucaj neki broj za kraj";
11. cin>>i;
12. return 0;
13. }

Nakon ispisivanja : Molim upisite cijeli broj raunalo je ekalo na odgovor. Ukucano je
78 pa obvezno enter. Raunalo je nakon toga odgovorilo:

52
Upisali ste broj 78
i njegova je dvostruka vrijednost 156

Posljednje dvije naredbe nemaju na izgled nikakvog znaenja, jer nakon to se ukuca broj
program zavrava s radom. One su samo za ilustraciju da je na taj nain izbjegnuta
potreba za upisivanjem naredbe

system("PAUSE");

jer ekran ostaje vidljiv u oekivanju da se unese traeni broj.

53
4. Naredbe za kontrolu toka programa

Slijed izvoenja naredbi u programu je jednak uobiajenom slijedu kojim itamo tekst,
dakle s lijeva na desno i od vrha stranice prema dnu. Postoje meutim naredne, kojima
se moe promijeniti opisani tijek izvoenja naredbi.

U nastavku e se opisati naredbe koje uzrokuju promjenu redoslijeda izvoenja naredbi.

4.1.Uvjetna naredba if i else

Opi oblik naredbe je :

if (uvjet) naredbaA else naredbaB

Ako je uvjet istinit (true) izvodi se naredbaA, inae se izvodi naredbaB.

Mogu je i oblik naredbe bez navoenje else, dakle:


True False
if (uvjet) naredbaA (else)
?
u tom sluaju, ako je uvjet istinit, izvodi se naredbaA,
inae se ona preskae.

U slijedeem primjeru ilustriran je sluaj if i else A B

if (x>0)
cout<< ''x je pozitivan'';
else
cout <<''x nije pozitivan''; Tok if-else
na ekranu e se pojaviti samo jedna poruka

x je pozitivan
ili Tok if
x nije pozitivan

U sluaju da nema else, dakle da se radi o


slijedeem slijedu

if (x>0)
?
True
cout<< ''x je pozitivan'';
cout <<''x nije pozitivan'';
False A

54
Tekst ''x nije pozitivan'' bi se uvijek ispisao na ekranu, ak i u sluaju kad je
zadovoljen uvjet x>0, samo to bi tada prije toga ispisao i tekst ''x je pozitivan''.
Dakle u konkretnom sluaju takav program ne bi bio korektan.
Slijedi primjer programa koji koristi naredbu if:

Primjer4.1.
1. /* Ovaj program provjerava djeljivost 2 broja */ 2
2. #include <iostream.h> m n
3. int main()
4. {
1 3
5. cout<<" Upisi dva prirodna broja"<<endl;
priv
6. int n,m, priv;
7. cin>>m>>n;
8. // Pretpostavka je m>n ako nije, mijenjaju mjesta
9. if (m<n) {
10. priv=n;
11. n=m;
12. m=priv;
13. }
14. if (m%n) cout<<m<<" nije djeljiv s "<<n<<endl;
15. else cout<<m<<" je djeljiv s "<<n<<endl;
16. system("PAUSE");
17. return 0;
18. }

Gornji primjer sadri dvije if naredbe, jednu bez else, drugu sa else. U prvoj if naredbi,
ako je uvjet zadovoljen, varijable m i n mijenjaju mjesta. To je za to to na primjer 8 je
djeljivi s 4, ali 4 nije djeljivo s 8. Ova se zamjena izvrava kroz tri naredbe, koje su
stavljene u vitiaste zagrade. Bez vitiastih zagrada izvrila bi se samo prva naredba
priv=n; dok bi se preostale dvije izvodile svaki put, neovisno da li je uvjet ispunjen.
Treba primijetiti da je naredba if (n%m) zadovoljena ako je izraz u zagradi razliit od 0.
Ako izraz nije 0 (false), onda je automatski true tj. m nije djeljiv s n.

Jo jedan pouan primjer:

int n;
cout<< '' upii cijeli broj ''<<endl;
cin>>n;
if (n=22) cout <<''n= ''<<n<<endl;

55
else cout<< ''n nije jednak 22 nego''<<n<<endl;

Iako izgleda sve u redu, gornji program sadri logiku greku. Naime, u naredbi
if (n=22). upotrijebljen je samo jedan znak jednakosti. Taj se znak interpretira kao znak
pridruivanja tj. vrijednost 22 prenosi se u varijablu n. Uvjet if e uvijek biti ispunjen jer
je vrijednost n razliita od nule (true). Dakle bez obzira koja se vrijednost unese, izlaz e
biti:

upii cijeli broj: 77


n = 22

Ispravna je slijedea naredba:


if (n==22) cout <<''n= ''<<n<<endl;

Slijedi primjer programa s ugnijeenom naredbom if:

Primjer4.2.
1. // Primjer programa u C++ koji odreuje manji od dva zadana cijela broja
2. /* Ovaj program ilustrira upotrebu naredbe if */
3. #include <iostream.h>
4. int main()
5. {
6. cout<<" Upii dva cijela broja"<<endl;
7. int m,n;
8. cin>>m>>n;
9. if (m<n) cout<<m<<" je manji od "<<n<<endl;
10. else if (n<m) cout<<n<<" je manji od "<<m<<endl;
11. else cout<< m<<" je jednako "<<n<<endl;
12. return 0;
13. }

Logika naredbi u zelenom: Ne Ne


m< n< Pii n=m
n m
Da

Pii m<n Pii n<m

Slijedi jo jedan slian primjer:

56
Primjer4.3.
1. // Primjer programa koji odreuje najmanji od tri zadana cijela broja
2. /* Ovaj program ilustrira upotrebu naredbe if */
3. #include <iostream.h>
4. int main()
5. {
6. cout<<" Upii tri cijela broja"<<endl;
7. int n1,n2,n3, min;
8. cin>>n1>>n2>>n3;
9. cout<<"Upisani brojevi su: "<<n1<<","<<n2<<","<<n3<<endl;
10. min=n1; // polazna je 'pretpostavka' da je n1 najmanji
11. if (n2<min) min=n2; // ako je pak n2 manji on e zamijeniti n1
12. if (n3<min) min=n3; // ako je n3 manji on e zamijeniti prethodnu vrijednost
13. cout<<"Najmanji je: "<<min<<endl;
14. return 0;
15. }

Sad s vidi da bi i Primjer4.2. mogao biti jednostavnije rijeen s logikom iz rjeenja


Primjer4.3.
Naredbe na zelenoj podlozi za Primjer4.3. bi se mogle mijenjati kao u nastavku a da
program i dalje radi korektno:

cout << ''Najmanji je:'';


if (n1<=n2 && n1<=n3) cout<<n1;
if (n2<=n1 && n2<=n3) cout<<n2;
if (n3<=n1 && n3<=n2) cout<<n3;

4.2.Naredba (petlja) while

Petlje u programu ponavljaju odreeni skup naredbi dok je zadovoljen neki uvjet. Opi
oblik ove petlje je:

while (uvjet) naredba;

F
Vrh petlje
?
Povratni
Naredbe skok s
u petlji kraja A
na
poetak
while petlja
Dno petlje

57
Naredba se ponavlja toliko puta dok je uvjet istinit. Dakle, samo je po sebi razumljivo
da se unutar naredbe mora mijenjati neka veliina koja utjee na vrijednost uvjeta, jer bi
inae petlja bila beskonana.
Upotreba while petlje je ilustrirana na primjeru izrauna n! (N-faktorijela):

Primjer4.4.
1. // primjer za izraun faktorijela Neka je upisan n=6
2. #include <iostream.h> i<=n k i cout k
3. int main () 1 2
4. { 2<=6 true 2 3
5. int n; // zadani broj
3<=6 true 6 4
6. int i =2; //broj koji ide od 2 do n
4<=6 true 24 5
7. int k=1; //rezultat mnoenja
5<=6 true 120 6
8. cout << ''Unesi prirodni broj n'';
6<=6 true 720 7
9. cin >>n;
10. while (i<=n) 7<=6 false preskae n!=720
11. { k=k*i; Operacije unutar petlje su u tamnijim poljima. Ova je
12. i++; } tablica primjer za tzv. stolno testiranje programa. Prati se
13. cout << ''n!= ''<<k; logika naredbi i unose se redom vrijednosti pojedinih
14. return 0; varijabli.
15. }
Izlaz je slijedei:
...
Unesi prirodni broj n
15
n!= 2004310016
Press any key to continue . . .

4.3.Naredba do-while

Opi oblik

do naredba while (uvjet);

Ova je petlja identina s prethodnom (while) s izuzetkom da se uvjet provjerava nakon


izvoenja naredbe.

do while petlja

58
A
T

Kada bi prethodni zadatak za izraun faktorijela htjeli rijeiti s do-while petljom, onda
bi on na primjer mogao biti:

Primjer4.4a:
// primjer za izraun faktorijela Neka je upisan n=6
#include <iostream.h> i k i<=n cout k
int main () 1 1
{ 2 2 2<6 true
int n; 3 6 3<6 true
int i =1; 4 24 4<6 true
int k=1; 5 120 5<6 true
cout << ''Unesi prirodni broj n''; 6 720 6<6 false n!=720
cin >>n; Operacije unutar petlje su u tamnijim poljima.
do{ k=k*i; i++; } while (i<=n);
cout << ''n!= ''<<k;
return 0;
}
// druga varijanta
Unesi prirodni broj n
15 cout << ''Unesi prirodni broj n'';
n!= 2004310016 cin >>n;
Press any key to continue . . . k=n;
do { n- - ; k=k*n);} while (n=1);
cout << ''n!= ''<<k

4.4. Nardedba for

Opi oblik naredbe je :

for (poetna vrijednost; uvjet; korak poveanja) naredbe;

Ova se petlja ponavlja sve dok je uvjet istinit slino kao u while petlji uz dodatak da for
petlja ukljuuje i poetnu vrijednost i korak poveanja.

59
Redoslijed izvoenja naredbi u petlji for je slijedei:

1. Postavlja vrijednost varijable na poetnu vrijednost (to radi samo prvi put)
2. Ispituje izraz uvjet, ako nije istinit (dakle false) naputa petlju, inae
3. Izvode se naredbe
4. izvede korak poveanja
5. Ponavlja naredbe 2-4

for petlja

i= poetna
vrijednost

Ne

Uvj
et
OK
Da ?
Naredbe

Korak
poveanja

Primjer programa za izraun faktorijela bi mogao bi se rijeiti i na slijedei nain:

Primjer4.4b.
1. // primjer za izraun faktorijela

2. #include <iostream.h>
U konkretnom sluaju program
3. int main () bi radio isto i bez vitiastih
zagrada. One su nune ako je
broj naredbi u petlji vei od 1.
4. {

5. int n;

6. int k=1;

60
7. cout << ''Unesi prirodni broj n''<<endl;

8. cin >>n;

9. for (int i=2; i<=n; i++) {k=k*i;} Neka je upisan n=6


i<=n i k cout k
10. cout << ''n!= ''<<k<<endl; 2 1
2<=6 true 2
11. return 0;} 3<=6 true 3 6
4<=6 true 4 24
Unesi prirodni broj n 5<=6 true 5 120
15 6<=6 true 6 720
n!= 2004310016 7 n!=720
Press any key to Operacije unutar petlje su u tamnijim poljima
continue . . .

4.5. Naredba break

Naredba break slui za nasilno naputanje petlje, ak i kad uvjeti petlje za njeno
naputanje nisu zadovoljeni.

break;

Upotreba naredbe break pokazana je na primjeru odbrojavanja (countdown).

61
Primjer4.5.
1. // primjer za odbrojavanje
2. #include <iostream.h>
3. int main (){ 10,9,8,7,6,5,4,3,2,1,PALI!
4. int n; Press any key to continue . . .
5. for (n=10; n>0; n--)
6. {cout<<n<<",";}
7. cout<< "PALI!"<<endl;
8. system("PAUSE");
9. return 0;
10. }

U slijedeem je primjeru dodana naredba break.

Primjer4.6.
1. // primjer za odbrojavanje s break
2. #include <iostream.h>
3. int main (){
4. int n;
5. for (n=10; n>0; n--)
6. {
7. if (n==3)
8. {
9. cout<<"Preskacemo odbrojavanje,"; Ubaeno u odnosu Primjer4.5
10. break;
11. }
12. cout<<n<<",";
13. }
14. cout<< "PALI!"<<endl;
15. system("PAUSE");
16. return 0;
17. }

10,9,8,7,6,5,4,Preskacemo odbrojavanje,PALI!
Press any key to continue . . .

4.6.Naredba continue

62
Naredba continue radi slino kao break uz razliku da continue preskae samo tekuu
iteraciju. Dakle nakon naredbe continue program odmah prelazi na slijedeu iteraciju.
Ako na primjer u odbrojavanju elimo preskoiti broj 5, to se moe uiniti na slijedei
nain:

continue

Ako se u prethodnom primjeru (Primjer4.6) naredba break zamijeni s naredbom


continue, dobije se slijedei izlaz:

10,9,8,7,6,5,4,Preskacemo odbrojavanje,2,1,PALI!
Press any key to continue . . .

Dakle nakon Preskacemo odbrojavanje program nastavlja s 2 i 1, tj. preskae se samo


iteracija s n=3.

4.7. Naredba goto

Ova naredba znai bezuvjetni skok na naredbu koju pokazuje.

Opi oblik joj je:

goto labela;

Labela je identifikator kojim se oznaava pojedina naredba a zavrava s dvotokom (:).

63
labela: naredba;

Labele su se koristile prilikom izrade dijagrama toka, oznaene su krugovima, no u


modernim koncepcijama programiranja one se izbjegavaju kao i naredba goto. Ipak
ponekad je pored postojanja naredbi continue i break neophodno koristiti i goto. Naime,
upotreba prve dvije naredbe ima za posljedicu naputanje petlje while, do while ili for.
Meutim kad se radi s ugnijeenim petljama to moe predstavljati problem jer se
naredbama continue i break naputa samo zadnja petlja.
Slijedei primjer zbraja tri broja i ispisuje samo one sume koje su manje ili jednake
zadanom broju, u konkretnom sluaju 5.

Primjer4.7.

int main () {
int N =5;
for (int i=0; i<N;i++) {
for (int j = 0; j<N; j++) {
for (int k=0; k<N; k++) Petlja j Petlja i
if (i+j+k>N) goto van; Petlja k
else cout<<i+j+k<< '' '';
}
van: cout<<''. ''<<endl;
}
system("PAUSE"); Izvan petlje j, ali unutar petlje i
return 0;
}

0 1 2 3 4 1 2 3 4 5 2 3 4 5 .
1 2 3 4 5 2 3 4 5 .
2 3 4 5 .
3 4 5 .
4 5 .
Press any key to continue . . .

Da se je umjesto naredbe goto van upisala naredba break, ona bi izazvala izlazak iz
petlje k, ali ne i iz petlje j, pa bi izlaz bio:
0 1 2 3 4 1 2 3 4 5 2 3 4 5 3 4 5 4 5 .
1 2 3 4 5 2 3 4 5 3 4 5 4 5 5 .
2 3 4 5 3 4 5 4 5 5 .
3 4 5 4 5 5 .
4 5 5 .
Press any key to continue . . .

64
Postavlja se pitanje kako bi se problem mogao rijeiti bez upotrebe naredbe goto ? To se
moe rijeiti ubacivanjem jedne dodatne varijable tipa bool.

// Primjer4.7 bez goto


#include <iostream.h>
int main () {
int N =5;
bool uvjet=false;
for (int i=0; i<N;i++) {
for (int j = 0; j<N && !uvjet; j++) {
for (int k=0; k<N && !uvjet; k++)
if (i+j+k>N) uvjet=true; Kada uvjet postane true, naputaju se
else cout<<i+j+k<< " "; obje petlje.
}
cout<<". "<<endl;
uvjet=false;
}
return (0);
}

4.8 Naredba switch

Ova se naredba koristi kada treba ispitati izraze koji mogu poprimiti vie razliitih
vrijednosti, a za svaku je vrijednost potrebna druga naredba.

Opi oblik je:

switch ( izraz) {
case sluaj1: skup naredbi 1; break; switch
case sluaj2: skup naredbi 2; break;
. case 1 case 2 case3 default

.
. a b c d
default: skup naredbi;
}

Na primjer:

switch (x) {
case 1: cout<< ''x je jednak 1''; break;
case 2: cout<<''x je jednak 2''; break;
case 3: cout<<''x je jednak 3''; break;
default: cout<<'' x nije ni 1 ni 2 ni 3'';
}

65
Uz case se mogu usporeivati samo konstante, tj. ne mogu se pisati izrazi kao npr.
case (n*2).

Primjer 4.8:
// Upotreba naredbe switch
#include <iostream.h>
int main(){
int ocjena;
cout<<"Ukucati ocjenu"<<endl;
cin>>ocjena;
switch (ocjena){
case 1: {cout<< "Nedovoljan "; break;}
case 2: {cout<< "Dovoljan "; break;}
case 3: {cout<< "Dobar "; break;}
case 4: {cout<< "Vrlo dobar"; break;}
case 5: {cout<< "Izvrstan "; break;}
default: cout<<"Krivi unos";
}
system("PAUSE");
return 0;
}

4.9. Generiranje sluajnih brojeva

Jedna od znaajnih svojstava raunala je mogunost simulacija realnih dogaaja. U tom


kontekstu esto je potrebno da raunalo generira niz sluajnih brojeva. Razvijeni su
razliiti postupci za generiranje takvih brojeva no svi oni maju neke zajednike
karakteristike. Prva je znaajka raunala da je to deterministiki sustav u smislu da e za
isti ulaz, uz iste uvjete uvijek dati isti izlaz. Zbog toga raunalo ni ne moe generirati
stvarne nego tzv. pseudo sluajne brojeve. Generiranje sluajnog broja uvijek polazi od
izbora jednog poetnog broja koji se naziva sjeme (ili seed) a zatim se s njim rade
razliite raunske operacije. Za generiranje slijedeeg sluajnog broja uzima se prethodno
izraunati itd.

Primjer4.9.
/* Ovaj program generira sluajne brojeve */
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
int main()
{
unsigned sjeme;
cout<<"Ukucati sjeme"<<endl;
cin>>sjeme;
srand(sjeme); // inicijalizira sjeme

66
for (int i=0; i<8; i++)
cout<<rand()<<endl // funkcija rand generira sluajne brojeve;
return 0;
}

Program je izveden 3 puta i dobiveni su slijedei izlazi:

1. prolaz 2. prolaz 3. prolaz


Ukucati sjeme Ukucati sjeme Ukucati sjeme
1 2 1
41 45 41
18467 29216 18467
6334 24198 6334
26500 17795 26500
19169 29484 19169
15724 19650 15724
11478 14590 11478
29358 26431 29358

Prve broj u svakom stupcu, nakon poruke 'Ukucati sjeme' je onaj koji je sjeme koje je
ukucano putem tipkovnice. Vidi se da je kod treeg prolaza upisano isto sjeme kao i za
prvi prolaz pa su i sve generirane 'sluajne' varijable bile iste.

Da bi se izbjeglo ovakvo ponavljanje sluajnih brojeva, kao sjeme se koriste neka


neovisna polja kao to je na primjer broja vremena u raunalu.

Primjer4.9a.
/* Ovaj program generira sluajne brojeve iz time */
#include <iostream.h>
#include <stdlib.h>
#include <time.h> // ukljuuje se funkcija time()
int main()
{
unsigned sjeme=time(0) // dobiva trenutnu vrijednost vremena u raunalu;
cout<<"Sjeme je: "<<sjeme<<endl;
srand (sjeme); // generira sjeme za rand funkciju da se broj ne ponavlja
for (int i =0; i<8; i++)
cout<<rand()<<endl;
return 0;
}

67
Izlaz je: 1. prolaz 2. prolaz
Sjeme je: 1138462312 Sjeme je: 1138462405
12703 13007
2329 18891
12424 2624
16405 26069
4499 13482
10136 14874
25918 20464
3995 26670

S obzirom da funkcija time mjeri apsolutno vrijeme, odnosno broji sekunde od 1.1.1970.
ona se nikad ne ponavlja, pa s njom nije mogue ponoviti isti niz sluajnih brojeva.

Ponekad je potrebno generirati sluajne brojeva unutar nekog zadanog intervala.


Ako kao sluajnu varijablu elimo imati brojeve izmeu na primjer 101 i 222. Obje
granice ukljuene. Onda se to uini na slijedei nain. Izmeu 100 i 222 ima 122
razliite vrijednosti. Ako se sluajna varijabla n stavi u operaciju modul, na primjer n
%122, kao rezultat se dobiju ostatak dijeljenja koji moe poprimiti vrijednost od 0 do
121. Doda li se tom broju 101 dobiju se vrijednosti izmeu 101 i 222.

Dakle za generiranje sluajnih brojeva izmeu 101 i 222 moe se koristiti program sa
slijedeim naredbama:

int n;
srand (time(0));
n=rand ()%122+101;

Napomenimo da postoji i funkcija RAND_MAX koja vraa najveu vrijednost sluajnog


broja. U sluaju ovog raunala vraena je vrijednost 32 767.

Slijedi primjer programa za igru protiv raunala. Raunalo generira sluajni broj izmeu
1 i 256 a igra ga treba pogoditi. Uz dobro izabranu taktiku, broj se moe pogoditi u
najvie 8 pokuaja.

68
Primjer 4.10.
1. // Igra pogaanja brojeva koje generira raunalo
2. /* Pravila igre: raunalo generira sluajni broj izmeu 1 i 256,
3. a igra ga pokuava pogoditi tako to unos po jedan broj. Raunalo odgovara
4. da li je broj koji se eli pogoditi manji jednak ili ve od upisanog broja */
5. #include <iostream.h> // tu su spremljene naredbe cout i cin
6. #include <cstdlib> // ukljuuje se biblioteka standardnih funkcija
7. #include <ctime> // ukljuuje se biblioteka s vremenom(sjeme sluajnih brojeva)
8. int n=1; // broj kojeg igra unosi u raunalo
9. int br; //sluajni broj kojeg generira raunalo
10. char odg;
11. int i=0; // Broj pokuaja da se pogodi zadani broj
12. int main (){
13. while (n!=0){
14. srand (time(0));
15. br=rand()%256+1;
16. // generirani sluajni broj u operaciji modul 256 daje ostatak djeljenja
17. // izmeu 0 i 255 pa mu se doda 1 da bi broj bio u traenim okvirima.
18. do {
19. cout<<" Ukucaj cijeli broj izmeu 1 i 256"<<endl;
20. cin>>n;
21. if (n<1||n>256) {cout<<" Ukucani broj je izvan dozvoljenih
granica"<<endl;
22. continue; }
23. i++;
24. if (n==br) cout<< " Cestitam pogodili ste u "<<i<<" koraka"<<endl;
25. if (n>br) cout<<"Trazeni broj je manji"<<endl;
26. if (n<br) cout<<"Trazeni broj je veci"<<endl;
27. } while (n!=br);
28. cout<<" Ako zelis nastaviti upisi bilo koji broj, inace upisi 0"<<endl;
29. cin>>n;
30. i=0;
31. }
32. system("PAUSE");
33. return 0;
34. }

Primjer4.10. sadri po jednu while i do while petlju. Prva petlja while ide izmeu
naredbi u 13. i 31. retku i izvodi se dok je ispunjen uvjet daje n razliit od 0. Kao to se
iz programa moe vidjeti, za izlazak iz navedene petlje treba ukucati vrijednost za n
jednaku 0.
Druga petlja do while nalazi se izmeu naredbi od 18. do 27. retka i ponavlja se sve dok
je ispunjen uvjet da je n razliit od broja kojeg treba pogoditi. Iz te petlje se moe izai
samo tako da se pogodi sluano generirani broj br, koji je generiran u 14. i 15. retku.

69
U nastavku je druga verzija programa. Sada igra zadaje broj izmeu 1- 256 a raunalo
ga pogaa. Moe se provjeriti da raunalo uvijek pogodi u najvie 8 pokuaja.
Metoda pogaanja broja koja je ugraena u program naziva se 'binarno pretraivanje' i
detaljno je pojanjena u poglavlju 6.5. Sutina je metode da se u svakom koraku interval
pretraivanja prepolovi, pa se u 8 koraka svede na jedan broj (256=28). Igra najprije
unosi broj, a za tim odgovara sa <,= ili > ovisno da li je zadani broj manji, jednak ili vei
od broja kojeg raunalo predlae.

Primjer4.11.
1. // Igra pogaanja brojeva
2. /* Pravila igre: upisati jedan cijeli broj izmeu 1 i 256.
3. Raunalo pogaa a na odgovor mora biti
4. <, = ili > ovisi o tome da li je upisani broj manji,
5. jednak ili veci od onog kojeg je racunalo prikazalo na ekranu*/
6. #include <iostream.h>
7. int n=1; // broj kojeg treba upisati i kojeg e raunalo pogaati
8. int lo=1, hi=256; //gornja i donja granica intervala u kojem se pogaa
9. int br; // broj kojeg raunalo generira da 'pogodi' n
10. char odg;
11. int i=1; // Broj pokuaja da se pogodi zadani broj
12. int main (){
13. while (n!=0) {
14. cout<<" Ukucaj cijeli broj izmeu 1 i 256"<<endl;
15. cin>>n;
16. if (n<1||n>256) {cout<<" Ukucani broj je izvan dozvoljenih granica"<<endl;
17. continue;}
18. br=(lo+hi)/2;
19. cout<<"Je li to broj "<<br<<" ?"<<endl;
20. cin>>odg;
21. while(odg!='=') {
22. if (odg=='<') hi=br;
23. if (odg=='>') lo=br;
24. if (odg=='>' && br>=n || odg=='<' && br<=n) {cout<<"Poceli smo
lagati?"<<endl;
25. goto kraj;}
26. br=(lo+hi)/2;
Koritena je
27. cout<<"Da li je to broj "<<br<<" ?"<<endl;
naredba goto,
28. cin>>odg;
koja se inae
29. i++; izbjegava.
30. }
31. cout <<"Pogodio u "<< i<<"koraka"<<endl;
32. kraj: lo=1; hi=256;
33. cout<<" Ako eli nastaviti upisi bilo koji broj, inae upisi 0"<<endl;
34. cin>>n;
35. }

70
36. return 0;
37. }

Za razumijevanje logike u programu Primjer4.11 treba pojasniti 'trik' sa granicama


intervala. Kao to se iz programa vidi donja granica je oznaena sa lo (od low) a gornja
sa hi (od high) i u retku 8. su dobile poetnu vrijednost lo=1 i hi =256 . U retku 18. te
se dvije vrijednosti zbroje i podijele s 2. Dakle kod prvog prolaska programa kroz tu
neredbu varijabla br s kojom program pokuava pogoditi zadani broj (u retku 19.),
poprima vrijednost 128 ( tj. 257/2 bez decimala).

Rezultat moe biti slijedei:


1.Ako je zadani broj upravo 128, tada je odgovor u retku 20 jednak '=' i program
preskae while petlju od retka 21. do 30. te ide na 31. redak gdje pie poruku pogodio.
2. Ako je odgovor '<' tj. traeni broj je manji od 128. u slijedeem ga pokuaju treba
'gaati' na prvoj polovici intervala, dakle izmeu 1 i 128 zbog toga se u naredbi 22.
mijenja gornja granica intervala hi s br tj s 128.
3. Ako je odgovor '>' znai da je traeni broj izmeu 128 i 256, pa se zbog iste logike u
naredbi 23. donja granica lo postavlja na br odnosno 128.

5.Funkcije

U poetnoj fazi razvoja tehnike programiranja, funkcije su nastale kao rjeenje nekoliko
problema.
Kada se na vie mjesta u nekom programu treba obaviti isti slijed naredbi mogua su
bila dva rjeenja, jedno je da se na svakom mjestu ponove iste naredbe. Drugo je
rjeenje da se te naredbe piu samo na jednom mjestu pa da se program grana na to
mjesto kada treba izvriti dotine naredbe. Prvo rjeenje trai dosadno ponavljanje
naredbi i poveanje programa, drugo rjeenje komplicira logiku programa.
Neki su se poslovi uporno ponavljali iz programa u program. Na primjer izraun drugog
korijena, logaritma ili vrjednosti trigonometrijskih funkcija u tehnikim programima ili
izraun kamate u komercijanm programima. Bili je logino da se ti zadaci rijee jednom
za uvijek, te da ih svi mogu koristiti kao gotovu i provjerenu stvar.
Programi u praktinoj primjeni su u pravilu puno veeg opsega od primjera koji su
prikazani u ovom priruniku. Zbog toga je est sluaj da na izradi jednog programa
sudjeluje vie osoba. Izrada i kasnije odravanje velikih i kompleksnih programa
nametnuli su potrebu da se oni razgrade na manje samostalne dijelove, koji se openito
nazivaju potprogramima.
Funkcije predstavljaju jednu vrstu potprograma unutar glavnog programa i njihovim se
koritenjem struktura programa moe znatno pojednostaviti. Nain izvoenja programa
koji sadri funkcije, ilustrirano je na slijedeoj slici:

71
Slika 5.1: Odnos glavnog programa i funkcija

int main () { funkcija1 () {


//
poziv funkcije1 return; }
funkcija3 () {
//
funkcija2 () { //
poziv funkcije2
// return; }
// poziv funkcije3
return 0; return; }
}

Iako sama funkcija ima strukturu poput bilo kojeg programa, ona nema neredbu
int main () koja se smije pojaviti samo jedan put u svakom programu, kao oznaka odakle
poinje izvoenje dotinog programa.
Pozivom funkcije izvoenje se od glavnog programa (main) prenosi na naredbe funkcije.
Po zavretku izvoenja naredba funkcije, nastavlja se izvoenje glavnog programa od
naredbe koja slijedi iza naredbe s kojom je funkcija pozvana. Sama funkcija npr.
funkcija2, moe pozivati neku drugu funkciju3, po istoj logici koja vrijedi za odnos
glavnog programa i funkcije2.
Kada se u jednom programu isti postupak ponavlja na vie mjesta, onda se to moe
rijeiti na nain da se odgovarajue naredbe kopiraju. To meutim poveava opseg
programa i komplicira njegovo odravanje. Uvoenjem funkcije, taj se problem rjeava
njenim pozivanjem sa vie mjesta u programu. Pri tome se funkcije mogu prevoditi
zajedno s programom ili izdvojeno.

Jezik C++ ukljuuje u sebi niz funkcija koje su pohranjene u standardnim bibliotekama.
Ako se na primjer, eli izraunati drugi korijen zadanog broja to se moe uiniti
slijedeim programom:

Primjer5.1.
1. // Program za izraun drugog korijena brojeva od 0 do 5
2. #include <cmath.h> // ukljuuje matematike funkcije
3. // za izraun drugog korijena koristi se sqrt (square root)
4. #include <iostream.h>
5. using namespace std:
6. int main(){
7. for (int x=0; x<6; x++)
8. cout<<Drugi korijen od <<x<< = <<sqrt(x) <<endl;
9. } Drugi korijen od 0 = 0 8
Drugi korijen od 1 = 1 8
Drugi korijen od 2 = 1.41241 8
Drugi korijen od 3 = 1.73205 8
Svaki programer moe i sam napisati funkcju kada
Drugi za to od
korijen ima4 potrebu.
=2 Opi8oblik naredbi
za definiciju funkcije je: Drugi korijen od 5 = 2.23607 8

72
type ime (argument1,argument2,....) {naredbe}

Opi oblik deklaracije funkcije je:

povratni tip- definira tip podatka (int, float,...) kojeg funkcija vraa u glavni program.

ime je identifikator funkcije, tj. naziv prema pravilima za nazive varijabli, s kojim se
poziva.

argumenti su tipovi i nazivi varijabli koje se prenose u funkciju (npr. int x) .

naredbe opisuju to funkcija radi.

Primjer5.2.
1. // program za zbrajanje dviju varijabli
2. #include <iostream.h>
3. int zbrajanje (int a, int b) // boldani dio teksta predstavlja funkciju
4. { int r;
5. r=a+b; Izlaz e biti:
6. return (r); }
Rezultat je 8
7. int main ()
8. {
9. int z;
10. z = zbrajanje (5,3);
11. cout << "Rezultat je " << z;
12. return 0;
13. }

Sada treba ponovo naglasiti da se program uvijek poinje izvoditi od naredbe main ().
Dakle, iako je funkcija smjetena ispred glavnog programa, prilikom izvoenja ona se
preskae i izvodi tek kada se poziva iz programa koji je oznaen sa main.

Kada se unutar main djela programa pozove funkcija

z=zbrajanje (5 , 3); uspostavi se veza s naredbom

int zbrajanje (int a, int b);

Kada se poinje izvoditi funkcija zbrajanje, vrijednosti varijabli a i b su jednake 5


odnosno 3.

73
Unutar funkcije definirana je nova varijabla r. Naredba return r; uspostavlja
korespondenciju izmeu varijable r i varijable z, koja je navedena u naredbi s kojom se
poziva funkcija.

Zbog toga je vrijednost varijable z nakon zavretka rada funkcije zbrajanje jednaka 8.

Pitanje: Da li bi program bio ispravan da je u naredbi za pisanje umjesto z stajalo r ?

Dakle:
cout << "Rezultat je " << r;

Odgovor je negativan jer je r prema nainu definicije lokalna varijabla, koja nije poznata
u main programu.

Isto tako unutar funkcije zbrajanje nije se mogla koristiti varijabla z, jer ona je
definirana unutar main vitiastih zagrada. Da se varijabla z definirala izvan vitiastih
zagrada, mogla bi se koristiti u cijelom programu.

Bitno je naglasiti jo jedno bitno svojstvo funkcije. Naredba

z=zbrajanje (5 , 3);

promijenila je tok izvoenja naredbi u programu, jer se prelo na izvoenje naredbi


unutar funkcije. Kada je funkcija zavrila s radom, program nastavlja izvoditi naredbe
koja slijedi iza naredbe kojom je funkcija pozvana. Ovo svojstvo funkcija olakava
praenje toka programa.

Ako se prethodni program izmjeni tako da se deklaracija varijable r stavi izvan vitiastih
zagrada, ona e biti prepoznatljiva u cijelom programu, pa se u naredbi za ispisivanje
umjesto z moe staviti r.

// program za zbrajanje dviju varijabli


#include <iostream.h>
int r;
int zbrajanje (int a, int b) {
r=a+b;
return (r); }
int main ()
{
int z;
z = zbrajanje (5,3);
cout << "Rezultat je " << r;
return 0;
}

74
Prilikom prevoenja prevoditelj (Borland) daje upozorenje da se varijabla z nigdje ne
koristi, ali program ipak daje isti rezultat kao i prije.

Jo jedan primjer za funkciju:

Primjer5.3.
1. // primjer funkcije 2. Prvi rezultat je 5 12
2. #include <iostream.h> Drugi rezultat je 5 13
3. int oduzimanje (int a, int b) Trei rezultat je 2 14
4. { etvrti rezultat je 6 16
5. int r;
6. r=a-b;
7. return (r);
8. }
9. int main () {
10. int x=5, y=3, z;
11. z = oduzimanje (7,2);
12. cout << "Prvi rezultat je " << z << '\n';
13. cout << "Drugi rezultat je " << oduzimanje (7,2) << '\n';
14. cout << "Trei rezultat je " << oduzimanje (x,y) << '\n';
15. z= 4 + oduzimanje (x,y);
16. cout << "etvrti rezultat je " << z << '\n';
17. return 0;
18. }
U ovom su primjeru prikazani razliiti naini pozivanja funkcije, no efekt je uvijek kao i
u prethodnom primjeru.

Postoje i funkcije koje ne trebaju vraati nikakvu vrijednost u glavni program. Tada se u
definiciji funkcije umjesto type( tj. int, float,...) navodi void.

Na primjer funkcija koja treba neto ispisati na ekranu.

// primjer funkcije void


#include <iostream.h>
void laznafunkcija (void)
{ Ja sam funkcija !
cout << "Ja sam funkcija !";
}
int main ()
{
laznafunkcija ();
return 0;
}
Oznaka void pokazuje da funkcija nema argumenata i/ili parametra.

75
5.1.Prijenos argumenata po vrijednosti i po referenci

U prethodno navedenim primjerima, argumenti su prenijeti po vrijednosti. Dakle ako je

int x=5, y=3, z;


z= zbrajanje ( x , y );

int zbrajanje
5 (int a, int
3 b);

Prenose se vrijednosti 5 (za vrijednost od x) i 3 ( za vrijednost y).

Postoji i drugi nain prijenosa argumenta, prijenos po referenci, koji se prikazuje u


slijedeem primjeru.

Primjer5.4.
1. // prijenos parametara po referenci , program udvostruuje vrijednost
varijabli
2. #include <iostream.h>
3. void duplicate (int& a, int& b, int& c)
4. {
5. a*=2; // a=a*2,
6. b*=2; // b=b*2
7. c*=2; // c=c*2 x=2, y=6, z=14
8. }
9. int main ()
10. {
11. int x=1, y=3, z=7;
12. duplicate (x, y, z);
13. cout << "x=" << x << ", y=" << y << ", z=" << z;
14. return 0;
15. }

Treba primijetiti da je funkcija duplicate tipa void jer ona ne navodi nikakav parametar
kojeg vraa u main program.

Meutim, s obzirom da su u definiciji funkcije varijable navedene s & (ampersand)


ovdje se pridruivanje vrijednosti izvrava na drugi nain.

Kada se varijable prenose 'po referenci' prenose se same varijable i svaka promjena u
vrijednosti varijabli koja se izvri unutar funkcije ima neposredni utjecaj na samu
varijablu u main programu.

76
Dakle, varijabla x se prenosi na mjesto varijable a, na isti nain y na b i z na c.

Promjenom vrijednosti varijabli a,b i c automatski se mijenjaju vrijednosti varijabli x,y i


z.

5.2.Podrazumijevane (defaults) vrijednosti u argumentima

Prilikom definiranja funkcije i navoenja argumenata moe se unaprijed nodrediti


vrijednost argumenta. Ta e se vrijednost uzimati ako se u pozivu funkcije taj argument
izostavi.
Na primjer, funkcija za dijeljenje.

Primjer5.5.
1. // default vrijednosti u n funkciji

2. #include <iostream>

3. using namespace std;

4. float podijeli (float a, float b=2);

5. {

6. float r;

7. r=a/b;

8. return (r);

9. }

10. int main ()

11. {

12. cout << podijeli (12);

13. cout << endl;


6 12
5 14
14. cout << podijeli (20,4)<<endl;

77
15. system("PAUSE");

16. return 0;

17. }

U prvom sluaju podijeli (12), za drugi argument je uzeta pretpostavljena vrijednost 2.


U drugom sluaju, kada su navedena oba argumenta, uzete su navedene vrijednosti.

78
5.3.Prenapregnute funkcije (overloaded)

Dvije funkcije mogu imati isto ime ako im se razlikuje broj argumenata ili tip
argumenata. Na primjer:

Primjer5.6.
1. // prenapregnute (overloaded) funkcije
2. #include <iostream.h>
3. int podijeli (int a, int b)
4. {return (a/b);} Prva funkcija
5. float podijeli (float a, float b)
6. {return (a/b);}
7. int main () Druga funkcija s istim nazivom
8. { 2
9. int x=5,y=2; 2.5
10. float n=5.0,m=2.0;
11. cout << podijeli (x,y); 2 11
12. cout << ''\n''; 2.5 13
13. cout << podijeli (n,m);
14. cout << ''\n'';
15. return 0;
16. }

Definirane su dvije funkcije s istim imenom ali razliitim argumentima. Prevoditelj bira
funkciju prema zadanim argumentima.

5.4.Jo neka svojstva funkcija

Ako se ispred definicije funkcije napie kljuna rije inline, prevoditelj e prevesti
izvorni kod funkcije na mjestu gdje se funkcije poziva. Na taj se nain izbjegava prijenos
parametara koji za neke, vrlo kratke funkcije, moe poveati vrijeme njihovog
izvoenja.

Rekurzivnost je svojstvo funkcije da moe pozvati samu sebe. To je vrlo korisno kod
rjeavanja nekih tipova zadataka. Navedimo primjer funkcije za izraun faktorijela.

Primjer5.7.
1. // izraun faktorijela-rekurzijom
2. #include <iostream>
3. using namespace std;
4. long faktorijela (long a)
5. {
6. if (a > 1) Ukucaj broj:
7. return (a * faktorijela (a-1)); 9! = 362880

79
8. else
9. return (1);
10. } Kako to radi ?

11. int main () U polje a stavlja 9 * faktorijela (8 ) to je


9*8* faktorijela(7) itd. do
12. { 9*8*7*6*5*4*3*2 i tada zbog a=1 (tj. 2-1)
ide na else koji prekida pozivanje funkcije.
13. long k;

14. cout << "Ukucaj broj: ";

15. cin >> k;

16. cout << k << "! = " << faktorijela (k);

17. return 0;

18. }

Vidi se da je funkcija faktorijela pozivala samu sebe sve dok a nije poprimio vrijednost
1. Inae bi program uao u beskonanu petlju.

80
5.5. Postupka izrade programa -pseudokod

Do sada su obraeni neki osnovni elementi programskog jezika C++ na temelju kojih se
moe stvoriti predodba o postupku kodiranja programa. Kao to je ve reeno svaki
programski jezik predstavlja suelje za komunikaciju ovjeka sa raunalom. Vii
programski jezici, kakav je i C++, bolje su prilagoeni komunikaciji ovjekom. Dakle u
njih je ugraena logika bliska ljudskom razmiljanju. Program prevoditelj prevodi
naredbe pisane u C++ u strojni jezik koji je jedini 'razumljiv' raunalu.
Program sadri naredbe, varijable i konstante koje se za vrijeme izvoenja programa
nalaze u memoriji raunala. Naredbe su poredane jedna iza druge kao to su u programu
napisane i tim se redom i izvode. Izuzetak su one naredbe koje izazivaju skretanje
programa od slijednog izvoenja. Naredbe sadre adrese polja u kojima su smjetene
varijable i konstante te 'uputu' to s tim veliinama treba uiniti kao na primjer: zbrojiti
dvije veliine i rezultat pohraniti u neko polje (itaj adresu u memoriji), usporediti dvije
veliine i u ovisnosti od rezultata usporeivanja izvriti neku treu naredbu itd.

Postupak izrade programa od faze definiranja problema, opisa algoritma pseudokodom,


do kodiranja i testiranja programa prikazan je na poetku ove knjige na slici 1.6. Tad nisu
prikazani primjeri koritenja pseudokoda, jer je za njegovo pisanje neophodno
poznavanje osnovne logike programskih jezika. Zbog toga e se u nastavku prikazati
izradu pseudokoda na nekoliko primjera vezanih za odreivanja prim brojeva. Na
temelju navedenog pseudokoda izraeni su i programi, koji ilustriraju primjenu dosad
izloenog gradiva iz C++.

Radi lakeg praenja logike izrade programa, razradit e se dva zadatka.

1. U prvom zadatku e se preko konzole traiti da se upie broj n, a program e provjeriti


da li je zadani n prim broj ili nije .

2. U drugom zadatku e se ponovno traiti da se upie broj n, a program e ispisati sve


prim brojeve manje od n.

1. Definicija problema

to je prim broj? To je prirodni broj koji nije djeljiv ni s jednim drugim brojem osim s 1 i
sa samim sobom. Ni jedan parni broj (osim 2) nije prim broj, jer paran je onaj broj koji
je djeljiv s 2. Zato je onda 2 prim broj ? Zato to je u skladu s definicijom prim broja
djeljiv samo s jedan i sa samim sobom.

Prema tome, prim brojevi su: 2,3,5,7,11,13,17,19,23,29, .... 6

2. Definiranje i opis algoritma

Kako moemo provjeriti da li je neki broj prim broj ?

6
Broj 1 prema dananjem stanju stvari nije ni prim ni sloen broj. Nekad se smatrao prim brojem ali s
obzirom na neke njegove specifinosti danas je izbaen iz tog drutva.

81
Tako da ga pokuavamo dijeliti s brojevima koji su manji od njega (osim s 1), pa ako je
s nekim od njih djeljiv, taj broj oito nije prim broj. Na primjer 13 je prim broj jer nije
djeljiv ni s jednim brojem manjim od 13, dok 14 nije prim broj jer je djeljiv s 2 i sa 7.
Da li je nuno da se broj koji se ispituje dijeli sa svim brojevima od poevi od 2 pa do
broja koji je za 1 manji od njega?
Nije nuno, dovoljno je provjeravati djeljivost do prirodnog broja koji je jednak
cjelobrojnom korijenu zadanog broja .
Ilustrirajmo to na primjeru broja 64, koji se moe napisati kao produkt slijedea dva
broja:
8x8
4x16
2x32

Drugi korijen od 64 je 8, pa ako se broj 64 moe dobiti kao produkt dvaju brojeva koji
nisu njegov korijen, onda za njih mora vrijediti da je jedan vei od korijena, a drugi
mora biti manji7. Dakle ako broj nije djeljiv ni s jednim brojem do njegovog korijena, nije
djeljiv ni s jednim brojem veim od njegovog korijena.

Opis algoritma pseudokodom.

Pseudokod je nain opisivanja logike programa ljudskim jezikom. Svrha mu je da sistem


analitiar odnosno informatiar koji je strunjak za problem objasni programeru, odnosno
informatiaru koji je iskusan u programiranju, kakav program mora izraditi. Radi
izbjegavanja nesporazuma bitno je da obojica razgovaraju 'istim jezikom'. S obzirom da
e konani proizvod tj. program biti napisan u nekom od programskih jezika koji e se na
kraju prevesti u strojni jezik koji jedini raunalu 'razumljiv', u opisu algoritma se sistem
analitiar nastoji pribliiti 'logici raunala'.

7
Naime, kada bi se 64 mogao dobiti kao umnoak dva broja koji su oba vea od 8, onda bi se oni mogli
napisati kao 8+k i 8+ m, gdje su m, n >0.

Njihov umnoak bi bio


(8+m)*(8+k)= 64 + 8*m+8*k +m*k =64

slijedi
8*(m+k)+m*k=0

odnosno
mk
8
mk

S obzirom da su m i k brojevi vei od nule, razlomak s lijeve strane jednakosti ne moe nikad poprimiti
negativnu vrijednost. Prema tome je polazna pretpostavka nemogua.

82
1. zadatak: Napisati program kojemu se zadaje broj n i program ispituje da li je
taj n prim broj.

/* n- je broj koji upisujemo na konzoli


j- je broj kojeg mijenjamo od 2 do korijena od n, radi provjere dali je n djeljiv s j */
Pii na ekranu: ''Unesi prirodni broj vei od 2'',
itaj n;
Ako je n nije vei od dva napii ''Upisani broj nije vei od 2'';
Inae nastavi;
Postavi j na vrijednost 2, ponavljaj slijedee naredbe dok je j<= korijenu od n,
te poveavaj j za 1;

ako je (n%j) razliit od 0, dakle n nije djeljiv s j vrati se na poetak petlje ;


inae pii: '' n nije prim broj'' i idi na kraj programa.
Pii: '' n je prim broj''
Kraj programa.

Vano je istaknuti!
Dovoljno je da se nae jedna vrijednost j za koju je (k%j) false, dakle 0, odnosno n je djeljiv
s j, pa da zakljuimo da n nije prim broj.
Iz injenice da je (k%j) true, dakle razliito od 0, tj. n nije djeljiv s j, ne moe se zakljuiti da
je n prim broj.
To se moe zakljuiti tek ako to svojstvo vrijedi za sve j vee od 1 i manje od korijena od n.

83
Primjer5.8.
1. // Program koji ispituje da li zadani broj prim ili ne
2. /* n- je broj koji upisujemo na konzoli
3. j- je broji ide od 2 do korijena od n, i s njime dijelimo n */
4. #include <iostream.h>
5. #include <cmath>
6. int j, k=1,n;
7. int main ()
8. {
9. cout << "Unesi prirodan broj vei od 2"<<endl;
10. cin >> n;
11. if (n<=2) cout<<"Upisani broj nije vei od 2";
12. else {
13. for (j=2; j<=sqrt(n); j++) {
14. k=n%j;
15. if (k==0) { cout<<n<< " nije prim broj, djeljiv je s " <<j;
16. break; }
17. }
18. if (k!=0) cout<< n <<" je prim broj";
19. }
20. return 0;
21. }

Program dolazi na ovu naredbu na dva naina:


1. Kada je prisilno napustio petlju nakon naredbe break.
2. Ako je zavrio petlju jer je j postao vei od sqrt(n)

Naredbom if (k!=0) se zapravo ispituje radi li se o sluaju 1. ili 2. Ovo se ispitivanje


moglo izbjei na primjer tako da se umjesto naredbe break koristila naredba goto
kojom bi se preskoila naredba za pisanje '' n je prim broj''

84
Usporedba pseudokoda i programa

Pseudokod C++ naredbe

// Program koji ispituje da li zadani broj prim ili ne


/* n- je broj koji upisujemo na konzoli /* n- je broj koji upisujemo na konzoli
j- je broj kojeg mijenjamo od 2 do korijena od n, j- je broji ide od 2 do korijena od n, i s njime dijelimo n */
radi provjere dali je n djeljiv s j */
#include <iostream.h>
Poetak programa int main () {
definirati cjelobrojne varijable j,k i n int j, k=1,n;
Pii na ekranu: ''Unesi prirodni broj vei od 2'', cout << "Unesi prirodan broj vei od 2"<<endl;
itaj n; cin >> n;
Ako je n nije vei od dva napii ''Upisani broj nije vei od 2''; if (n<=2) cout<<"Upisani broj nije vei od 2";
Inae nastavi; else {
Postavi j na vrijednost 2, ponavljaj slijedee naredbe dok je for (j=2; j<=sqrt(n); j++) {
j<= korijenu od n, te poveavaj j za 1;
staviti u k ostatak kod djeljenja n sa j k=n%j;
ako je (k==0), dakle n je djeljiv s j pii: n nije prim if (k==0) { cout<<n<< " nije prim broj, djeljiv je s "
broj idi na kraj programa. <<j; goto kraj; }
Pii: '' n je prim broj'' cout<< n <<" je prim broj";
Kraj programa. kraj: return 0;
}

U konkretnom programskom rjeenju izbjegnuta je upotreba naredbe goto nego je koritena naredba break. Zbog toga se prije pisanja
da je n prim broj moralo ispitati kako je program doao do te naredbe.

85
2 zadatak: Napisati program koji ispisuje sve prim brojeve koji su manji od zadanog
broja n

/* n- je broj koji upisujemo na konzoli i do kojeg traimo prim brojeve


i- je broj za kojega provjeravamo da li je djeljiv s nekim brojem. Oni se poveava od
3 do n
j- je broj kojeg mijenjamo od 2 do korijena od i, i s njime dijelimo i */

Pii na ekranu ''Unesi prirodni broj vei od 2'',


itaj n;
Ako je n nije vei od dva napii ''Upisani broj nije vei od 2'';
Inae nastavi;
Pii na ekranu '2,''
Postavi i na vrijednost 3, ponavljaj slijedee naredbe dok je i<n, te poveavaj i za 2;
Postavi j na vrijednost 2, ponavljaj slijedee naredbe dok je j<= korijenu od i,
te poveavaj j za 1;

k =i%j;

Ako je k=0 (znai i je djeljiv s j) i nije prim broj pa naputamo j petlju i idemo
na kraj i petlje;
Kraj j petlje;
Ako je k!=0 pii i;
Kraj i petlje;
Kraj inae;
Kraj programa.

86
Pisano u C++ , prikazane su dvije verzije koda, sa i bez koritenja funkcije.

Primjer5.9.
1. // primbra.cpp- program za ispisivanje prim brojeva
2. /* n- je broj koji upisujemo na konzoli do kojeg trazimo prim brojeve
3. i- je broj koji se poveava od 3 do n, za kojega provjeravamo da li je d
4. brojem.
5. j- je broj kojeg mijenjamo od 2 do korijena od i, i s njime dijelimo i
6. #include <iostream.h>
7. #include <cmath>
8. int i,j,n;
9. int main () {
10. cout << "Unesi prirodan broj vei od 2"<<endl ;
11. cin >> n;
12. if (n<=2) cout<<"Upisani broj nije vei od 2";
13. else {
14. cout<< "2,"; Primjer5.9a.
15. for (i=3; i<=n; i=i+2) { // koristi funkciju
16. for (j=2; j<=sqrt(i); j++) #include <iostream.h>
17. if (i%j==0) break; #include <cmath>
18. if (i%j) cout<< i <<","; int i,k,n;
19. } /* slijedi funkcija - ona vraa vrijednost 0 ako
20. } ispitivani broj nije prim broj */
21. return 0; int primbroj (int i) {
22. } int a,c;
for (a=2; a<=sqrt(i); a++) {
c=i%a;
Lokiga glavnog programa je znatno if (c==0) break;
jednostavnija ako se koristi funkcija . }
Funkcija se moe odvojeno prevesti i return (c);
pohraniti. Bitno je znati da joj se predaje }
jedan cjelobrojni argument i da ona vraa int main () {
0 ako taj argument nije prim broj. cout << "Unesi prirodan broj vei od 2"<<endl ;
cin >> n;
if (n<=2) cout<<"Upisani broj nije vei od 2";
else {
cout<< "2,";
for (i=3; i<=n; i=i+2) {
k= primbroj(i);
if (k== 0) continue;
else cout<< i <<","; }
}
return 0;
}

87
I trei primjer programa za generiranje prim brojeva koji koristi funkciju i Boolove
varijable:

Primjer5.9b.
1. // Ispisivanje prim brojeva - koristi se funkcija i Boolova varijabla
2. #include <cmath> // radi upotrebe sqrt ()
3. #include <iostream.h>
4. bool jeprim (int); // vraa true ako n je prim broj, inae false
5. int main()
6. {
7. int x;
8. cout <<"Unesi cijeli broj vei od 2"<<endl;
9. cin>>x;
10. if (x<=2) cout<< "Broj nije vei od 2";
11. for (int i=0; i<=x; i++) U ovom je primjeru funkcija (od naredbe
12. if (jeprim(i)) cout<<i<<","; 15)smjetena nakon glavnog programa.
13. return 0; Kako bi glavni program prepoznao funkciju
14. } neophodno je prije programa (naredba 4.)
15. // slijedi opis funkcije staviti samo njenu deklaraciju.
16. bool jeprim (int n){
17. float sqrtn=sqrt(n);
18. if (n<2) return false; // 1 nije prim broj
19. if (n<4) return true; // zato to 2 i 3 jesu prim brojevi
20. if (n%2==0 )return false;
21. for (int d=3; d<=sqrtn; d+=2)
22. if (n%d==0) return false;
23. return 1; // to je ekvivalentno return true
24. }

88
6. Polja podataka (arrays)

Polja podataka se upotrebljavaju za rukovanje skupovima istovjetnih podataka. Uzmimo


na primjer da trebamo statistiki obraditi rezultate 100 mjerenja, pri emu svaki podatak
prolazi kroz isti niz raunskih operacija. Ako bi imali zasebna imena za podatke iz
svakog mjerenja npr. x1 do x100 program bi morao sadravati 100 istovjetnih blokova
naredbi. To bi bilo vrlo neefikasno rjeenje. Polja nam omoguuju pristup svakom
elementu pozivom na naziv polja i navoenjem indeksa koji upuuje na redni broj
elementa u polju.

6.1. Jednodimenzionalna polja

Polja ili nizovi podataka omoguavaju pojednostavljenu obradu takvih zadataka.


Naredbom

float x[5];

prevoditelj e rezervirati kontinuirani prostor u memoriji za 5 podataka tipa float.

x[0] x[1] x [2] x[3] x[4]

4 bajta

20 bajta

Sadraj pojedinih elemenata ovako deklariranog polja nije predvidljiv, jer lanovi polja
nisu inicijalizirani..

Inicijalizacija polja se izvodi slijedeom naredbom:

float x[] ={123.4, 5.6, 7., 12.2, -5. };

sadraj polja bi bio slijedei;:

x[0] x[1] x [2] x[3] x[4]


123.4 5.6 7. 12.2 -5.

Vidi se dakle da prvo polje nosi indeks nula (0), a posljednje duljinu polja 1.

Navede li se kod deklaracija duljina polja, kao npr.

89
float a[5] ={123.4, 5.6, 7., 12.2, -5. };

onda treba paziti da broj varijabli u vitiastim zagradama bude jednak navedenoj duljini
polja.

Ako je broj varijabli u vitiastim zagradama vei od duljine polja, prevoditelj e javiti
greku, npr:

int b[2] = {10, 20, 30} // greka

U obrnutom sluaju ako je broj varijabli u vitiastim zagradama manji od duljine polja,
onda e se one 'puniti' navedenim redom a ostatak e biti iniciran s nulom.

int x[5] = {1,2};

inicirat e se na slijedei nain:

1 2 0 0 0

Pojedini element u polju poziva se navoenjem imena varijabli i indeksa. Npr.

x[3] = x[0] + x[1];

daje rezultat

1 2 0 3 0

No moe se napisati i

for (i=0; i<=3, i++) {


x[4] = x[4] + x[i];
}

ime e se zbrojiti sadraj prva etiri polja i rezultat smjestiti u x[4], pa e rezultat biti:

1 2 0 3 6

Ime polja se ne smije podudarati s imenom neke druge varijable sa ili bez indeksa.

Treba drati na umu da indeks polja poinje od nule, pa indeks 4 predstavlja peto po redu
polje u tablici itd.

90
Primjer inicijalizacije polja: a [0] = 22.2 8
a [1] = 44.4 8
Primjer6.1. a [2] = 66.6 8
1. // polja -arrays b [0] = 33.3 12
2. #include <iostream.h> b [1] = 44.4 12
3. int main ( ) { b [2] = 55.5 12
4. float a[ ] = {22.2, 44.4, 66.6}; b [3] = 66.6 12
5. // slijedi izraun broja elemenata u polju b [4] = 7.93931e+033 12
6. int brpolja = sizeof (a)/ sizeof (float); b [5] = 5.61501e-039 12
7. for (int i=0; i< brpolja; i++) b [6] = 5.60519e-045 12
8. cout<<"a [" <<i<<"] = " <<a[i] <<endl; Press any key to continue . . .
9. const int VELICINA=4; // ovo je konstanta !!!
10. float b[VELICINA ] = {33.3, 44.4, 55.5, 66.6};
11. for (int i=0; i< 7; i++) //GREKA!!! vrijednost indeksa izvan granica/
12. cout<<"b [" <<i<<"] = " <<b[i] <<endl;
13. system("PAUSE");
14. return 0;
15. }

Zadnje tri ispisane vrijednosti su sluajne, njihov sadraj ovisi o tome to je trenutno
pohranjeno u memoriji. Puno je opasnija greka kada se polje s 'promaenim' indeksom
pojavljuje s lijeve strane znaka pridruivanja, jer se tada nekontrolirano mijenja sadraj
na tim adresama, to moe izazvati nepredvidive posljedice.

6.2. Prijenos polja funkcijama

Kada se polje deklarira kao na prinjer float a[]; program prevoditelj dobija uputu da e
elementi polja a biti tipa float, a sam simbol a predstavlja adresu polja. Program
prevoditelj ne zahtijeva da se definira broj elemenata u polju. Na isti nain je rijeen
prijenos polja nekoj funkciji.

Slijedi primjer funkcije koja zbraja elemente polja i vraa njihov zbroj:

91
Primjer6.2:
1. // polja i funkcije- zbraja vrijednosti u polju
2. #include <iostream.h>
3. int zbroj (int [], int);
4. int main ( ) {
5. int a[ ] = {11, 33, 55, 77};
6. int brpolja = sizeof (a)/ sizeof (int);
7. cout<<"Zbroj (a, broj polja) = " <<zbroj (a, brpolja)<<endl;
8. // funkcija u gornjoj naredbi ina isti uinak kao x= zbroj (a, brpolja);
9. // pa zatim cout<<x;
10. system("PAUSE");
11. return 0;
12. }
13. // gotov main program poinje funkcija Zbroj (a, broj polja) = 176
14. int zbroj (int a[], int n) { Press any key to continue . . .
15. int zbroj=0;
16. for (int i=0; i<n; i++)
17. zbroj += a[i]; // zbroj = zbroj + a[i];
18. return zbroj;
19. }

U gornjem primjeru je deklaracija funkcije data u prvom retku, prije main programa koju
je poziva.To je bilo neophodno kako bi prevoditelj 'znao' da zbroj predstavlja funkciju.
Sama funcija je opisana iza main programa.

Nazivi argumenata funkcije su u deklaraciji isputeni i navodi se samo njihov tip. Kada se
u main programu poziva funkcija zbroj (a, brpolja) onda se navode samo nazivi varijabli
bez da se navodi njihov tip, ali su tipovi istovjetni onima koji su navedeni u deklaraciji
funkcije.

Kada se ovako prenosi polje funkciji u stvari se prenosi samo adresa prvog polja koju
sadri varijabla naziv polja, u konkretnom sluaju zbroj.

Funkcija moe neposredno mijenjati sadraj tih polja jer je prijenos polja bez obzira na
formu, analogan prijenosu varijabli po referenci.

6.3 Sortiranje elemenata u polju po veliini (Bubble sort)

Jedna od najjednostavnijih naina za sortiranje elemenata u polju poznat je po nazivu


Bubble sort ili mjehuriasti sort. Naziv dolazi kao asocijacija na metodu sortiranja po
kojoj se najvei elementi skupljaju na kraju polja kao, to mjehurii kod gaziranih pia
putuju prema vrhu ae.

92
Metoda e se pojasniti na primjeru polja s 4 broja u redoslijedu 2,4,3,1. Sutina metode
je da se svaki element polja usporedi sa slijedeim, pa ako je vei od njega mijenjaju
mjesta. U prvom prolazu se tako najvei element u polju smjesti na posljednje mjesto,
nakon toga se u slijedeem koraku opet trai najvei od preostalih itd.

Prvi prolaz Drugi prolaz Trei prolaz


2 4 3 1 2 3 1 4 2 1 3 4

2 3 4 1 2 1 3 4 1 2 3 4

2 3 1 4

U prvom prolazu najprije su usporeeni 2 i 4 (prvi i drugi stupac) i kako 2 nije vei od 4
nije se uinilo nita. Nakon toga su usporeeni 4 i 3 (drugi i trei stupac) i s obzirom da
je 4>3, zamijenili su mjesta, pa je polje izgledalo kao u drugom retku. Nakon toga su
usporeeno 4 i 1 (3. i 4. stupac) pa kako je 4>1 ponovo su zamijenili mjesta i broj 4 je
postao posljednji element polja.

Drugi prolaz zapoinje sa zavrnim stanjem prvog prolaza. Opet se usporeuju 1. i 2.


stupac i kako je 2<3 ne radi se nita. Zatim se usporeuju 2. i 3. stupac, pa kako je 3>1
oni mijenjaju mjesta i 3 dolazi na predzadnju poziciju.

Trei korak ponovno zapoinje s usporedbom 1. i drugog stupca i kako je 2>1 oni
mijenjaju mjesto. Bitno je uoiti da savki korak poinje usporedbom 1. i 2. stupca ali
zavrava jedan korak prije prethodnog.

Nakon ovog pojanjenja, slijedi program za sortiranje:

93
Primjer6.3.
1. // Bubble sort

2. // glavni program ima samo definiciju polja i tri naredbe pii, sortiraj i opet pii

3. #include <iostream.h>

4. void print (float [ ], int); // funkcija koja ispisuje polje

5. void sort (float [ ], int); // funkcija koja sortira elemente polja

6. void swap (float&, float&); // funkcija koja zamjenjuje vrijednost dviju


varijabli
7. int main () {

8. float a[ ] ={55.5, 22.5, 99.9, 66.6, 44.4, 88.8, 33.3, 77.7};

9. print (a,8);
2.
10. sort (a,8);

11. print (a,8);


x y
12. system("PAUSE");

13. return 0;
1.
14. } privr 3.
15. // funkcija swap

16. void swap (float& x, float& y) {

17. float privr=x;

18. x=y;

19. y=privr;

20. }

21. // funkcija bubble sort

22. void sort (float a[ ], int n) {

23. for (int i=1; i<n; i++) // i je broj koraka

94
24. for (int j=0; j<n-i; j++)// j je indeks tablice

25. // ako je element vei od slijede, mijenjaju mjesta

26. if (a[j] > a[j+1]) swap (a[j], a[j+1]);

27. }

28. // funkcija print

29. void print (float a[ ],int n) {

30. for (int i=0; i<n; i++) cout<<a[i]<<" ";

31. cout<<endl;

32. }

Ispis programa je slijedei:


55.5 22.5 99.9 66.6 44.4 88.8 33.3 77.7 9.
22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9 11
Press any key to continue . . .

Radi ilustracije rada programa, izvrit e se manje izmjene u funkciji bubble sort.
na utoj podlozi su dodatne naredbe:

95
// funkcija bubble sort
void sort (float a[ ], int n) {
cout<<" i "<<" j "<<" Tablica "<<endl; // prikazujem zaglavlje
for (int i=1; i<n; i++)
for (int j=0; j<n-i; j++){
if (a[j] > a[j+1]) swap (a[j], a[j+1]);
cout<<" "<<i<<" "<<j<<" "; // piu se vrijednosti indeksa petlji
print (a,8); // Ispisuju se elementi tablice
} Dodan je i par
} vitiastih zagrada

Dodatne naredbe omoguuju da se prate promjene varijabli i , j i tablice a[] koja se


sortira u tijeku cijelog izvoenja programa. Ova se ideja moe koristiti i za testiranje
programa, kada program ne daje oekivane rezultate.

Za interpretaciju dobivenh vrijednosti dobro je drati na umu slijedee injenice:

1. Varijabla i (prvi stupac) pokazuje o kojem se prolazu radi.


2. Varijabla j (drugi stupac) pokazuje koji se element tablice usporeuje sa
slijedeim
3. Tablica se ispisuje nakon to su elementi eventualno zamijenili mjesta.

96
55.5 je bio ispred 22.5 ali su upravo zamijenili mjesta

55.5 22.5 99.9 66.6 44.4 88.8 33.3 77.7 - Ispis iz main programa, poetni sadraj
i j Tablica * polja
1 0 22.5 55.5 99.9 66.6 44.4 88.8 33.3 77.7
1 1 22.5 55.5 99.9 66.6 44.4 88.8 33.3 77.7
1 2 22.5 55.5 66.6 99.9 44.4 88.8 33.3 77.7
Broj 99.9 je najvei element u tablici
1 3 22.5 55.5 66.6 44.4 99.9 88.8 33.3 77.7
i on je u 1. koraku poput mjehuria
1 4 22.5 55.5 66.6 44.4 88.8 99.9 33.3 77.7
'isplivao' na zadnje mjesto. U drugom
1 5 22.5 55.5 66.6 44.4 88.8 33.3 99.9 77.7
je koraku broj 88.8 'isplivao' na
1 6 22.5 55.5 66.6 44.4 88.8 33.3 77.7 99.9
pretposljednje mjesto itd.
2 0 22.5 55.5 66.6 44.4 88.8 33.3 77.7 99.9
2 1 22.5 55.5 66.6 44.4 88.8 33.3 77.7 99.9
2 2 22.5 55.5 44.4 66.6 88.8 33.3 77.7 99.9
2 3 22.5 55.5 44.4 66.6 88.8 33.3 77.7 99.9 Ispis iz funkcije sort. Naredba za
2 4 22.5 55.5 44.4 66.6 33.3 88.8 77.7 99.9 ispis se nalazi iza pozivanja funkcije
2 5 22.5 55.5 44.4 66.6 33.3 77.7 88.8 99.9 swap, dakle nakon to su dva
3 0 22.5 55.5 44.4 66.6 33.3 77.7 88.8 99.9 elementa polja (eventualno)
3 1 22.5 44.4 55.5 66.6 33.3 77.7 88.8 99.9 zamijenila mjesto. Ako je element
3 2 22.5 44.4 55.5 66.6 33.3 77.7 88.8 99.9 upravo zamijenio mjesto nalazi se na
3 3 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 plavoj podlozi. Poredak elemenata
3 4 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 prije toga vidi se u retku iznad.
4 0 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 Na utoj je podlozi oznaen redak
4 1 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 kad poinje novi korak tj. promjena
4 2 22.5 44.4 33.3 55.5 66.6 77.7 88.8 99.9 vrijednosti varijable i.
4 3 22.5 44.4 33.3 55.5 66.6 77.7 88.8 99.9
5 0 22.5 44.4 33.3 55.5 66.6 77.7 88.8 99.9
5 1 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
5 2 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
6 0 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
6 1 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
7 0 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
Ispis iz main programa, konani
22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9 sadraj polja

Prethodni primjer je pokazao kako se sortiraju elementi polja u rastuem redoslijedu tj.
od manjeg elementa prema veem. Postavlja se pitanje kako bi izgledao program za
sortiranje elemenata u padajuem redoslijedu ?

Jedno od moguih rjeenja moglo bi biti da se polje najprije sortira u rastuem


redoslijedu, pa da ga se zatim ita obrnuto, od zadnjeg elementa prema prvom.

97
Jednostavnije je ipak rjeenje da se u funkciji sort zamijeni naredba

if (a[j] > a[j+1]) swap (a[j], a[j+1]);

Na nain da se umjesto znaka > stavi znak < , dakle

if (a[j] < a[j+1]) swap (a[j], a[j+1]);

Kako bi izgledao program za ispisivanje polja u obrnutom redoslijedu?


Ijedea funkcija printo.

// funkcija printo- ispisuje polje u obrnutom redoslijedu


void printo (float a[ ],int n) {
for (int i=n-1; i>=0; i--) cout<<a[i]<<" ";
cout<<endl;
}

6.4.Linearno pretraivanje polja

Ponekad je potrebno provjeriti da li u polju postoji element ija je vrijednost jednaka


nekoj zadanoj vrijednosti. Najjednostavniji nain da se to provjeri je da se elementi polja
redom usporeuju sa zadanom vrijednosti i ako naie na jednaku vrijednost na neki nain
to signalizira.

Za ilustraciju ovog postupka u nastavku se prikazuje funkcija nazvana indeks koja


pretrauje zadano polje i vraa vrijednost indeksa polja u kojem je pronaena traena
vrijednost odnosno n (broj elemenata u polju, ako ga nije nala. Podsjetimo se da polje s
n elemenata ima najvei indeks jednak n-1)

Zadana je tablica
int p[]= { 22, 77, 33, 44, 11, 55, 66, 88};

koja sadri 8 cjelobrojnih elementa.

Treba napisati programski kod funkcije koja provjerava da li se u tablici p nalazi neka
zadana vrijednost i na kojem je to mjestu.

Na primjer, u konkretnom sluaju za vrijednost 44 funkcija mora vratiti vrijednost 3, a


za 18 vratiti vrijednost 8.

Dakle funkcija je:

int indeks (int x, int a[], int n);

98
gdje je x broj (konstanta) kojim pretraujemo tablicu, a [ ] je tablica a n broj elemenata u
tablici.

Primjer6.4.
1. // Funkcija za linearno pretraivanje tablice
2. #include <iostream.h>
3. int index (int, int [], int);
4. int main (){
5. int a[] = {22, 77, 33, 44, 55, 11, 66, 88 };
6. cout<<"index (44,a,8)= "<<index(44,a,8)<<endl;
7. cout<<"index (60,a,8)= "<<index(60,a,8)<<endl;
8. system("PAUSE");
9. return 0;
10. }
11. int index (int x, int a[], int n){
12. for (int i =0; i<n; i++)
13. if (x== a[i]) return i;
14. return n; // x nije pronadjen
15. }

Dobije se slijedei rezultat:


index (44,a,8)= 3 6
index (60,a,8)= 8 7
Press any key to continue . . .

6.5. Binarno pretraivanje polja

Drugi nain pretraivanja polja je tzv. binarno pretraivanje. Kod linearnog pretraivanja
zadani se broj usporeuje sa svim elementima polja, odnosno dok ne naie na jednak
broj. Za polja s velikim brojem elemenata to moe usporavati program. Kod binarnog je
pretraivanja taj broj usporedbi daleko manji, no uvjet je da polje bude sortirano.
Postupak binarnog pretraivanja je ve prikazana u programu Primjer4.11.

Neka su zadani tablica a[ ] i zadani broj x.


Postupak se svodi na usporeivanje zadanog broja x sa srednjim elementom u tablici
a[ ]. Neka taj srednji element ima indeks i.

Pri tome postoje tri mogunosti:

1. x=a[i], tada treba vratiti i kao oznaku mjesta n na kojemu se nalazi.


2. x< a[i], tada se isti postupak tj. 'gaanje' sredine ponavlja u donjoj polovici
tablice.
3. x>a[i], tada se isti postupak ponavlja u gornjoj polovici tablice.

99
Drugi ili trei korak tj. postupak 'raspolavljanja' dijelova polja a[ ] se nastavljaju dok se
segment polja ne svede na jedan element. Ako x nije jednak tom elementu znai da ga
nema u polju.
Ovaj postupak u svakom koraku (ako nije pronaen traeni broj) odbacuje pola segmenta
polja segmenta koji se razmatra. Prema tome, najvei broj koraka koji je neophodan da
bi se ispitalo neko polje, jednak je broju znamenaka koji broj elemenata toga polja ima u
binarnom obliku, umanjenom za 1.
Na primjer broj 256 ima binarni prikaz 100000000, dakle 9 znamenaka. Dijeljenjem 256
sa 2 dobija se redom 128, 64, 32, 16, 8, 4, 2,1. Dakle segment polja od 256 brojeva svodi
na jedan element u 8 koraka.

Primjer6.5.
1. Slijedi primjer programa za binarno pretraivanje:

2. #include <iostream.h>

3. /* argumenti funkcije index su: prvi je zadani broj x, drugi je polje

4. a trei je broj elemenata u polju

5. Povratna vrijednost je broj elemenata u polju, a to je n

6. ako x nije pronaen, odnosno indeks elementa polja u kojem se nalazi pronaeni x */

7. int index (int, int [], int);

8. int main (){

9. int a[] = {22, 33, 44, 55, 66, 77, 88}; // polje mora biti sortirano!!

10. cout<<"index (44, a, 7) = "<<index(44,a,7)<<endl; // trazi broj 44

11. cout<<"index (60, a, 7) = "<<index(60,a,7)<<endl; // trazi broj 60

12. system("PAUSE");

13. return 0;

14. }

15. // sljedi funkcija index

16. int index (int x, int a[], int n){

17. int lo=0, hi=n-1, i; // lo je najnii, a hi je najvisi indeks u segmentu polja

100
18. while(lo<=hi){

19. i = (lo +hi)/2; // srednja vrijednost

20. if (a[i]==x) return i; // vraca indeks polja u kojemu je vrijednost x

21. if (a[i] < x) lo = i+1; // nastavlja traziti izmedju a[i+1] do a[hi]

22. else hi = i-1; // nastavlja traiti izmedju a[lo] i a[i-1]

23. }

24. return n; // x nije pronaen

25. }

26.

Izlaz iz programa je:

index (44, a, 7) = 2 10
index (60, a, 7) = 7 11
Press any key to continue . . .

6.6.Dvodimenzionalna (viedimenzionalna) polja

Dosad su se razmatrala jednodimenzionalna, odnosno polja iji su elementi bili obine


varijable. Meutim elementi polja u C++ mogu biti i polja i na taj nain dolazimo do
dvodimenzionalnih polja , odnosno viedimenzionalnih polja.

Na primjer

int tablica [3] [5];

rezervira u memoriji strukturu

1.stupac 2.stupac 3.stupac 4.stupac 5.stupac


1.redak
2.redak
3.redak

lanovima takvog polja pristupamo preko dva indeksa, na primjer:

101
tablica [0] [0] = 214;
tablica [2] [1] = 122;
tablica [1] [3] = 322;

popunit e slijedea polja:

1.stupac (0) 2.stupac (1) 3.stupac (2) 4.stupac (3) 5.stupac (4)
1.redak (0) 214
2.redak (1) 322
3.redak (2) 122

Dvodimenzionalno polje int tablica [3] [5] moemo shvatiti i kao tri
jednodimezionalna polja s pet elemenata.

U C++ jeziku indeksi se moraju navoditi u zasebnim uglatim zagradama. Na primjer


izraz
tablica [2,1]

koji je dozvoljen u mnogim programskim jezicima (FORTRAN, BASIC,..) e biti


pogreno interpretiran.

Za inicijalizaciju dvodimenzionalnih polja vrijede slina pravila kao za


jednodimenzionalna.

int tablica [3] [5] ={ {11,12,13,14,15}, {21,22,23,24,25}};

ovom se naredbom iniciraju samo prva dva retka. Naime, svaki par unutarnjih vitiastih
zagrada predstavlja jedan redak. Na primjer

int tablica [3] [5] ={ {11}, {21,22}, {31} };

iniciraju se samo slijedei lanovi :

tablica [0][0], tablica [1][0], tablica [1][1] i tablica [2][0].

Ako se vitiaste zagrade izostave, popunjavanje se vri po redovima, bez preskakanja.

U nastavku je prikazan primjer programa za rad s tablicama:

Primjer6.6.
1. // program za rad s tablicama

2. #include <iostream.h>

102
3. int mjeseci []={31,28,31,30,31,30,31,31,30,31,30,31};

4. int dvodim [3] [5] = { {1,2,3,4,5}, {11,12,13}, {21,22}};

5. int main () {

6. int i,j;

7. for (i=0; i<= 11; i++)

8. cout <<"Mjesec["<<i+1<<"]="<<mjeseci [i]<<endl;

9. cout<<endl;

10. cout<<"Druga tablica "<<endl;

11. for (i=0; i<=2; i++) {

12. for (j=0; j<=4; j++)

13. cout<<"Dvodim ["<<i<<","<<j<<"]="<< dvodim [i] [j]<< endl;

14. }

15. system("PAUSE");

16. return 0;

17. }

103
Izlaz iz prethodnog programa je:
Mjesec[1]=31 8
Mjesec[2]=28 8
Mjesec[3]=31 8
Mjesec[4]=30 8
Mjesec[5]=31 8
Mjesec[6]=30 8
Mjesec[7]=31 8
Mjesec[8]=31 8
Mjesec[9]=30 8
Mjesec[10]=31 8
Mjesec[11]=30 8
Mjesec[12]=31 8
9
Druga tablica 10
Dvodim [0,0]=1 13
Dvodim [0,1]=2 13
Dvodim [0,2]=3 13
Dvodim [0,3]=4 13
Dvodim [0,4]=5 13
Dvodim [1,0]=11 13
Dvodim [1,1]=12 13
Dvodim [1,2]=13 13
Dvodim [1,3]=0 13
Dvodim [1,4]=0 13
Dvodim [2,0]=21 13
Dvodim [2,1]=22 13
Dvodim [2,2]=0 13
Dvodim [2,3]=0 13
Dvodim [2,4]=0 13
Press any key to continue . . .

104
7. Znakovni nizovi

Za pohranjivanje tekstova koriste se znakovni nizovi (character strings). Znakovni nizovi


su jednodimenzionalna polja iji je sadraj ispunjen znakovima (char). Znakovni nizovi
su uvedeni u C jezik, a u C++ su preuzeti i dograeni, o emu e biti govora kasnije.
Slijedei se tekst odnosi na tzv. C nizove u C++.

C niz se deklarira kao polje s znakovima tipa char. Prilikom inicijalizacije znakovnog
niza njegov se sadraj stavlja u navodnike, kao na primjer:

char pisac [] = ''August Cesarec'';

Znakovni niz e imati slijedei sadraj

A u g u s t C e s a r e c \0

Znakovni niz uvijek zavrava s oznakom ''\0'' nul-znak (null-character). Njega nije
potrebno eksplicitno navoditi prilikom inicijalizacije, ali treba imati na umu da on
zauzima jedno znakovno mjesto.

Ako bi htjeli ispisati znakovni niz pisac program bi izgledao kako slijedi:

Primjer7.1. Ispis je (naredba 7.):


A
1. // ispis niza znakova u
2. #include <iostream.h> g
3. char pisac[] = '' August Cesarec''; u
4. int main () s
5. { t
6. for (int i=0; i<16; i++)
7. cout<<pisac[i]<<endl; C
8. return 0; e
9. } s
10. a
r
e
c
kada bi se u naredbi

cout<<pisac[i]<<endl;
ispustilo endl itav bi tekst bio u istome retku.

Meutim nizu se moe pristupiti i bez navoenja indeksa. Na primjer naredba:

cout<<pisac<<endl;

105
(uz dodatak da se izbaci i for petlja iz gornjeg primjera), bi ispisala cijeli sadraj niza
pisac u jednom retku kao i u prethodnom sluaju.
August Cesarec
Press any key to continue . . .

Naime, kada su u pitanju nizovi, znakovi se automatski prenose u cout dok ne naie
nul-znak. Na isti nain se ponaa i unos podataka sa cin.

Slijedei kratki primjer ilustrira rad s nizovima:

Primjer7.2. s[0]=A
1. // ispis niza znakova s[1]=B
2. #include <iostream.h> s[2]=C
3. char s[] = "ABCD"; s[3]=D
4. int main () s[4]=
5. { Press any key to continue . . .
6. for (int i=0; i<5; i++)
7. cout<<"s["<<i<<"]="<<s[i]<<endl;
8. system("PAUSE");
9. return 0;
10. }

Slijedi malo izmjenjeni primjer 7.2.

Primjer7.2a. cijeli niz je ABCD 6


1. // ispis niza znakova s[0]=A, 65 8
s[1]=B, 66 8
2. #include <iostream.h>
s[2]=C, 67 8
3. char s[] = "ABCD";
s[3]=D, 68 8
4. int main ()
s[4]= , 0 8
5. { Press any key to continue .
6. cout<<"cijeli niz je "<<s<<endl; . .
7. for (int i=0; i<=4; i++)
8. cout<<"s["<<i<<"]="<<s[i]<<", "<<int(s[i])<<endl;
9. system("PAUSE");
10. return 0;
11. }

Iz ovako izmjenjenog programa vidi se da se niz s moe ispisati bez navoenja indeksa,
kao da je obina varijabla. Nakon toga je niz ispisan preko indeksa i pri tome je izvrena
i konverzija tipa iz char u int. Vidi se da je zadnji lan niza s[4] jednak 0, odnos nul
znak. Moe se dakle ponoviti: naredba cout ispisuje sve lanove niza dok ne naie na
nul znak.

106
U C++ postoji mogunost konverzje niza u broj, to je ilustrirano u primjeru 7.2b.

Primjer7.2b:
1. // Konverzija niza znakova u broj
2. #include <iostream.h>
3. #include <stdlib.h> // ukljuuje funkciju atoi
4. int main ()
5. {
6. char s[] = "5432";
7. int broj;
8. broj=atoi(s); // konverzija alfa to integer
9. cout<<broj<<endl;
10. system("PAUSE"); 5432
11. return 0; Press any key to continue
12. }

Pored funkcije atoi postoje i druge sline funkcije kao atol koja konvertira niz u long
format itd.
Zbog razliitih primjena nizova u ve su u C prevoditelju ukljuene razliite funkcije
za njihovu obradu, koje su ukljuene u biblioteku funkcija za obradu nizova <cstring>.

U slijedeoj se tablici prikazuju neke karakteristine funkcije:

Funkcija Parametri Opis funkcije


strlen (s) niz Vraa broj znakova u nizu ispred nul-znaka
(STRing LENgth)
strcpy (s1, s2) nizovi Prenosi niz s2 u s1, nakon izvedbe funkcije
sadraj s1 i s2 je identian (STRing CoPY)
strcat (s1, s2) nizovi 'Nadovezuje' s2 na s1, niz s1 se nastavlja s s2.
(STRing conCATenation)

Pregled svih funcija u biblioteci <cstring> moe se na primjer nai na adresi:


http://www.cplusplus.com/ref/cstring/

Uporaba navedenih funcija ilustrirano je u slijedeem primjeru.

Primjer7.3.
1. // Rad s C nizovima u C++
2. #include <iostream.h>
3. #include <string.h>
4. int main()
5. {
6. char pisac []= "August Cesarec";// inicira se string pisac
7. char slikar []= "Edo Murtic ";// inicira se string slikar
8. char niz [50]; // polje za prebacivanje
9. cout<<"duljina niza pisac je "<<strlen(pisac)<<endl;

107
10. cout<<"duljina niza slikar je "<<strlen(slikar)<<endl;
11. strcpy (niz,slikar); // kopirati slikar u niz
12. cout<<"Niz: "<<niz<<endl; // da vidimo sto je preslo u niz
13. strcpy (slikar,pisac); //prebacuje sadraj iz pisac u slikar
14. cout<< slikar << " nakon strcpy(slikar,pisac)"<<endl;
15. strcpy (slikar,niz); // vraa pocetni sadraj
16. cout<<slikar<<"nakon vracanja vrijednosti" <<endl;
17. strcpy (niz, pisac);
18. cout <<niz<<endl;
19. strcat (niz, slikar);
20. cout<< niz << " nakon strcat"<<endl;
21. return 0;
duljina niza pisac je 14 9
22. }
duljina niza slikar je 10 10
Niz: Edo Murtic 12
August Cesarec nakon strcpy(slikar,pisac) 14
Edo Murtic nakon vracanja vrijednosti 16
August Cesarec 18
August CesarecEdo Murtic nakon strcat 20

Iako je rad s nizovima u nekim aspektima jednostavan, postoje i mogue komplikacije.


Na primjer slijedei je program ispravan:

#include <iostream.h>
#include <string.h>
int main()
{ Iako se u naredbi cout moe navesti
char pisac []= "August Cesarec"; niz slikar bez indeksa, to na primjer ne vrijedi
char slikar []= "Edo Murti "; za pridruivanje. Da se na primjer napisalo
char niz [50];
for (int i=0; i<16; i++) slikar= pisac;
slikar[i]=pisac[i];
cout<<slikar; prevoditelj bi javio greku.
return 0;
}

108
7.1. Uporaba nizova na primjeru obrade prijavnica

Neka je zadano polje s podacima o poloenim ispitima slijedeeg sadraja:

Tablica 7.1: Podaci o poloenim ispitima


Matini broj ifra Ocjena
Prezime i ime predmeta
1 15 16 20 23 25 31
Mario Kalac 20616 P01 3
Mario Kalac 20616 P02 5
Tone Cvek 20701 P01 4
Tone Cvek 20701 P01 4
Tone Cvek 20701 P03 3
Mara Gruji 20855 P01 5
Mara Gruji 20855 P03 3
Aldo Burul 21446 P01 4
Aldo Burul 21446 P02 5
Aldo Burul 21446 P03 2

Podaci u utom redu pokazuju redni broj bajta u odnosu na poetak tj. prezime i ime je
smjeteno u prvih 15 bajtova, Matini broj je od 16 do 20, ifra predmeta od 23 do 25 i
ocjena u 31. bajtu.
Gornja se tablica moe smjestiti u dvodimenzionalno polje ocjene [] [40], gdje svaka
prijavnica predstavlja jedan redak, a unutar retka je niz od 40 bajta sa strukturom
prikazanoj u tablici 7.1. Treba izraditi program koji e izlistati navedenu tablicu i
izraunati prosjenu ocjenu po studentu.

Polje ocjene [] [] e u programu biti prikazano kao polje stringova koje je ve sortirano
po studentima. Ova je injenica bitna za definiciju algoritma, koji e se najprije
prikazati u pseudokodu.
Prosjena ocjena po studentu dobije se tako da se zbroje sve njegove ocjene i suma se
podijeli s brojem ocjena.

Na temelju tablice 7.1. mogu se definirati slijedei (pod)stringovi koje treba 'izvaditi'
iz polja ocjene [] []:

char ime [15], mbr [6], sifra[3], ocjena;

Sami nazivi navedenih stringove i njihove duljine govore koji e se podaci smjestiti u
njih. Potreno je jo definirati i slijedee varijable: n je broj elemenata u polju, odnosno
broj prijavnica, suma je polje u kojem se zbrajaju ocjene po studentu, i k- u kojem se
pamti broj ocjena po studentu, tako da bude:

suma
prosjek
k
Logika programa za prikaz podataka iz polja ocjene je jednostavna, treba redom oitavati
podatke iz polja i prikazivati ih na ekranu. Za izraun prosjene ocjene po studentu

109
potrebno je imati broj ocjena i njihov zbroj. Postavlja se pitanje kako znati da su za
pojedinog studenta prebrojene i zbrojene sve njegove ocjene?

S obzirom da su podaci sortirani po studentu tj. po njegovom matinom broju, kada se


matini broj mijenja, znai da nailazimo na novog studenta.
Radi lakeg razumijevanja logike programa na slici 7.1. prikazan je djelomini dijagram
toka.

110
Slika 7.1. Djelomini dijagram toka postupka obrade prijavnica

Start
Dijagram toka nije suma je polje u kojem se
potpun jer nema na zbrajaju ocjene za
primjer naznaen pojedinog studenta.
kraj programa. On suma=0; br je polje u kojem se
bi u realnoj situaciji br=0; broji broj ocjena (odnosno
nastao kad se prijavnica) po pojedinom
proita zadnji slog studentu.
u datoteci
prijavnica. prosjek=suma/br;
Prikazana logika Uzmi
nije dobra za prvi prijavnicu
slog, jer bi se kod
njega raunao i
pisao prosjek, a ni
za zadnji slog, za
kojeg se prosjek ne Da
Promje Raunaj
bi ni izraunao ni
na prosjek
pisao.
MBR ?

Pii MBRstari, A
prosjek
Ne

suma=0;
br=0;
Oznake A i B u
krugovima nemaju,
zasad, nikakvo
znaenje

B Kako provjeriti da li se
Pii redak za
promijenio MBR?
prijavnicu, MBR

Treba ga usporediti s MBR


s prethodne prijavnice. Zbog
toga se on pohranjuje u
suma=suma+ocj; polju MBRstari .
br=br+1;
MBRstari=MBR; Polje MBRstari se ispisuje
uz prosjek jer se i taj odnosi
na prethodnog studenta

111
Slijedi opis rjeenja pseudokodom:

int n, suma=0, br=0, prosjek;


char ime [15], mbr [6], sifra[3], ocjena ;// podnizovi u koje se prebacujuvrijednosti iz prijavnice
int mbrstari=0; // tu e se pamtiti prethodni maticni broj
for (int i=0; i<n; i++) { //za svaki i nova prijavnica jer se ita tablica umjesto datoteke
Uitaj ocjene [i] [40] // zapravo se ne uitavaju nego se pozicionira na dotini redak
Prebaci podatke u ime, mbr, sifra, ocjena
if (mbrstari !=0 & mbrstari!= mbr) { //iskljuuje da se ne radi o prvoj prijavnici po redu
// pa ako je dolo do promjene mbr, rauna prosjek
prosjek= suma/j;
cout<<''Prosjek za ''<<mbrstari<< '' je ''<< prosjek<<endl;
suma=0;
j=0;
}
suma=suma +ocjena; // u svakom sluaju tekua se ocjena zbraja u sumu, za sluaj da se
// radi o novom mbr, suma se nakon ispisa postavlja na vrijednost 0
br=br+1; // broji broj ocjena, koji se u sluaju promjene mbr takoer postavlja na 0
mbrstari=mbr; }// prije itanja novog mbr treba upamtiti prethodni

Primjer7.4.
1. /* Ovaj program lista prijavnica i rauna prosjene ocjene po studentu */

2. #include <iostream.h>

3. #include <cstring>

4. int main()

5. {

6. char podaci [10][40] = {

7. "Mario Kalac 20616 P01 3",

8. "Mario Kalac 20616 P02 5",

9. "Tone Cvek 20701 P01 4",

10. "Tone Cvek 20701 P02 4",

11. "Tone Cvek 20701 P03 3",

12. "Mara Gruja 20855 P01 5",

13. "Mara Gruja 20855 P02 3",

112
14. "Aldo Burul 21446 P01 4",

15. "Aldo Burul 21446 P02 5",

16. "Aldo Burul 21446 P03 2" };

17. char ime [15], mbr [5], sifra[3], ocjena;

18. char mbrstari[]="000000"; // pamti stari mbr radi kontrole promjene

19. int k=0; // k umjesto j pamti broj ocjena s obzirom da je j indeks petlje

20. float suma=0, prosjek;

21. int brocj; // brocj je numeriko polje za ocjenu koja je char varijabla

22. // Ispisuje se zaglavlje

23. cout<<"Mbr"<<" Ime i prezime "<<" Sifra Ocjena"<<endl;

24. for (int i=0; i<10; i++) { // svaki i jedna prijavnica

25. for (int j=0; j<15; j++)

26. ime[j]=podaci[i][j]; // prenose se podaci o imenu i prezimenu

27. for (int j=15; j<20; j++) mbr[j-15]=podaci[i][j];// prenosi se mat. broj u mbr

28. for (int j=23; j<26; j++) sifra[j-23]=podaci[i][j]; //prenosi se sifra predmeta

29. ocjena = podaci[i][31]; // prenosi se ocjena

30. // sada treba kontrolirati jeli se promijenio mbr

31. // funkcija strcmp- string compare vraa 0 ako su dva niza jednaka

32. if (strcmp(mbrstari,"000000")!=0 && strcmp(mbr,mbrstari)!=0){

33. // Prvi uvjet iskljuuje da se to radi za prvi slog

34. prosjek=suma/k;

35. cout<<" Prosjek za "<<mbrstari<<" je "<<prosjek<<endl<<endl;

36. suma=0;

113
37. k=0;

38. }

39. brocj=ocjena-48; // naime nula je ASCII 48, pa se char varijabla konvertira


}
40. suma = suma + brocj;

41. k++;

42. strcpy(mbrstari, mbr); // prebacuje se tekui mbr u mbrstari

43. // Ispisuju se podaci-

44. cout<<mbr<<"-"<<ime<<"-"<<sifra<<"- -"<<ocjena<<endl;

45. }

46. // kada se doe na kraj tablice, nije se ispisao prosjek

47. // ove su naredbe potrebne za izraun i ispis prosjeka za zadnjeg studenta

48. prosjek=suma/k;

49. cout<<" Prosjek za "<<mbrstari<<" "<<prosjek<<endl<<endl;

50. system("PAUSE");

51. return 0;

52. }
Mbr Ime i prezime Sifra Ocjena Mbr Ime i prezime Sifra Ocjena
20616-Mario Kalac -P01- -3
Izlaz iz programa
20616-Mario je: -P02- -5
Kalac Ovakav bi izlaz
20616-Mario bio pregledniji:
Kalac -P01- -3
Prosjek za 20616 je 4 P02- -5
Prosjek = 4.00
20701-Tone Cvek -P01- -4
20701-Tone Cvek -P02- -4 20701-Tone Cvek -P01- -4
20701-Tone Cvek -P03- -3 P02- -4
Prosjek za 20701 je 3.66667 P03- -3
Prosjek = 3.67
20855-Mara Gruja -P01- -5
20855-Mara Gruja -P02- -3 20855-Mara Gruja -P01- -5
Prosjek za 20855 je 4 P02- -3
Prosjek = 4.00
21446-Aldo Burul -P01- -4
21446-Aldo Burul -P02- -5 21446-Aldo Burul -P01- -4
21446-Aldo Burul -P03- -2 P02- -5
Prosjek za 21446 3.66667 P03- -2114
Prosjek = 3.67
Press any key to continue . . . Press any key to continue . . .
Koje bi se izmjene u programu trebale uiniti pa da se dobije, ovaj pregledniji izlaz?
Namee se promjena logike ispisivanja. Ispisivanje cijelog retka treba napraviti samo
kada se student pojavljuje prvi put, a kad se on ponavlja ispisuje se samo Sifra i Ocjena.
Rjeenje se moe ilustrirati pozivom na logiku u dijagramu 7.1. Kod naredbe oznaene s
A u krugu, treba nakon ispisivanja MBrstari i prosjek 'skoiti' na novi red i ispisati MBR i
ime studenta. (Ostat e samo problem za prvog studenta, jer se za njega ta petlja ne
izvrava. U primjeru 7.4a u nastavku problem prve prijavnice je rijeen u naredbama
34,35 i 36). U naredbi oznaenoj s B umjesto ispisivanja itavog retka za prijavnicu treba
ispisati samo ifru predmeta i ocjenu.

Ove su izmjene uinjene u slijedeem programu s time da su naredbe za izraun i


ispisivanje prosjeka stavljene u zasebnu funkciju, te su koriteni neki manipulatori za
formiranje izlaza.

Primjer 7.4a.
1. /* Ovaj program lista prijavnica i rauna prosjene ocjene po studentu */

2. #include <iostream.h>

3. #include <cstring>

4. #include <iomanip.h> // manipulatori za formiranje izlaza

5. void sumred(float, int);

6. int main()

7. {

8. char podaci [10][40] = {

9. "Mario Kalac 20616 P01 3",

10. "Mario Kalac 20616 P02 5",

11. "Tone Cvek 20701 P01 4",

12. "Tone Cvek 20701 P02 4",

13. "Tone Cvek 20701 P03 3",

115
14. "Mara Gruja 20855 P01 5",

15. "Mara Gruja 20855 P02 3",

16. "Aldo Burul 21446 P01 4",

17. "Aldo Burul 21446 P02 5",

18. "Aldo Burul 21446 P03 2" };

19. char ime [15], mbr [5], sifra[3], ocjena;

20. char mbrstari[]="000000"; // pamti stari mbr radi kontrole promjene

21. int k=0; // k umjesto j pamti broj ocjena s obzirom da je j indeks petlje

22. float suma=0;

23. int brocj; // brocj je numeriko polje za ocjenu koja je char varijabla

24. // Ispisuje se zaglavlje

25. cout<<"Mbr"<<" Ime i prezime "<<" Sifra Ocjena"<<endl<<endl;

26. for (int i=0; i<10; i++) { // svaki i jedna prijavnica

27. for (int j=0; j<15; j++)

28. ime[j]=podaci[i][j]; // prenose se podaci o imenu i prezimenu

29. for (int j=15; j<20; j++) mbr[j-15]=podaci[i][j];// prenosi se mat. broj u mbr

30. for (int j=23; j<26; j++) sifra[j-23]=podaci[i][j]; //prenosi se sifra predmeta

31. ocjena = podaci[i][31]; // prenosi se ocjena

32. // sada treba kontrolirati jeli se promijenio mbr

33. // funkcija strcmp- string compare vraa 0 ako su dva niza jednaka

34. if (strcmp(mbrstari,"000000")==0) {// uitan je prvi slog, treba ispisati puni red

35. cout<<mbr<<"-"<<ime<<"-"<<sifra<<"- -"<<ocjena<<endl;

36. strcpy(mbrstari, mbr); // prebacuje se tekui mbr u mbrstari

116
37. }

38. else {

39. if (strcmp(mbr,mbrstari)!=0) {// nije prvi slog, ali se mijenja mbr

40. sumred (suma, k);

41. suma=0;

42. k=0;

43. // sada treba napisati cijeli red

44. cout<<mbr<<"-"<<ime<<"-"<<sifra<<"- -"<<ocjena<<endl;

45. strcpy(mbrstari, mbr); // prebacuje se tekui mbr u mbrstari

46. }

47.

48. else cout<< " "<<sifra<<"- -"<<ocjena<<endl;

49. }

50. brocj=ocjena-48; // naime nula je ASCII 48, pa se char varijabla konvertira


}
51. suma = suma + brocj;

52. k++;

53.

54. }

55. // kada se doe na kraj tablice, nije se ispisao prosjek

56. // ove su naredbe potrebne za izraun i ispis prosjeka za zadnjeg studenta

57. sumred (suma, k);


Manipulatori:
setw (30) set width postavlja polje koje
58. system("PAUSE");
slijedi na 30 mjesta
fixed- prikazuje brojeve s fiksnim zarezom
59. return 0;
setprecision(2) prikazuje 2 decimale

117
60. }

61. // slijedi funkcija

62. void sumred (float zbroj , int broj){

63. float prosjek;

64. prosjek=zbroj/broj;

65. cout<<setw(30)<<"Prosjek =
"<<fixed<<setprecision(2)<<prosjek<<endl<<endl;
66. }

118
8. Pokazivai (pointers)

Memorija pojedinog raunala se moe predoiti kao jedno veliko polje (array), iji su
elementi bajtovi. Na primjer raunalo sa 256 MB RAM-a sadri 268.435.456 odnosno 2 8
bajtova. Zamiljeni kao polje ovi bajtovi imaju indekse od 0 do 268.435.455 ili
heksadecimalno pisano od 0x00000000 do 0x0fffffff.

Deklaracijom pojedine varijable pridodaju joj se tri bitna atributa: njen naziv, tip i
adresa u memoriji. Na primjer deklaracija
int n;

pridruuje nazivu n tip int (dakle 4 bajta) i neku adresu u memoriji na kojoj je pohranjena
vrijednost od n. Neka je to na primjer adresa 0x0064fdf4

0x0064fdf0
0x0064fdf1
0x0064fdf2
0x0064fdf3
0x0064fdf4
0x0064fdf5
0x0064fdf6
0x0064fdf7
0x0064fdf8

Dakle u memoriji su 4 bajta rezervirana za sadraj varijable n

Kada se u programu eli pristupiti navedenoj adresi dovoljno je navesti naziv varijable,
no sadraju se moe pristupiti i tako da se umjesto naziva varijable, navede adresa na
kojoj je pohranjena dotina varijabla.
Pokazivai su varijable (objekti) koji sadre adrese i na taj nain 'pokazuju' na neke druge
varijable (objekte).

Prije definiranja pokazivaa opisati e se operator adrese i operator dereference.

8.1. Operator adrese (&)

Svaka se varijabla prilikom deklaracije smjeta na neko mjesto (adresu) u memoriji. U


naelu mjesto u memoriji u koje e se smjestiti program odreuje operativni sustav, a
mjesto unutar programa na koje e se smjestiti pojedina varijabla odreuje prevoditelj.
U nekim sluajevima mi elimo znati gdje je pojedina varijabla smjetena i to nam
kazuje operator &. Taj operator itamo kao adresa od.

119
ted=&andy

u varijablu ted se smjestila adresa od varijable andy.

Dakle im smo ispred varijable stavili znak & (ampersand), vie ne govorimo o sadraju
varijable nego o njenoj adresi u memoriji.
Neka je na primjer varijabla andy smjetena na adresi 1776 u memoriji, onda se to moe
ilustrirati na slijedei nain:

andy = 25;
fred = andy;
ted = &andy;

Koristei pokazivae moe se pojasniti to se dogaa kada se polju daje indeks koji
premauje granice polja:

Primjer8.1.
1. /* Ovaj program ilustrira rad s tablicama (array) */
2. #include <iostream.h>
3. int main()
4. {
5. int p [5], q [] = {22, 44, 11}, s[4]= {77, 88};
6. cout<<p[6]<< " "<<q[1]<<" " <<s[1]<<endl;
7. return 0;
8. }
izlaz je (kod Borland prevoditelja):
Oito je da je p[6] izvan dozvoljenih
44 44 88
granica, pa se postavlja pitanje zato je
ispisana vrijednost 44 ?
Pojanjenje daje slijedei program:

120
Primjer8.2:
1. /* Ovaj program ilustrira rad s tablicama (array) */
2. #include <iostream.h>
3. int main() Ovaj program najprije ispisuje adrese od
4. { polja p i q a tek nakon toga navedene
5. int p [5], q [] = {22, 44, 11}, s[4]= {77, 88}; vrijednosti.
6. cout << &p <<" "<<&q<<endl; Ispisane adrese su u heksadecimalnom
7. cout<<p[6]<< " "<<q[1]<<" " <<s[1]<<endl;obliku, odbije li se druga adresu od prve
8. return 0; dobije se 14 to prevedeno u dekadski
9. } sustav daje broj 20 (1*161 + 4*160 ).
Izlaz je : Tablica p zauzima u memoriji 20 bajtova
0012FF6C 0012FF80 (5*4) i nakon toga je smjetena tablica q.
44 44 88 Najvei indeks unutar polja p je 4 (5-1)
Zbog toga p[6] i q[1] predstavljaju istu
adresu u memoriji, to ilustrira slika.

Prekoraenje
p[5] p[6] p[7] p[8] p[9]
p[0] p[1] p[2] p[3] p[4] q[0] q[1] q[2] s[0] s[1]
? ? ? ? ? 22 44 11 77 88

S obzirom da sva polja sadre


Sadraj polja p nije poznat jer nije elemente tipa int, onda se prekoraena
inicijalizirano adresa i element slijedeeg polja
preklapaju. U suprotnom bi se moglo
dogoditi da se zahvate dijelovi dva
elementa slijedeeg polja.

Zanimljivo je da se uporabom prevoditelja Dev-C++, dobije drugaiji rezultat:


0x22ff50 0x22ff40
2088809675 44 88
Press any key to continue . . .

Prva je razlika u pisanju heksadecimalnih adresa, jer se eksplicitno navodi '0x', zatim se
primjeuje da adrese u memoriji nisu iste, kao u sluaju kad se program prevede s
Borland prevoditeljem, ali najbitnije je to je polje p smjeteno da adresi veoj od polja
q, pa se s adresom p[6] ne zahvaa element polja q, nego neki drugi sadraj.

121
Oznaka & koristi se i za dodjeljivanje sinonima pojedinoj varijabli ili reference. Ako se
na primjer napie
int& moj_brat = fred;

onda je varijabla moj_brat sinonim za varijablu fred. Tip int se odnosi na varijablu fred.
U programu se naziv fred ili moj_brat koriste ravnopravno. Identifikator moj_brat ne
zauzima nikakvo mjesto u memoriji, odnosno zauzima isto mjesto koje i varijabla fred.

8.2. Operator dereference (*)

Ovaj operator itamo kao vrijednost koju pokazuje i ima slijedee znaenje. Napiemo li
naredbu

int med=*ted;

uz pretpostavku da varijabla ted pokazuje adresu od andy, njen je uinak prikazan


slijedeim crteom.

andy

med

Dakle sadraj varijable ted je 1776, ali *ted upuuje na sadraj polja na adresi 1776, a
to je 25.

Ponovimo dakle:
med =ted ; // sadraj polja med je 1776
med=*ted; // sadraj polja med je 25

andy == 25
Primjer: Sve su izjave &andy == 1776
istinite ted == 1776
andy = 25;
*ted == 25
ted = &andy;
*ted == andy;

122
8.3. Uporaba pokazivaa

Pokazivai su varijable koje sadre adresu drugih varijabli. Deklaracija pokazivaa ima
oblik
tip * ime_pokazivaa;

pri emu tip pokazuje na tip varijable (int, char, float) iju adresu pokaziva treba
prikazivati, dakle ne govori o tipu pokazivaa nego o tipu varijable koju on pokazuje. U
tom kontekstu zvjezdicu * treba shvatiti samo kao 'ovo je pokaziva' i ne treba je
mijeati s operatorom dereference.
Slijedei primjer ilustrira upotrebu pokazivaa:

Primjer8.3:
1. // primjer rada pokazivaima
2. #include <iostream.h> broj1 = 10 broj2 = 20
3. int main ()
4. {
5. int broj1 = 5, broj2 = 15;
6. int * pokazivac;
7. pokazivac = &broj1; // pokazivac sadri adresu od broj1
8. *pokazivac = 10; // na adresu broj1 staviti 10
9. pokazivac = &broj2; // piokazivac sadri adresu od broj2
10. *pokazivac = 20; // na adresu broj2 staviti 20
11. cout << "broj1=" << broj1 << "/broj2=" << broj2;
12. return 0;
13. }
Dakle pomou pokazivaa je izmjenjen sadraj varijabli broj1 i broj2, bez da se navode
nazivi dotinih varijabli. Slijedi jo jedan primjer rada s pokazivaima:

Primjer8.4:
1. // Primjer rada s pokazivaima
2. #include <iostream>
3. using namespace std;
4. int main()
5. {
6. int* ted, andy; &ted: 0x22ff74 9
7. ted=&andy; ted: 0x22ff70 10
8. andy=777; *ted: 777 11
9. cout<< "&ted: "<<&ted<<endl; andy: 777 12
10. cout << "ted: " <<ted << endl; andy: 555 14
11. cout << "*ted: " <<*ted<<endl; Press any key to continue . . .
12. cout << "andy: " << andy<<endl;
13. *ted=555;
14. cout << "andy: " << andy<<endl;
15. return 0;
16. }

123
U prethodnom je primjeru varijabla ted pokaziva, dok je andy obina varijabla tipa
int. Vidi se da je pokaziva ted (0x22ff74) smjeten neposredno nakon varijable andy
(0x22ff70). S obzirom da pokaziva ted sadri adresu od andy, vrijednosti *ted i andy su
identine.
*ted treba itati kao 'sadraj
Primjer8.5: polja na adresi ted '.
1. // primjer rada s pokazivaima

2. #include <iostream.h>

3. int m=10, n=20;

4. int * p1, * p2;

5. // sve su globalne varijable

6. int main ()

7. {

8. p1=&m;

9. p2=&n;

10. *p1=*p1+5; //poveavamo za 5, odnosno 7

11. *p2+=7;
12
12. cout<<endl; p1=0x43f000 13
*p1=15 m=15 14
13. cout<<"p1=" <<p1<<endl; p2=0x43f004 15
*p2=27 n=27 16
14. cout<<"*p1="<<*p1<<" m="<<m<<endl; povecavam p1 za 1 0x43f004 18
p2 bi trebao biti p1+1 0x43f008 20
15. cout<<"p2="<<p2<<endl; povecani p2=0x43f00c 22
a sto je tu ? 0 23
16. cout<<"*p2="<<*p2<<" n="<<n<<endl; Press any key to continue

17. p1++;

18. cout<<"povecavam p1 za 1 "<<p1<<endl;

19. p2=p1+1;

20. cout<<" p2 bi trebao biti p1+1 "<<p2<<endl;

124
21. p2++;

22. cout<<"povecani p2="<<p2<<endl;

23. cout<<" a sto je tu ? "<<*p2<<endl;

24. return 0;

25. }

Kao to se u primjeru8.5 vidi deklarirane su dvije cjelobrojne varijable m i n te dva


pokazivaa p1 i p2 koji su usmjereni na cjelobrojne varijable tipa int..
U naredbama 8 i 9 su pokazivaima dodjeljene adrese varijabli m i n a za tim je u
naredbi 10 varijabli m dodano 5, a u naredbi 11 varijabli n je dodano 7. To dodavanje je
izvreno posredno putem pokazivaa tj. dodaj 5 u polje (tipa int jer je pokaziva tipa
int) koje se nalazi na adresi koju pokazuje p1 i analogno za p2.
Nakon toga se ispisuju vrijednosti : u naredbi 13 ispisuje se sadraj od p1 koji je adresa
od polja m, za tim se vidi iz ispisa u naredbi 14 da su sadraji *p1 i m identini. To mora
biti tako jer se radi o istom polju u memoriji raunala. Iz ispisa u naredbama 15 i 16 vidi
se da je analogna situacija s p2 i n. Pored toga se vidi da je varijabla n smjetena
neposredno iza varijable m (jer je 0x43f004 - 0x43f000=4, kolika je duljina varijabli tipa
int). Nakon toga je u naredbi 17 pokaziva p1 povean za 1, i u naredbi 18 je ispisana
vrijednost 0x43f004. Vidi se dakle da sadraj p1 nije povean za 1 nego za 4. To je zbog
toga to je pokaziva p1 tipa int, a varijable tipa int su dugake 4 bajta, pa se dodavanjem
1 pokazivau, on automatski pozicionira na slijedee polje tipa int (koje je u konkretnom
sluaju takoer tipa int, jer je to adresa varijable n, ali to ne mora biti tako, o tome brigu
mora voditi programer). U naredbi 19 se u p2 stavlja sadraj p1 uvean za 1, pa se zbog
iste logike u naredbi 20 ispisuje sadraj p2 koji je zapravo povean za 4.
Konano se u naredbi 21 p2 dodavanjem 1, poveava za jo 4 to se vidi u ispisu iz
naredbe 22. U naredbi 23 se ispisuje sadraj s adrese koje trenutno ima p2 i vidi se da je
tamo 0. Ako se programa prevede s Borland prevoditeljem, onda je u tom polju neka
druga vrijednost.

Pokaziva moe pokazivati drugi pokaziva, kao na primjer:

Primjer8.6:
1. // primjer koritenja pokazivaa n = 44 5
&n = 0x22ff74 6
2. #include <iostream.h> pn = 0x22ff74 8
&pn = 0x22ff70 9
3. int main (){ *pn = 44 10
ppn = 0x22ff70 12
4. int n =44; &ppn = 0x22ff6c 13
*ppn = 0x22ff74 14
5. cout <<" n = " << n <<endl; **ppn = 44 15
Press any key to continue

125
6. cout <<" &n = " << &n <<endl;

7. int* pn =&n; // pn sadri adresu od n

8. cout <<" pn = " << pn <<endl;

9. cout <<" &pn = " << &pn <<endl;

10. cout <<" *pn = " <<*pn <<endl;

11. int** ppn = &pn; // ppn sadri adresu od pn

12. cout <<" ppn = " <<ppn <<endl;

13. cout <<" &ppn = " <<&ppn <<endl;

14. cout <<" *ppn = " <<*ppn <<endl;

15. cout <<"**ppn = " <<**ppn <<endl;

16. system("PAUSE");

17. return 0;

18. }

U primjeru 8.6. deklarirana je jedna varijabla n s poetnom vrijednosti 44 koja se u


programu ne mijenja i dva pokazivaa pn i ppn.

U naredbama 5 i 6 ispisani su sadraj polja n i njegova adresa. Nakon to je deklariran


pokaziva pn prodruena mu je poetna vrijednost ' adresa od n'. Naredba 8 ispisuje
sadraj pn i vidi se da je on jednak &n. naredba 10 ispisuje sadraj polja na adresi koju
pokazuje pn i vdi se da je to 44, jer se zapravo radi o polju n.
U naredbi 11 deklarira se novi pokaziva ppn s dvije zvjezdice, jer je to 'pokaziva na
pokaziva' i daje mu se poetna vrijednost 'adresa od pn'. Naredba 12 ispisuje sadraj
pokazivaa ppn i vidi se da je to adresa od pn. Naredba 13 ispisuje adresu od ppn.
Naredba 14 ispisuje sadraj polja na adresi koju pokazuje ppn, a to je zapravo sadraj
polja pn. Konano naredba 15 ispisuje sadraj polja na adresi koju pokazuje pn i vidi se
da je to polje n. Ovo je dodatno pojanjeno na slici 8.1.

Naziv polja Sadraj Adresa


n xx 0x22ff74
**ppn= *ppn ( *pn) *pn

126
pn=&n;

Naziv polja Sadraj Adresa


pn 0x22ff74 0x22ff70

*ppn ppn=&pn;

ppn 0x22ff6c

Slika 8.1. Odnos varijabli i pokazivaa

8.4.Odnos pokazivaa i polja

Naziv polja (array) je u sutini pokaziva kojemu se adresa ne moe mijenjati. To


ilustrira slijedei primjer:

Primjer8.7:
1. // odnos pokazivaa i polja

2. #include <iostream>

3. using namespace std;

4. int main (){

5. int brojevi[5];

6. int * p; 10, 20, 30, 40, 50,


0x22ff50,0x22ff54,0x22ff58
7. p =brojevi; Press any key to continue . . .
...
8. *p = 10;

9. p[1] = 20;

10. p = &brojevi[2]; *p = 30;

11. p = brojevi + 3; *p = 40;

12. p = brojevi; *(p+4) = 50;

13. for (int n=0; n<5; n++)

127
14. cout << brojevi[n] << ", ";

15. cout<<endl;

16. cout<<brojevi<<","<<brojevi+1<<","<<brojevi+2<<endl;

17. system("PAUSE");

18. return 0;

19. }

U primjeru 8.7. je naredbom 5. deklarirano polje brojevi koje ima 5 elemenata tipa int. U
naredbi 6. je deklariran pokaziva p za varijable tipa int. Naredba 7. je neuobiajena, jer
bi se oekivalo da pie p =&brojevi; Naime, kada varijabla brojevi ne bi bila polje (array)
prevoditelj bi javio greku. Naziv polja je u sutini pokaziva koji sadri adresu
prvog elementa u polju. Zbog toga se naredbom 8 u prvi element polja brojevi unosi
10. Iz slijedeih se naredbi (9,10,11 i 12) vidi da se varijabli p moe dodijeliti i indeks,
odnosno da se dodavanjem razliitih konstanti varijabli brojevi zapravo poveava adresa,
tj. dohvaaju se odgovarajui elementi polja. Ispis naredbom 16 pokazuje da se varijabla
naziva polja ponaa poput pokazivaa i kod raunskih operacija, tj. da se dodavanjem 1
ili 2 zapravo dodaju viekratnici duljine elemenata polja.

8.5. Dinamika alokacija memorije (Operatori new i delete)

Sve varijable koje su koritene u dosadanjim primjerima, bez obzira na inenicu da li su


bile lokalne ili globalne, bile su statike varijable. Zajedniko im je svojstvo da im se
mjesto u memoriji rezervira prilikom prevoenja programa i one zauzimaju mjesto u
memoriji cijelo vrijeme dok se program prilikom izvoenja nalazi u memoriji. Zamislimo
on-line program koji radi s dva skupa podataka na primjer profesori i studenti. Ti skupovi
podataka nisu isti jer na primjer za studente postoje podaci o poloenim ispitima, to za
profesore ne postoji, dok na primjer profesori imaju podatke iz radnog odnosa koji nisu
primjenljivi na studente. Neka je logika programa takva da odmah na poetku pita da li
je korisnik student ili profesor, pa se nakon toga poziva jedna funkcija koja se odnosi na
studente ili druga koja se odnosi na profesore. Ako se radi sa statikim varijablama one
e biti sve u memoriji, bez obzira da li je korisnik student ili profesor. Dakle zauzimaju
mjesto i kad ih program uope ne treba. Ovaj se problem moe rijeiti tzv. dinamikim
varijablama. To su varijable koje se stvaraju i unitavaju u vrijeme izvoenja programa.
Dakl u gornjem primjeru ako se poziva funkcija za studente, generirat e se samo
(dinamike) varijable koje se odnose na studente, a ako se poziva funkcija za profesore
onda se generiraju samo ove druge varijable.

Ponovimo dakle, kada se deklarira varijabla, na primjer:

128
int x;

na taj se nain daje prevoditelju uputu da rezervira u memoriji 4 bajta u kojima e


pohraniti cijeli brojevi. Ta se varijabla smjeta na neku adresu u RAM, recimo 1000.
Dakle deklaracijom int x; rezervirane su adrese 1000,1001,1002 i 1003. Taj se dio
memorije naziva stog (engleski stack) i zbog toga je x statika varijabla. Brigu oko
zauzimanja dijela memorije za dotinu varijablu i njeno oslobaanje vode prevoditelj i
operativni sustav. Bitno je istaknuti da statike varijable zauzimaju svoje mjesto u
memoriji ve u fazi prevoenja programa. Dakle ako je program uitan u memoriju ,
makar bio neaktivan, ona zauzima prostor koji odgovara veliini njegovog koda (tj.
naredbi) plus veliina statikih varijabli. U stog se pohranjuju podaci s kratkim vijekom
trajanja prema LIFO naelu (last-in-first-out).

S obzirom da je veliina memorije ograniena, htjelo se je da neke varijable, naroito


one koje zauzimaju puno memorije, pamtiti u memoriji samo za vrijeme izvoenja
programa. Dio memorije u koji se smjetaju takve varijable zove se hrpa (engleski heap).
Brigu oko zauzimanja prostora za takve varijable i njeno oslobaanje, vodi programer. U
hrpi se pohranjuju i podaci s duljim vijekom trajanja prema FIFO naelu (first-in-first-
out). Postupak dinamike alokacije i dealokacije memorije obavlja se naredbama new i
delete.

Operator new se koristi za dinamiko alociranje memorije. Kada se na primjer deklarira

float* p;

u memoriji se rezervira mjesto za taj pokaziva, ali taj pokaziva ne pokazuje na neku
varijablu u memoriji tj. sadraj pokazivaa nije predvidljiv.

Kada bi program naiao na naredbu:

*p = 3.14159; // greka !!!

javio bi greku jer pokaziva ne pokazuje na nikakvu memoriju. Zbog toga je dobro
inicirati pokaziva prilikom deklaracije kao na primjer:

float* p=&x;

Drugi nain da se izbjegne problem s neiniciranim pokazivaima je da se memorija


alocira pomou operatora new.

float* q;
q = new float;
*q =3.14159;

129
Operator new omoguava da memorija za pokaziva q alocira za vrijeme izvoenja
programa umjesto za vrijeme prevoenja. Naredbom q = new float; su se u memoriji
(zapravo u hrpi) zauzela 4 bajta za float varijablu, tako to je pokazivau q pridruena
odgovarajua adresa. Programera se u naelu ne tie koja je to adresa, mada je moe
doznati ispisivanjem sadraja pokazivaa q. Nakon toga je u odgovarajue float polje
unesen sadraj s naredbom : *q =3.14159;

Kada se se navedeno polje eli osloboditi za druge potrebe, ono se oslobaa s naredbom r
delete .

delete q;

Operator delete se smije koristiti samo za pokazivae koji su eksplicitno alocirani s


naredbom new.

Deklaracija pokazivaa koji zauzima mjesto u


Na primjer: stogu
Zauzimanje 4 bajta memorije u hrpi ija
float* pok; adresa se stavlja u pok.
pok=new float(); 'Punjenje' navedenih 4 bajta sa 10,234
*pok=10.234;

Prvo se naredbom deklarira pokaziva. U drugoj se naredbi pokaziva postavlja na


vrijednost nove varijable, a u treoj se naredbi u to polje stavlja vrijednost 10.234.

Istu bi stvar mogli napisati i :

float* pok=new float(10.234);

Na kraju koritenja treba dinamike objekte unititi sa:

delete pok;

Primjer 8.8 u nastavku je zapravo modificirani primjer8.7 s time da su koritene


dinamike varijable.

Primjer8.8.
1. // primjer za dinamiko alociranje memorije

2. #include <iostream>

3. using namespace std;

4. int main (){

5. int * p1;

130
6. int * p;

7. p = new int [5] ; // kreira se polje sa 5 elemenata tipa int

8. cout<<"&p = "<<&p<<" &p1= "<<&p1<<endl;

9. cout<<"p = "<<p<<endl;
&p = 0x22ff70 &p1= 0x22ff74 8
10. *p = 10; p = 0x3d24d0 9
10, 19
11. p[1]= 20; 20, 19
30, 19
12. p[4]=50; 40, 19
50, 19
13. p=p+2; // preskace se p[1] p1= 0x3d2468, *p1= 19 23
1718356 26
14. *p=30; Press any key to continue . . .

15. p++;

16. *p=40;

17. p=p-3;

18. for (int n=0; n<5; n++)

19. cout << p[n] << ", "<<endl;

20. delete p;

21. p1= new int();

22. *p1=19

23. cout<<"p1= "<<p1<<", *p1= "<<*p1<<endl

24.

25. int a;

26. a= int(p1)-int(&p1); // izraunava se udaljenost adresa

27. cout<<a<<endl;

28. system("PAUSE");

131
29. return 0;

30. }

U programu su deklarirana dva pokazivaa, p namijenjen kreiranju dinamikog polja i p1


za kreiranje dinamike varijable. Sve su dinamike varijable tipa int. Ispis naredbom 8
pokazuje da su pokazivai nalaze na adresama jedan iza drugog, dok naredba 9 ispisuje
sadraj pokazivaa p, koji zapravo pokazuje adresu dinamikog polja koje je kreirano s
naredbom 7. Vidi se da je adresa dinamikog polja daleko od adrese pokazivaa p za .
1.713.504 bajtova (ispis iz naredbe 26). Nakon toga se od naredbe 9 do 16 dinamiko
polje puni vrijednostima od 10 do 50 na dva naina: navoenjem indeksa polja ili
poveavanjem vrijednosti pokazivaa.
Naredbom 18 i 19 se ispisuje polje, ali se prije toga naredbom 17 adresa pokazivaa
vratila na poetnu adresu polja.

Slika 8.2: Alokacija memorije i ivotni vijek objekata

Objekti ive od poziva do kraja Stog Parametri funkcija i lokalni objekti


funkcije Stack (varijable)
Objekti ive od poziva s new dok Hrpa Dinamiki objekti (sve varijable
ih se ne uniti sa delete Heap koje moraju 'nadivjeti' funkciju)
Objekti ive za vrijeme izvoenja Opi podaci Globalne varijable, one koje su
programa definirane izvan funkcija main ()
Objekti ive dok je program u Kod Definicije funkcija, konstante
memoriji i ne mogu se mijenjati Code

Polja (arrays) mogu zauzimati puno mjesta u memoriji. Zbog toga ih je esto bolje
spremiti u hrpi, kako bi se memorija zauzela samo i tijeku izvoenja dijela programa koji
koristi navedena polja. Dakle ako se polje deklarira kao:

int tablica[10]; // tablica se smjeta u stog


tablica[0]= 235; // prvi element tablice dobiva vrijednost 235

Ako se polje eli smjestiti u hrpu treba ga deklarirati:

int * poktablice;
poktablice = new int[10] // tablica se smjeta u hrpu
poktablica [0]= 235; // prvi element tablice dobiva vrijednost 235

Uoiti razliku !
float pok*= &x;
*pok=10.234;

132
Kada se radi s pokazivaem na obinu varijablu mora se staviti *, a kod polja ne

Na primjer kada su se u tablicu smjetali podaci o studentima. Pitanje je koliko veliku


tablicu treba rezervirati ?

Ako se rezevira dovoljno velika tablica, na primjer za 3000 studenata, onda e se


program mou koristiti za obradu bilo kojeg broja studenata koji ne premauje 3000.
S druge strane takva e tablica zauzimati puno memorije ak i u sluajevima da se ele
obraditi podaci za samo 5 ili deset studenata.
Taj se problem moe rijeiti tako da se tablica alocira dinamiki tj. u fazi izvoenja
programa, nakon to se definirao i upisao broj studenata koji e se obraditi.
To je ilustrirano slijedeim primjerom:

Primjer8.9:
1. // primjer za dinamiko alociranje polja

2. #include <iostream>

3. using namespace std;

4. void zauzmi(double *& a, int & n) {

5. cout<<" Ukucaj broj elemenata u polju: "<<endl;

6. cin>>n;

7. a=new double[n];

8. cout<<"Unesi "<<n <<" elemenata, iza svakog enter"<<endl;

9. for (int i=0; i<n; i++) cin>>a[i];

10. }

11. void pisi(double *& a, int & n) {

12. for (int i=0; i<n; i++) cout<<a[i]<<",";

13. cout<<endl; Ukucaj broj elemenata u polju: 5


7 6
14. } Unesi 7 elemenata, iza svakog enter 8
11 9
15. int main () 22 9
33 9
16. { 44 9
55 9
66 9
77 9
133
11,22,33,44,55,66,77, 13
Press any key to continue . . .
17. double *p;

18. int n;

19. zauzmi (p,n);

20. pisi (p,n);

21. delete [] p;

22. system("PAUSE");

23. return 0;

24. }

Sada se moe dodatno protumaiti prijenos parametara kod pozivanja funkcija.

134
Prijenos parametara po vrijednosti

int zbroj (int a, int b) { Unutar funkcije se stvara se lokalna kopija


return a+b; } od a i b
....

int a, b, suma;
suma=zbroj (a,b);

Prijenos parametara po referenci

int zbroj (int &x, int &y) { int zbroj (int *x, int *y) {
return x+y; } return *x+*y; }
.... ....

int a, b, suma; int a, b, suma;


suma=zbroj (a,b); suma=zbroj (&a ,&b);

U oba sluaja se prenose pokazivai koji pokazuju na a i b. Promjene na a i b vide se i


izvan funkcije zbroj.

135
9. Ulazno izlazni tokovi

Za razliku od drugih programskih jezika C++ nema definirane naredbe za uitavanje i


ispis podataka. Na taj se je nain htjelo poveati fleksibilnost programskog jezika, jer
programski jezici koji imaju takve naredbe su ogranieni na pojedine tipove ulazno
izlaznih jedinica i organizacije podataka.

Umjesto ulazno izlaznih naredbi C++ koristi razrede8 koji su pohranjeni u standardnim
bibliotekama, kao na primjer iostream, koji omoguuju razliite ulazno izlazne operacije.

Sam koncept tokova je u skladu s naelima objektno orijentiranog programiranja izraen


na nain da su unos ili ispis podataka neovisni od tipa jedinice.

Prije pojanjenja samih ulazno izlaznih tokova neophodno je pojasniti neke osnovne
pojmove. Prvi je postupak meupohranjivanja podataka ili engleski buffering. Dva su
osnovna razloga zbog kojeg je uveden ovaj koncept prijenosa podataka. Prvi je u brzini
centralne jedinice u kojoj je brzina pristupa do pojedinog podatka reda veliine tisuu ili
vie puta vea nego kod najbrih vanjjskih jedinica kao to je magnetni disk. Drugi je
razlog u nainu pohranjvanja podataka na vanjskim jedinicama. Mali fiziki slogovi u
pravilu slabo iskoritavaju kapacitete vanjskih jedinica, pa se nekoliko slogova 'pakira' u
vee fiziki slog.

Pod pojmom blok, ili fiziki slog, se podrazumijeva odreeni broj logikih slogova koji
se sastoje od polja (field). Ti se blokovi spremaju (izmeu dva fizika prijenosa
podataka) u meuspremnik (buffer). Kod pisanja datoteke operativni sustav eka da se
taj meuspremnik napuni, kako bi se cijeli sadraj prenijeo na izlaznu jedinicu. Ovo
pranjenje meuspremnika se izvrava automatski i programer o tome ne mora voditi
rauna. Meutim, broj podataka ne mora biti viekratnik kapaciteta meuspremnika, pa
bi posljednji podaci kod zavretka programa, bez naknadne intervencije mogli ostati u
meuspremniku, ekajui da se ovaj popuni. Da bi se i ti podaci ispisali neophodno je
prisilno isprazniti meuspremnik (flush-isplahnuti). To se u pravilu ini automatski
prilikom zatvaranja toka, ali je ponekad, kada program prekine s radom na nepredvieni
nain, neophodno da to uini programer.
Kod itanja se u meuspremnik uita itav fiziki slog, koji se nakon toga prenosi u
memoriju programa slog po slog (kakav je deklariran u programu) u ulazno polje
definirano programom.
Za ulaz i izlaz podataka u C++ koriste se polja iz standardnog razreda string.

8
O razredima e biti govora kasnije. Za sada treba znati da je razred posebno definiran skup varijabli i
funkcija koje koriste te varijable koji se prema okolini ponaa kao zarvoreni objekt sa sueljem za
komunikaciju. Sutina U/I tokova je pojanjena bez oslanjanja na razrede.

136
9.1.Standardni razred string

U poglavlju 7. istaknut je problem nul-znaka kod nizova o kojem mora brinuti


programer. Navedeni znakovni nizovi, o kojima je ranije bila rije, preuzeti su iz jezika
C. Kasnije je u C++ uveden standardni razred predloaka basic-string odnosno iz njega
izvedeni razred string, koji omoguava jednostavnije rukovanje znakovnim nizovima. Za
razliku od ranije navedenih nizova koji se nazivaju C- nizovi, nizovi iz razreda string
nazivaju se i C++ nizovima. Kod rada sa C++ stringovima, programer ne mora brinuti o
null-znaku. Podatak o duljini stringa je ukljuen (uahuren eng. encapsulated) u samom
stringu. Unutar razreda definirane su standardne funkcije, odnosno metode za rad s
nizovima.

Rad s nizovima razreda string e se ilustrirati sa slijedeim primjerom:

Primjer9.1:
1. // Primjer rada s nizovima razreda string
2. #include <iostream>
3. #include <string> // mora se razred ukljuiti u program
4. using namespace std;
5. int main()
6. {
7. string S1;
8. string S2("Bog !");
9. string S3("To sam ja "); // stringovi S2 i S3 su inicirani kao i C-nizovi
10. string S4(S3);
11. // S4 je inicijaliziran s pomou drugog string objekta S3
12. S2: Bog ! 13
13. cout << "S2: " << S2 << endl; S3: To sam ja 14
14. cout << "S3: " << S3 << endl; S4: To sam ja 15
15. cout << "S4: " << S4 << endl; S1: Bog ! 19
16. S1: To sam ja 23
17. S1 = S2; // preoptereeni operator pridruivanja Press any key to continue . . .
18. // Pridruivanje jednog niza drugome
19. cout << "S1: " << S1 << endl;
20.
21. S1 = S3;
22. // S1 se sam podesio na potrebnu veliinu.
23. cout << "S1: " << S1 << endl;
24. system("PAUSE");
25. return 0;
26. }

U primjeru 9.1. deklarirana su 4 stringa S1, S2, S3 i S4 koji su tipa C++ od kojih S1
nema poetnu vrijednost, S2 i S3 su inicirani kao stringovi tipa C navodei niz karaktera
u navodnicima, dok je S4 iniciran pomou niza S3 to je mogunost koju nude C++

137
stringovi (naredbe 7-10). U naredbama 13-15 su ispisani sadraji tih stringova. Naredba
17. pokazuje da se C++ stringovi mogu pridruivati jedan drugome poput obinih
varijabli, pomou preoptereenog operatora pridruivanja. Isti je sluaj ponovljen u
naredbi 21, kada je S1 koji nije iniciran, pa nije mogao dobiti nikakvu duljinu, automatski
podesio svoju duljinu na duljinu niza S3 iji mu je sadraj pridruen.
Slijedei primjer ilustrira dodatne mogunosti rada s razredom string:

Primjer9.2:
1. // Primjer rada s razredom string dodatne mogunosti

2. #include <iostream>

3. #include <string>

4. using namespace std;

5. int main()

6. {

7. string S1;

8. string S2("od ");

9. string S3("Mene");

10. string S4;

11. if (S1.empty()) {

12. cout << "S1 je prazan" << endl;

13. cout << "Duljina mu je " << S1.size() << endl;

14. }

15. else

16. { cout << " Ne nije prazan" << endl;

17. }

18. S1 = "Pozdrav ";

19. cout << "S1 ima sada duljinu " << S1.size() << endl;

138
20. if (S3 < S1) // Usporedna relacija-preoptereena

21. { cout << " M je prije P" << endl; }

22. S4 = S1 + S2 + S3; // Konkatenacija-preoptereeni +

23. cout << "S4: " << S4 << endl;


S1 je prazan 12
Duljina mu je 0 13
24. S1 += S2; // Konkatenacija
S1 ima sada duljinu 8 19
M je prije P 21
25. S1 += S3;
S4: Pozdrav od Mene 23
S1: Pozdrav od Mene 26
26. cout << "S1: " << S1 << endl; S1[0] P 28
S1[1] o 29
27. // podnizovi S1[2] z 30
S1[3] d 31
28. cout << "S1[0] " << S1[0] << endl; S1[4] r 32
S1[5] a 33
29. cout << "S1[1] " << S1[1] << endl; S1[6] v 34
Press any key to continue . . .
30. cout << "S1[2] " << S1[2] << endl;

31. cout << "S1[3] " << S1[3] << endl;

32. cout << "S1[4] " << S1[4] << endl;

33. cout << "S1[5] " << S1[5] << endl;

34. cout << "S1[6] " << S1[6] << endl;

35. system("PAUSE");

36. return 0;

37. }

U prethodnom su primjeru iskoritene su funkcije empty i size razreda string. Funkcija


empty() vraa istinu (true) ako je string prazan, a funkcija size() vraa broj elemenata u
stringu.Kao to e se kasnije vidjeti u razredima (class) funkcije se nazivaju i metode.
Popis svih standardnih funkcija ili metoda, razreda string moe se nai na primjer na
adresi http://cplus.about.com/library/weekly/aa051202d.htm .

139
Nakon to se je u naredbi 7. deklarirao string S1 bez zadavanja poetne vrijednosti, u
naredbi 11 ispituje se da li je niz prazan. Oznaka S1.empty() treba samo shvatiti da se
ispituje S1, jer funkcija empty se odnosi openito na sve objekte na razreda string, oznaka
S1. specificira koji se objekt ispituje. Iz injenice da su se naredbe 12 i 13 izvodile to se
vidi iz ispisa, zakljuuje se da je uvjet S1.empty() bi zadovoljen.
U naredbi 18 je u S1 prenesen sadraj 'Pozdrav ' ukljuivi i prazno mjesto (blank) na
kraju, pa se iz ispisa u naredbi 19 vidi da je duljina S1 postala jednaka 8.
Poevi od naredbe 20 pa do 26 ilustrira se rad sa preotptereenim operatorima koji
omoguuju da se sa objektima tipa string radi kao s obinim varijablama.
U naredbi 20 usporeuju se stringovi S1 i S3. S obzirom da je u tom trenutku sadraj
stringa S1 jednak 'Pozdrav ak kojim sluajem ' a stringa S3 je ' Mene' zadovoljen je uvjet
S3<S1 jer je u ASCII tablici u prilogu A na kraju teksta znak M ispred znaka P. Zbog toga
je program i izvodio naredbu 21. Da su stringovi S1 i S3 imali na prvom mjestu isti znak,
usporeivao bi se slijedei itd. U naredbi 22 vidi se da se stringovi mogu 'zbrajati'. Ovo
se 'zbrajanje' zove konkatenacija (ulanavanje) a radi kao da se jedan string 'zalijepi' na
kraj prethodnog.
Rezultat se vidi u ispisu iz naredbe 23. Naredbe 24. 25 i ispis 26. takoer ilustriraju
mogunost konkatenacije. Konano naredbe od 28 do 34 pokazuju kako se pomou
ideksa mogu ispisivati podnizovi (ili im pristupiti). Objekti razreda string koriste se u
ulazno/izlaznim tokovima.

9.2. Ulazni i izlazni tokovi

Ve je opisano kako se tokovi cin i cout koriste za rad s konzolom, odnosno ispisivanje
podataka na ekranu i upisivanje putem tipkovnice. U jeziku C++ su ulazno izlazni
tokovi rijeeni na nain da budu neovisni od tipa ulazno izlazne jedinice.

Definiran je poseban razred ios_base iz koga su izvedeni razredi basic_istream i basic-


ostream koji su principom nasleivanja granaju dalje, kao to je prikazano na slici 9.1.

140
ios_base
ios
/\
/ \
/ \
istream ostream
/ | \ / | \
/ | | | \
/ / | \ \
/ / | \ \
/ / | \ \
istring ifstream iostream ofstream ostring
stream /\ stream
/ \
fstream stringstrea

Slika 9.1. Stablo ulazno/izlaznih tokova i nasljeivanje

Za dosege ove knjige dovoljno je znati da se razred ofstream koristi kada se eli pisati
podatke, dakle radi se s izlaznom datotekom, razred ifstream kada se podaci ele itati,tj.
kada se radi s ulaznom datotekom. Razred fstream se koristi kad se eli itati i pisati
podatke, odnosno aurirati datoteku.

To je ilustrirano na slijedeem jednostavno primjeru :

Primjer9.3:
1. // primjer za kreiranje datoteke

2. #include <iostream>// radi cout

3. #include <fstream> // ukljucuje se razred s kojim se moze pisati i citati

4. using namespace std;

5. int main(){

6. ofstream mojFile("primj1.txt");

7. // kreira se ofstream objekt s nazivom mojFile

8. // podaci u zagradam i navodnicima predstavljaju naziv i lokaciju datoteke.

9. if (! mojFile) // uvijek se provjerava ako je file otvoren

10. { cout << " Greska u otvaranju izlazne datoteke" << endl;

11. return -1; }

141
12. char ch; // Ovo je polje za uitavanje elemenata stringa

13. // slijedi naredba za ispisivanje stringa, vidi se da umjesto cout stoji naziv datoteke

14. mojFile << "Evo malo mojeg niza podataka" << endl;

15. mojFile.close();

16. // Otvara istu datoteku kao input radi itanja i ispisivanja sadraja

17. ifstream mojFilei ("primj1.txt");

18. if (! mojFilei) // provjera da je otvorena

19. {cout << " Nije otvorena ulazna datoteka"<< endl; return -1; }

20. while (mojFilei.get (ch)) cout<<ch;// opet se koristi cout za pisanje na ekran

21. system("PAUSE");

22. return 0;

23. }

Izlaz iz programa je na lokalnom disku C pod Borland\Bcc55\Bin u datoteci 'primj1':

Evo malo mojeg niza podataka


Press any key to continue

Da se umjesti 'primj1.txt' upisalo 'c:/primj1.txt' datoteka bi se upisala na disku C izvan


navedenih direktorija Borland\Bcc55\Bin.

Kad bi se naredbe u retku 20 promijenile tako da se za unos koristi operator izluivanja


>> umjesto get,

while (mojFilei) {mojFilei>>ch; cout<<ch;}

Izlaz na ekran bi bio:

Evomalomojegniza podatakaaPress any key to continue

Vid se da operator izluivanja >> preskae prazna polja. Naime, ne moe biti problem
u naredbi cout jer je ona ostala ista.
Izlazna datoteka mojFile otvorena je u naredbi 6. Postoje dva naina (mode) obrade
output datoteke truncated i append. Truncated znai da e nailaskom na otvorenu

142
datoteku u kojoj ve postoje neki podaci, oni biti izbrisani, a append da e se novi podaci
dodati iza postojeih. Ako se nita ne navede podrazumijeva se truncated.

Slog 'Evo malo mojeg niza podataka' je upisan u datoteku naredbom 14. Nakon toga
datoteka je naredbom 15 zatvorena. Naredbom 17 se ponovo otvara ista datoteka, ali ovaj
put kao ulazna. Vidi se da joj je u programu dano novo ime mojFilei (i na kraju) kako bi
je program prevoditelj razlikovao od prethodne.
Naredba 20. while (mojFilei.get (ch)) uitava podatke iz datoteke (bajt po bajt) i
pohranjuje u polje ch kojeg zatim naredba cout ispisuje. Ova se naredba ponavlja dok je
ispunjen uvjet da je mojFilei.get (ch) istinit ( true,) dakle do uitavanja kraja datoteke.
Kada se uita kraj datoteke, prestaju se izvoditit naredbe iz petlja while, tj. program ide
na naredbu system("PAUSE"); te na kraj programa.

Prilikom deklaracije datoteke nekad treba navesti i argumente tzv. mode, koji opisuje
nain pristupa podacima, kao n primjer:

ofstream mojFile("NekoImeDatoteke");
ofstream mojFile("NekoImeDatoteke",ios::out);
ofstream mojFile("NekoImeDatoteke",ios::out | ios::trunc);

U konkretnom sluaju sve tri deklaracije imaju isti uinak jer su out i trunc
podrazumijevani modovi za ofstream datoteku.

U tablici 9.1. prikazani su mogui argumenti kod definiranja datoteka.

143
Tablica 9.1. Argumenti (mode) datoteka
Mode Znaenje
out Otvara se file ili stream za izlaz (default za ofstream datoteku)
in Otvara se file ili stream za ulaz ( default za ifstream datoteku)
app Svako insertiranje bit e ispisano iza postojeih podataka
trunc Izbrisati e postojee podatke (default )
ate Otvara datoteku i pozicionira se na kraj.
Podatke tretira binarno umjesto kao tekst. Na primjer float varijabla e se
binary
pohraniti u svom standardnom obliku od 4 bajta, a ne kao niz.

Ako se na primjer u datoteku eli dodavati podaci iza postojeih, deklarirat e se na


slijedei nain:

ofstream moFile("NekoImeDatoteke ",ios::app);

Neki operacijski sustavi pored tekstualnih, podravaju i binarne datoteke. U tablici 9.2.je
prikazana usporedba ovih dviju vrsta datoteka.

Tablica 9.2:Usporedba tekstualnih i binarnih datoteka

Tekst datoteka Binarna datoteka


Jednostavna (ljudima) za itanje Nemogua ljudima za itanje
Jednostavno izmjene Tee izmjene
Jednostavni prijenos ( transfer) Sloeniji prijenos
Sporiji pristup Bri pristup
Manje precizna (zbog moguh greaka
Podaci su precizno pohranjeni
kod konverzije podataka)

Tekstualne datoteke su jednostavnije za obradu ali su kompliciranije kod uitavanja


numerikih podataka koje treba konvertirati iz tekstualnog u odgovarajui numeriki
oblik. Binarna datoteka nema problema s konverzijom podataka ali nije pregledna.
U praksi izbor tipa datoteke ovisi o tome koje su karakteristike u konkretnom sluaju
bitnije.
Rad s datotekama je u nastavku ilustriran s tri programa: prvi pie datoteku na disk,
drugi dodaje jedan slog iza navedene datoteke, a trei ita navedenu datoteku i uitane
podatke ispisuje na ekranu . Pri tome e se ispitivanje stanja datoteka, otvorenost ili kraj
datoteke, namjerno izvoditi na razliite naine, kako bi se pokazale te mogunosti.

144
Primjer9.4:
1. // Primjer pisanja teksta u datoteku
2. #include <iostream> // za cout
3. #include <fstream>
4. using namespace std;
5. int main () {
6. ofstream primjerfile ("primjer9_4.txt"); // otvara se izlazna datoteka
7. if (primjerfile.is_open()) // ispituje se da li je datoteka otvorena
8. {
9. primjerfile << "To je prvi red.\n"; // ispisuju se redom 1. 2. i 3. red
10. primjerfile << "A ovo je drugi red.\n";
11. primjerfile << "Ne bi se reklo, ali sad su tri.\n";
12. primjerfile.close();
13. }
14. cout<<"Eto ja zavrsih"<<endl;
15. system("PAUSE");
16. return 0;
17. }

U naredbi 7 se provjera da li je datoteka otvorena izvodi putem funkcije is_open(), gdje


naziv datoteke i toka koje joj prethode definiraju datoteku koju se provjerava. Dakle
naredba if (primjerfile.is_open()) ima u konkretnom sluaju isti uinak kao
if (primjerfile).
U naredbama 9-11 ne navodi se cout, nego se umjesto njega navodi naziv datoteke.
Izlaznu operaciju u stvari izvodi operator << koji se zove operator umetanja (insertion
operator). Kljune rijei cin i cout koje se koriste za rad s konzolom u stvari govore
kamo treba pisati li itati, dok samo pisanje ili itanje izvode tzv. operator umetanja (<<)
odnosno operator izluivanja (>>) (extraction operator).

Izlaz iz programa na konzoli tj. ekranu je:

Eto ja zavrsih
Press any key to continue . . .

Gledajui na logiku primjer 9_4 ima nedostatak to u sluaju da datoteka nije otvorena
on e zavriti na potpuno isti nain, osim to nee ispisdati datoteku na disk. To se moe
provjeriti pretraivanjem i isitavajem datoteke 'primjer9_4' na lokalnom disku C u
folderu Borland\Bcc55\Bin gdje je upisana datoteka slijedeeg sadraja:
To je prvi red.
A ovo je drugi red.
Ne bi se reklo, ali sad su tri.

145
Slijedei program dodaje jedan slog na kraju datoteke 'primjer9_4.txt' iz prethodnog
primjera:

Primjer9.5:
1. // Primjer pisanja tekst file kojemu se dodaje sadraj na kraju

2. #include <fstream>

3. using namespace std;

4. int main () {

5. ofstream primjerfile ("primjer9_4.txt",ios::app); // mode app za dodavanje

6. if (primjerfile.is_open()) // ispituje se da li je datoteka otvorena

7. {

8. primjerfile << "Je li to sad cetvrti red ?\n";

9. primjerfile.close();

10. }

11. return 0;

12. }

U naredbi 5 je prilikom otvaranja datoteke navedeno ios::app kao uputu da e se u


izlaznoj datoteci novi slogovi dodavati iza postojeih.
Sadraj datoteke 'primjer9_4.txt' je nakon izvoenja prethodnog programa postao:
To je prvi red.
A ovo je drugi red.
Ne bi se reklo, ali sad su tri.
Je li to sad cetvrti red ?

To e pokazati slijedei program koji ispisuje sadraj datoteke na ekran.

Primjer9.6
1. // Citanje i ispis text file
2. #include <iostream>
3. #include <fstream>
4. using namespace std;
5. int main () {
6. char buffer[256];

146
7. ifstream primjerfile ("primjer9_4.txt");
8. if (! primjerfile.good())
9. { cout << "Greka u otvaranju datoteke"; exit (1); }
10. while (! primjerfile.eof())
To je prvi red. 13
11. {
A ovo je drugi red. 13
12. primjerfile.getline (buffer,100);
Ne bi se reklo, ali sad su tri. 13
13. cout << buffer << endl;
Je li to sad cetvrti red ? 13
14. }
Press any key to continue . . .
15. system("PAUSE");
16. return 0;
17. }

Ovdje se za itanje koristi funkcijski lan getline iz


razreda istream. Ona za razliku od naredbe cin ne Kada bi se u programu primjer9.6
preskae prazna mjesta (a ni neke druge znakove umjesto getline htjelo koristiti get,
kao novi red, tabulacija,). trebalo bi izvriti slijedee izmjene:
Parametri funkcije getline su polje u koje se Naredba 6. izmjeniti tako da buffer
uitava sadraj (buffer) i duljina tog polja (100). U bude obina char varijabla
konkretnom sluaju buffer je polje od 256 char buffer;
znakova, a uitava se u prvih 100. zatim naredbe 12 i 13 da budu:
Funkcija getline izbacuje zavrni znak niz '\n' iz primjerfile.get(buffer);
ulaznog toka . U razredu istream postoji i funkcijski cout << buffer;
lan get koja uitava znak po znak . Izlaz iz programa bi ostao isti.

Kod ispitivanja stanja datoteka koriteni su izrazi good i eof. Postoje 4 funkcijska lana
tipa bool za oitavanjanja stanja

eof () vraa true ako je uitan znak za kraj datoteke (end of file)
bad () vraa true ako operacija nije uspjela zbog nepopravljivih greaka
fail () vraa true ako operacija nije uspjela zbog bilo kojeg razloga
good() vraa true, ako ni jedna prethodna nije true tj. operacija je uspjeno izvedena

Pretpostavimo da imamo slijedei tekst napisan u Notepad-u:

''Za razliku od drugih programskih jezika C++ nema definirane naredbe za


uitavanje i ispis podataka. Na taj se je nain htjelo poveati fleksibilnost
programskog jezika, jer programski jezici koji imaju takve naredbe su ogranieni na
pojedine tipove ulazno izlaznih jedinica i organizacije podataka.
Umjesto ulazno izlaznih naredbi C++ koristi razrede koji su pohranjeni u
standardnim bibliotekama, kao na primjer iostream, koji omoguuju razliite ulazno
izlazne operacije.''

Ovaj je tekst memoriran u datoteci ..\..\..\Borland\BCC55\Bin\tekst1.txt.

147
U nastavku je prikazan program koji uitava taj tekst te broji broj znakova, broj praznih
mjesta (ili rjei) i broj reenica u njemu (otprilike kao to u MS Wordu radi Word
Count).

Primjer 9_7:
1. // Program koji ita tekst u broji znakove, rijei i reenice
2. #include <iostream>
3. #include <fstream>
4. using namespace std;
5. int main()
6. {
7. int blankbroj = 0; // broja praznih polja
8. int charbroj = 0; // broja znakova
9. int recenbroj = 0; // broja reenica
10. char ch;
11. ifstream iFile("tekst1.txt");
12. if (! iFile) // provjera da je datoteka otvorena
13. {
14. cout << " Greka u otvaranju ulazne datoteke" << endl;
15. return -1;
16. }
17. while (iFile.get(ch))
18. {
19. switch (ch) {
20. case ' ': // ako je blank poveaj broja za 1
21. blankbroj++;
22. break;
23. case '\n': break;
24. case '\t': break;
25. case '.': // Ako je toka dri da je to kraj reenice
26. recenbroj++;
27. break;
28. default: // ako nije nita od navedenog, to je karakter koji se broji.
29. charbroj++;
30. break;
31. }
32. }
33.
34. cout << "Ima " << blankbroj << " praznih mjesta" << endl;
35. cout << "Ima " << charbroj << " znakova" << endl;
36. cout << "Ima " << recenbroj << " recenica" << endl;
37. system("PAUSE");
38. return 0;
39. }

148
Ima 70 praznih mjesta 34
Ima 405 znakova 35
Ima 3 recenica 36
Press any key to continue . . .

Slijedi jo jedan primjer programa, koji ita sadraj jedne datoteke i pie ga u drugu.
Specifinost je ovog programa da moe posluiti za prijepis bilo koje datoteke, jer se
naziv datoteka definira u fazi izvoenja programa.

Primjer9.8
1. // Primjer opeg programa za prijepis datoteka
2. #include <iostream>
3. #include <fstream>
4. #include <string>
5. using namespace std;
6. int main(){
7. char ch;
8. string Ulazna;
9. string Izlazna;
10. cout << "Upisi naziv ulazne datoteke: ";
11. cin >> Ulazna;
12. cout << "Upisi naziv izlazne datoteke: ";
13. cin >> Izlazna;
14. cout<<"pocinje otvaranje"<<endl ;
15. ifstream iFile (Ulazna.c_str()); // Nazivi iFile i oFile su po izboru programera
16. ofstream oFile (Izlazna.c_str());
17. if (! iFile.good()) { cout<<"Greska u otvaranju ulazne datoteke"<<endl;
18. return -1; }
19. if (! oFile) { cout<<"Greska u otvaranju izlazne datoteke"<<endl;
20. //sa ili bez good() uinak je isti
21. return -1; }
22. while (! iFile.eof()){
23. iFile.get(ch);
24. oFile.put(ch);
25. cout<< ch; // samo da se vidi sto je prepisano
26. }
27.nazivsystem("PAUSE");
Upisi ulazne datoteke: tekst1.txt 10,11
28.naziv izlazne
Upisi return datoteke:
0; tekst2.txt 12,13
pocinje
29. }otvaranje 14
Za razliku od drugih programskih jezika C++ nema definirane naredbe za uitavan 25
je i ispis
Izlaz podataka. na
iz programa Naekranu,
taj se je nain
bio jehtjelo poveati fleksibilnost programsko
slijedei: 25
g jezika, jer programski jezici koji imaju takve naredbe su ogranieni na pojed 25
ine tipove ulazno izlaznih jedinica i organizacije podataka. 25
Umjesto ulazno izlaznih naredbi C++ koristi razrede koji su pohranjeni u standar 25
dnim bibliotekama, kao na primjer iostream, koji omoguuju razliite ulazno izl 25
azne operacije.\n 25
Press any key to continue . . . 149
Provjere radi moe se pogledati sadraj datoteke..\..\..\Borland\BCC55\Bin\tekst2.txt.

Treba naglasiti da su se u datoteku tekst2.txt i hrvatski dijakritiki znakovi prenijeli


ispravno, samo se krivo prikazuju samo na ekranu.

Da je naredba za itanje umjesto iFile.get(ch); bila iFile>>ch; onda bi se na ekranu, a i


u tekst2.txt (osim to bi hrvatska slova bila ispravno prenijeta) dobio slijedei izlaz:

Upisi naziv ulazne datoteke: tekst1.txt


Upisi naziv izlazne datoteke: tekst2.txt
pocinje otvaranje
ZarazlikuoddrugihprogramskihjezikaC+
+nemadefiniranenaredbezauitavanjeiispispodataka.Natajsejenainhtjelopoveatifleksibilnostpr
ogramskogjezika,jerprogramskijez
icikojiimajutakvenaredbesuogranieninapojedinetipoveulaznoizlaznihjedinicaiorgan
izacijepodataka.UmjestoulaznoizlaznihnaredbiC++koristirazredekojisupohranjeniust
andardnimbibliotekama,kaonaprimjeriostream,kojiomoguujurazliiteulaznoizlazneoper
acije. .Press any key to continue . . .

Razlika je u tome to operator izluivanja (extraction operator) '>>' isto kao i cin
odbacuju prazna polja.

U primjeru 7.4 obraivao se problem vezan za evidenciju studenata. Podaci o poloenim


ispitima su bili smjeteni u polje (tablicu) koja je bila definirana u programu. U nastavku
su prikazani programi za upis podataka o poloenim ispitima u datoteku i za izlistavanje
te datoteke.
Primjer 9.9:
1. // Primjer kreiranja datoteke studenata
2. #include <fstream>
3. #include <iomanip> // radi ukljuivanja manipulatora
4. #include <stdlib.h>
5. int main () {
6. string stmbr=("00000"), mbr, ime , prez, pred;// sva su polja stringovi

150
7. char ocj;
8. ofstream stdev ("studenti.txt",ios::app);// u datoteku se mogu dodavati
slogovi
9. if (!stdev.is_open())
10. { cout<<"Greska u otvaraju datoteke "; exit (1);
11. }
12. cout<<"Upisi maticni broj student do 5 znamenaka, 99999 za kraj "<<endl;
13. cin>>mbr;
14. while (mbr!="99999") {
15. if (mbr!=stmbr) {
16. cout<<"Upisi ime te prezime studenta"<<endl;
17. cin>>ime>>prez;
18. stmbr=mbr; }
19. cout<<"Upisi sifru predmeta i ocjenu"<<endl;
20. cin>>pred>>ocj;
21. stdev <<setw(5)<<mbr<< setw(10)<<ime<<setw(15)<< prez<<
22. setw(3)<<pred<<ocj<<endl;
23. cout<<"Upisi maticni broj studenta, 99999 za kraj "<<endl;
24. cin>>mbr;
25. }
26. stdev.close();
27. system("PAUSE");
28. return 0;}

Gornji je primjer pojednostavljena verzija programa, jer mu nedostaju neke dodatne


kontrole kao na primjer da su matini brojevi strogo s 5 znamenaka. Kao to se iz ispisa
vidi program pita da se upie ime i prezime studenta samo kada se odreeni matini broj
prvi put pojavi.
U gornjem se primjer koristio manipulator setw () koji slui za formiranje slogova
datoteke. Na primjer setw(10) postavlja duljinu niza ime na duljinu 10, a setw(15)
postavlja prez na 15 mjesta. U datoteku studenti je upisan slijedei sadraj:

11111 Tone Tomacp014


11111 Tone Tomacp023
11111 Tone Tomacp033
22222 Nina Malap015
22222 Nina Malap024

151
U nastavku je ispis s konzole za Primjer9.9.
Upisi maticni broj student do 5 znamenaka, 99999 za kraj 12
11111 13
Upisi ime te prezime studenta 16
Tone Tomac 17
Upisi sifru predmeta i ocjenu 19
p01 4 20
Upisi maticni broj studenta, 99999 za kraj 23
11111 24
Upisi sifru predmeta i ocjenu 19
p02 20
3 20
Upisi maticni broj studenta, 99999 za kraj 23
11111 24
Upisi sifru predmeta i ocjenu 19
p03 3 20
Upisi maticni broj studenta, 99999 za kraj 23
22222 24
Upisi ime te prezime studenta 16
Nina Mala 17
Upisi sifru predmeta i ocjenu 19
p01 5 20
Upisi maticni broj studenta, 99999 za kraj 23
22222 24
Upisi sifru predmeta i ocjenu 19
p02 4 20
Upisi maticni broj studenta, 99999 za kraj 23
99999 24
Press any key to continue . . .

Vidi se da se na primjer da su se predmet i ocjena mogli unijeti u jednom retku, tako da


su razmaknuti praznim poljem ili u dva retka ukucavanjem enter nakon svakog.

Tablica 9.1. Primjeri i opis I/O manipulatora


setfill (int) znak s kojim se popunjuje polje, na primjer za ubacivanje vodeih nula
setprecision broj znamenki koji e se prikazati na ekranu . Vrijedi za sve floating point
(int) brojeve dok se ne navede neka druga vrijednost.
flush prazni se izlazni tok
endl takoer spada u manipulatore a funkcija mu je da isprazni izlazni tok
(flush) i umee znak za novi redak ( '\n')
dec dekadski prikaz brojeva
hex heksadecimalni prikaz brojeva
oct oktalni prikaz brojeva
bin binarni prikaz brojeva

152
scientific eksponencijalni prikaz brojeva

Slijedei primjer ilustrira upotrebu manipulatora:

Primjer9.10:
1. /* Ovaj program ilustrira upotrebu manipulatora */
2. #include <iostream> To je x 128.457 8
3. #include <iomanip> xxxxoooooooooxoooo 9
4. using namespace std; 1. 128.4567- 13
5. int main() 2. 128.4567- 14
3. 128.4567- 15
6. {
4. 128.46 - 16
7. float x=128.4567; Press any key to continue . . .
8. cout<<"To je x "<<x<<endl;
9. cout<<"xxxxoooooooooxoooo"<<endl; // za brojanje mjesta na listi
10. cout<<fixed<<showpoint;//ova je neophodno za aktiviranje setprecision
11. // fixed aktivira prikaz brojki u obliku fiksnog zareza npr.12,34
12. // showpoint aktivira prikaz decimalne toke
13. cout<<"1. "<<setprecision(4)<<setw(12)<<x<<"-"<<endl;
14. cout<<"2. "<< x<<"-"<<endl;
15. cout<<"3. "<<setw(10)<<x<<"-"<<endl;
16. cout<<"4. "<<setprecision(2)<<setw(10)<<left<<x<<"-"<<endl;
17. return 0;
18. }

Naredbom 9 su ispisani znakovi radi lakeg brojenja praznih mjesta u pojedinim


redovima. Treba napomenuti da se kod operacije copy, paste ti odnosi djelomino
promjene.
U naredbama 13 do 16 se ispisuju redni brojevi s dva prazna mjesta, a za tim se ispisuje
varijabla x. U naredbi 13. je ispisana varijabla x na 12 mjesta uz 4 decimalna mjesta. U
naredbi 14 nije navedena irina polja za varijablu x, ali je zadrana preciznost na 4
decimale od ranije. U naredbi 15. je za x rezevirana irina od 10 mjesta, pa je polje za 2
mjesta krae od onog u naredbi 13. U naredbi 16 je preciznost smanjena na dvije
decimale i sa left je izlaz lijevo poravnat. U naredbi 14. se vidi da je setprecision i dalje
na snazi, ali ne i setw, to pokazuje da setprecision() vrijedi dok se ne navede neki drugi
podatak , dok se setw() odnosi samo na polje koje mu neposredno slijedi.

153
10. Koncept objektno orijentiranog programiranja
(Object-oriented Programming)

Jezik C++ predstavlja primjer jezika koji podrava objektno orijentirano


programiranje. Radi lakeg razumijevanja ovog koncepta u nastavku e se ukratko
izloiti kako je tekao razvoj tehnika programiranja. Razvoj tehnika programiranja bio je
usmjeren prema poveanju produktivnosti i kvalitete programa. Poznato je takoer da
najvei dio trokova softvera nastaje u fazi njegovog odravanja.
Jedno istraivanje poetkom 70-tih godina9 pokazalo je da se trokovi za otklanjanje
greaka u programu kreu u slijedeim odnosima.

Tablica 10.1: Relativni trokovi otklanjanja greke u raznim fazama razvoja softvera
Relativni troak
Faza razvoja
otklanjanja
aplikacije
greke
Definiranje problema
(specifikacija 0.1 -- 0.2
zahtjeva)
Opis algoritma
0.5
-Modeliranje
Kodiranje 1
Pojedinano
2
testiranje programa
Testiranje cijele
5
aplikacije
Odravanje 20

Dakle, troak otklanjanja greaka u fazi odravanja aplikacije je 20 puta vei od troka
otklanjanja iste greke u fazi kodiranja. U fazi odravanja programa se 'ispravci'
programa ne rade samo zbog naknadno otkrivenih greaka. Neke promjene u programu
nastaju kao rezultat objektivnih promjena u realnom svijetu. To su na primjer promjene
zakona koji imaju utjecaja na nain voenja knjigovodstva, obrauna poreza itd. Razvoj
znanosti i tehnologije takoer mogu nametnuti neka nova rjeenja 'starih' problema itd.

Neprekidno nastojanje za smanjenjem trokova u dananjem gospodarstvu, nametnulo je


da i razvoj tehnika programiranja ide u tom smjeru.

Tako su se u tijeku razvoja tehnika programiranja prolo kroz slijedee 4 razvojne faze:
Nestrukturirano programiranje
Proceduralno programiranje
Modularno programiranje
Objektno orijentirano programiranje

9
A.M. Davis. Software Requirements, Analysis and Specification. Prentice-Hall, 1990.

154
10.1. Nestrukturirano programiranje

Nestrukturirano programiranje pojavljuje se na poetku njegovog razvoja kada su se svi


elementi programa smjetali u jedan (glavni) program. Taj je program imao neposredan
pristup do svih podataka koje je obraivao. Ubrzo se pokazalo da u sluaju
kompleksnijih i opsenih programa ovakav pristup vodi k mnogim komplikacijama u
fazi izrade samog programa a i prilikom njegove eksploatacije i odravanja. Izrada i
odravanje kompleksnih programa postala je vrlo sloen posao. Kada se na primjer neki
niz naredbi morao ponavljati na vie mjesta u programu (zamislimo da treba izraunati
drugi korijen nekog broja), to se u naelu moglo rijeiti na dva naina. Prvi nain je
dupliciranje navedenh naredbi na svakom mjestu na kojem je trebalo izvriti navedene
naredbe, ime se poveavao opseg programa tj. broj njegovih naredbi ime se oteavao
pregled nad njime. Drugi nain kojim se izbjegavalo dupliciranje bilo je uvoenje
naredbe za grananje, ime se zakompliciralo praenje logike programa. To je ilustrirano
na slijedeem primjeru. Pretpostavimo da na tri mjesta u programu imamo potrebu za
ponavljanjem istog niza naredbi na primjer izraun drugog korijena i da ne elimo
duplicirati naredbe za izraun.

int main () {
gr0: int indgr= 0; // indikator grananja koji pokazuje odakle smo doli
.. // ostale naredbe u programu
..
goto kor; // neka je niz naredbi za izraun korijena identificiran s oznakom kor
..
gr1: indgr=1;
.. // nastavak naredbi
..
..
goto kor;
..
gr2: indgr=2;
.. // nastavak naredbi
..
goto kraj; // zato da se preskoi sekvencijlni izraun korijena

155
kor: // slijede naredbe za izraun korijena
..
..
if (indgr==0) goto gr0; // vraa se odakle je doao
if (indgr==1) goto gr1;
if (indgr==2) goto gr2;
if (indgr<0 || indgr>2) cout<< '' Odakle si stigao? ''<<endl;
kraj: return 0;
}

Zbog toga se ubrzo rodila ideja da se takav niz naredbi 'izvue' iz programa u posebne
procedure. Te su procedure poput dananjih funkcija izraerne tako da se prilikom
njihovog poziva automatski pohranjivala adresa povratka, koja pokazuje na naredbu
neposredno iza one kojom je dotina procedura (ili funkcija) pozvana. Tako je stvoren
koncept proceduralnog programiranja.

10.2. Proceduralno (strukturirano)programiranje

'Izvlaenjem' slijeda naredbi iz programa i njihovom ugradnjom u posebne procedure,


razvijene su tehnike za poziv tih procedura, te povratom kontrole izvoenja na glavni
program nakon to se procedura izvede.

Nain pozivanja procedure i povrata kontrole na glavni program, prikazan je na


slijedeoj slici: Glavni program
Procedura
(potprogram)

Slika 10.1. Odnos glavnog programa i potprograma

U glavnom se programu nalazi naredba za poziv procedure. Izvravanjem ove naredbe


kontrola izvoenja se prenosi na proceduru. Pri tome glavni program moe (ali ne mora)
prenijeti proceduru i neke podatke koje e procedura obraditi. Program mora proceduri
na odgovarajui nain prenijeti adresu povratka, kako bi procedura 'znala' od kuda

156
glavni program treba nastaviti izvoenje nakon to je procedura zavrila s radom. U
pravilu je to prva naredba koja slijedi iza naredbe kojom je pozvana procedura. Adrese
grananja i popvratka su u pravilu pohranjene u posebnim pokazivaima.
Na taj su se nain stvorili uvjeti da se sloeni program 'razgradi' na manje jednostavne
procedure ili potprograme iju logiku nije teko pratiti. Glavni program na taj nain
postaje bitno manjeg opsega, a zbog jednostavnosti naina poziva potprograma i povrata
kontrole izvoenja na glavni program, nije teko pratiti logiku njegovog izvoenja.
To se moe ilustrirati na primjeru programa Primjer6.3 za sortiranje (Buble sort):

#include <iostream.h>
void print (float [ ], int); // funkcija koja ispisuje polje
void sort (float [ ], int); // funkcija koja sortira elemente polja
void swap (float&, float&); // funkcija koja zamjenjuje vrijednost dviju varijabli
int main () {
float a[ ] ={55.5, 22.5, 99.9, 66.6, 44.4, 88.8, 33.3, 77.7};
print (a,8);
sort (a,8);
print (a,8);
}
Glavni program ima u sutini samo tri izvrne naredbe: ispisivanje tablice prije sortiranja,
sortiranje i ponovno ispisivanje.

Shematski bi se strukturirani program mogao prikazati na slijedei nain:

Glavni program
Podaci

Procedura 1 Procedura 2 Procedura 3

Uloga je glavnog programa da bude 'skretniar' te da osigura razmjenu odgovarajuih


podataka (parametara) izmeu njega i procedura, pa neizravno i izmeu samih
procedura.

157
10.3. Modularno programiranje

Modularno programiranje je rezultat nastojanja da se pojedine procedure u


proceduralnom programiranju mogu koristiti u razliitim programima. Zbog toga su se
pojedine procedure ugradile u samostalne module. Dok se u proceduralnom
programiranju program sastojao od jednog dijela, koji poziva potprograme, u
modularnom se programiranju program sastoji od vie samostalnih modula koji
interaktivno komuniciraju s glavnim programom ali po potrebi i meusobno meusobno.

Modularni bi se program slikovito mogao prikazati na slijedei nain:

Glavni program
Podaci

Modul 2
Modul 1
Podaci + podaci2
Podaci +podaci
1

Procedura 1 Procedura 2 Procedura 3

Svaki modul moe sadravati vlastite podatke. Ti podaci omoguuju, da modul ima
odgovarajue stanje, koje se pozivom procedura moe modificirati.

158
10.4. Objektno orijentirano programiranje

Kod objektno orijentiranog programiranja umjesto modula postoje samostalni objekti


koji komuniciraju meusobno putem poruka koje si meusobno alju. Svaki se objekt
samostalno inicira i unitava pa nije potrebno pozivati procedure koje to ine.

Objekt
Objekt11 Objekt
Objekt44
Podaci
Podaci Podaci
Podaci

Objekt
Objekt33
Objekt
Objekt22 Podaci
Podaci
Podaci
Podaci

Iako ovo slii na malo bolje modularno programiranje, to ipak nije sluaj. Pored ovog
opisa objektno orijentirano programiranje mora zadovoljavati i niz drugih svojstava, kao
to su:

Apstrakcija podataka (data abstraction) i ponovna iskoristivost koda (code


reusability).

I pojmovi u vezi s tim:

Enkapsulacija ili uahurenje (encapsulation)- predstavlja mogunost programa


da sakrije svoje podatke i metode (tj. funkcije) od ostatka svijeta.
Naslijeivanje (inheritance) mogunost programa da pojedini razred moe
naslijediti neka svojstva drugog razreda. Ideja je da se postojei kod moe
prilagoditi novoj situacju uz male ili ak nikakve izmjene.
Polimorfizam (polymorphism) mogunost da se pojedini objekt reagira razliito
na istu poruku ovisno o njegovom tipu.

159
Za primjenu naela OOP (Objektno Orjentiranog Programiranja) u C++ jeziku
neophodno je uvesti pojam razreda (class).

10.5. Razredi (Class)

Razredi predstavljaju metodu kojom se podaci i funkcije organiziraju u zajednike


strukture. Razred se moe interpretirati kao polje (array) koje sadri razliite tipove
podataka, meutim za razliku od polja koje moe sadravati samo podatke i to sve istog
tipa, razredi pored podataka mogu sadravati i funkcije.

Opi oblik naredbe, kojom se definira klasa, je:

class naziv_klase { // ovo je zaglavlje

dozvola pristupa-1:
lanovi_1;

dozvola pristupa_2: Ovo je tijelo


lanovi-2;

....

} naziv-objekta; // naziv objekta moe biti naveden i kasnije

Razredom se definira struktura objekta, dok se stvarni objekt definira njegovim nazivom,
koji moe biti naveden u samoj definiciji razreda ili posebnom naredbom.

Odnos iz meu razreda i objekta je isti kao odnos tipa varijable i same varijable. Na
primjer:

float broj;

Ovom se deklaracijom definira varijabla broj tipa float to znai da se za tu varijablu


rezerviraju 4 bajta koji se interpretiraju kao decimalni brojevi.

Analogno tome, ako na primjer elimo definirati vektore u Kartezijevom sustavu u


ravnini, koje prikazujemo pomou njihovih komponenti x i y, to moemo uiniti , na
primjer:

class vektor {
public:
float ax, ay;
} vektor1;

160
Ovom se naredbom definira razred vektor koji sadri dva realna broja, koji predstavljaju
komponente vektora u ravnini. Razred vektor u ovom sluaju predstavlja tip podatka po
analogiji sa float iz prethodne deklaracije. Varijabla vektor1 pak predstavlja objekt po
analogiji s varijablom broj. Nakon to je u programu definiran razred vektor kao u
gornjem primjeru,objekt se moe i naknadno deklariratit:

vektor vektor2;

Deklarcije objekata vektor1 i vektor2 su potpuno ravnopravne. Deklaracijom razreda ne


zauzima se mjesto u memoriji, nego se samo opisuje struktura objekata koji pripadaju
tom razredu. Deklaracijom pojedinog objekta (dakle u konkretnom primjeru vektor1 i/ili
vektor2) rezervira se i mjesto u memoriji za taj objekt.

Nakon ovako definiranog razreda vektor, mogu se definirati i drugi objekti, na primjer:

vektor sila, brzina;

Na taj smo nain definirali dva nova objekta sila i brzina koji pripadaju razredu vektor.

Deklaracijom razreda u programu, opisuje se samo novi tip varijabli, tj. njihova
struktura, dozvola pristupa i po potrebi funkcije za operacije meu njima i ne
zauzima se mjesto u memoriji.

Deklaraciju razreda treba shvatiti kao poopenje pojma tipa varijable (int, float) za koje
ne treba u programu nita dodatno navoditi jer su svojstva tih varijabli ve 'ugraena' u
C++. Na primjer ako se neka varijabla deklarira kao int, onda joj C++ dodijeli 4 bajta u
memoriji i interpretira kao cijeli broj. Razred je poopenje pojma tip, koji omoguuje
korisniku da definira nove tipove varijabli kojima dodjeljuje i neke funkcije.

Primjer razreda ilustrirat e se na primjeru razreda vektor kojim emo u C++ uvesti
elemente vektorske algebre.

161
Podsjetimo se:
Vektor se u ravnini prikazuje kao zbroj dva realna broja koji predstavljaju njegove
projekcije na koordinatne osi x i y:

a=ax+ay

Na tako definiuranim veliinama uvedene su i raunske operacije , kao na primjer


mnoenje sa skalarom10 , zbrajanje vektora i skalarni produkt vektora.
Mnoenje skalarom (na primjer 5*a) izvodi se:

5*a= 5*ax+5*ay

Zbroj dva vektora a=ax+ay i b=bx+by definiran je kao a+b = (ax+bx ) +(ay+by)
Skalarni vektora a=ax+ay i b=bx+by definiran je kao a*b = (ax*bx ) +(ay*by)
Kako je produkt jedininih vektora i*i odnosno j*j jednak 1, skalarni produkt vie nije
vektor nego skalar i otud mu i naziv.

Deklaracija razreda vektor je :

class vektor {
public:
float ax, ay;
void mnoziskalarom (float skalar);
};

U ovoj je deklaraciji naveden samo prototip funkcije, tj. njen naziv i parametri, a opis
same funkcije bit e naveden kasnije. Funkcija je mogla biti opisana i unutar deklaracije
razreda, no ovo je odvajanje u skladu s uobiajenom praksom.

Definicija (opis) funkcije mnoziskalarom je:

void vektor::mnoziskalarom(float skalar){


ax *=skalar;
ay *=skalar;
}
Simbol '::' u konkretnom sluaju pokazuje da se tu radi o funkciji iz razreda vektor.

Nakon toga mnoenje konkretnog vektora, nazovimo ga (ax+bx ), sa skalarom, izvodi se:

vektor sila;
sila.mnoziskalarom(5.0);

Slijedei primjer ilustrira zbrajanje vektora i mnoenje sa sa skalarom:


10
Pojam skalar uveden je radi razlikovanja od vektora tj. za nas je skalar sve ono to nije vektor

162
Primjer 10.1:
1. // operacije s vektorima koritenjem razreda
2. #include <iostream.h>
3. class vektor {
4. public:
5. float ax, ay;
6. vektor zbrojvektora (vektor a, vektor b); // Opet se navode samo prototipovi
7. void mnoziskalarom (float skalar);
8. float skalprod (vektor a, vektor b);
9. };
10. // slijedi opis funkcije zbrajanja
11. vektor zbrojvektora (vektor a , vektor b) {
12. vektor c;
13. c.ax= a.ax + b.ax;
14. c.ay= a.ay + b.ay;
15. return c;
16. }
17. // slijedi opis skalarnog produkta
18. float skalprod (vektor a , vektor b) {
19. float c;
20. c= a.ax * b.ax+ a.ay * b.ay;
21. return c;
22. }
23. // slijedi mnoenje sa skalarom
24. void vektor::mnoziskalarom(float skalar){
25. ax *=skalar;
26. ay *=skalar;
27. }

163
28. // slijedi main program
29. int main() {
30. vektor v1, v2, v3;
31. char ch='a';
32. float m=0, skal;
33. while (ch!='k') {
34. cout<<" Ovo je program za raunanje s vektorima"<<endl;
35. cout<<" Ukucaj + ako eli zbrajati vektore"<<endl;
36. cout<<" * za mnoenje sa skalarom"<<endl;
37. cout<<" x za skalarni produkt vektora"<<endl;
38. cout<<" k za kraj"<<endl;
39. cin>>ch;
40. if (ch=='+'||ch=='x') {
41. cout<<" Unesi x i y komponentu 1. vektora " <<endl;
42. cin>>v1.ax>>v1.ay;
43. cout<<" Unesi x i y komponentu 2. vektora " <<endl;
44. cin>>v2.ax>>v2.ay;
45. if (ch=='+') {v3=zbrojvektora (v1,v2);
46. cout<<"v3= "<<v3.ax<<" + "<<v3.ay<<endl;
47. }
48. else {skal=skalprod (v1,v2);
49. cout <<''Skalarni produkt je ''<<skal<<endl;
50. }
51. }
52. if (ch=='*'){
53. cout<<" Unesi x i y komponentu vektora i skalar " <<endl;
54. cin>>v1.ax>>v1.ay>>m;
55. v1.mnoziskalarom(m);
56. cout<<"v1= "<<v1.ax<<" + "<<v1.ay<<endl;
57. }
58. }
59. return 0;
60. }

U prethodnom sluaju razred vektor sadri dvije veliine koje predstavlju x i y


komponentu vektora i tri funkcije koje predstavljaju operacije s njima.
Upotreba razreda ilustrirana je i primjerom programa za izraun povrine pravokutnika

164
Primjer10.2:
1. // izraun povrine pravokutnika
2. #include <iostream.h>
3. class pravokutnik {
4. // Default dozvola pristupa je privat
5. int x, y;
6. public:
7. void zadaj_vrijednosti (int,int);
8. int povrsina (void) {return (x*y);}
9. };
10. void pravokutnik::zadaj_vrijednosti (int a, int b) {
11. x = a;
12. y = b; prvi= 12 17
13. } drugi= 30 19
14. int main () {
15. pravokutnik prvi, drugi;
16. prvi.zadaj_vrijednosti (3,4);
17. cout << "prvi= " << prvi.povrsina()<<endl;
18. drugi.zadaj_vrijednosti (5,6);
19. cout << "drugi= " << drugi.povrsina();
20. }

Treba uoiti da razred pravokutnik sadri dvije funkcije: zadaj-vrijednosti i povrsina.


Za prvu funkciju je unutar razreda navedena samo deklaracija (prototip) dok je sama
definicija funkcije navedena izvan razreda. Za drugu funkciju (povrsina) to nije sluaj,
ona je u cijelosti definirana unutar razreda.

Kada se funkcija definira izvan razreda mora se navesti :: kao uputstvo


prevoditelju da navedena funkcija (zadaj_vrijednosti) pripada navedenom razredu
(pravokutnik).

Da su se kojim sluajem u deklaraciji razreda pravokutnik varijable x i y nazvale a i b


prema svemu dosad reenom, dakle da se umjesto x i y u programu pie a i b ne bi trebalo
biti nikakvih problema.

Problem bi se pojavio u definiciji funkcije zadaj_vrijednosti. Tamo bi umjesto x=a; i


y=b; trebalo pisati a=a; i b=b; Prevoditelj ne bi mogao zakljuiti koji je a lijevi a koji
desni. U C++ postoji rjeenje i za takve probleme.
Svaki put kada se poziva funkcijski lan nekog razreda, automatski se proslijeuje i jedan
pokaziva koji sadri adresu objekta kojemu dotini funkcijski lan pripada. Taj
pokaziva nema svoj naziv ali ga se dibije pomou kljune rijei this.

Rjeenje problema naziva varijabli u prethodnom programu ilustrira koritenje


pokazivaa this.

165
Primjer10.3:
1. // izraun povrine pravokutnika pomou pokazivaa this
2. #include <iostream.h>
3. class pravokutnik {
4. int a, b;
5. public:
6. void zadaj_vrijednosti (int,int);
7. int povrsina (void) {return (a*b);}
8. };
9. void pravokutnik::zadaj_vrijednosti (int a, int b) {
10. this->a = a;
11. this->b = b;
12. }
13. int main () {
14. pravokutnik prvi, drugi;
15. prvi.zadaj_vrijednosti (3,4);
16. cout << "prvi= " << prvi.povrsina()<<endl;
17. drugi.zadaj_vrijednosti (5,6);
18. cout << "drugi= " << drugi.povrsina();
19. }

Dozvolu pristupa u deklaraciji razreda moe biti: private:, public: ili protected.

private: odreuje da su lanovi koji slijede dostupni samo od lanova unutar istog
razreda ili prijateljskog razreda o emu e biti govora kasnije. Slino svojstvo ima i
oznaka protected:
public: lanovi su dostupni svugdje gdje je vidljiv sam razred. Varijable koje
predstavljaju suelje razreda, tj. preko kojih se komunicira s razredom imaju dozvolu
pristupa public.

166
10.6 . Konstruktor i destruktor

Dinamika alokacija memorije koristi se i kod razreda, o emu e biti rijei neto kasnije.

Na primjeru razreda pravokutnik koristile su se dvije funkcije zadaj_vrijednosti i


povrsina. One su se u programu uvijek koristile tim redom.

int main () {
pravokutnik prvi, drugi; 1. 2.
prvi.zadaj_vrijednosti (3,4);
cout << "prvi= " << prvi.povrsina()<<endl;
drugi.zadaj_vrijednosti (5,6); 1.
cout << "drugi= " << drugi.povrsina(); 2.
}

Naime deklaracijom razreda se opisuje samo 'tip varijable', a objekt (odnosno instanca ili
engleski instance) se stvara konkretnom deklaracijom objekta, u konkretnom sluaju
naredbom:

pravokutnik prvi, drugi;

to bi se dogodilo da je funkcija povrsina pozvana bez da je prije toga pozvana


zadaj_vrijednosti ?
Rezultat je nepredvidljiv jer vrijednosti x i y nisu definirane.

Radi izbjegavanja ovakvih problema razredi mogu ukljuiti specijalne funkcije koje se
nazivaju konstruktor i destruktor.

Konstruktor se poziva svaki put kada se formira novi objekt, a destruktor kada se taj
objekte eli izbrisati. Konstruktor omoguava da se s razredima postupa po istoj logici
kao i s varijablama, kada se na primjer navodi:

int n= 22; ili char s = ''Hello'' ;

Podsjetimo se razreda nazvanog pravokutnik:

class pravokutnik {
int x, y;
public:
void zadaj_vrijednosti (int,int);
int povrsina (void) {return (x*y);}
};

Ako elimo u taj razred ukljuiti konstruktor on mora imati isto ime kao i razred i
koristi se za formiranje objekta, tj. za dodjeljivanje adrese u memoriji i davanja poetnih
vrijednosti varijablama. Jedan razred moe imati vie konstruktora.

167
Destruktor je funkcija koja poinje sa znakom ~ (tilda) i slijedi naziv razreda. Razred
moe imati samo jedan destruktor.
U nastavku je primjer konstruktora i destruktora za razred pravokutnik:

Primjer10.4:
1. // primjeri rada s razredima i konstruktorima
2. #include <iostream>
3. using namespace std;
4. class pravokutnik {
5. int x, y;
6. public:
7. pravokutnik(int, int); // ovo je konstruktor
8. ~pravokutnik (void); // ovo je destruktor
9. // slijede ostali podaci za razred
10. void zadaj_vrijednosti (int,int); // ona vienje neophodna
11. int povrsina (void) {return (x*y);}
12. } ;
13. // definicija konstruktora
14. pravokutnik::pravokutnik (int a, int b) {
15. x = a;
16. y = b;
17. }
18. // funkcija zadaj_vrijednost vie ne treba jer je to uinio konstruktor
19. // slijedi program
20. int main () {
21. pravokutnik prvi (3,4), drugi (5,6);
22. cout << "prvi= " << prvi.povrsina()<<endl;
23. cout << "drugi= " << drugi.povrsina()<<endl;
24. pravokutnik* treci;
25. treci = new pravokutnik (4,7);
26. cout <<"treci = " << treci->povrsina()<< endl;
27. cout <<&prvi <<" "<<&drugi<<" "<<treci;
28. }
prvi = 12 22
drugi = 30 23
treci = 28 26
0012FF5C 0012FF54 00913380 27

Objekti koji se koriste u programu mogu se smjestiti u stogu ili u hrpi. To ovisi o nainu
njihovog deklariranja.

168
Alokacija u stogu

pravokutnik prvi(3,4);
cout << "prvi= " << prvi.povrsina()<<endl;

Alokacija u hrpi

pravokutnik* treci;
treci=new pravokutnik(5,6);
cout << "treci = " << trecii->povrsina()<<endl;

Za pojedini se razred moe definirati vie konstruktora. S obzirom da im se svima naziv


mora poklapati s nazivom razreda, oni su prenapregnuti.

Koncept prenapregnutih funkcija i prenapregnutih operatora je bitan sastavni dio


koncepta objektno orijentiranog programiranja, pa e o tome biti rijei kasnije.

Slijedi primjer programa koji ilustrira navedene mogunosti:


Primjer 10.5:
1. class pravokutnik {
2. int x, y;
3. public:
4. // slijedi prvi konstruktor
5. pravokutnik () {x=1; y=1;}
6. // slijedi drugi konstruktor
7. pravokutnik (int n) { x =n; y =1;}
8. // slijedi trei konstruktor
9. pravokutnik (int n, int m) {x =n; y= m; }
10. // slijedi destruktor, ako i nije eksplicitno deklariran on se generira automatski
11. ~pravokutnik (void);
12. // definicija funkcije povrsina
13. int povrsina (void) {return (x*y);}
14. } ;
15. int main () {
16. pravokutnik* treci; prvi = 1
17. pravokutnik prvi, drugi (8); // smjesteni u stogu drugi = 8
18. treci = new pravokutnik (5,6;) // smjesten u hrpi trei = 30
19. cout << "prvi= " << prvi.povrsina()<<endl;
20. cout << "drugi= " << drugi.povrsina()<<endl;
21. cout << "trei= " << treci->povrsina()<<endl;
22. }

U programu su deklarirana tri objekta razreda pravokutnik. Ovisno o navedenim


parametrima poziva se odgovarajui konstruktor. Ako se za objekt u programu ne navedu

169
konstruktor i destruktor, oni se stvaraju i pozivaju automatski. Slijedei primjer ilustrira
nain pozivanja konstruktora i destruktora:

Primjer10.6:
1. // Ovaj primjer ilustrira automatsko pozivanje konstruktora destruktora
2. class pravokutnik {
3. int x, y;
4. public:
5. // slijedii konstruktor
6. pravokutnik () {cout<< Objekt je roen<<endl;}
7. // slijedi destruktor
8. ~pravokutnik (void) {cout << Unitih ga<<endl;}
9. // definicija funkcije povrsina koja se u ovom primjeru ne koristi
10. int povrsina (void) {return (x*y);}
11. };
12. int main () { Objekt je roen 13,6
13. {pravokutnik x; // automatski se poziva konstruktor Sada x ivi 14
14. cout<< Sada x ivi<<endl; Unitih ga 15,8
15. } // automatski poziva destruktor Sada sam izmeu 16
16. cout <<Sada sam izmeu<<endl; Objekt je roen 17,6
17. {pravokutnik y; // opet poziva konstruktor Sada y ivi 18
18. cout<< Sada y ivi<<endl; Unitih ga 19,8
19. } // automatski poziva destruktor
20. }

Zbog injenice da se destruktor poziva automatski, moglo bi se pogreno zakljuiti da ga


nikad nije potrebno posebno navoditi, meutim kada pojedina funkcija prekine s radom
zbog nepredviene greke, program ne dolazi do kraja bloka (vitiaste zagrade), pa
objekt moe ostati iv.

Postoje naredbe za prisilan izlaz iz programa, kako bi se sprijeio nekontrolirani izlazak.


To su naredbe exit i abort. One se razlikuju po tome to exit zatvara otvorene datoteke i
poziva destruktore a abort ne.

10.7. Konstruktor kopije

Kada u programu ima potrebe da se pojedini objekt preslika (kopira) u drugi istog
sadraja, ako je u pitanju obina varijabla to se postie operarorom pridruivanja (na
primjer x=y;). Za kopiranje sadraja razreda postoje vie mogunosti.

Kod kopiranja objekata (razreda) koriste se pojmovi plitke (shallow) i duboke (deep)
kopije.

Plitka je kopija ona kod koje se preslikavaju samo vrijednosti elemenata objekta. Na
primjer, pokazivai se kopiraju, ali se ne kopiraju dijelovi dinamiki alocirane memorije

170
na koju su ti pokazivai usmjereni, to u nekim sluajevima moe stvarati probleme.
Takva se kopija dobija upotrebom operatora pridruivanja kao i za obine varijable.

Za duboku kopiju neophodan je konstruktor kopije (copy constructor), ali nije dovoljan.
Potrebno je ukljuiti destruktor i prenapregnuti operator pridruivanja koji kopira
dinamiki alociranu memoriju.
Taj se konstruktor razlikuje od ostalih po tome to ima samo jedan parametar i to
referencu na konstantni objekt istog razreda.

// primjer konstruktora kopija


class Pok {
public:
...
Pok (const Pok& p); // kconstruktor kopije
...
// definicija pok konstruktora kopije
Pok::Pok (const Pok& p) { // parametar je referenca na konstantni objekt istog razreda
x = p.x;
y = p.y;
}
// slijedi program
int main (){
...
Pok p; // automatski poziv default konstruktora
Pok s = p; // automatski poziva copy constructor.
p = s; // obino pridruivanje, nema copy constructor-a

Ako preslika vrijednosti zadovoljava (tj. plitka kopija), ne preporua se upotreba


konstruktora kopije.

10.8 Nasljeivanje (inheritance)

Mehanizam nasljeivanja predstavlja vaan element koncepta OOP. Nasljeivanje je


nain da se iz postojeih razreda stvaraju novi.

Koncept nasljeivanja e se pojasniti na primjeru geometrijskih likova. Pretpostavimo da


treba napraviti program za crtanje geometrijskih likova u ravnini, na primjer, linije,
isjeke elipse, krugove, poligone i pravokutnike. Sa stajalita programiranja, svi ovi
likovi predstavljaju objekte. Oni imaju neka zajednika svojstva kao na primjer mogu
biti odreene boje, mogu se translatirati (micati po pravcu) za neki vektor ili rotirati oko
neke toke za eljeni kut. Svaki od navedenih objekata ima i neka specifina svojstva
koja upisuju upravo njega. Tako za liniju treba odrediti poetnu i zavrnu toku, za
isjeak elipse treba zadati njeno sredite, veliku i malu poluos te poetnui zavrni kut
isjeka. Poligon definiraju toke koje ine njegove vrhove.

171
Na slijedeoj je slici prikazano hijerarhijsko stablo grafikih elemenata.

Grafobjekt

Elipsin isjeak Linija Poligon

Krug Pravokutnik

Na vrhu stabla postoje neka zajednika svojstva svih elemenata a na niim razinama
postoje specifina svojstva.

Kako se ta hijerarhija prikazuje pomou alata jezika C++ ?

Na najvioj razini je zajedniki element boja i funkcije crtanja, translacije i rotacije.


Prema tome deklaracija razreda Grafobjekt bi mogla biti:

class Grafobjekt {
private:
int Boja;
public:
void Postaviboju (int nova) { Boja=nova;}
int Citajboju () {return Boja;}
void Crtaj();
void Translatiraj (int, int) {}
void Rotiraj (int, int, int) {}
};

Sada bi se mogao opisati razred Linija, na slijedei nain:

class Linija : public Grafobjekt {


.....
// ovdje se mogu navoditi specifini elementi
// kao koordinate poetne i zavrne toke linije
}

172
Ovom je deklaracijom reeno da e objekti razreda Linija sadravati sve elemente
(funkcijske i podatkovne ) razreda Grafobjekt. To je praktiki isti uinak kao da se je u
deklaraciji razreda Linija ukljuio sadraj osnovnog razreda Grafobjekt.

Iako je razred Linija naslijedio elemente iz razreda Grafobjekt, pa na taj nain ima pristup
svim njegovim elementima, on ima vlastito suelje. Pravo pristupa pojedinim
elementima koji se deklariraju u naslijeenom razredu se definira na isti nain kao i za
bilo koji drugi razred, dakle tako da se pojedinim elementima pridodaje atribut public,
protected ili private. Meutim pitanje je kakav je status naslijeenih elemenata ?

Njihov se status definira deklaracijom naslijeenog razreda tj. u deklaraciji


.
class Linija : public Grafobjekt {

atributom public se odreuje da e svi elementi osnovnog razreda imati isto pravo
pristupa u naslijeenom razredu. Dakle Boja ima pravo pristupa privat, a ostali su public.

Da je deklaracija razreda Linija bila

class Linija : protected Grafobjekt {

Onda bi svi elementi koji u osnovnom razredu imaju pravo pristupa public ili protected
(ovih u konkretnom sluaju nema), u naslijeenom razredu dobili pravo pristupa
protected. Dakle, Boja bi zadrala pravo pristupa privat a svi ostali elementi bi dobili
pravo pristupa protected.

Konano da je deklaracija bila :

class Linija : private Grafobjekt {

svi bi elementi razreda Grafobjekt u razredu Linija dobili pravo pristupa private.

Slijedi primjer koji ilustrira pravila naslijeivanja:

// primjer za ilustraciju nasljeivanja


class Osnovna {
public:
int i;
protected:
int j;
private:
int k;
};

class Izvedena:protected Osnovna {


public:

173
void Pristupi ();
};

void Izvedena::Pristupi {
i=8; // OK lan je preuzet kao protected
j=9; // OK lan je preuzet kao protected
k=10; // greka, lan je privatan
}

int main () {
Izvedena obj;
obj.i=7; // pogreka lan je protected
obj.j=6; // pogreka lan je protected
obj.k=5; // pogreka, lan je privat
return 0;
}

Iz primjera se vidi razlika izmeu prava pristupa protected i private. Izvedeni razredi
mogu pristupiti lanovima protected iz osnovnog razreda ali ne mogu pristupiti
lanovima private.

1o.9. Polimorfizam (polymorphism)

Polimorfizam je jo jedno vano svojstvo jezika koji podrava OOP. Svojstvo


polimorfizma omoguuje definiranje operacija koje ovise o tipu objekta.
Ilustrirat e se na primjeru grafikih objekat. U razredu Grafobjekt definirana je funkcija
Crtaj koja nita ne radi.

class Grafobjekt {
private:
int Boja;
public:
void Postaviboju (int nova) { Boja=nova;}
int Citajboju () { return Boja;}
void Crta j();
void Translatiraj (int, int) {}
void Rotiraj (int, int, int) {}
};

Naime, s obzirom da se na primjer postupak crtanja linije i kruga bitno razlikuju, nije
mogue opisati taj postupak na razini razreda Grafobjekt. Taj opis treba napraviti na

174
razini razreda Linija ili Krug, a program treba omoguiti da se funkcija Crtaj generira u
skladu s konkretnim sluajem.
To se ini pomou virtualnih funkcijskih lanova (virtual function members) .
Ilustracija upotrebe virtualnih lanova prikazana je u slijedeem primjeru:

class Grafobjekt {
private:
int Boja;
public:
void Postaviboju (int nova) { Boja=nova;}
int Citajboju () { return Boja;}
virtual void Crta j();
virtual void Translatiraj (int, int) {}
virtual void Rotiraj (int, int, int) {}
};

class Linija : public Grafobjekt {


private:
int x1, y1, x2, y2; // koordinate poetne i zavrne toke
public:
Linija (int lx1, int ly1, int lx2, int ly2) : x1 (lx1), y1 (ly1), x2 (lx2), y2 (ly2) {}
virtual void Crtaj();
virtual void Translatiraj (int vx, int vy);
virtual void Rotiraj(int cx, int cy, int kut);
};
Nakon toga slijedi na primjer definicija lana Crtaj (), koja izgleda :

void Linija:: Crtaj () {


.......
// ne navodi se virtual
}
Prevoditelj e sve virtualne lanove pohraniti u tablicu virtualnih lanova. Svaki objekt
koji pripada virtuelnom razredu sadri skriveni pokaziva vptr na virtualnu tablicu
vtable.
Poziv lana preko virtualne tablice zove se dinamiki poziv (dynamic call). Prilikom
dinamikog poziva funkcijskog lana, prevoditelj e generirati kod koji e pomou
pokazivaa vptr pronai tablicu virtualnih funkcija vtable, a u njoj adresu funkcije koju
treba pozvati. Na taj je nain odluka o tome koja se funkcija poziva odgoena za
trenutak izvoenja programa.
Za razliku od dinamikog poziva nevirtualni lanovi se pozivaju statiki.

Princip dinamikog pozivanja prikazan je na slici:

175
Objekt razreda Linija
vptr
Boja
x1 Konkretna funkcija
y1 Crtaj () Crtaj()
x2 Translatiraj ()
y2 Rotiraj ()

Objekt razreda Krug


vptr
Boja
x1
y1
r

Dinamiko pozivanje funkcija omoguava da se isti programski kod koristi za razliite


namjene to se naziva polimorfizmom.

11. Predloci (templates)

Predloci takoer predstavljaju jednu mogunost da se isti programski kod koristi u


razliitim situacijama. Predloci se dijele na predloke funkcija i predloke razreda.

Upoznat emo nekoliko primjera predloka funkcija:

Podsjetimo se funkcije swap koja je mijenjala sadraj dviju varijabli. Za sluaj da su


varijable bile cijeli brojevi, kod funkcije je:

void swap (int& m, int& n)


{ int temp=m;
m=n;
n= temp;
}

U sluaju da da mjesto trebaju zamijeniti dva objekta tipa string, kod funkcije je razliit:

void swap (string& s1, string& s2)


{ int temp=s1;
s1=s2;
s2= temp;
}

176
Postavlja se pitanje, kako se mogu oba sluaja rijeiti s istim kodom ?

Taj se problem moe rijeiti predlokom:

template <class T>


void swap (T& x,T& y)
{ int temp=x;
x=y;
y= temp;
}

Simbol T se naziva parametar tipa, on jednostavno pokazuje mjesto na kojem e se


zamijeniti s nekim konkretnim tipom (varijable) i razredom (objekta) kada se funkcija
bude pozivala.
Dakle, model funkcije se prikazuje na isti nain kao i sama funkcija uz dodatak naredbe:

template <class T>

gdje se parametar tipa T koristi umjesto uobiajenih tipova koji se navode u definiciji
funkcije.
Koritenje predloka funkcije ilustrirat e se i na primjeru predloka za bubble sort:

Primjer11.1:
1. // predloak funkcije sortiranja
2. #include <iostream>
3. using namespace std;
4. template <class T>
5. void sort(T* v, int n) {
6. for (int i= 1; i < n; i++)
7. for (int j = 0; j< n-i; j++)
8. if (v[j] > v[j+1]) swap (v[j], v[j+1]);
9. }
10. // predloak funkcije za pisanje
11. template <class T>
12. void print (T* v, int n){
13. for (int i = 0; i< n; i++)
14. cout<<" " << v[i]<<endl;
15. }
16. int main ()
17. { int a[9]= {55, 33, 88, 11, 44, 99, 77, 22, 66};
18. print (a, 9);
19. cout<<" Sada ide sort"<<endl;
20. sort (a,9);
21. print(a,9);
22. cout<<" Sada idu string varijable"<<endl;

177
23. string s[7]={"Ivo", "Ana", "Bob", "Tom", "Edi", "Sue", "Dan" };
24. print (s,7);
25. cout<<" Sada ide sort"<<endl;
26. sort (s,7);
27. print(s,7);
28. system("PAUSE");
29. return 0;
30. }

Izlaz iz programa je:

55 33 88 11 44 99 77 22 66 18
Sada ide sort 19
11 22 33 44 55 66 77 88 99 21
Sada idu string varijable 22
Ivo Ana Bob Tom Edi Sue Dan 24
Sada ide sort 25
Ana Bob Dan Edi Ivo Sue Tom 27
Press any key to continue . . .

Prevoditelj koristi predloke za generiranje konkretnih funkcija. U kokretnom sluaju


stvorene su po dvije verzije funkcije sort i funkcije print. Pojedina funkcija naziva se
instanca predloka , a sam postupak stvaranja pojedine funkcije instantacija.

Predloci razreda su u naelu istovjetni predlocima funkcija s time da umjesto


funkcija generiraju razrede.
Opi oblik predloka razreda je:

template<class T, ...> class X {....};

Prilikom instantacije predloka tj. kada ga se u programu poziva, navodi se tip varijabli s
kojima e se generirati razred. Za ilustraciju uzmimo primjer predloka za

template<class T>
class CCalculator
{
public:
CCalculator(const T &x, const T &y) : m_x(x), m_y(y){ } // konstruktor
~CCalculator(void){ } // destruktor

// slijedi definicija funkcija za osnovne raunske operacije


const T add(void){ return m_x + m_y; }
const T sub(void){ return m_x - m_y; }
const T mult(void){ return m_x * m_y; }
const T div(void){ return m_x / m_y; }
private:
const T m_x;

178
const T m_y;
};

Za instantaciju ovog predloka, treba mu definirati konkretan tip:

// Kreiranje kalkulatora za cijele brojeve


CCalculator<int> calc(5, 2);
// naveden je tip int i zadani su brojevi 5 i 2.
const int z = calc.mult();

179
Prilog A

ASCII znakovi

Hex Symbol ASCII Hex Symbol ASCII Hex Symbol ASCII Hex Symbol
ASCII
16 10 DLE 32 20 (space) 48 30 0
0 0 NUL
17 11 DC1 33 21 ! 49 31 1
1 1 SOH
18 12 DC2 34 22 " 50 32 2
2 2 STX
19 13 DC3 35 23 # 51 33 3
3 3 ETX
20 14 DC4 36 24 $ 52 34 4
4 4 EOT
21 15 NAK 37 25 % 53 35 5
5 5 ENQ
22 16 SYN 38 26 & 54 36 6
6 6 ACK
23 17 ETB 39 27 ' 55 37 7
7 7 BEL
24 18 CAN 40 28 ( 56 38 8
8 8 BS
25 19 EM 41 29 ) 57 39 9
9 9 TAB
26 1A SUB 42 2A * 58 3A :
10 A LF
27 1B ESC 43 2B + 59 3B ;
11 B VT
28 1C FS 44 2C , 60 3C <
12 C FF
29 1D GS 45 2D - 61 3D =
13 D CR
30 1E RS 46 2E . 62 3E >
14 E SO
31 1F US 47 2F / 63 3F ?
15 F SI

ASCII Hex Symbol ASCII Hex Symbol ASCII Hex Symbol ASCII Hex Symbol

64 40 @ 80 50 P 96 60 ` 112 70 p
65 41 A 81 51 Q 97 61 a 113 71 q
66 42 B 82 52 R 98 62 b 114 72 r
67 43 C 83 53 S 99 63 c 115 73 s
68 44 D 84 54 T 100 64 d 116 74 t
69 45 E 85 55 U 101 65 e 117 75 u
70 46 F 86 56 V 102 66 f 118 76 v
71 47 G 87 57 W 103 67 g 119 77 w
72 48 H 88 58 X 104 68 h 120 78 x
73 49 I 89 59 Y 105 69 i 121 79 y
74 4A J 90 5A Z 106 6A j 122 7A z
75 4B K 91 5B [ 107 6B k 123 7B {
76 4C L 92 5C \ 108 6C l 124 7C |
77 4D M 93 5D ] 109 6D m 125 7D }
78 4E N 94 5E ^ 110 6E n 126 7E ~
79 4F O 95 5F _ 111 6F o 127 7F 

180
Dodatak B:

Popis kljunih rijei u C++

asm insert an assembly instruction

auto declare a local variable

bool declare a boolean variable

break break out of a loop

case a block of code in a switch statement

catch handles exceptions from throw

char declare a character variable

class declare a class

const declare immutable data or functions that do not change data

const_cast cast from const variables

continue bypass iterations of a loop

default default handler in a case statement

delete make memory available

do looping construct

double declare a double precision floating-point variable

dynamic_cast perform runtime casts

else alternate case for an if statement

enum create enumeration types

explicit only use constructors when they exactly match

extern tell the compiler about variables defined elsewhere

false the boolean value of false

float declare a floating-point variable

181
for looping construct

friend grant non-member function access to private data

goto jump to a different part of the program

if execute code based off of the result of a test

inline optimize calls to short functions

int declare a integer variable

long declare a long integer variable

mutable override a const variable

namespace partition the global namespace by defining a scope

new allocate dynamic memory for a new variable

operator create overloaded operator functions

private declare private members of a class

protected declare protected members of a class

public declare public members of a class

register request that a variable be optimized for speed

reinterpret_cast change the type of a variable

return return from a function

short declare a short integer variable

signed modify variable type declarations

sizeof return the size of a variable or type

static create permanent storage for a variable

static_cast perform a nonpolymorphic cast

struct define a new structure

switch execute code based off of different possible values for a variable

182
template create generic functions

this a pointer to the current object

throw throws an exception

true the boolean value of true

try execute code that can throw an exception

typedef create a new type name from an existing type

typeid describes an object

typename declare a class or undefined type

a structure that assigns multiple variables to the same memory


union
location

unsigned declare an unsigned integer variable

using import complete or partial namespaces into the current scope

virtual create a function that can be overridden by a derived class

void declare functions or data with no associated data type

warn the compiler about variables that can be modified


volatile
unexpectedly

wchar_t declare a wide-character variable

while looping construct

183

You might also like