You are on page 1of 104

1

0. To C++ or not to C++?


Vie nego bilo kada u povijesti, ovjeanstvo
se nalazi na razmei. Jedan put vodi u oaj i
krajnje beznae, a drugi u potpuno
istrebljenje. Pomolimo se da emo imati
mudrosti izabrati ispravno.
Woody Allen, Popratne pojave (1980)

Prilikom pisanja ove knjige mnogi su nas, s podsmijehom kao da gledaju posljednji
primjerak snjenog leoparda, pitali: No zato se bavite C++ jezikom? To je
kompliciran jezik, spor, nedovoljno efikasan za primjenu u komercijalnim programima.
Na kraju, ja to sve mogu napraviti u obinom C-u. Prije nego to ponemo objanjavati
pojedine znaajke jezika, nalazimo vanim pokuati dati koliko-toliko suvisle odgovore
na ta i slina pitanja.
Osnovno pitanje je to C++ ini boljim i pogodnijim openamjenskim jezikom za
pisanje programa, od operacijskih sustava do baza podataka. Da bismo to razumjeli,
pogledajmo kojim putem je tekao povijesni razvoj jezika. Na taj nain e moda biti
jasnija motivacija Bjarne Stroustrupa, oca i majke jezika C++. Dakle, krenimo od
stoljea sedmog.

0.1. Povijesni pregled razvoja programskih jezika


Prva raunala koja su se pojavila bila su vrlo sloena za koritenje. Njih su koristili
iskljuivo strunjaci koji su bili osposobljeni za komunikaciju s raunalom. Ta
komunikacija se sastojala od dva osnovna koraka: davanje uputa raunalu i itanje
rezultata obrade. I dok se itanje rezultata vrlo brzo uinilo koliko-toliko snoljivim
uvoenjem pisaa na kojima su se rezultati ispisivali, unoenje uputa programiranje
se sastojalo od mukotrpnog unosa niza nula i jedinica. Ti nizovi su davali raunalu upute
kao to su: zbroji dva broja, premjesti podatak s neke memorijske lokacije na drugu,
skoi na neku instrukciju izvan normalnog slijeda instrukcija i slino. Kako je takve
programe bilo vrlo sloeno pisati, a jo sloenije itati i ispravljati, ubrzo su se pojavili
prvi programerski alati nazvani asembleri (engl. assemblers).
U asemblerskom jeziku svaka strojna instrukcija predstavljena je mnemonikom koji
je razumljiv ljudima koji itaju program. Tako se zbrajanje najee obavlja
mnemonikom ADD, dok se premjetanje podataka obavlja mnemonikom MOV. Time se
postigla bolja itljivost programa, no i dalje je bilo vrlo sloeno pisati programe i
ispravljati ih jer je bilo potrebno davati sve, pa i najmanje upute raunalu za svaku
pojedinu operaciju. Javlja se problem koji e kasnije, nakon niza godina, dovesti i do
1

0. To C++ or not to C++?

pojave C++ programskog jezika: potrebno je razviti programerski alat koji e osloboditi
programera rutinskih poslova te mu dopustiti da se usredotoi na problem koji rjeava.
Zbog toga se pojavljuje niz viih programska jezika, koji preuzimaju na sebe neke
dosadne programerske poslove. Tako je FORTRAN bio posebno pogodan za
matematike proraune, zatim BASIC koji se vrlo brzo uio, te COBOL koji je bio u
pravilu namijenjen upravljanju bazama podataka.
Oko 1972. se pojavljuje jezik C, koji je direktna pretea dananjeg jezika C++. To
je bio prvi jezik ope namjene te je postigao nevien uspjeh. Vie je razloga tome: jezik
je bio jednostavan za uenje, omoguavao je modularno pisanje programa, sadravao je
samo naredbe koje se mogu jednostavno prevesti u strojni jezik, davao je brzi kd. Jezik
nije bio optereen mnogim sloenim funkcijama, kao na primjer skupljanje smea (engl.
garbage collection): ako je takav podsustav nekome trebao, korisnik ga je sam napisao.
Jezik je omoguavao vrlo dobru kontrolu strojnih resursa te je na taj nain omoguio
programerima da optimiziraju svoj kd. Do unatrag nekoliko godina, 99% komercijalnih
programa bili su pisani u C-u, ponegdje dopunjeni odsjecima u strojnom jeziku kako bi
se kritini dijelovi sustava uinili dovoljno brzima.
No kako je razvoj programske podrke napredovao, stvari su se i na podruju
programskih jezika poele mijenjati. Sloeni projekti od nekoliko stotina tisua, pa i vie
redaka vie nisu rijetkost, pa je zbog toga bilo potrebno uvesti dodatne mehanizme
kojima bi se takvi programi uinili jednostavnijima za izradu i odravanje, te kojima bi
se omoguilo da se jednom napisani kd iskoristi u vie razliitih projekata.
Bjarne Stroustrup (roen u Danskoj) je 1979. godine zapoeo rad na jeziku C s
razredima (engl. C with Classes). Prije toga, on je radio na svom doktoratu u
Computing Laboratory of Cambridge te istraivao distribuirane sustave: granu
raunalne znanosti u kojoj se prouavaju modeli obrade podataka na vie jedinica
istodobno. Pri tome koristio se jezikom Simula, koji posjedovao neka vana svojstva
koja su ga inila prikladnim za taj posao. Na primjer, Simula je posjedovala pojam
razreda: strukture podataka koje objedinjavaju podatke i operacije nad podacima.
Koritenje razreda omoguilo je da se koncepti problema koji se rjeava izraze direktno
pomou jezinih konstrukcija. Dobiveni kd je bio vrlo itljiv i razumljiv, a g.
Stroustrup je bio posebno fasciniran nainom na koji je sam programski jezik upuivao
programera u razmiljanju o problemu. Takoer, jezik je posjedovao sustav tipizacije,
koji je esto pomagao korisniku u pronalaenju pogreaka ve prilikom prevoenja.
Naoko idealan u teoriji, jezik Simula je posrnuo u praksi: prevoenje je bilo
iznimno dugotrajno, a kd se izvodio izuzetno sporo. Dobiveni program je bio
neupotrebljiv i, da bi ipak poteno zaradio svoj doktorat, gospodin Stroustrup se morao
potruditi i ponovo napisati cjelokupni program u jeziku BCPL jeziku niske razine koji
je omoguio vrlo dobre performanse prevedenog programa. No iskustvo pisanja
sloenog programa u takvom jeziku je bilo uasno i g. Stroustrup je, po zavretku svog
posla na Cambridgeu, vrsto sebi obeao da vie nikada nee takav sloen problem
pokuati rijeiti neadekvatnim alatima poput BCPL-a ili Simule.
Kada se 1979. zaposlio u Bell Labs (kasnije AT&T) u Murray Hillu, zapoeo je rad
na onome to e kasnije postati C++. Pri tome je iskoristio svoje iskustvo steeno

0.2. Osnovna svojstva jezika C++

prilikom rada na doktoratu te pokuao stvoriti univerzalni jezik koji e udovoljiti


dananjim zahtjevima. Pri tome je uzeo dobra svojstva niza jezika: Simula, Clu, Algol68
i Ada, a kao osnovu je uzeo jezik C.

0.2. Osnovna svojstva jezika C++


etiri su vana svojstva jezika C++ koja ga ine objektno orijentiranim:
1. enkapsulacija (engl. encapsulation),
2. skrivanje podataka (engl. data hiding),
3. nasljeivanje (engl. inheritance) i
4. polimorfizam (engl. polymorphism).
Sva ta svojstva doprinose ostvarenju takozvane objektno orijentirane paradigme
programiranja.
Da bismo to bolje razumjeli, pogledajmo koji su se programski modeli koristili u
prolosti. Pri tome je svakako najvaniji model proceduralno strukturiranog
programiranja.
Proceduralno programiranje zasniva se na promatranju programa kao niza
jednostavnih programskih odsjeaka: procedura. Svaka procedura je konstruirana tako
da obavlja jedan manji zadatak, a cijeli se program sastoji od niza procedura koje
sudjeluju u rjeavanju zadatka.
Kako bi koristi od ovakve podjele programa bile to izraenije, smatralo se dobrom
programerskom taktikom odvojiti proceduru od podataka koje ona obrauje: time je bilo
mogue pozvati proceduru za razliite ulazne podatke i na taj nain iskoristiti je na vie
mjesta. Strukturirano programiranje je samo dodatak na proceduralni model: ono
definira niz osnovnih jezinih konstrukcija, kao to su petlje, grananja i pozivi
procedura, koje unose red u programe i ine samo programiranje daleko jednostavnijim.
Princip kojim bismo mogli obiljeiti proceduralno strukturirani model jest podijelipa-vladaj: cjelokupni program je presloen da bi ga se moglo razumjeti pa se zbog toga
on rastavlja na niz manjih zadataka procedura koje su dovoljno jednostavne da bi se
mogle izraziti pomou naredbi programskog jezika. Pri tome, pojedina procedura
takoer ne mora biti rijeena monolitno: ona moe svoj posao obaviti kombinirajui rad
niza drugih procedura.
Ilustrirat emo to primjerom: zamislimo da elimo izraditi kompleksan program za
obradu trodimenzionalnih objekata. Kao jednu od mogunosti koje moramo ponuditi
korisnicima jest rotacija objekata oko neke toke u prostoru. Koristei proceduralno
programiranje, taj zadatak bi se mogao rijeiti ovako:
1. Listaj sve objekte redom.
2. Za pojedini objekt odredi njegov tip.
3. Ovisno o tipu, pozovi ispravnu proceduru koja e izraunati novu poziciju objekta.
4. U skladu s tipom podataka auriraj koordinate objekta.
Operacije odreivanja tipa, izraunavanje nove pozicije objekta i auriranje koordinata
mogu se dalje predstaviti pomou procedura koje sadravaju niz jednostavnijih akcija.

0. To C++ or not to C++?

Ovakav programski pristup je bio vrlo uspjean do kasnih osamdesetih, kada su


njegovi nedostaci postajali sve oitiji. Naime, odvajanje podataka i procedura ini
programski kd teim za itanje i razumijevanje. Prirodnije je o podacima razmiljati
preko operacija koje moemo obaviti nad njima u gornjem primjeru to znai da o
kocki ne razmiljamo pomou koordinata njenih kutova ve pomou moguih operacija,
kao to je rotacija kocke.
Nadalje, pokazalo se sloenim istodobno razmiljati o problemu i odmah
strukturirati rjeenje. Umjesto rjeavanja problema, programeri su mnogo vremena
provodili pronalazei naine da programe usklade sa zadanom strukturom.
Takoer, dananji programi se pokreu pomou mia, prozora, izbornika i dijaloga.
Programiranje je pogonjeno dogaajima (engl. event-driven) za razliku od starog,
sekvencijalnog naina. Proceduralni programi su korisniku, u trenutku kada je bila
potrebna interakcija korisnika (na primjer zahtjev za ispis na pisau) prikazivali ekran
nudei mu opcije; ovisno o odabranoj opciji, izvoenje kda se usmjeravalo na odreeni
programski odsjeak. Pogonjeno dogaajima znai da se program ne odvija po
unaprijed odreenom slijedu, ve se programom upravlja pomou niza dogaaja.
Dogaaja ima raznih: pomicanje mia, pritisak na tipku, izbor stavke iz izbornika i
slino. Sada su sve opcije dostupne istodobno, a program postaje interaktivan, to znai
da promptno odgovara na korisnikove zahtjeve i odmah (ovo ipak treba uvjetno shvatiti)
prikazuje rezultat svoje akcije na zaslonu raunala.
Kako bi se takvi zahtjevi jednostavnije proveli u praksi, razvijen je objektni pristup
programiranju. Osnovna ideja je razbiti program u niz zatvorenih cjelina koje zatim
meusobno surauju u rjeavanju problema. Umjesto specijaliziranih procedura koje
barataju podacima, radimo s objektima koji objedinjavaju operacije i podatke. Pri tome
je vano to objekt radi, a ne kako on to radi. To omoguava da se pojedini objekt moe
po potrebi izbaciti i zamijeniti drugim, boljim, ako oba rade istu stvar.
Klju za postizanje takvog cilja jest spajanje podataka i operacija, poznato pod
nazivom enkapsulacija (engl. encapsulation). Pritom su podaci privatni za svaki objekt
te ne smiju biti dostupni ostalim dijelovima programa. To svojstvo se naziva skrivanje
podataka (engl. data hiding). Svaki objekt svojoj okolini prua iskljuivo podatke koji
su joj neophodni da bi se objekt mogao iskoristiti. Ti podaci zajedno s operacijama koje
ih prihvaaju ili vraaju ine suelje objekta. Programer koji e koristiti taj objekt vie
se ne mora zamarati razmiljajui o nainu na koji objekt funkcionira on jednostavno
trai od objekta odreenu uslugu.
Kada PC preprodava, vlasnik poduzea Taiwan/tavan-Commerce sklapa
raunalo, on zasigurno treba kuite (iako se i to ponekad pokazuje nepotrebnim). To ne
znai da e on morati poeti od nule (miksajui atome eljeza u aici od Kinderlade);
on e jednostavno otii kod susjednog dilera i kupiti gotovo kuite koje ima prikljuak
na mreni napon, ATX napajanje, ladice za montau diskova te otvor za disketu. Tako je
i u programiranju: mogue je kupiti gotove programske komponente koje se zatim mogu
iskoristiti u programu. Nije potrebno razumjeti kako komponenta radi dovoljno je
poznavati njeno suelje da bi ju se moglo iskoristiti.

0.3. Usporedba s C-om

Takoer, kada projektanti u Renaultu ele izraditi novi model automobila, imaju
dva izbora: ili mogu poeti od nule i ponovo proraunavati svaki najmanji dio motora,
asije i ostalih dijelova, ili mogu jednostavno novi model bazirati na nekom starom
modelu. Kako je kompaniji vrlo vjerojatno u cilju to bre razviti novi model kako bi
pretekla konkurenciju, gotovo sigurno e jednostavno uzeti uspjean model automobila i
samo izmijeniti neka njegova svojstva: promijenit e mu liniju, pojaati motor, dodati
ABS konice. Slino je i s programskim komponentama: prilikom rjeavanja nekog
problema moemo uzdahnuti i poeti kopati, ili moemo uzeti neku ve gotovu
komponentu koja je blizu rjeenja i samo dodati nove mogunosti. To se zove ponovna
iskoristivost (engl. reusability) i vrlo je vano svojstvo. Za novu programsku
komponentu kae se da je naslijedila (engl. inherit) svojstva komponente iz koje je
izgraena.
Korisnik koji kupuje auto sigurno nee biti presretan ako se njegov novi model
razlikuje od starog po nainu koritenja (primjerice da se umjesto pritiskom na papuicu
gasa auto ubrzava povlaenjem ruice na krovu vozila ili sputanjem suvozaevog
sjedala): on jednostavno eli pritisnuti gas, a stvar je nove verzije automobila primjerice
krae vrijeme ubrzanja od 0 do 100 km/h. Slino je i s programskim komponentama:
korisnik se ne treba optereivati time koju verziju komponente koristi on e
jednostavno traiti od komponente uslugu, a na njoj je da to obavi na adekvatan nain.
To se zove polimorfizam (engl. polimorphism).
Gore navedena svojstva zajedno sainjavaju objektno orijentirani model
programiranja. Evo kako bi se postupak rotiranja trodimenzionalnih likova proveo
koristei objekte:
1. Listaj sve objekte redom.
2. Zatrai od svakog objekta da se zarotira za neki kut.
Sada glavni program vie ne mora voditi rauna o tome koji se objekt rotira on
jednostavno samo zatrai od objekta da se zarotira. Sam objekt zna to uiniti ovisno o
tome koji lik on predstavlja: kocka e se zarotirati na jedan nain, a kubini spline na
drugi. Takoer, ako se bilo kada kasnije program proiri novim tijelima, nije potrebno
mijenjani program koji rotira sve objekte samo je za novi objekt potrebno definirati
operaciju rotacije.
Dakle, ono to C++ jezik ini vrlo pogodnim jezikom ope namjene za izradu
sloenih programa jest mogunost jednostavnog uvoenja novih tipova te naknadnog
dodavanja novih operacija.

0.3. Usporedba s C-om


Mnogi okorjeli C programeri, koji sanjaju strukture i dok se voze u tramvaju ili
razmiljaju o tome kako e svoju novu rutinu rijeiti pomou pokazivaa na funkcije,
dvoume se oko toga je li C++ doista dostojan njihovog kda: mnogi su u strahu od
nepoznatog jezika te se boje da e im njihov supermunjeviti program za zbrajanje dvaju
jednoznamenkastih brojeva na novom jeziku biti sporiji od programa za raunanje
fraktalnog skupa. Drugi se, pak, kunu da je C++ odgovor na sva njihova ivotna pitanja,

0. To C++ or not to C++?

te u fanatinom zanosu umjesto Kristovog roenja slave roendan gospodina


Stroustrupa.
Moramo odmah razoarati obje frakcije: niti jedna nije u pravu te je njihovo
miljenje rezultat nerazumijevanja nove tehnologije. Kao i sve drugo, objektna
tehnologija ima svoje prednosti i mane, a takoer nije svemogua te ne moe rijeiti sve
probleme (na primjer, ona vam nee pomoi da opljakate banku i umaknete Interpolu).
Kao prvo, C++ programi nisu nuno sporiji od svojih C ekvivalenata. U vrijeme
adolescencije jezika C++ to je bio est sluaj kao posljedica neefikasnih prevoditelja
zbog toga se uvrijeilo miljenje kako programi pisani u jeziku C++ daju sporiji
izvedbeni kd. Meutim, kako je rastao broj prevoditelja na tritu (a time i meusobna
konkurencija), kvaliteta izvedbenog kda koju su oni generirali se poboljavala. No u
pojedinim sluajevima izvedbeni kd dobiven iz C++ izvornog kda doista moe biti
sporiji, a na programeru je da shvati kada je to dodatno usporenje prevelika smetnja da
bi se toleriralo.
Nadalje, koncept razreda i enkapsulacija uope ne usporavaju dobiveni izvedbeni
program. Dobiveni strojni kd bi u mnogim sluajevima trebao biti potpuno istovjetan
onome koji e se dobiti iz analognog C programa. Funkcijski lanovi pristupaju
podatkovnim lanovima objekata preko pokazivaa, na slian nain na koji to korisnici
proceduralne paradigme ine runo. No C++ kd e biti itljiviji i jasniji te e ga biti
lake napisati i razumjeti. Ako pojedini prevoditelj i daje loiji izvedbeni kd, to je
posljedica loeg prevoditelja, a ne mana jezika.
Takoer, koritenje nasljeivanja ne usporava dobiveni kd ako se ne koriste
virtualni funkcijski lanovi i virtualni osnovni razredi. Nasljeivanje samo uteuje
programeru viestruko pisanje kda te olakava ponovno koritenje ve napisanih
programskih odsjeaka.
Virtualne funkcije i virtualni osnovni razredi, naprotiv, mogu unijeti znaajno
usporenje u program. Koritenje virtualnih funkcija se obavlja tako da se prije poziva
konzultira posebna tablica, pa je jasno da e poziv svake takve funkcije biti sporiji.
Takoer, pristup lanovima virtualnih osnovnih razreda se redovito obavlja preko
jednog pokazivaa vie. Na programeru je da odredi hoe li koristiti inkriminirana
svojstva jezika ili ne. Da bi se precizno ustanovilo kako djeluje pojedino svojstvo jezika
na izvedbeni kd, nije dobro nagaati i kriviti C++ za loe performanse, ve izmjeriti
vrijeme izvoenja te locirati problem.
No razmislimo o jo jednom problemu: asembler je jedini jezik u kojemu programer
tono zna to se deava u pojedinom trenutku prilikom izvoenja programa. Kako je
programiranje u asembleru bilo sloeno, razvijeni su vii programski jezici koji to
olakavaju. Prevedeni C kd takoer nije maksimalno brz posebno optimiran
asemblerski kd e sigurno dati bolje rezultate. No pisanje takvog kda danas
jednostavno nije mogue: problemi koji se rjeavaju su ipak previe sloeni da bi se
mogli rjeavati tako da se pazi na svaki ciklus procesora. Sloeni problemi zahtijevaju
nove pristupe njihovom rjeavanju: zbog toga imamo na raspolaganju nova raunala s
veim mogunostima koja su sposobna uiniti gubitak performansi beznaajnim u
odnosu na dobitak u brzini razvoja programa.

0.4. Usporedba s Javom

Slino je i s objektnom tehnologijom: moda e i dobiveni kd biti sporiji i vei od


ekvivalentnog C kda, no jednostavnost njegove izrade e sigurno omoguiti da
dobiveni program bude bolji po nizu drugih karakteristika: bit e jednostavnije izraditi
program koji e biti laki za koritenje, s vie mogunosti i slino. Uostalom, manje
posla vea zarada! (Raj zemaljski!) Tehnologija ide naprijed: dok se gubi neznatno na
brzini i memorijskim zahtjevima, dobici su viestruki.
Takoer, C++ nije svemoan. Koritenje objekata nee napisati pola programa
umjesto vas: ako elite provesti crtanje objekata u tri dimenzije i pri tome ih realistino
osjenati, namuit ete se poteno koristite li C ili C++. To niti ne znai da e
poznavanje objektne tehnologije jamiti da ete ju i ispravno primijeniti: ako se ne
potrudite prilikom izrade razreda te posao ne obavite u duhu objektnog programiranja,
nee biti nita od ponovne iskoristivosti kda. ak i ako posao obavite ispravno, to ne
znai da jednog dana neete naii na problem u kojem e jednostavno biti lake
zaboraviti sve napisano i poeti od jajeta.
Ono to vam objektna tehnologija prua jest mogunost da manje panje obratite
jeziku i nainu na koji ete svoju misao izraziti, a usredotoite se na ono to zapravo
elite uiniti. U gornjem sluaju trodimenzionalnog crtanja objekata to znai da ete
manje vremena provesti razmiljajui gdje ste pohranili podatak o poloaju kamere koji
vam ba sad treba, a vie ete razmiljati o tome kako da ubrzate postupak sjenanja ili
kako da ga uinite realistinijim.
Objektna tehnologija je pokuala dati odgovore na neke potrebe ljudi koji rjeavaju
svoje zadatke raunalom; na vama je da procijenite koliko je to uspjeno, a u svakom
sluaju da prije toga proitate ovu knjigu do kraja i preporuite ju prijateljima, naravno.
Jer tak dobru i guba knjigu niste vidli ve sto godina i ba vam je bilo fora ju itat.

0.4. Usporedba s Javom


Nakon to je izalo prvo izdanje knjige, jedan od eih komentara je bio: A zato
(radije) niste napisali knjigu o Javi?. Odgovor je vrlo jednostavan: da smo onda
napisali knjigu o Javi, ta knjiga bi ve nakon godinu dana bila zastarjela! Kada smo
krajem 1995. godine poeli pisati knjigu, Java je bila tek u povojima (u svibnju te
godine objavljena je prva alfa verzija Jave). Danas (listopad 2000.) je to ve prilino
zrela tehnologija koja je prola niz izmjena, a realno je oekivati jo takvih promjena do
njena potpunog sazrijevanja. Upravo zbog toga je (barem za sada) nezahvalno raditi
iskljuive usporedbe tipa ovo je puno bolje napravljeno u jeziku A nego u jeziku B.
Pokuajmo stoga samo naznaiti koje su znaajnije razlike izmeu Jave i jezika C++;
konane zakljuke preputamo itatelju.
0.4.1. Java je potpuno objektno orijentirani programski jezik
To znai da se sve operacije odvijaju iskljuivo kroz objekte, odnosno preko njihovih
funkcijskih lanova (metoda). Stoga je programer od poetka prisiljen razmiljati na
objektno orijentirani nain. S druge strane, jezik C++ omoguava pisanje i

0. To C++ or not to C++?

proceduralnog kda. Iako se nekome moe uiniti kao prednost, ovo je zamka u koju
vrlo lako mogu upasti poetnici, posebice ako prelaze sa nekog proceduralnog
programskog jezika, kao to je jezik C. Naime, ako usvoji proceduralni nain
razmiljanja, programer e se teko prealtati na objektni pristup i iskoristiti sve
njegove pogodnosti. Ovo je danak to ga jezik C++ plaa zbog insistiranja na
kompatibilnosti s jezikom C. Stvaratelji jezika C++ (ukljuujui i gospodina
Stroustrupa) nisu eljeli izmisliti potpuno novi jezik koji bi iziskivao da se sve aplikacije
prepiu u tom novom jeziku, ve su nastojali da postojei izvorni kdovi mnotva
aplikacija pisanih u jeziku C (ne zaboravimo da je jezik C osamdesetih godina bio
najrasprostranjeniji programski jezik) budu potpuno zdruivi s novim jezikom i da se ti
kdovi bez potekoa mogu prevesti na prevoditeljima za jezik C++. Ovakav pristup
podrazumijevao je mnotvo kompromisa, ali je omoguio tisuama programera i
programskih kua postepeni i bezbolan prijelaz s jezika C na jezik C++. To je znaajno
doprinijelo popularnosti i opem prihvaanju jezika C++.
S druge strane, Java je potpuno novi programski jezik, neoptereen takvim
nasljeem zbog toga su neke stvari rijeene daleko elegantnije nego u jeziku C++.
Uostalom, Javu je stvorila grupa C++ programera koji su bili frustrirani nedostacima
jezika C++.
0.4.2. Java kd se izvodi na virtualnom stroju
Java izvorni kd se ne prevodi u strojni kd matinog procesora (matini kd, engl.
native code) nego u poseban, tzv. Java binarni kd (engl. Java bytecode) kojeg Java
virtualni stroj (engl. Java Virtual Machine, JVM) interpretira i izvodi. Prednost ovakvog
pristupa jest da e prevedeni Java kd biti izvodljiv na bilo kojem raunalu s bilo kojim
procesorom i operacijskim sustavom. Naravno, pod uvjetom da na tom stroju postoji i
vrti se (odgovarajui) virtualni stroj. No, takav kd nee biti optimiziran za dotini
procesor. Na primjer, velika veina dananjih procesora ima ugraene instrukcije za
operacije s realnim brojevima koje omoguavaju da se dijeljenje dva realna broja izvede
u svega nekoliko taktova procesora. Budui da se Java binarni kd mora izvoditi i na
raunalima s procesorima koja nemaju ugraene instrukcije za realne brojeve, izvoenje
takvih operacija bit e openito sporije.
Zbog toga, kao i zbog injenice da se Java binarni kd interpretira, a ne izvodi
izravno, Java programi su i do desetak puta sporiji od ekvivalentnih programa
prevedenih iz nekog drugog jezika. Dodue, Java virtualni strojevi pruaju mogunost
Prevoenja upravo na vrijeme (engl. Just-In-Time compilation), kojim se Java binarni
kd prevodi u matini izvedbeni kd i kao takav izvodi; brzina izvoenja takvog kda je
usporediva s brzinom matinog izvedbenog kda. Meutim, taj kd treba prvo prevesti,
to znai da se dio vremena namijenjenog izvoenju programa troi na prevoenje iz
Java binarnog u matini izvedbeni kd. Za programe u kojima se vei dio kda izvodi
samo jednom to e predstavljati znaajni gubitak vremena, odnosno usporenje
programa.

0.4. Usporedba s Javom

0.4.3. Java nema pokazivaa


Davno su prola vremena kada su se na sm spomen rijei pokaziva zatvarali prozori
i zakljuavala vrata, a djecu tjeralo na spavanje (i kada se osoba koja je javno izjavila da
je napravila funkciju koja vraa pokaziva na neki objekt smatrala genijalnim
ekscentrikom koji i usred ljeta nosi vunenu kapu i duge gae). Meutim, jo i danas su
pokazivai baba-roga kojom se plae programeri-utokljunci. Stoga e takvi
aklamacijom prihvatiti istrijebljenje pokazivaa.
Dodue, zavirimo li pod haubu vidjet emo da se u Javi objekti uglavnom
dohvaaju preko pokazivaa i referenci ono to je dobro jest da nema pretvorbi
izmeu pokazivaa i objekata koje omoguavaju raznorazne (obino nenamjerne)
hakeraje i obino zavravaju blokiranjem programa. Iako su pokazivai jedan od
najeih uzroka pogreaka u programima, mnogi iskusniji programeri znaju koliko je
neke stvari tee napraviti bez pokazivaa na funkcije ili funkcijske lanove.
0.4.4. Java nema predloaka niti viestrukog nasljeivanja.
Predloci omoguavaju da se isti kd moe koristiti za razliite tipove podataka, bez
potrebe da se taj kd ponovno pie za nove tipove ili da se metodom kopiraj-i-umetni
preslikava na razliita mjesta i naknadno dorauje.
Nasljeivanje omoguava kreiranje korisniki definiranih tipova podataka koristei
i proirujui osobine ve postojeih tipova. esto je poeljno naslijediti osobine
razliitih tipova tada se u jeziku C++ primjenjuje viestruko nasljeivanje. U Javi
nema viestrukog nasljeivanja implementacije, ali nudi se viestruko nasljeivanje
suelja korisniki definiranih podataka prema korisniku. To zahtijeva drugaiji stil
programiranja koji je orijentiran prema sueljima objekata.
0.4.5. Java ima ugraeno automatsko sakupljanje smea.
U jeziku C++ programer mora eksplicitno navesti u kdu da eli osloboditi memoriju
koju je prethodno zauzeo za neki objekt. Propusti li to napraviti, tijekom izvoenja
programa memorija e se troiti, smanjujui raspoloivu memoriju za ostatak
programa ili za ostale programe. Napravi li pak to prerano u kdu, unitit e objekt koji
bi eventualno mogao kasnije zatrebati. Curenje memorije ili prerano unitenje objekata
je vrlo esti uzrok blokiranja rada programa ili cijelog raunala. Dobar C++
programer mora imati pod kontrolom gdje je rezervirao prostor za neki objekt i gdje e
taj prostor osloboditi.
U Javi se sam sustav brine da oslobodi memoriju koja vie nije potrebna
mehanizam za sakupljanje smea (engl. garbage collection) ugraen je u sustav i
automatski se pokree po potrebi. Naravno da za sve one koji su iskusili gore opisane
probleme u jeziku C++ ovo predstavlja pravi melem. Dodue, za jezik C++ postoje
komercijalne i besplatne biblioteke koje ugrauju mehanizme za skupljanje smea u
kd, meutim injenica je da ono nije ugraeno u sam sustav.

10

0. To C++ or not to C++?

S druge strane, mnogi programeri imaju zamjerku na automatsko sakupljanje smea


jer sustav sam procjenjuje kada treba to sakupljanje zapoeti i nerijetko se dogaa da to
bude upravo u trenutku kada va program obavlja neku zahtjevnu operaciju te e
sakupljanje smea usporiti izvoenje programa. Zato i kod ugraenog automatskog
sustava za sakupljanje smea treba esto paziti da se novi objekti u memoriji ne stvaraju
neracionalno i bez ozbiljnije potrebe.
0.4.6. Java podrava vienitnost
Vienitnost (engl. multithreading) omoguava pisanje programa koji izvode dvije ili vie
operacija istovremeno. Primjerice, moete napisati sportsku simulaciju u kojoj va
automobil vozite trkaom stazom, a istovremeno se u gornjem kutu ekrana odbrojava
vrijeme svaku od ove dvije radnje stavit ete u vlastitu nit. Procesor e, ovisno o
prioritetu pojedinih niti, naizmjence odreeni dio vremena posvetiti izvoenju
instrukcija u svakoj od niti.
U Javu je vienitnost podrana od poetka, ukljuujui i sve detalje, kao to su
meusobna sinkronizacija niti te zakljuavanje kritinih podataka i metoda. U jeziku
C++ vienitnost nije ugraena, ve morate imati odgovarajuu biblioteku koja sadri
podrku.
0.4.7. Java ne podrava preoptereenje operatora
Preoptereenje operatora omoguava da se funkcija operatora moe proiriti i za
korisniki definirane podatke. Primjerice, operator zbrajanja + definiran je za ugraene
tipove podataka kao to su cijeli ili realni brojevi i znakovni nizovi. No, ako uvedemo
kompleksne brojeve kao svoj novi tip podataka, realno je za oekivati da emo poeljeti
zbrajanje kompleksnih brojeva izvoditi pomou operatora +. Bez mehanizma
preoptereenja operatora to nije mogue, ve smo prisiljeni koristiti neitljiviju sintaksu
preko poziva funkcijskog lana.
0.4.8. U Javi su operacije s decimalnim brojevima loije podrane
Izvorno je Java bila koncipirana uz pretpostavku da ju veina korisnika nee
upotrebljavati za sofisticirane numerike proraune. Budui da je osnovna misao vodilja
autora Jave bila prenosivost kda, nisu do kraja implementirani svi zahtjevi koje
postavlja IEEE 754 standard za raunanje s decimalnim brojevima te nisu do kraja
iskoritene sve sklopovske mogunosti nekih procesora (npr. Intelovih) koji imaju
ugraene instrukcije za operacije s decimalnim brojevima. Rezultat toga je i neto
sporije izvoenje takvih operacija. No, kako je u specifikaciji jezika Java zapisano,
prosjeni korisnik ove nedostatke najvjerojatnije nee nikada primijetiti.

0.5. Zato primjer iz knjige ne radi na mom raunalu?

11

0.5. Zato primjer iz knjige ne radi na mom raunalu?


Zahvaljujui velikoj popularnosti jezika C, programski jezik C++ se brzo proirio i
prilino rano su se pojavili mnogi komercijalno dostupni prevoditelji. Od svoje pojave,
jezik C++ se dosta mijenjao, a prevoditelji su kaskali za tim promjenama. Zbog toga
se redovito dogaalo da je program koji se dao korektno prevesti na nekom prevoditelju,
bio neprevodiv ve na sljedeoj inaici prevoditelja istog proizvoaa.
Takva raznolikost i nekompatibilnost prevoditelja nagnala je Ameriki Nacionalni
Institut za Standarde (American National Standards Institute, ANSI) da krajem 1989.
godine osnuje odbor (s kdnom oznakom X3J16) iji je zadatak bio napisati Standard za
jezik C++. Osim eminentnih strunjaka (poput g. Stroustrupa) u radu odbora sudjelovali
su i predstavnici svih najznaajnijih softverskih tvrtki. U lipnju 1991. rad odbora je
preao u nadlenost Meunarodne Organizacije za Standarde (International Standards
Organization, ISO). U listopadu 1997. godine prihvaen je ISO standard jezika C++
(ANSI/ISO/IEC 14882).
Pojavom zavrnog oblika standarda je dinamiki proces promjena u jeziku C++
zaustavljen (barem na neko vrijeme) . Stoga bi bilo logino oekivati da se svi
prevoditelji koji su se na tritu pojavili nakon 1997. ponaaju u skladu sa Standardom.
Naalost, to nije sluaj, tako da vam se moe lako dogoditi da i na najnovijem
prevoditelju nekog proizvoaa (imena neemo spominjati Sjedni Bille, nitko ti nije
rekao da se digne!) ne moete prevesti kd iz knjige ili da vam prevedeni kd radi
drukije od onoga to smo mi napisali.
Naravno (unaprijed se posipamo pepelom), ne otklanjamo mogunost da smo i mi
napravili pogreku. Veinu primjera smo istestirali pomou prevoditelja koji je
uglavnom usklaen sa Standardom, ... ali nikad se ne zna. Oznaku prevoditelja neemo
navoditi da nam netko ne bi prigovorio da objavljujemo (strane) plaene reklame (a ne
zato jer bi se radilo o piratskoj kopiji kopija je legalno kupljena i licencirana).

0.6. Literatura
Tijekom pisanja knjige koristili smo sljedeu literaturu (navodimo ju abecednim
slijedom autora):
[ANSI95]
Working Paper for Draft Proposed International Standard for
Information Systems Programming Language C++, Technical
Report X3J16/95-0087, American National Standards Institute (ANSI),
April 1995
[Barton94]
John J. Barton, Lee R. Nackman: Scientific and Engineering C++ An
Introduction with Advanced Techniques and Examples, AddisonWesley, Reading, MA, 1994, ISBN 0-201-53393-6
[Borland94]
Borland C++ 4.5 Programmers Guide, Borland International, Scotts
Valley, CA
[Carroll95]
Martin D. Carroll, Margaret A. Ellis: Designing and Coding Reusable
C++, Addison-Wesley, Reading, MA, 1995, ISBN 0-201-51284-X

12

[Eckel99]

0. To C++ or not to C++?

Bruce Eckel: Thinking in C++, Prentice Hall, Englewood Cliffs , NJ,


1999, ISBN 0-13-917709-4
[Ellis90]
Margaret A. Ellis, Bjarne Stroustrup: The Annotated C++ Reference
Manual, Addison-Wesley, Reading, MA, 1990, ISBN 0-201-51459-1
[Hanly95]
Jeri R. Hanly, Elliot B. Koffman, Joan C. Horvath: C Program Design
for Engineers, Addison-Wesley, Reading, MA, 1994, ISBN 0-20159064-6
[Horstmann96] Cay S. Horstmann: Mastering C++ An Introduction to C++ and
Object-Oriented Programming for C and Pascal Programmers (2nd
Edition), John Wiley and Sons, New York, 1996, ISBN 0-471-10427-2
[ISO/IEC98]
ISO/IEC 14882 International Standard: Programming Languages
C++, American National Standards Institute, 1998.
[Josuttis99]
Nicolai M. Josuttis: The C++ Standard Library A Tutorial and
Handbook, Addison Wesley Longman, Reading MA, 1999, ISBN 0201-37926-0
[Kernighan88] Brian Kernighan, Dennis Ritchie: The C Programming Language (2nd
Edition), Prentice-Hall, Englewood Cliffs, NJ, 1988, ISBN 0-13937699-2
[Kukrika89]
Milan Kukrika: Programski jezik C, kolska knjiga, Zagreb, 1989,
ISBN 86-03-99627-X
[Liberty96]
Jesse Liberty, J. Mark Hord: Teach Yourself ANSI C++ in 21 Days,
Sams Publishing, Indianapolis, IN, 1996, ISBN 0-672-30887-6
[Lippman91]
Stanley B. Lippman: C++ Primer (2nd Edition), Addison-Wesley,
Reading, MA, 1991, ISBN 0-201-53992-6
[Lippman96]
Stanley B. Lippman: Inside the C++ Object Model, Addison-Wesley,
Reading, MA, 1996, ISBN 0-201-83454-5
[Lippman98]
Stanley B Lippman, Jose Lajoie: C++ Primer (3rd Edition), AddisonWesley Longman, Reading, MA, 1998, ISBN 0-201-82470-1
[Lippman00]
Stanley B Lippman: Essential C++, Addison-Wesley Longman,
Reading, MA, 2000, ISBN 0-201-48518-4
[Meyers98]
Scott Meyers: Effective C++ 50 Specific Ways to Improve Your
Programs and Design (2nd Edition), Addison-Wesley Longman,
Reading, MA, 2000, ISBN 0-201-92488-9
[Murray93]
Robert B. Murray: C++ Strategies and Tactics, Addison-Wesley,
Reading, MA, 1993, ISBN 0-201-56382-7
[Schildt90]
Herbert Schildt: Using Turbo C++, Osborne/McGraw-Hill, Berkeley,
CA, 1990, ISBN 0-07-881610-6
[Stepanov95] Alexander Stepanov, Meng Lee: The Standard Template Library,
Hewlett-Packard Laboratory, Palo Alto, CA, 1995

0.6. Literatura

13

[Stroustrup91] Bjarne Stroustrup: The C++ Programming Language (2nd Edition),


Addison-Wesley, Reading, MA, 1991, ISBN 0-201-53992-6
[Stroustrup94] Bjarne Stroustrup: The Design and Evolution of C++, AddisonWesley, Reading, MA, 1994, ISBN 0-201-54330-3
[Strostrup00] Bjarne Stroustrup: The C++ Programming Language (Special
Edition), Addison-Wesley Longman, Reading, MA, 2000, ISBN 0-20170073-5
[Weidl96]
Johannes Weidel: The Standard Template Library Tutorial, Technical
University Vienna, 1996
Ponegdje se pozivamo na neku od knjiga, navodei pripadajuu, gore navedenu oznaku
u uglatoj zagradi. Takoer smo koristili lanke iz asopisa C++ Report u kojem se moe
nai mnotvo najnovijih informacija. asopis izlazi od 1989. godine, deset puta
godinje, a izdaje ga SIGS Publications Group, New York. Godita 19911995
objavljena su na CDROM-u (SIGS Books, New York, ISBN 1-884842-24-0). Krajem
2000. godine, asopis se stopio sa slinim asopisom Journal of Object-Oriented
Programming. Uz to, mnotvo odgovora te praktinih i korisnih rjeenja moe se nai na
Usenet grupama za rasprave (newsgroups): comp.lang.c++, comp.lang.c++.moderated
kao i na mnotvu WWW stranica na Internetu. Obavezno posjetite osobne stranice
Bjarnea Stroustrupa (http://www.research.att.com/~bs), na kojima ete nai mnotvo
zanimljivih informacija o povijesti i specifinostima jezika C++, kao i putokaze na
druge zanimljive stranice.
Od svih navedenih knjiga, najreferentniji je C++ standard; moe se kupiti kod
Amerikog Nacionalnog Instituta za Standarde (ANSI) ili se (uz plaanje USD 18) moe
skinuti u PDF formatu sa WWW stranica Nacionalnog Odbora za Standarde
Informatike Tehnologije (National Committee for Information Technology Standards)
http://www.ncits.org/. Na Internetu (npr. ftp://ftp.research.att.com/dist/c++std/WP/CD2/)
se jo uvijek moe nai zavrna inaica nacrta Standarda iz travnja 1995., koja je
besplatna. Dostupna je u istom tekstovnom formatu, PDF (Acrobat Reader) formatu ili
u PostScript formatu. Broji oko 600 stranica formata A4 (oko 4MB komprimirane
datoteke), a kao kuriozitet navedimo da je preko CARNet mree trebalo u kolovozu
1995. oko 6 sati vremena da se prebaci na nae raunalo (toliko o Internetu u Hrvata!).
Sm Standard ne preporuujemo za uenje jezika C++, a takoer vjerujemo da nee
trebati niti iskusnijim korisnicima Standard je prvenstveno namijenjen proizvoaima
softvera; svi noviji prevoditelji (engl. compilers) bi se trebali ponaati u skladu s tim
standardom (to, na alost, nije sluaj). No, smatramo da bi svaki ozbiljni C++
programer morao imati knjigu B. Stroustrupa: The C++ Programming Language (tree
izdanje!) to je uz Standard svakako najreferentnija knjiga u kojoj ete nai odgovor na
vjerojatno svaki detalj vezan uz jezik C++ (knjigu ne preporuujemo za uenje jezika).

Iako se radi o nacrtu Standarda, on u potpunosti definira sve karakteristike programskog jezika
kako je definirano u konanoj verziji Standarda. Sve promjene koje su se dogaale od objave
Nacrta u travnju 1995. odnosile su se iskljuivo na tekst standarda sintaksa jezika i definicije
biblioteka ostale su nepromijenjene.

14

0. To C++ or not to C++?

Uz nju, najtopliju preporuku zasluuje knjiga S. Lippmana i J. Lajoie: C++ Primer


(tree izdanje) u kojoj su mnogi detalji jasnije objanjeni nego u Stroustrupovoj knjizi.
Zadnje poglavlje ove knjige posveeno je principima objektno orijentiranog
programiranja. Naravno da to nije dovoljno za ozbiljnije sagledavanje detaljnije o
objektno orijentiranom programiranju zainteresirani itatelj moe proitati u referentnoj
knjizi Grady Booch: Object-Oriented Analysis and Design with Applications (2nd
Edition), Benjamin/Cummings Publishing Co., Redwood City, CA, 1994, ISBN 0-80535340-2, kao i u nizu lanaka istog autora u asopisu C++ Report. Jedna od knjiga koju
bi svaki ozbiljniji programer trebao na svojoj polici jest Design Patterns: Elements of
Reusable Object-Oriented Software, iji su autori Erich Gamma, Richard Helm, Ralph
Johnson, John Vlissides, izdava Adison Wesley Longman, Reading Massachusetts,
1995 (ISBN 0201633612).
Nakon to je izalo prvo izdanje knjige, jedan od najeih upita koje smo dobivali
jest bio: Moe li se pomou vae knjige programirati u (MS) Windowsima?. Ova
knjiga prua osnove jezika C++ i vjerujemo da ete se, kada nakon par mjeseci zaklopite
zadnju stranu, moi pohvaliti da ste nauili jezik C++. Za pisanje Windows programa
trebaju vam, meutim, specijalizirane knjige koje e vas nauiti kako steeno znanje
jezika C++ iskoristiti za tu namjenu. Od takvih knjiga svakako vam preporuujemo (to
nije samo naa preporuka!) sljedee dvije knjige, tono navedenim redoslijedom:

- Jeff Prosise: Programming Windows with MFC (2nd Edition), Microsoft Press, 1999,
ISBN 1-57231-695-0

- Jeffrey Richter: Programming Applications for Microsoft Windows, Microsoft Press,


1999, ISBN 1-57231-996-8.

0.7. Zahvale
Zahvaljujemo se svima koji su nam izravno ili posredno pomogli pri izradi ove knjige.
Posebno se zahvaljujemo Branimiru Pejinoviu (Portland State University) koji nam je
omoguio da doemo do Nacrta ANSI C++ standarda, Vladi Glaviniu (Fakultet
elektrotehnike i raunarstva) koji nam je omoguio da doemo do knjiga [Stroustrup94]
i [Carroll95] te nam je tijekom pripreme za tisak dao na raspolaganje laserski pisa, te
Zdenku imiu (Fakultet elektrotehnike i raunarstva) koji nam je, tijekom svog
boravka u SAD, pomogao pri nabavci dijela literature.
Posebnu zahvalu upuujemo Ivi Mesari koja je proitala cijeli rukopis te svojim
korisnim i konstruktivnim primjedbama znatno doprinijela kvaliteti iznesene materije.
Takoer se zahvaljujemo Zoranu Kalafatiu (Fakultet elektrotehnike i raunarstva) i
Damiru Hodaku koji su itali dijelove rukopisa i dali na njih korisne opaske.
Boris se posebno zahvaljuje gospoama ribar na tonama kolaa pojedenih za
vrijeme dugih, zimskih noi itanja i ispravljanja rukopisa, a koje su ga kotale kure
mravljenja.

0.7. Zahvale

15

I naravno, zahvaljujemo se Bjarne Stroustrupu i dekima iz AT&T-a to su izmislili


C++, na najdrai programski jezik. Bez njih ne bi bilo niti ove knjige (ali moda bi bilo
sline knjige iz FORTRAN-a).
0.7.1. Zahvale uz drugo izdanje
U prvom redu zahvaljujemo se svima koji su kupili prvo izdanje knjige koje je
rasprodano u relativno kratkom vremenu bez njih ne bi bilo drugog izdanja knjige. A
onima koji su fotokopirali knjigu poruujemo da e se posthumno pei u vjenoj vatri
Xeroxovih i Canonovih tonera, a djeca e im izgledati kao izblijedjele fotokopije
dobivene mokrim postupkom (naravno, svoje grijehe e iskupiti unite li odmah
fotokopiju i kupe primjerak knjige u knjiari).
Zahvale upuujemo i svima koji su dali prijedloge ili nas upozorili na pogreke u
prvom izdanju. Takoer, zahvaljujemo se Julijanovim bivim kolegama sa Zavoda za
elektroniku, mikroelektroniku, raunalne i inteligentne sustave Fakulteta elektrotehnike i
raunarstva koji su dozvolili da na njihovom posluiteljima odravamo WWW stranice
vezane uz ovu knjigu.

16

0. To C++ or not to C++?

17

1. Oluja kroz jezik C++


to je to naredba?
Da ugasim svjetiljku. Dobra veer. I on je ponovo upali.
Ne razumijem ree mali princ.
Nema to tu razumjeti ree noobdija. Naredba je
naredba. Dobar dan. I on ugasi svoju svjetiljku.
Antoine de Saint-Exupry (19001944), Mali princ

U prvom poglavlju proletjet emo kroz osnovne pojmove vezane uz programiranje i


upoznat emo se s strukturom najjednostavnijih programa pisanih u programskom jeziku
C++. Ovo poglavlje prvenstveno je namijenjeno itateljicama i itateljima koji nisu
nikada pisali programe u bilo kojem viem programskom jeziku i onima koji su to
moda radili, ali je od tada prola itava vjenost.

1.1. to je program i kako ga napisati


Elektronika raunala su danas postala pribor kojim se svakodnevno koristimo kako
bismo si olakali posao ili se zabavili. Istina, tonost prvog navoda e mnogi poricati,
istiui kao protuprimjer injenicu da im je za podizanje novca prije trebalo znatno
manje vremena nego otkad su alteri u banci kompjuterizirani. Ipak, injenica je da su
mnogi poslovi danas nezamislivi bez raunala; u krajnjoj liniji, dokaz za to je knjiga
koju upravo itate koja je u potpunosti napisana pomou raunala.
Samo raunalo, ak i kada se ukljui u struju, nije kadro uiniti nita korisno. Na
dananjim raunalima se ne moe ak ni zagrijati prosjeni ruak, to je inae bilo
mogue na raunalima s elektronskim cijevima. Ono to vam nedostaje jest pamet
neophodna za koristan rad raunala: programi, programi, mnotvo programa. Pod
programom tu podrazumijevamo niz naredbi u strojnom jeziku koje procesor u vaem
raunalu izvodi i shodno njima obrauje podatke, provodi matematike proraune,
ispisuje tekstove, iscrtava krivulje na zaslonu ili gaa va avion F-16 raketama srednjeg
dometa. Pokretanjem programa s diska, diskete ili CD-ROM-a, program se uitava u
radnu memoriju raunala i procesor poinje s mukotrpnim postupkom njegova
izvoenja.
Programi koje pokreete na raunalu su u izvedbenom obliku (engl. executable),
razumljivom samo procesoru vaeg (i njemu slinih) raunala, sretnim procesorovim
roditeljima negdje u Silicijskoj dolini i nekolicini zadrtih hakera irom svijeta koji jo
uvijek programiraju u strojnom kdu. U sutini se strojni kd sastoji od nizova binarnih
znamenki: nula i jedinica. Budui da su dananji programi tipino duljine nekoliko

17

18

1. Oluja kroz jezik C++

Poetak

Upis i ispravke
izvornog kda

Prevoenje

Da

Pogreke tijekom
prevoenja?

Ne
Povezivanje

Da

Pogreka tijekom
povezivanja?

Ne
Izvoenje programa

megabajta, nasluujete da ih autori nisu pisali


izravno u strojnom kdu (kamo sree da je
tako ne bi Microsoft tek tako svake dvije
godine izbacivao nove Windowse!).
Gotovo svi dananji programi se piu u
nekom od viih programskih jezika
(FORTRAN, BASIC, Pascal, C) koji su
donekle razumljivi i ljudima (barem onima
koji imaju neto pojma o engleskom jeziku).
Naredbe u tim jezicima se sastoje od
mnemonika. Kombiniranjem tih naredbi
programer slae izvorni kd (engl. source
code) programa, koji se pomou posebnih
programa prevoditelja (engl. compiler) i
povezivaa (engl. linker) prevodi u izvedbeni
kd. Prema tome, pisanje programa u uem
smislu podrazumijeva pisanje izvornog kda.
Meutim, kako pisanje kda nije samo sebi
svrhom, pod pisanjem programa u irem
smislu podrazumijeva se i prevoenje,
odnosno povezivanje programa u izvedbeni
kd. Stoga moemo govoriti o etiri faze
izrade programa:
1. pisanje izvornog kda
2. prevoenje izvornog kda,
3. povezivanje u izvedbeni kd te
4. testiranje programa.

Da bi se za neki program moglo rei da je


uspjeno zgotovljen, treba uspjeno proi kroz
Da
Pogreke tijekom
sve etiri faze.
izvoenja?
Kao i svaki drugi posao, i pisanje
programa
iziskuje odreeno znanje i vjetinu.
Ne
Prilikom pisanja programera vrebaju Scile i
Haribde, danas poznatije pod nazivom
Konac
pogreke ili bugovi (engl. bug - stjenica) u
programu. Uoi li se pogreka u nekoj od faza
Slika 1.1. Tipian razvoj programa
izrade programa, izvorni kd treba doraditi i
ponoviti sve prethodne faze. Zbog toga
postupak izrade programa nije pravocrtan, ve manje-vie podsjea na mukotrpno
petljanje u krug. Na slici 1.1 je shematski prikazan cjelokupni postupak izrade
programa, od njegova zaetka, do njegova okonanja. Analizirajmo najvanije faze
izrade programa.

1.1. to je program i kako ga napisati

19

Prva faza programa je pisanje izvornog kda. U principu se izvorni kd moe pisati
u bilo kojem programu za ureivanje teksta (engl. text editor), meutim velika veina
dananjih prevoditelja i povezivaa se isporuuje kao cjelina zajedno s ugraenim
programom za upis i ispravljanje izvornog kda. Te programske cjeline poznatije su pod
nazivom integrirane razvojne okoline (engl. integrated development environment, IDE).
Nakon to je (prema obino nekritikom miljenju programera) pisanje izvornog kda
zavreno, on se pohrani u datoteku izvornog kda na disku. Toj datoteci se obino daje
nekakvo smisleno ime, pri emu se ono za kdove pisane u programskom jeziku C++
obino proiruje nastavkom .cpp, .cp ili samo .c, na primjer pero.cpp. Nastavak je
potreban samo zato da bismo izvorni kd kasnije mogli lake pronai.
Slijedi prevoenje izvornog kda. U integriranim razvojnim okolinama program za
prevoenje se pokree pritiskom na neku tipku na zaslonu, pritiskom odgovarajue tipke
na tipkovnici ili iz nekog od izbornika (engl. menu) ako prevoditelj nije integriran,
poziv je neto sloeniji. Prevoditelj tijekom prevoenja provjerava sintaksu napisanog
izvornog kda i u sluaju uoenih ili nasluenih pogreaka ispisuje odgovarajue poruke
o pogrekama, odnosno upozorenja. Pogreke koje prijavi prevoditelj nazivaju se
pogrekama pri prevoenju (engl. compile-time errors). Nakon toga programer e
pokuati ispraviti sve navedene pogreke i ponovo prevesti izvorni kd sve dok
prevoenje kda ne bude uspjeno okonano, nee se moi pristupiti povezivanju kda.
Prevoenjem izvornog dobiva se datoteka objektnog kda (engl. object code), koja se
lako moe prepoznata po tome to obino ima nastavak .o ili .obj (u naem primjeru bi
to bio pero.obj).
Nakon to su ispravljene sve pogreke uoene prilikom prevoenja i kd ispravno
preveden, pristupa se povezivanju objektnih kdova u izvedbeni. U veini sluajeva
objektni kd dobiven prevoenjem programerovog izvornog kda treba povezati s
postojeim bibliotekama (engl. libraries). Biblioteke su datoteke u kojima se nalaze ve
prevedene gotove funkcije ili podaci. One se isporuuju zajedno s prevoditeljem, mogu
se zasebno kupiti ili ih programer moe tijekom rada sam razvijati. Bibliotekama se
izbjegava opetovano pisanje vrlo esto koritenih operacija. Tipian primjer za to je
biblioteka matematikih funkcija koja se redovito isporuuje uz prevoditelje, a u kojoj
su definirane sve funkcije poput trigonometrijskih, hiperbolnih, eksponencijalnih i sl.
Prilikom povezivanja provjerava se mogu li se svi pozivi kdova realizirati u
izvedbenom kdu. Uoi li poveziva neku nepravilnost tijekom povezivanja, ispisat e
poruku o pogreki i onemoguiti generiranje izvedbenog kda. Ove pogreke nazivaju se
pogrekama pri povezivanju (engl. link-time errors) sada programer mora prionuti
ispravljanju pogreaka koje su nastale pri povezivanju. Nakon to se isprave sve
pogreke, kd treba ponovno prevesti i povezati.
Uspjenim povezivanjem dobiva se izvedbeni kd. Meutim, takav izvedbeni kd
jo uvijek ne jami da e program raditi ono to ste zamislili. Primjerice, moe se
dogoditi da program radi pravilno za neke podatke, ali da se za druge podatke ponaa

Ovdje neemo opisivati konkretno kako se pokreu postupci prevoenja ili povezivanja, jer to
varira ovisno o prevoditelju, odnosno povezivau. Saeti opis za neke popularnije prevoditelje
dan je u Prilogu D na kraju knjige.

20

1. Oluja kroz jezik C++

nepredvidivo. U tom se sluaju radi o pogrekama pri izvoenju (engl. run-time errors).
Da bi program bio potpuno korektan, programer treba istestirati program da bi uoio i
ispravio te pogreke, to znai ponavljanje cijelog postupka u lancu ispravljanje
izvornog kda-prevoenje-povezivanje-testiranje. Kod jednostavnijih programa broj
ponavljanja e biti manji i smanjivat e se proporcionalno s rastuim iskustvom
programera. Meutim, kako raste sloenost programa, tako se poveava broj moguih
pogreaka i cijeli postupak izrade programa neiskusnom programeru moe postati
mukotrpan.
Za ispravljanje pogreaka pri izvoenju, programeru na raspolaganju stoje programi
za otkrivanje pogreaka (engl. debugger). Radi se o programima koji omoguavaju
prekid izvoenja izvedbenog kda programa koji testiramo na unaprijed zadanim
naredbama, izvoenje programa naredbu po naredbu, ispis i promjene trenutnih
vrijednosti pojedinih podataka u programu. Najjednostavniji programi za otkrivanje
pogreaka ispisuju izvedbeni kd u obliku strojnih naredbi. Meutim, veina dananjih
naprednih programa za otkrivanje pogreaka su simboliki (engl. symbolic debugger)
iako se izvodi prevedeni, strojni kd, izvoenje programa se prati preko izvornog kda
pisanog u viem programskom jeziku. To omoguava vrlo lagano lociranje i ispravljanje
pogreaka u programu.
Osim pogreaka, prevoditelj i poveziva redovito dojavljuju i upozorenja. Ona ne
onemoguavaju nastavak prevoenja, odnosno povezivanja kda, ali predstavljaju
potencijalnu opasnost. Upozorenja se mogu podijeliti u dvije grupe. Prvu grupu ine
upozorenja koja javljaju da kd nije potpuno korektan. Prevoditelj ili poveziva e
zanemariti nau pogreku i prema svom nahoenju generirati kd. Drugu grupu ine
poruke koje upozoravaju da nisu sigurni je li ono to smo napisali upravo ono to smo
eljeli napisati, tj. radi se o dobronamjernim upozorenjima na zamke koje mogu
proizii iz naina na koji smo program napisali. Iako e, unato upozorenjima, program
biti preveden i povezan (moda ak i korektno), pedantan programer nee ta upozorenja
nikada zanemariti ona esto upuuju na uzrok pogreaka pri izvoenju gotovog
programa. Za precizno tumaenje poruka o pogrekama i upozorenja neophodna je
dokumentacija koja se isporuuje uz prevoditelj i poveziva.
Da zakljuimo: to nam dakle treba za pisanje programa u jeziku C++? Osim
raunala, programa za pisanje i ispravljanje teksta, prevoditelja i povezivaa trebaju vam
jo samo tri stvari: interes, puno slobodnih popodneva i dooobra knjiga. Interes
vjerojatno postoji, ako ste s itanjem stigli ak do ovdje. Slobodno vrijeme e vam
trebati da isprobate primjere i da se sami okuate u bespuima C++ zbiljnosti. Jer, kao
to stari junohrvatski izrijek kae: Nima dopisne kole iz plivanja. Stoga ne gubite
vrijeme i odmah otkaite sudar deku ili curi. A za dooobru knjigu(ta-ta-daaam
tu sada mi upadamo!).

1.2. Moj prvi i drugi C++ program

21

1.2. Moj prvi i drugi C++ program


Bez mnogo okolianja i filozofiranja, napiimo najjednostavniji program u jeziku C++:
int main() {
return 0;
}

Utipkate li nadobudno ovaj program u svoje raunalo, pokrenete odgovarajui


prevoditelj, te nakon uspjenog prevoenja pokrenete program, na zaslonu raunala
sigurno neete dobiti nita! Nemojte se odmah hvatati za glavu, laati telefona i zvati
svoga dobavljaa raunala. Gornji program zaista nita ne radi, a ako neto i dobijete na
zaslonu vaeg raunala, znai da ste negdje pogrijeili prilikom utipkavanja. Unato
jalovosti gornjeg kda, promotrimo ga, redak po redak.
U prvom retku je napisano int main(). main je naziv za glavnu funkciju u svakom
C++ programu. Izvoenje svakog programa poinje naredbama koje se nalaze u njoj.
Svaki program napisan u C++ jeziku mora imati tono (ni manje ni vie) jednu
main() funkciju.
Pritom valja uoiti da je to samo simboliko ime koje daje do znanja prevoditelju koji se
dio programa treba prvo poeti izvoditi ono nema nikakve veze s imenom izvedbenog
programa koji se nakon uspjenog prevoenja i povezivanja dobiva. eljeno ime
izvedbenog programa odreuje sam programer: ako se koriteni prevoditelj pokree iz
komandne linije, ime se navodi kao parametar u komandnoj liniji, a ako je prevoditelj
ugraen u neku razvojnu okolinu, tada se ime navodi kao jedna od opcija. Tone detalje
definiranja imena izvedbenog imena itateljica ili itatelj nai e u uputama za
prevoditelj kojeg koristi.
Rije int ispred oznake glavne funkcije ukazuje na to da e main() po zavretku
izvoenja naredbi i funkcija sadranih u njoj kao rezultat tog izvoenja vratiti cijeli broj
(int dolazi od engleske rijei integer koja znai cijeli broj). Budui da se glavni
program pokree iz operacijskog sustava (DOS, UNIX, MS Windows), rezultat glavnog
programa se vraa operacijskom sustavu. Najee je to kd koji signalizira pogreku
nastalu tijekom izvoenja programa ili obavijest o uspjenom izvoenju.
Iza rijei main slijedi par otvorena-zatvorena zagrada (). Unutar te zagrade trebali
bi doi opisi podataka koji se iz operacijskog sustava prenose u main(). Ti podaci
nazivaju se argumenti ili parametri funkcije. Za funkciju main() to su parametri koji se
pri pokretanju programa navode u komandnoj liniji iza imena programa, kao na primjer:
pkunzip -t mojzip

U nekim programskim jezicima glavna funkcija se zove glavni program, a sve ostale funkcije
potprogrami.

22

1. Oluja kroz jezik C++

Ovom naredbom se pokree program pkunzip i pritom mu se predaju dva parametra: -t


i mojzip. U naem C++ primjeru unutar zagrada nema nita, to znai da ne prenosimo
nikakve argumente. Tako e i ostati do daljnjega, tonije do poglavlja 5.11 u kojem
emo detaljnije obraditi funkcije, a posebice funkciju main().
Slijedi otvorena vitiasta zagrada {. Ona oznaava poetak bloka naredbi u kojem
e se nalaziti naredbe glavne funkcije, dok zatvorena vitiasta zagrada } u zadnjem retku
oznaava kraj tog bloka . U samom bloku prosjeni itatelj uoit e samo jednu naredbu,
return 0. Tom naredbom glavni program vraa pozivnom programu broj 0, a to je
poruka operacijskom sustavu da je program uspjeno okonan, togod on radio.
Uoimo znak ; (toka-zarez) iza naredbe return 0! On oznaava kraj naredbe te
slui kao poruka prevoditelju da sve znakove koji slijede interpretira kao novu naredbu.
Znak ; mora zakljuivati svaku naredbu u jeziku C++.
Radi kratkoe emo u veini primjera u knjizi izostavljati uvodni i zakljuni dio glavne
funkcije te emo podrazumijevati da oni u konkretnom kdu postoje.
Pogledajmo jo na trenutak to bi se dogodilo da smo kojim sluajem napravili neku
pogreku prilikom upisivanja gornjeg kda. Recimo da smo zaboravili desnu vitiastu
zagradu na kraju kda:
int main() {
return 0;

Prilikom prevoenja prevoditelj e uoiti da funkcija main() nije pravilno zatvorena, te


e ispisati poruku o pogreki oblika Pogreka u prvi.cpp xx: sloenoj naredbi nedostaje
} u funkciji main(). U ovoj poruci je prvi.cpp ime datoteke u koju smo na izvorni kd
pohranili, a xx je broj retka u kojem se pronaena pogreka nalazi. Zaboravimo li
napisati naredbu return:
int main() {
}

neki prevoditelji e javiti upozorenje oblika Funkcija bi trebala vratiti vrijednost. Iako
se radi o pogreki, prevoditelj e umetnuti odgovarajui kd prema svom nahoenju i
prevesti program. Ne mali broj korisnika e zbog toga zanemariti takva upozorenja.
Meutim, valja primijetiti da esto taj umetnuti kd ne odgovara onome to je
programer zamislio. Zanemarivanjem upozorenja programer gubi pregled nad
korektnou kda, pa se lako moe dogoditi da rezultirajui izvedbeni kd daje na prvi
pogled neobjanjive rezultate.
Zadatak. Izbacite iz gornjeg kda desnu vitiastu zagradu } te pokuajte prevesti kd.
Pogledajte koje e pogreke javiti prevoditelj.

1.2. Moj prvi i drugi C++ program

23

Programi poput gornjeg nemaju ba neku praktinu primjenu, te daljnju analizu


gornjeg kda preputamo poklonicima minimalizma. We need some action, man! Stoga
pogledajmo sljedei primjer:
#include <iostream>
using namespace std;
int main() {
cout << "Ja sam za C++!!! A vi?" << endl;
return 0;
}

U ovom primjeru uoavamo tri nova retka. U prvom retku nalazi se naredba
#include <iostream> kojom se od prevoditelja zahtijeva da u na program ukljui
biblioteku iostream. U toj biblioteci nalazi se izlazni tok (engl. output stream) te
funkcije koje omoguavaju ispis podataka na zaslonu. Ta biblioteka nam je neophodna
da bismo u prvom retku glavnoga programa ispisali tekst poruke. Naglasimo da
#include nije naredba C++ jezika, nego se radi o pretprocesorskoj naredbi
(pretprocesorskim naredbama posveeno je poglavlje 17). Naletjevi na nju, prevoditelj
e prekinuti postupak prevoenja kda u tekuoj datoteci, skoiti u datoteku iostream,
prevesti ju, a potom se vratiti u poetnu datoteku na redak iza naredbe #include. Sve
pretprocesorske naredbe poinju znakom #.
iostream je primjer datoteke zaglavlja (engl. header file). U takvim datotekama se
nalaze deklaracije funkcija sadranih u odgovarajuim bibliotekama. Jedna od osnovnih
znaajki (zli jezici e rei mana) jezika C++ jest vrlo oskudan broj funkcija ugraenih u
sam jezik. Ta oskudnost olakava uenje samog jezika, te bitno pojednostavnjuje i
ubrzava postupak prevoenja. Za specifine zahtjeve na raspolaganju je veliki broj
odgovarajuih biblioteka funkcija i razreda.
Datoteke zaglavlja nalaze se obino u potkazalu include unutar kazala u kojem je
instaliran prevoditelj. Znatieljnicima eljnima znanja preporuujemo da zavire u te
datoteke budui da se u njima moe nai dosta korisnih informacija, ali svakako valja
paziti da se sadraj tih datoteka ne mijenja.
U drugom retku kda napisana je naredba using namespace std. using i
namespace su kljune rijei jezika C++ kojima se aktivira odreeno podruje imena
(imenik, engl. namespace), a std je naziv imenika u kojem su obuhvaane sve
standardne funkcije, ukljuujui i funkcije iz gore opisane iostream biblioteke. Imenici
su se prilino kasno pojavili u jeziku C++, a uvedeni su da se izbjegne kolizija istih
imena funkcija ili varijabli iz razliitih biblioteka. Na primjer, ako dvije razliite
funkcije iz razliitih biblioteka imaju isto ime, prevoditelj e javiti pogreku. Kada ne
bismo imali na raspolaganju imenike, jedino rjeenje u takvom sluaju bilo bi
promijeniti ime funkcije u jednoj od biblioteka, to ponekad nije mogue jer proizvoai
redovito te biblioteke isporuuju u ve prevedenom obliku. Detaljnije o imenicima bit e
govora u poglavlju 11, a do tada uzmite naredbu using namespace std zdravo za
gotovo.

24

1. Oluja kroz jezik C++

Korisno je znati da je iostream novi (Standardom propisani) naziv za iostream.h


zaglavlje. Do te promjene imena dolo je ne bez razloga. Naime, kada su uvedeni
imenici, trebalo je sve standardne biblioteke uvrstiti u imenik std. Kako je ve tada
postojalo mnotvo kda koji je koristio iostream.h biblioteku, ona se zbog spojivosti sa
tim starim kodom nije smjela mijenjati. Rjeenje je bilo definirati novu biblioteku slina
naziva u kojoj su definirane sve funkcije kao i u iostream.h zaglavlju, ali unutar
imenika std. Zato je u bibliotekama veine dananjih prevoditelja zapravo unutar
iostream datoteke samo ukljuena (pretprocesorskom naredbom #include) iostream.h
datoteka, uz ukljuivanje te biblioteke u std imenik. Slino vrijedi za zaglavlja svih
ostalih standardnih biblioteka. Inae Standard dozvoljava upotrebu starog nazivlja, ali se
ono ne preporuuje.
Trea novina u gornjem primjeru jest naredba unutar glavne funkcije koja poinje
sa cout.cout je ime izlaznog toka definiranog u biblioteci iostream, pridruenog
zaslonu raunala. Operatorom << (dva znaka manje od) podatak koji slijedi upuuje se
na izlazni tok, tj. na zaslon raunala. U gornjem primjeru to je kratka promidbena
poruka:
Ja sam za C++!!! A vi?

Ona je u programu napisana unutar znakova navodnika, koji upuuju na to da se radi o


tekstu koji treba ispisati doslovce. Biblioteka iostream bit e detaljnije opisana kasnije,
u poglavlju 15.
Meutim, to jo nije sve! Iza znakovnog niza ponavlja se operator za ispis, kojeg
slijedi endl. endl je konstanta u biblioteci iostream koja prebacuje ispis u novi redak,
to jest vraa znaku (ili kurzor, engl. cursor) na poetak sljedeeg retka na zaslonu.
Dovitljiva itateljica ili itatelj e sami zakljuiti da bi se operatori za ispis mogli dalje
nadovezivati u istoj naredbi:
cout << "Ja sam za C++!!! A vi?" << endl << "Ne, hvala!";

Zadatak. Utipkajte gornji kd u raunalo, pohranite ga u datoteku te pokrenite


prevoditelj/poveziva. Izvrite dobiveni program i pogledajte ispis na zaslonu.
Ako koristite prevoditelj na operacijskom sustavu s grafikim sueljem (npr. Windows
95/98/2000, Windows NT) i rezultirajui program ne pokreete iz terminalskog (DOS)
prozora ve izravno iz grafikog okruenja, tada se lako moe dogoditi da se nakon
pokretanja programa na trenutak otvori terminalski prozor, koji e se nestati prije nego
to uspijete proitati ijedno slovo teksta koji se ispisao. Osjeat ete se nasamareni
(Iaaa!!! Zar sam zato platio punih 20 kuna lokalnom piratu za kopiju najnovijeg
prevoditelja?). Vjerojatno e odmah vam pasti na pamet neka od sljedeih perverznih
ideja:
nabaviti neko ultra-staro, hiper-sporo raunalo s ekstremno sporom grafikom
karticom i monitor s perzistencijom od desetak sekundi;
nabaviti najmoderniji foto-aparat s vrlo brzim zatvaraem. Bljeskalica dodue nije
neophodna, ali bi dobro doao mreni (po mogunosti 100 megabitni) prikljuak na

1.3. Moj trei C++ program

25

raunalo preko kojeg bi se sinkroniziralo okidanje aparata s otvaranjem prozora.


Alternativa je video kamera s mogunou ubrzanog (10) snimanja;
pozvati cijelu obitelj pred raunalo i objaviti natjeaj s posebnom nagradom za onog
tko prvi uspije proitati cijeli tekst (ako ste izuzetno sadistiki nastrojeni, proirit
ete tekst poruke na barem dva retka).
Mi vam nudimo sljedea dva rjeenja:
otvorite komandni (DOS) prozor i program pokrenite iz komandne linije, ili
pri kraju kda, ispred naredbe return dodajte sljedee dvije naredbe:
char z;
cin >> z;

Njima se deklarira znakovna (char) varijabla z, i potom u naredbi cin program oekuje
da utipkamo vrijednost te varijable; kada program prilikom izvoenja doe na naredbu
cin, izvoenje e se prekinuti sve dok ne pritisnemo neki znak (samo jedan znak!) i
potom tipku Enter. To e nam omoguiti da u miru Bojem, duboko u no prouavamo
ispis naih umotvorina. No, unaprijed vas upozoravamo da neke od ispisanih poruka
neete uspjeti vidjeti niti na ovaj nain. Naime, u poglavlju o razredima i njihovim
destruktorima neki od primjera poruke ispisuju pri izlasku iz programa, tj. nakon gore
spomenutih naredbi.
Zadatak. Kako bi izgledao izvorni kd ako bismo eljeli ispis endl znaka staviti u
posebnu naredbu? Dodajte u gornji primjer ispis poruke Imamo C++!!! u sljedeem
retku (popratno euforiko sklapanje ruku iznad glave nije neophodno). Nemojte
zaboraviti dodati i ispis endl na kraju tog retka!
Zadatak. Izbacite iz gornjeg kda pretprocesorsku naredbu #include te pokuajte
prevesti kd. Pogledajte koje e pogreke javiti prevoditelj. Ponovite to za sluaj da
izbacite naredbu using namespace.

1.3. Moj trei C++ program


Sljedei primjer je pravi mali dragulj interaktivnog programa:
#include <iostream>
using namespace std;
int main() {
int a, b, c;
cout << "Upii prvi broj:";
cin >> a;

// oekuje prvi broj

cout << "Upii i drugi broj:";


cin >> b;

// oekuje drugi broj

c = a + b;
// rauna njihov zbroj
// ispisuje rezultat (vidi sljedeu stranicu):

26

1. Oluja kroz jezik C++

cout << "Njihov zbroj je: " << c << endl;


return 0;
}

U ovom primjeru uoavamo nekoliko novina. Prvo, to je redak


int a, b, c;

u kojem se deklariraju tri varijable a, b i c. Kljunom rijei (identifikatorom tipa) int


deklarirali smo ih kao cjelobrojne, tj. tipa int. Deklaracijom smo pridijelili simboliko,
nama razumljivo i lako pamtljivo ime memorijskom prostoru u koji e se pohranjivati
vrijednosti tih varijabli. Naiavi na te deklaracije, prevoditelj e zapamtiti njihova
imena, te za njih rezervirati odgovarajui prostor u memoriji raunala. Kada tijekom
prevoenja ponovno sretne varijablu s nekim od tih imena, prevoditelj e znati da se radi
o cjelobrojnoj varijabli i znat e gdje bi se ona u memoriji trebala nalaziti. Osim toga,
tip varijable odreuje raspon dozvoljenih vrijednosti te varijable, te definira operacije
nad njima. Opirnije o deklaracijama varijabli i o tipovima podataka govorit emo u
sljedeem poglavlju.
Slijedi ispis poruke Upii prvi broj:, ije znaenje ne trebamo objanjavati.
Iza poruke nismo dodali ispis znaka endl, jer elimo da nam znaka ostane iza poruke, u
istom retku, spreman za unos prvog broja.
Druga novina je ulazni tok (engl. input stream) cin koji je zajedno s izlaznim tokom
definiran u datoteci zaglavlja iostream. On slui za uitavanje podataka s konzole, tj.
tipkovnice. Operatorom >> (dvostruki znak vee od) podaci s konzole upuuju se u
memoriju varijabli a (prvi broj), odnosno b (drugi broj). Naglasimo da uitavanje
poinje tek kada se na tipkovnici pritisne tipka za novi redak, tj. tipka Enter. To znai da
kada pokrenete program, nakon ispisane poruke moete utipkavati bilo to i to po
potrebi brisati tek kada pritisnete tipku Enter, program e analizirati unos te pohraniti
broj koji je upisan u memoriju raunala. Napomenimo da taj broj u naem primjeru ne
smije biti vei od 32767 niti manji od 32768, jer je to dozvoljeni raspon cjelobrojnih

int varijabli . Unos veeg broja nee imati nikakve dramatine posljedice na daljnji rad
vaeg raunala, ali e dati krivi rezultat na kraju rauna.
Svaki puta kada nam u programu treba ispis podataka na zaslonu ili unos
podataka preko tipkovnice pomou ulazno-izlaznih tokova cin ili cout, treba
ukljuiti zaglavlje odgovarajue iostream biblioteke pretprocesorskom
naredbom #include.
Radi saetosti kda, u veini primjera koji slijede, pretprocesorska naredba za
ukljuivanje iostream biblioteke nee biti napisana, ali se ona podrazumijeva. Koriste li
se ulazno-izlazni tokovi, njeno izostavljanje prouzroit e pogreku kod prevoenja.

Opseg dozvoljenih vrijednosti ovisi o prevoditelju i nije strogo definiran Standardom. Za neke
prevoditelje raspon je od 2.147.483.648 do 2.147.483.647. Detaljnije o rasponu dozvoljenih
vrijednosti bit e rijei u odjeljku 2.4.1.

1.4. Komentari

27

No, zavrimo s naim primjerom. Nakon unosa prvog broja, po istom principu se
unosi drugi broj b, a zatim slijedi naredba za raunanje zbroja
c = a + b;

Ona kae raunalu da treba zbrojiti vrijednosti varijabli a i b, te njihov zbroj pohraniti u
varijablu c, tj. u memoriju na mjesto gdje je prevoditelj rezervirao prostor za tu
varijablu.
U poetku e itatelj zasigurno imati problema s razluivanjem operatora << i >>. U
vjeri da e olakati razlikovanje operatora za ispis i uitavanje podataka, dajemo sljedei
naputak.
Operatore << i >> moemo zamisliti kao strelice koje pokazuju smjer
prijenosa podataka [Lippman91].
Primjerice,
>> a

preslikava vrijednost u a, dok


<< c

preslikava vrijednost iz c.
Zadatak. Pokrenite Moj trei program nekoliko puta, unosei svaki puta sve vee
brojeve i pratite rezultate. Na primjer, pokuajte sa sljedeim parovima: 326766 i 1;
326766 i 2; 2147483646 i 1; 2147483646 i 2. Ponovite to i za identine negativne
brojeve.

1.4. Komentari
Na nekoliko mjesta u gornjem kdu moemo uoiti tekstove koji zapoinju dvostrukim
kosim crtama (//). Radi se o komentarima. Kada prevoditelj naleti na dvostruku kosu
crtu, on e zanemariti sav tekst koji slijedi do kraja tekueg retka i prevoenje e
nastaviti u sljedeem retku. Komentari dakle ne ulaze u izvedbeni kd programa i slue
programerima za opis znaenja pojedinih naredbi ili dijelova kda. Komentari se mogu
pisati u zasebnom retku ili recima, to se obino rabi za dulje opise, primjerice to
odreeni program ili funkcija radi:
//
// Ovo je moj trei C++ program, koji zbraja
// dva broja unesena preko tipkovnice, a zbroj
// ispisuje na zaslonu.
//
Autor: N. N. Hacker III
//

28

1. Oluja kroz jezik C++

Za krae komentare, na primjer za opise varijabli ili nekih operacija, komentar se pie u
nastavku naredbe, kao to smo vidjeli u primjeru.
Uz gore navedeni oblik komentara, jezik C++ podrava i komentare unutar para
znakova /* */. Takvi komentari zapoinju slijedom /* (kosa crta i zvjezdica), a
zavravaju slijedom */ (zvjezdica i kosa crta). Kraj retka ne znai podrazumijevani
zavretak komentara, pa se ovakvi komentari mogu protezati na nekoliko redaka
izvornog kda, a da se pritom znak za komentiranje ne mora ponavljati u svakom retku:
/*
Ovakav nain komentara
preuzet je iz programskog
jezika C.
*/

Stoga je ovakav nain komentiranja naroito pogodan za (privremeno) iskljuivanje


dijelova izvornog kda. Ispred naredbe u nizu koji elimo iskljuiti dodat emo oznaku
/* za poetak komentara, a iza zadnje naredbe u nizu nadodat emo oznaku */ za
zakljuenje komentara.
Iako komentiranje programa iziskuje dodatno vrijeme i napor, u kompleksnijim
programima ono se redovito isplati. Dogodi li se da netko drugi mora ispravljati va kd,
ili (jo gore) da nakon dugo vremena vi sami morate ispravljati svoj kd, komentari e
vam olakati da proniknete u ono to je autor njime htio rei. Svaki ozbiljniji programer
ili onaj tko to eli postati mora biti svjestan da e nakon desetak ili stotinjak napisanih
programa poeti zaboravljati emu pojedini program slui. Zato je vrlo korisno na
poetku datoteke izvornog programa u komentaru navesti osnovne generalije, na
primjer ime programa, ime datoteke izvornog kda, kratki opis onoga to bi program
trebao raditi, funkcije i razrede definirane u datoteci te njihovo znaenje, autor(i) kda,
uvjeti pod kojima je program preveden (operacijski sustav, ime i oznaka prevoditelja),
zabiljeke, te naknadne izmjene:
/**********************************************************
Program:
Moj trei C++ program
Datoteka:
Treci.cpp
Funkcije:
main() - cijeli program je u jednoj datoteci
Opis:
Uitava dva broja i ispisuje njihov zbroj
Autori:
Boris (bm)
Julijan (j)
Okruenje: Penderi MEeee
Gledljivi C++ 7.0 prevoditelj
Zabiljeke: Znam Boris da si ti protiv ovakvih komentara,
ali sam ih morao staviti
Izmjene:
15.07.1996. (j) prva inaica
21.08.1996. (bm) svi podaci su iz float
promijenjeni u int
08.07.2000. (j) iostream.h promijenjen u
iostream te ubaen namespace
**********************************************************/

1.5. Rastavljanje naredbi

29

S druge strane, s koliinom komentara ne treba pretjerivati, jer e u protivnom izvorni


kd postati nepregledan. Naravno da ete izbjegavati komentare poput:
c = a + b;
i++;
y = sqrt(x)

// zbraja a i b
// uveava i za 1
// poziva funkciju sqrt

Nudimo vam sljedee naputke gdje i to komentirati [Strustrup91]:


Na poetku datoteke izvornog kda opisati sadraj datoteke.
Kod deklaracije varijabli, razreda i objekata obrazloiti njihovo znaenje i primjenu.
Ispred funkcije dati opis to radi, to su joj argumenti i to vraa kao rezultat.
Eventualno dati opis algoritma koji se primjenjuje.
Dati saeti opis na mjestima u programu gdje nije potpuno oito to kd radi.
Radi bolje razumljivosti, primjeri u knjizi bit e redovito prekomentirani, tako da e
komentari biti pisani i tamo gdje je iskusnom korisniku jasno znaenje kda. Osim toga,
redovito emo ubacivati komentare uz naredbe za koje bi prevoditelj javio pogreku.

1.5. Rastavljanje naredbi


Razmotrimo jo dva problema vana svakoj poetnici ili poetniku: praznine u izvornom
kdu i produljenje naredbi u vie redaka. U primjerima u knjizi intenzivno emo koristiti
praznine izmeu imena varijabli i operatora, iako ih iskusniji programeri esto
izostavljaju. Tako smo umjesto
c = a + b;

mogli pisati
c=a+b;

Umetanje praznina doprinosi preglednosti kda, a esto je i neophodno da bi prevoditelj


interpretirao djelovanje nekog operatora onako kako mi oekujemo od njega. Ako je
negdje dozvoljeno umetnuti prazninu, tada broj praznina koje se smiju umetnuti nije
ogranien, pa smo tako gornju naredbu mogli pisati i kao
c=

to je jo nepreglednije! Istaknimo da se pod prazninom (engl. whitespace) ne


podrazumijevaju iskljuivo prazna mjesta dobivena pritiskom na razmaknicu (engl.
space), ve i praznine dobivene tabulatorom (engl. tabs) te znakove za pomak u novi red
(engl. newlines).
Naredbe u izvornom kdu nisu ograniene na samo jedan redak, ve se mogu
protezati na nekoliko redaka zavretak svake naredbe jednoznano je odreen znakom
;. Stoga pisanje naredbe moemo prekinuti na bilo kojem mjestu gdje je dozvoljena
praznina, te nastaviti pisanje u sljedeem retku, na primjer

30

1. Oluja kroz jezik C++

c =
a + b;

Naravno da je ovakvim potezom kd iz razmatranog primjera postao nepregledniji.


Razdvajati naredbe u vie redaka ima smisla kod vrlo dugakih naredbi, kada one ne
stanu u jedan redak, odnosno postanu zbog svoje duljine nepregledne. Veina
programera ograniava svoj kd na 60-80 stupaca budui da je to broj znakova koji
standardno stane u jedan redak ispisa na listu A4 formata. Zbog formata knjige duljine
redaka u naim primjerima su manje.
Posebnu panju treba obratiti na razdvajanje znakovnih nizova. Pokuamo li
prevesti sljedei primjer, dobit emo pogreku prilikom prevoenja:
#include <iostream>
using namespace std;
int main() {
// pogreka: nepravilno razdvojeni znakovni niz
cout << "Pojavom jezika C++ ostvaren je
tisuljetni san svih programera" << endl;
return 0;
}

Prevoditelj e javiti pogreku da znakovni niz Pojavom ... ostvaren je nije zakljuen
znakom dvostrukog navodnika, jer prevoditelj ne uoava da se niz nastavlja u sljedeem
retku. Da bismo mu to dali do znanja, zavretak prvog dijela niza treba oznaiti lijevom
kosom crtom \ (engl. backslash):
cout << "Pojavom jezika C++ ostvaren je \
tisuljetni san svih programera" << endl;

pri emu nastavak niza ne smijemo uvui, jer bi prevoditelj dotine praznine prihvatio
kao dio niza. Stoga je u takvim sluajevima preglednije niz rastaviti u dva odvojena
niza:
cout << "Pojavom jezika C++ ostvaren je "
"tisuljetni san svih programera" << endl;

Pritom se ne smije zaboraviti staviti prazninu na kraj prvog ili poetak drugog niza.
Gornji niz mogli smo rastaviti na bilo kojem mjestu:
cout << "Pojavom jezika C++ ostvaren je tis"
"uljetni san svih programera" << endl;

ali je oito takav pristup manje itljiv.


Budui da znak ; oznaava kraj naredbe, mogue je vie naredbi napisati u jednom
retku. Tako smo Moj trei program mogli napisati i na sljedei nain:

1.5. Rastavljanje naredbi

31

#include <iostream>
using namespace std;
int main() {
int a, b, c; cout << "Upii prvi broj:"; cin >> a;
cout << "Upii i drugi broj:"; cin >> b; c = a + b;
cout << "Njihov zbroj je: " << c << endl;
return 0;
}

Program e biti preveden bez pogreke i raditi e ispravno. No, oito je da je ovako
pisani izvorni kd daleko neitljiviji pisanje vie naredbi u istom retku treba
prakticirati samo u izuzetnim sluajevima.

32

1. Oluja kroz jezik C++

33

2. Osnovni tipovi podataka


Postoje dva tipa ljudi: jedni koji nose
nabijene pitolje, drugi koji kopaju...
Clint Eastwood, u filmu Dobar, lo, zao

Svaki program sadri u sebi podatke koje obrauje. Njih moemo podijeliti na
nepromjenjive konstante, odnosno promjenjive varijable (promjenjivice).
Najjednostavniji primjer konstanti su brojevi (5, 10, 3.14159). Varijable su podaci koji
openito mogu mijenjati svoj iznos. Stoga se oni u izvornom kdu predstavljaju ne
svojim iznosom ve simbolikom oznakom, imenom varijable.
Svaki podatak ima dodijeljenu oznaku tipa koja govori o tome kako se dotini
podatak pohranjuje u memoriju raunala, koji su njegovi dozvoljeni rasponi vrijednosti,
kakve su operacije mogue s tim podatkom i sl. Tako razlikujemo cjelobrojne, realne,
logike, pokazivake podatke. U poglavlju koje slijedi upoznat emo se ugraenim
tipovima podataka i pripadajuim operatorima.

2.1. Identifikatori
Mnogim dijelovima C++ programa (varijablama, funkcijama, razredima) potrebno je
dati odreeno ime, tzv. identifikator. Imena koja dodjeljujemo identifikatora su
proizvoljna, uz uvjet da se potuju sljedea tri osnovna pravila:
1. Identifikator moe biti sastavljen od kombinacije slova engleskog alfabeta (A - Z, a z), brojeva (0 - 9) i znaka za podcrtavanje '_' (engl. underscore).
2. Prvi znak mora biti slovo ili znak za podcrtavanje.
3. Identifikator ne smije biti jednak nekoj od kljunih rijei (vidi tablicu 2.1) ili nekoj
od alternativnih oznaka operatora (tablica 2.2). To ne znai da kljuna rije ne moe
biti dio identifikatora moj_int je dozvoljeni identifikator iako je int kljuna rije.
Takoer, treba izbjegavati da naziv identifikatora sadri dvostruke znakove
podcrtavanja (_ _) ili da zapoinje znakom podcrtavanja i velikim slovom, jer su
takve oznake rezervirane za C++ implementacije i standardne biblioteke (npr.
_ _LINE_ _, _ _FILE_ _).
Stoga si moemo pustiti mati na volju pa svoje varijable i funkcije nazivati svakojako.
Pritom je vjerojatno svakom jasno da je zbog razumljivosti kda poeljno imena
odabirati tako da odraavaju stvarno znaenje varijabli, na primjer:
Pribrojnik1
Pribrojnik2
rezultat

33

34

2. Osnovni tipovi podataka

Tablica 2.1. Kljune rijei jezika C++


asm
auto
bool
break
case
catch
char
class
const
const_cast
continue
default
delete
do
double
dynamic_cast

else
enum
explicit
export
extern
false
float
for
friend
goto
if
inline
int
long
mutable
namespace

new
operator
private
protected
public
register
reinterpret_cast
return
short
signed
sizeof
static
static_cast
struct
switch
template

this
throw
true
try
typedef
typeid
typename
union
unsigned
using
virtual
void
volatile
wchar_t
while

a izbjegavati imena poput


Snjeguljica_i_7_patuljaka
MojaPrivatnaVarijabla
FrankieGoesToHollywood
RockyXXVII

Odmah uoimo da nije dozvoljena upotreba naih dijakritikih znakova u


identifikatorima. ak i ako naletite na neki prevoditelj koji bi ih prihvatio, zbog
prenosivosti kda te znakove neizostavno izbjegavajte; program s varijablama
BeiJankec ili TeksakiMasakrMotornjaom na veini prevoditelja prouzroit e
pogreku prilikom prevoenja.
Valja uoiti da jezik C++ razlikuje velika i mala slova u imenima, tako da
identifikatori
maliNarodiVelikeIdeje
MaliNarodiVelikeIdeje
malinarodiVELIKEIDEJE

predstavljaju tri razliita naziva. Takoer, ne postoji teoretsko ogranienje na duljinu


imena, no neki stariji prevoditelji razlikuju imena samo po prvih nekoliko znakova
(pojam nekoliko je ovdje prilino rastezljiv). Stoga e prevoditelj koji uzima u obzir
samo prvih 14 znakova, identifikatore

Tablica 2.2. Alternativne oznake operatora


and
and_eq

bitand
bitor

compl
not

not_eq
or

or_eq
xor

xor_eq

2.2. Varijable, objekti i tipovi

35

Snjeguljica_i_7_patuljaka
Snjeguljica_i_sedam_patuljaka

interpretirati kao iste, iako se razlikuju od petnaestog znaka ('7' odnosno 's') na dalje.
Naravno da dugaka imena treba izbjegavati radi vlastite komocije, posebice za
varijable i funkcije koje se esto ponavljaju.
Ponekad je pogodno koristiti sloena imena zbog boljeg razumijevanja kda. Iz
gornjih primjera itateljica ili itatelj mogli su razluiti dva najea pristupa
oznaavanju sloenih imena. U prvom pristupu rijei od kojih je ime sastavljeno
odvajaju se znakom za podcrtavanje, poput
Snjeguljica_te_sedam_patuljaka

(praznina umjesto znaka podcrtavanja izmeu rijei oznaavala bi prekid imena, to bi


uzrokovalo pogreku prilikom prevoenja). U drugom pristupu rijei se piu spojeno, s
velikim poetnim slovom:
SnjeguljicaTeSedamPatuljaka

Mi emo u primjerima preferirati potonji nain samo zato jer tako oznaene varijable i
funkcije zauzimaju ipak neto manje mjesta u izvornom kdu.
Iako ne postoji nikakvo ogranienje na poetno slovo naziva varijabli, veina
programera preuzela je iz programskog jezika FORTRAN naviku da imena cjelobrojnih
varijabli zapoinje slovima i, j, k, l, m ili n.

2.2. Varijable, objekti i tipovi


Bez obzira na jezik u kojem je pisan, svaki program sastoji se od niza naredbi koje
mijenjaju vrijednosti objekata pohranjenih u memoriji raunala. Raunalo dijelove
memorije u kojima su smjeteni objekti razlikuje pomou pripadajue memorijske
adrese. Da programer tijekom pisanja programa ne bi morao pamtiti memorijske adrese,
svi programski jezici omoguavaju da se vrijednosti objekata dohvaaju preko
simbolikih naziva razumljivih inteligentnim biima poput ljudi-programera. Gledano iz
perspektive obinog raunala (lat. computer vulgaris ex terae Tai-wan), objekt je samo
dio memorije u koji je pohranjena njegova vrijednost u binarnom obliku. Tip objekta,
izmeu ostalog, odreuje raspored bitova prema kojem je taj objekt pohranjen u
memoriju.
U programskom jeziku C++ pod objektima u uem smislu rijei obino se
podrazumijevaju sloeni tipovi podataka opisani pomou posebnih receptura
razreda, to e biti opisano u kasnijim poglavljima. Jednostavni objekti koji pamte jedan
cijeli ili realni broj se esto nazivaju varijablama.
Da bi prevoditelj pravilno preveo na izvorni C++ kd u strojni jezik, svaku
varijablu treba prije njena koritenja u kdu deklarirati, odnosno jednoznano odrediti

36

2. Osnovni tipovi podataka

njen tip. U Naem treem C++ programu varijable su deklarirane u prvom retku
glavne funkcije:
int a, b, c;

Tim deklaracijama je prevoditelju jasno dano do znanja da e varijable a, b i c biti


cjelobrojne prevoditelj e vrijednosti tih varijabli pohranjivati u memoriju prema svom
pravilu za cjelobrojne podatke. Takoer e znati kako treba provesti operacije na njima.
Prilikom deklaracije varijable treba takoer paziti da se u istom dijelu programa (tonije
bloku naredbi, vidi poglavlje 3.1) ne smiju deklarirati vie puta varijable s istim
imenom, ak i ako su one razliitih tipova. Zato e prilikom prevoenja sljedeeg kda
prevoditelj javiti pogreku o viekratnoj deklaraciji varijable a:
int a, b, c;
int a;

// pogreka: ponovno koritenje naziva a

Varijable postaju realna zbiljnost tek kada im se pokua pristupiti, na primjer kada im se
pridrui vrijednost:
a = 2;
b = a;
c = a + b;

Prevoditelj tek tada pridruuje memorijski prostor u koji se pohranjuju podaci. Postupak
deklaracije varijable a i pridruivanja vrijednosti simboliki moemo prikazati slikom
2.1. Lijevo od dvotoke je kuica koja simbolizira varijablu s njenim tipom i imenom.

int
int

aa

int
int
22

Slika 2.1. Deklaracija varijable i pridruivanje vrijednosti

Desno od dvotoke je kuica koja predstavlja objekt s njegovim tipom i konkretnom


vrijednou. Ako nakon toga istoj varijabli a pridruimo novu vrijednost naredbom
a = 5;

tada se u memoriju raunala na mjestu gdje je prije bio smjeten broj 2 pohranjuje broj
5, kako je prikazano slikom 2.2.
Deklaracija varijable i pridruivanje vrijednosti mogu se obaviti u istom retku kda.
Umjesto da piemo poseban redak s deklaracijama varijabli a, b i c i zatim im
pridruujemo vrijednosti, inicijalizaciju moemo provesti ovako:

2.3. Operator pridruivanja

37

int
int

aa

int
int
55

Slika 2.2. Pridruivanje nove vrijednosti

int a = 2;
int b = a;
int c = a + b;

Gornji oblik inicijalizacije naslijeen je iz jezika C i uobiajen je za ugraene tipove


podataka. Meutim, postoji i drugi mogui oblik zapisa naredbi za inicijalizaciju,
takozvanom konstruktorskom sintaksom():
int a(2);
int b(a);

Ovakav zapis redovito se koristi za inicijalizaciju sloenih korisniki definiranih tipova


koji iziskuju dva ili vie parametra prilikom inicijalizacije. Primjerice, prilikom
inicijalizacije kompleksnog broja treba inicijalizirati njegov realni i imaginarni.
Detaljnije o ovakvom nainu inicijalizacije govorit emo u poglavlju o korisniki
definiranim tipovima razredima. Za razliku od programskog jezika C u kojem sve
deklaracije moraju biti na poetku programa ili funkcije, prije prve naredbe, u C++
jeziku ne postoji takvo ogranienje, pa deklaracija varijable moe biti bilo gdje unutar
programa. tovie, mnogi autori preporuuju da se varijable deklariraju neposredno
prije njihove prve primjene.

2.3. Operator pridruivanja


Operatorom pridruivanja mijenja se vrijednost nekog objekta, pri emu tip objekta
ostaje nepromijenjen. Najei operator pridruivanja je znak jednakosti (=) kojim se
objektu na lijevoj strani pridruuje neka vrijednost s desne strane. Ako su objekt s lijeve
strane i vrijednost s desne strane razliitih tipova, vrijednost se svodi na tip objekta
prema definiranim pravilima pretvorbe, to e biti objanjeno u poglavlju 2.4 o tipovima
podataka. Oito je da s lijeve strane operatora pridruivanja mogu biti iskljuivo
promjenjivi objekti, pa se stoga ne moe pisati ono to je inae matematiki korektno:
2 = 4 / 2
3 * 4 = 12
3.14159 = pi

// pogreka!!!
// pogreka!!!
// Bingooo!!! Trea pogreka!

Pokuamo li prevesti ovaj kd, prevoditelj e javiti pogreke. Objekti koji se smiju
nalaziti s lijeve strane znaka pridruivanja nazivaju se lvrijednosti (engl. lvalues, kratica
od left-hand side values). Pritom valja znati da se ne moe svakoj lvrijednosti
pridruivati nova vrijednost neke varijable se mogu deklarirati kao konstantne (vidi

38

2. Osnovni tipovi podataka

poglavlje 2.4.4) i pokuaj promjene njihove vrijednosti prevoditelj e naznaiti kao


pogreku. Stoga se posebno govori o promjenjivim lvrijednostima. S desne strane
operatora pridruivanja mogu biti i lvrijednosti i konstante.
Evo tipinog primjera pridruivanja kod kojeg se ista varijabla nalazi i s lijeve i s
desne strane znaka jednakosti:
int i = 5;
i = i + 3;

Naredbom u prvom retku deklarira se varijabla tipa int, te se njena vrijednost


inicijalizira na 5. Dosljedno gledano, operator = ovdje nema znaenje pridruivanja, jer
se inicijalizacija varijable i provodi ve tijekom prevoenja, a ne prilikom izvoenja
programa. To znai da je broj 5 ugraen u izvedbeni strojni kd dobiven prevoenjem i
povezivanjem programa. Obratimo, meutim, panju na drugu naredbu!
Matematiki gledano, drugi redak u ovom primjeru je besmislen: nema broja koji bi
bio jednak samom sebi uveanom za 3! Ako ga pak gledamo kao uputu raunalu to mu
je initi, onda taj redak treba poeti itati neposredno iza znaka pridruivanja: uzmi
vrijednost varijable i, dodaj joj broj 3..... Doli smo do kraja naredbe (znak ;), pa se
vraamo na operator pridruivanja: ...i dobiveni zbroj s desne strane pridrui varijabli i
koja se nalazi s lijeve strane znaka jednakosti. Nakon izvedene naredbe varijabla i imat
e vrijednost 8.
Jezik C++ dozvoljava vie operatora pridruivanja u istoj naredbi. Pritom
pridruivanje ide od krajnjeg desnog operatora prema lijevo:
a = b = c = 0;

te ih je tako najsigurnije i itati: broj 0 pridrui varijabli c, iju vrijednost pridrui


varijabli b, iju vrijednost pridrui varijabli a. Budui da se svakom od objekata lijevo
od znaka = pridruuje neka vrijednost, svi objekti izuzev onih koji se nalaze desno od
najdesnijeg znaka = moraju biti lvrijednosti:
a = b = c + d;
a = b + 1 = c;

// OK!
// pogreka: b + 1 nije lvrijednost

2.4. Tipovi podataka i operatori


U C++ jeziku ugraeni su neki osnovni tipovi podataka i definirane operacije na njima.
Za te su tipove precizno definirana pravila provjere i pretvorbe. Pravila provjere tipa
(engl. type-checking rules) uoavaju neispravne operacije na objektima, dok pravila
pretvorbe odreuju to e se dogoditi ako neka operacija oekuje jedan tip podataka, a
umjesto njega se pojavi drugi. U sljedeim poglavljima prvo emo se upoznati s
brojevima i operacijama na njima, da bismo kasnije preli na pobrojenja, logike
vrijednosti i znakove.

2.4. Tipovi podataka i operatori

39

2.4.1. Brojevi
U jeziku C++ ugraena su u sutini dva osnovna tipa brojeva: cijeli brojevi (engl.
integers) i realni brojevi (tzv. brojevi s pominom decimalnom tokom, engl. floatingpoint). Najjednostavniji tip brojeva su cijeli brojevi njih smo ve upoznali u Naem
treem C++ programu. Cjelobrojna varijabla deklarira se rijeju int i njena e
vrijednost u memoriji raunala obino zauzeti dva bajta (engl. byte), tj. 16 bitova. Prvi
bit je rezerviran za predznak, tako da preostaje 15 bitova za pohranu vrijednosti. Stoga
se varijablom tipa int mogu obuhvatiti svi brojevi od najmanjeg broja (najveeg
negativnog broja)
215 = 32768
do najveeg broja
215 1 = 32767
Za veinu praktinih primjena taj opseg vrijednosti je dostatan. Meutim, ukae li se
potreba za veim cijelim brojevima varijablu moemo deklarirati kao long int, ili krae
samo long:
long int HrvataUDijasporiZaVrijemeIzbora = 3263456;
long ZrnacaPrasineNaMomRacunalu = 548234581;
// mogao bih uzeti krpu za prainu i svesti to na int!

Takva varijabla e zauzeti u memoriji vie prostora i operacije s njom e dulje trajati.
Cjelobrojne konstante se mogu u izvornom kdu prikazati u razliitima brojevnim
sustavima:
dekadskom,
oktalnom,
heksadekadskom.
Dekadski prikaz je razumljiv veini obinih nehakerskih smrtnika koji se ne sputaju
na razinu raunala. Meutim, kada treba raditi operacije nad pojedinim bitovima, oktalni
i heksadekadski prikazi su daleko primjereniji.
U dekadskom brojevnom sustavu, koji koristimo svakodnevno, postoji 10 razliitih
znamenki (0, 1, 2,..., 9) ijom kombinacijom se dobiva bilo koji eljeni vieznamenkasti
broj. Pritom svaka znamenka ima deset puta veu teinu od znamenke do nje desno. U
oktalnom brojevnom sustavu broj znamenki je ogranien na 8 (0, 1, 2,..., 7), tako da
svaka znamenka ima osam puta veu teinu od svog desnog susjeda. Na primjer, 11 u
oktalnom sustavu odgovara broju 9 u dekadskom sustavu (118 = 910). U
heksadekadskom sustavu postoji 16 znamenki: 0, 1, 2,..., 9, A, B, C, D, E, F. Budui da
za prikaz brojeva postoji samo 10 brojanih simbola, za prikaz heksadekadskih

Kod nas se esto za bajt koristi autohtona hrvatska rije oktet, budui da se byte sastoji od 8
bitova. U engleskom rije byte nema nikakvo izvorno znaenje, ve je samo umjetna
modifikacija rijei bit (engl. komadi, trun, mrvica).
Kao to smo ve spomenuli, ove granine vrijednosti nisu uvijek iste, ve ovise o
implementaciji prevoditelja.

40

2. Osnovni tipovi podataka

znamenki iznad 9 koriste se prva slova engleskog alfabeta, tako da je A16 = 1010,
B16 = 1110, itd. (vidi tablicu 2.3). Oktalni i heksadekadski prikaz predstavljaju
Tablica 2.3. Usporedba brojeva u razliitim sustavima
Dekadski

Oktalno

Heksadekadski

1
2
M
7
8
9
10
11
12
13
14
15
16
17
M
32

1
2
M
7
10
11
12
13
14
15
16
17
20
21
M
40

1
2
M
7
8
9
A
B
C
D
E
F
10
11
M
20

kompromis izmeu dekadskog prikaza kojim se koriste ljudi i binarnog sustava kojim se
podaci pohranjuju u memoriju raunala. Naime, binarni prikaz pomou samo dvije
znamenke (0 i 1) iziskivao bi puno prostora u programskom kdu, te bi bio nepregledan.
Oktalni i heksadekadski prikazi iziskuju manje prostora i iskusnom korisniku omoguuju
brzu pretvorbu brojeva iz dekadskog u binarni oblik i obrnuto.
Oktalne konstante se piu tako da se ispred prve znamenke napie broj 0 iza kojeg
slijedi oktalni prikaz broja:
int SnjeguljicaIPatuljci = 010;

// odgovara dekadsko 8!

Heksadekadske konstante zapoinju s 0x ili 0X:


int TucetPatuljaka = 0x0C;

// dekadsko 12

Slova za heksadekadske znamenke mogu biti velika ili mala.


Vodea nula kod oktalnih brojeva uzrokom je estih poetnikih pogreaka, jer
korisnik obino smatra da e ju prevoditelj zanemariti i interpretirati broj kao obini
dekadski.
Sve konstante koje zapoinju s brojem 0 prevoditelj interpretira kao oktalne
brojeve. To znai da e nakon prevoenja 010 i 10 biti dva razliita broja!

2.4. Tipovi podataka i operatori

41

Jo jednom uoimo da e bez obzira na brojevni sustav u kojem broj zadajemo, njegova
vrijednost u memoriju biti pohranjena prema predloku koji je odreen deklaracijom
pripadne varijable. To najbolje ilustrira sljedei primjer:
int i = 32;
cout << i << endl;
i = 040;
cout << i << endl;

// oktalni prikaz broja 32

i = 0x20;
cout << i << endl;

// heksadekadski prikaz broja 32

Bez obzira to smo varijabli i pridruivali broj 32 u tri razliita prikaza, u sva tri sluaja
na zaslonu e se ispisati isti broj, u dekadskom formatu.
Ako je potrebno raunati s decimalnim brojevima, najee se koriste varijable tipa
float:
float pi = 3.141593;
float brzinaSvjetlosti = 2.997925e8;
float nabojElektrona = -1.6E-19;

Prvi primjer odgovara uobiajenom nainu prikaza brojeva s decimalnim zarezom. U


drugom i treem primjeru brojevi su prikazani u znanstvenoj notaciji, kao umnoak
mantise i potencije na bazi 10 (2,997925108, odnosno 1,61019). Kod prikaza u
znanstvenoj notaciji, slovo 'e' koje razdvaja mantisu od eksponenta moe biti veliko ili
malo.
Praznine unutar broja, na primjer iza predznaka, ili izmeu znamenki i slova
e nisu dozvoljene.
Prevoditelj e broj
float PlanckovaKonst = 6.626 e -34;

// pogreka

interpretirati samo do etvrte znamenke. Prazninu koja slijedi prevoditelj e shvatiti kao
zavretak broja, pa e po nailasku na znak e javiti pogreku.
Osim to je ogranien raspon vrijednosti koje se mogu prikazati float tipom (vidi
tablicu 2.4), treba znati da je i broj decimalnih znamenki u mantisi takoer ogranien na
7 decimalnih mjesta. ak i ako se napie broj s vie znamenki, prevoditelj e zanemariti
sve nie decimalne znamenke. Stoga e ispis varijabli

Broj tonih znamenki ovisi o prevoditelju i o raunalu. U veini sluajeva broj tonih
znamenki i dozvoljene pogreke pri osnovnim aritmetikim operacijama ravnaju se po IEEE
standardu 754 za binarni prikaz brojeva s pominim decimalnim zarezom.

42

2. Osnovni tipovi podataka

float pi_tocniji
= 3.141592654;
float pi_manjeTocan = 3.1415927;

dati potpuno isti broj! Usput spomenimo da su broj i ostale znaajnije matematike
konstante definirani u biblioteci cmath, i to na veu tonost, tako da ukljuivanjem te
datoteke moete prikratiti muke traenja njihovih vrijednosti po raznim prirunicima i
srednjokolskim udbenicima.
Ako tonost na sedam decimalnih znamenki ne zadovoljava ili ako se koriste
brojevi vei od 1038 ili manji od 1038, tada se umjesto float mogu koristiti brojevi s
dvostrukom tonou tipa double koji pokrivaju opseg vrijednosti od 1.710308 do
1.710308, ili long double koji pokrivaju jo iri opseg od 3.4104932 do 1.1104932.
Brojevi vei od 1038 vjerojatno e vam zatrebati samo za neke astronomske proraune,
ili ako ete se baviti burzovnim meetarenjem. Realno gledano, brojevi manji od 1038
nee vam gotovo nikada trebati, osim ako elite izraunati vjerojatnost da dobijete dekpot na lutriji ili da Miloevi zavri u Haagu (ovo je napisano u prosincu 2000.).
Iako double ima veu duljinu i zauzima vie mjesta u memoriji, operacije s double
podacima ne moraju nuno biti sporije nego s podacima tipa float. Naime, velika
veina dananjih procesora ima ugraene instrukcije za aritmetike operacije s
brojevima tipa double pa se te operacije izvode gotovo jednako brzo kao i na kraim
tipovima podataka. Stoga se ne treba previe ustruavati u koritenju podataka tipa
double, naroito gdjegod nam je potrebna iole vea tonost.
U tablici 2.4 dane su tipine duljine ugraenih brojevnih tipova u bajtovima,
rasponi vrijednosti koji se njima mogu obuhvatiti, a za decimalne brojeve i broj tonih
decimalnih znamenki. Duljina memorijskog prostora i opseg vrijednosti koje odreeni
tip varijable zauzima nisu standardizirani i variraju ovisno o prevoditelju i o platformi za
koju se prevoditelj koristi. Stoga itatelju preporuujemo da za svaki sluaj konzultira
dokumentaciju uz prevoditelj koji koristi. Relevantni podaci za cjelobrojne tipove mogu
se nai u datoteci climits, a za decimalne tipove podataka u cfloat. Tako, primjerice
su konstante INT_MIN i INT_MAX (definirane pretprocesorskom naredbom #define u
datoteci climits) jednake najmanjoj (najveoj negativnoj) i najveoj vrijednosti brojeva
tipa int.
Ako elite sami provjeriti veliinu pojedinog tipa, to moete uiniti i pomou
sizeof operatora:
cout
cout
long
cout

<< "Veliina cijelih brojeva: " << sizeof(int);


<< "Veliina realnih brojeva: " << sizeof(float);
double masaSunca = 2e30;
<< "Veliina long double: " << sizeof(masaSunca);

Kod nekih prevoditelja navedeni podaci se nalaze u zaglavljima limits.h odnosno float.h
(koja su naslijeena iz jezika C), a ova su ukljuena u datoteke climits, odn. cfloat (glede
imena vidi slino zapaanje vezano uz iostream biblioteku na str. 24)

2.4. Tipovi podataka i operatori

43

Tablica 2.4. Ugraeni brojevni tipovi, njihove tipine duljine i rasponi vrijednosti

tip konstante

bajtova

raspon vrijednosti

tonost

char

short int
int

2
2
(4)

128 do 127
32768 do 32767

long int

float

3,41038 do 3,41038 i
3,41038 do 3,41038

7 dec. znamenki

double

1,710308 do 1,710308 i
1,710308 do 1,710308

15 dec. znamenki

long double

10

1,1104932 do 3,4104932 i
3,4104932 do 1,1104932

18 dec. znamenki

32768 do 32767
2147483648 do 2147483647
2147483648 do 2147483647

Gornje naredbe e ispisati broj bajtova koliko ih zauzimaju podaci tipa int, float,
odnosno double. Najvee i najmanje vrijednosti moete vidjeti ispisom odgovarajuih
konstanti iz prije navedenih climits i cfloat datoteka:
cout
cout
cout
cout
cout
cout

<<
<<
<<
<<
<<
<<

"Najmanji int: " << INT_MIN;


"Najvei int: " << INT_MAX;
"Najmanji long: " << LONG_MIN;
"Najvei long: " << LONG_MAX;
"Najvei float: " << FLT_MAX;
"Najmanji double: " << DBL_MIN;

Kada ete isprobavati gornji kd, nemojte zaboraviti ukljuiti zaglavlja climits i
cfloat!
Svi navedeni brojevni tipovi mogu biti deklarirani i bez predznaka, dodavanjem
rijei unsigned ispred njihove deklaracije:
unsigned int i = 40000;
unsigned long int li;
unsigned long double BrojZvijezdaUSvemiru;

U tom sluaju e prevoditelj bit za predznak upotrijebiti kao dodatnu binarnu znamenku,
pa se najvea mogua vrijednost udvostruuje u odnosu na varijable s predznakom, ali
se naravno ograniava samo na pozitivne vrijednosti. Pridruimo li unsigned varijabli
negativan broj, ona e poprimiti vrijednost nekog pozitivnog broja. Na primjer,
programski slijed
unsigned int i = -1;
cout << i << endl;

44

2. Osnovni tipovi podataka

e za varijablu i ispisati broj 65535 (ili 4294967295, ovisno o broju bajtova koji se
koriste za pohranjivanje int brojeva). Uoimo da je taj broj za 1 manji od najveeg
dozvoljenog unsigned int broja 65536 (odnosno 4294967296). Zanimljivo da
prevoditelj za gornji kd nee javiti pogreku.
Prevoditelj ne prijavljuje pogreku ako se unsigned varijabli pridrui
negativna konstanta korisnik mora sam paziti da se to ne dogodi!
Stoga ni za ivu glavu nemojte u programu za evidenciju stanja na tekuem raunu
koristiti unsigned varijable. U protivnom se lako moe dogoditi da ostanete bez
ekovne iskaznice, a svoj bijes iskalite na raunalu, ni krivom ni dunom.
2.4.2. Aritmetiki operatori
Da bismo objekte u programu mogli mijenjati, na njih treba primijeniti odgovarajue
operacije. Za ugraene tipove podataka definirani su osnovni operatori, poput zbrajanja,
oduzimanja, mnoenja i dijeljenja (vidi tablicu 2.5). Ti operatori se mogu podijeliti na
unarne, koji djeluju samo na jedan objekt, te na binarne za koje su neophodna dva
objekta. Osim unarnog plusa i unarnog minusa koji mijenjaju predznak broja, u jeziku
C++ definirani su jo i unarni operatori za uveavanje (inkrementiranje) i umanjivanje
vrijednosti (dekrementiranje) broja. Operator ++ uveat e vrijednost varijable za 1, dok
e operator --) umanjiti vrijednost varijable za 1:
int i = 0;
++i;
cout << i << endl;

// uvea za 1
// ispisuje 1

Tablica 2.5. Aritmetiki operatori


+x
-x

unarni operatori

x++
++x
x---x
x + y
x - y

binarni operatori

x * y
x / y
x % y

unarni plus
unarni minus
uveaj nakon
uveaj prije
umanji nakon
umanji prije
zbrajanje
oduzimanje
mnoenje
dijeljenje
modulo

2.4. Tipovi podataka i operatori

45

--i;
cout << i << endl;

// umanji za 1
// ispisuje 0

Pritom valja uoiti razliku izmeu operatora kada je on napisan ispred varijable i
operatora kada je on napisan iza nje. U prvom sluaju (prefiks operator), vrijednost
varijable e se prvo uveati ili umanjiti, a potom e biti dohvaena njena vrijednost. U
drugom sluaju (postfiks operator) je obrnuto: prvo se dohvati vrijednost varijable, a tek
onda slijedi promjena. To najbolje doarava sljedei kd:
int i =
cout <<
cout <<
cout <<
cout <<
cout <<

1;
i << endl;
(++i) << endl;
i << endl;
(i++) << endl;
i << endl;

//
//
//
//
//

ispii za svaki sluaj


prvo povea, pa ispisuje 2
ispisuje opet, za svaki sluaj
prvo ispisuje, a tek onda uvea
vidi, stvarno je uveao!

Na raspolaganju imamo pet binarnih aritmetikih operatora: za zbrajanje, oduzimanje,


mnoenje, dijeljenje i modulo operator:
float a
float b
cout <<
cout <<
cout <<
cout <<

= 2.;
= 3.;
(a + b)
(a - b)
(a * b)
(a / b)

<<
<<
<<
<<

endl;
endl;
endl;
endl;

//
//
//
//

ispisuje
ispisuje
ispisuje
ispisuje

5.
-1.
6.
0.666667

Operator modulo kao rezultat vraa ostatak dijeljenja dva cijela broja:
int i = 6;
int j = 4;
cout << (i % j) << endl;

// ispisuje 2

On se vrlo esto koristi za ispitivanje djeljivosti cijelih brojeva: ako su brojevi djeljivi,
ostatak nakon dijeljenja e biti nula.
Za razliku od veine matematiki orijentiranih jezika, jezik C++ nema ugraeni
operator za potenciranje, ve programer mora sam pisati funkciju ili koristiti funkciju
pow(). iz standardne matematike biblioteke deklarirane u datoteci zaglavlja cmath.
Valja uoiti dva sutinska problema vezana uz aritmetike operatore. Prvi problem
vezan je uz pojavu numerikog preljeva, kada uslijed neke operacije rezultat nadmai
opseg koji dotini tip objekta pokriva. Drugi problem sadran je u pitanju kakvog e
tipa biti rezultat binarne operacije s dva broja razliitih tipova?.
Razmotrimo pojavu brojanog preljeva. Donje naredbe e prvo ispisati najvei broj
tipa int. Izvoenjem naredbe u treem retku, na zaslonu raunala e se umjesto tog
broja uveanog za 1 ispisati najvei negativni int (32768 ili 2147483648)!
int i = INT_MAX;
cout << i << endl;
cout << (++i) << endl;

46

2. Osnovni tipovi podataka

Uzrok tome je preljev podataka do kojeg dolo zbog toga to oekivani rezultat vie ne
stane u bitove predviene za int varijablu. Podaci koji su se prelili uli su u bit za
predznak (zato je rezultat negativan), a raspored preostalih bitova daje broj koji
odgovara upravo onom to nam je raunalo ispisalo. Slino e se dogoditi oduzmete li
od najveeg negativnog broja neki broj. Ovo se moe ilustrirati brojevnom krunicom na
kojoj zbrajanje odgovara kretanju po krunici u smjeru kazaljke na satu, a oduzimanje
odgovara kretanju u suprotnom smjeru (slika 2.3).
Ako postoji mogunost pojave numerikog preljeva, tada deklarirajte
varijablu s veim opsegom u gornjem primjeru umjesto int uporabite
long int.
Gornja situacija moe se poistovjetiti s kupovinom automobila na sajmu rabljenih
automobila. Naravno da auto star 10 godina nije preao samo 5000 kilometara koliko
pie na brojau kilometara (kilometer-cajgeru), ve je nakon 99999 kilometara broja
ponovno krenuo od 00000. Budui da broja ima mjesta za 5 znamenki najvia
znamenka se izgubila! Sutinska razlika je jedino u tome da je kod automobila do
preljeva dolo hardverskom intervencijom prethodnog vlasnika, dok u programu do
preljeva obino dolazi zbog nepanje programera pri izradi programa.
Ponekad se pojava preljeva moe izbjei promjenom redoslijeda operacija.
Pogledajmo to na primjeru raunanja aritmetike sredine dva broja:
int prvi = INT_MAX - 1;
int drugi = i - 2;
int AritSred = (prvi + drugi) / 2;

Zagrade oko zbroja su neophodne, jer dijeljenje ima vii prioritet od zbrajanja (o
hierarhiji operacija govorit emo u odjeljku 2.7) da zagrada nema, s 2 bi se dijelio

-1

oduzimanje

-2

-3

zbrajanje

int

32766

-32767
-32768

32767

Slika 2.3. Prikaz preljeva na brojevnoj krunici

2.4. Tipovi podataka i operatori

47

samo drugi pribrojnik. Oba su pribrojnika manja od najveeg dozvoljenog broja tipa int
pa od toga mora biti manja i njihova aritmetika sredina. Meutim, meurezultat (zbroj
oba pribrojnika prije dijeljenja s 2) e premaiti tu granicu doi e do njegovog
preljeva zbog ega e i krajnji rezultat biti pogrean. No, prepiemo li zadnju naredbu na
drugi nain:
int AritSred = prvi / 2 + drugi / 2;

opasnost od preljeva emo otkloniti.


Slino vrijedi i za realne brojeve (tipa float i double). Napomenimo da neki
prevoditelji prije aritmetikih operacija podatke tipa float pretvaraju u tip double i
operacije obavljaju s tako proirenim brojevima. Tek po zavretku operacija, rezultat
vraaju u tip float. Zbog toga e tee doi do preljeva u meurezultatu, a samim tim je
smanjena mogunost pogreke u krajnjem rezultatu. Meutim, kako Standard ne
propisuje da se dva float broja prije meusobne aritmetike moraju pretvoriti u double
(kao to e se vidjeti u tekstu koji slijedi), ne treba se previe oslanjati na ovakvo
ponaanje, posebice ako elimo da kd jednako radi i na drugim prevoditeljima.
Drugo pitanje vezano na aritmetike operatore koje se namee jest kakvog e biti
tipa rezultat binarne operacije na dva broja. Za ugraene tipove tono su odreena
pravila uobiajene aritmetike pretvorbe. Ako su oba operanda istog tipa, tada je i
rezultat tog tipa, a ako su operandi razliitih tipova, tada se oni prije operacije svode na
zajedniki tip (to je obino sloeniji tip), prema sljedeim pravilima [ISO/IEC1998]:
1. Ako je jedan od operanada tipa long double, tada se i drugi operand pretvara u
long double.
2. Inae, ako je jedan od operanada tipa double, tada se i drugi operand pretvara u
double.
3. Inae, ako je jedan od operanada tipa float, tada se i drugi operand pretvara u
float.
4. Inae, se provodi cjelobrojna promocija (engl. integral promotion) oba operanda
(ovo je bitno samo za operande tipa bool, wchar_t i pobrojenja, tako da emo o
cjelobrojnoj promociji govoriti u odgovarajuim poglavljima o tim tipovima).
5. Potom, ako je jedan od operanada unsigned long, tada se i drugi operand pretvara u
unsigned long.
6. U protivnom, ako je jedan od operanada tipa long int, a drugi operand tipa
unsigned int, ako long int moe obuhvatiti sve vrijednosti unsigned int,
unsigned int se pretvara u long int; inae se oba operanda pretvaraju u
unsigned long int.
7. Inae, ako je jedan od operanada tipa long, tada se i drugi operand pretvara u long.
8. Inae, ako je jedan od operanada unsigned, tada se i drugi operand pretvara u
unsigned.
Na primjer, izvoenje kda

48

2. Osnovni tipovi podataka

int i = 3;
float a = 0.5;
cout << (a * i) << endl;

uzrokovat e ispis broja 1.5 na zaslonu, jer je od tipova int i float sloeniji tip float.
Cjelobrojnu varijablu i prevoditelj prije mnoenja pretvara u float (prema pravilu u
toki 3), tako da se provodi mnoenje dva broja s pominom tokom, pa je i rezultat tipa
float. Da smo umnoak prije ispisa pridruili nekoj cjelobrojnoj varijabli
int c = a * i;
cout << c << endl;

dobili bismo ispis samo cjelobrojnog dijela rezultata, tj. broj 1. Decimalni dio rezultata
se gubi prilikom pridruivanja umnoka cjelobrojnoj varijabli c.
Problem pretvorbe brojevnih tipova najjae je izraen kod dijeljenja cijelih brojeva,
to poetnicima (ali i nepaljivim C++ guruima) zna prouzroiti dosta glavobolje.
Pogledajmo sljedei jednostavni primjer:
int Brojnik = 1;
int Nazivnik = 4;
float Kvocijent = Brojnik / Nazivnik;
cout << Kvocijent << endl;

Suprotno svim pravilima zapadnoeuropske klasine matematike, na zaslonu e se kao


rezultat ispisati 0., tj. najobinija nula! Koristi li vae raunalo aborianski brojevni
sustav, koji poznaje samo tri broja (jedan, dva i puno)? Iako smo rezultat dijeljenja
pridruili float varijabli, pri izvoenju programa to pridruivanje slijedi tek nakon to
je operacija dijeljenja dva cijela broja bila zavrena (ili, u duhu junoslavenske narodne
poezije, Kasno float na Dijeljenje stie!). Budui da su obje varijable, Brojnik i
Nazivnik cjelobrojne, prevoditelj provodi cjelobrojno dijeljenje u kojem se zanemaruju
decimalna mjesta. Stoga je rezultat cjelobrojni dio kvocijenta varijabli Brojnik i
Nazivnik (0.25), a to je 0. Slina je situacija i kada dijelimo cjelobrojne konstante:
float DiskutabilniKvocijent = 3 / 2;

Brojeve 3 i 2 prevoditelj e shvatiti kao cijele, jer ne sadre decimalnu toku. Zato e
primijeniti cjelobrojni operator /, pa e rezultat toga dijeljenja biti cijeli broj 1.
Da bi se izbjegle sve nedoumice ovakve vrste, dobra je programerska navada
sve konstante koje trebaju biti s pominom decimalnom tokom (float i
double) pisati s decimalnom tokom, ak i kada nemaju decimalnih mjesta.
Evo pravilnog naina da se provede eljeno dijeljenje:
float TocniKvocijent = 3. / 2.;

2.4. Tipovi podataka i operatori

49

Dovoljno bi bilo decimalnu toku staviti samo uz jedan od operanada prema pravilima
aritmetike pretvorbe i drugi bi operand bio sveden na float tip. Iako je kd ovako
dulji, izaziva manje nedoumica i stoga svakom poetniku preporuujemo da ne tedi na
decimalnim tokama.
Neupueni poetnik postavit e logino pitanje zato uope postoji razlika izmeu
cjelobrojnog dijeljenja i dijeljenja decimalnih brojeva. Za programera bi bilo
najjednostavnije kada bi se oba operanda bez obzira na tip, prije primjene operatora
svela na float (ili jo bolje, na double), na takve modificirane operande primijenio
eljeni operator, a dobiveni rezultat se pretvorio u zajedniki tip. U tom sluaju
programer uope ne bi trebao paziti kojeg su tipa operandi rezultat bi uvijek bio
korektan (osim ako nemate procesor s pogrekom, to i nije nemogue). Nedostatak
ovakvog pristupa jest njegova neefikasnost. Zamislimo da treba zbrojiti dva broja tipa
int! U gornjem programer-ne-treba-paziti pristupu, izvedbeni kd dobiven nakon
prevoenja trebao bi prvo jedan cjelobrojni operand pretvoriti u float. Budui da se
razliiti tipovi podataka pohranjuju u memoriju raunala na razliite naine, ta pretvorba
nije trivijalna, ve iziskuje odreeni broj strojnih instrukcija. Istu pretvorbu treba
ponoviti za drugi operand. Ve sada uoavamo dvije operacije pretvorbe tipa koje kod
izravnog zbrajanja cijelih brojeva ne postoje! tovie, samo zbrajanje se provodi na dva
float-a, koji u memoriji zauzimaju vei prostor od int-a. Takvo zbrajanje iziskivat e
puno vie strojnih instrukcija i strojnog vremena, ne samo zbog vee duljine float
brojeva u memoriji, ve i zbog sloenijeg naina na koji su oni pohranjeni. Za mali broj
operacija korisnik zasigurno ne bi osjetio razliku u izvoenju programa s izravno
primijenjenim operatorima i operatorima la programer-ne-treba-paziti. Meutim, u
sloenim programima s nekoliko tisua ili milijuna operacija, ta razlika moe biti
zamjetna, a esto i kritina. U krajnjoj liniji, shvatimo da prevoditelj poput vjernog psa
nastoji to bre ispuniti gospodarevu zapovijed, ne pazei da li e pritom protrati kroz
upravo ureen susjedin cvjetnjak ili zagaziti u svjee betoniran plonik.
Zadatak. to e ispisati sljedee naredbe:
int a = 10;
float b = 10.;
cout << a / 3 << endl;
cout << b / 3 << endl;

Zadatak. Da li e postojati razlika pri ispisu u donjim naredbama (varijable a i b


deklarirane su u prethodnom zadatku):
float c
cout <<
c = a /
cout <<
c = b *
cout <<

= a
c *
3.;
c *
a;
c /

/ 3;
b << endl;
b << endl;
3 << endl;

50

2. Osnovni tipovi podataka

2.4.3. Operator dodjele tipa

to uiniti elimo li podijeliti dvije cjelobrojne varijable, a da pritom ne izgubimo


decimalna mjesta? Dodavanje decimalne toke iza imena varijable nema smisla, jer e
prevoditelj javiti pogreku. Za eksplicitnu promjenu tipa varijable valja primijeniti
operator static_cast kojim se nekom izrazu eksplicitno moe dodjeliti tip (engl. type
cast, krae samo cast):
int Brojnik = 1;
int Nazivnik = 3;
float TocniKvocijent = static_cast<float>(Brojnik) /
static_cast<float>(Nazivnik);

Openiti oblik primjene operatora static_cast jest:


static_cast< Tip >( izraz )

gdje se izmeu znakova < i > (manje i vee) navodi tip u koji elimo pretvoriti
izraz unutar zagrada koje slijede. U gornjem kdu se tako vrijednosti varijabli Brojnik
i Nazivnik pretvaraju u tip float prije nego to se one meusobno podijele, tako da je
krajni rezultat korektan. Naravno, bilo bi dovoljno operator dodjele tipa primijeniti
samo na jedan operand prema pravilima aritmetike pretvorbe i drugi bi operand bio
sveden na float tip. Da ne bi bilo zabune, same varijable Brojnik i Nazivnik i nadalje
ostaju tipa int, tako da e njihovo naknadno dijeljenje
float OpetKriviKvocijent = Brojnik / Nazivnik;

opet kao rezultat dati kvocijent cjelobrojnog dijeljenja.


Koritenje operatora dodjele tipa je najee pokazatelj loeg dizajna (Zato su
Brojnik i Nazivnik deklarirani kao int ako elimo s njima provesti float
dijeljenje?), tim vie to on predstavlja mogui izvor programskih pogreaka
njegovom uporabom programer onemoguava striktnu provjeru tipa koju provodi
prevoditelj. Meutim, postoje sluajevi kada ga jednostavno ne moemo izbjei
[Lipmann98]:
kada pokaziva tipa void * (neodreenog tipa) moramo usmjeriti na pokaziva
zadanog tipa (o pokazivaima e biti rijei u 4. poglavlju);
kada elimo izbjei standardne pretvorbe (spomenute u prethodnom odjeljku)
kada nije jednoznano odreeno u koji e se tip odreeni objekt pretvoriti, jer postoji
mogunost vie pretvorbi (ovo je izraeno kod korisniki definiranih tipova koji su
izvedeni iz vie razliitih tipova ovaj problem bit e obraen u poglavlju 8
posveenom nasljeivanju)

Takoer, operator dodjele tipa esto se koristi kada se koristi naslijeeni kd kojeg je
nezgodno mijenjati; ubacivanjem dodjela tipa iskljuuju se upozorenja o neistovjetnosti
tipova podataka koja bi inae prevoditelj izbacivao.

2.4. Tipovi podataka i operatori

51

Prije uvoenja operatora static_cast u zavrnoj inaici standarda, dodjela tipa u


jeziku C++ se obavljala na identian nain kao i u jeziku C navoenjem dodijeljenog
tipa u okruglim zagradama () ispred izraza:
float TocniKvocijent = (float)Brojnik / (float)Nazivnik;

Jezik C++ dozvoljavao je i funkcijski oblik dodjele tipa u kojem se tip navodi ispred
zagrade, a ime varijable u zagradi:
float TocniKvocijent2 = float(Brojnik) / float(Nazivnik);

Iako su ova dva oblika dodjele tipa u potpunosti podrana standardom, njihova upotreba
se ne preporuuje.
Operator dodjele tipa moe se koristiti i u obrnutom sluaju, kada elimo iz
decimalnog broja izluiti samo cjelobrojne znamenke:
float a = 3.1415926
cout << "Cijeli dio broja a: " << static_cast<int>(a) << endl;

O operatorima dodjele tipa bit e jo detaljno govora u 12. poglavlju koje se bavi
identifikacijom tipa tijekom izvoenja.
Zadatak. Odredite koje e od navedenih naredbi za ispis:
int a = 100000;
int b = 200000;
long c = a * b;
cout
cout
cout
cout
cout

<<
<<
<<
<<
<<

c << endl;
(a * b) << endl;
(static_cast<float>(a) * b) << endl;
static_cast<long>(a * b) << endl;
(a * static_cast<long>(b)) << endl;

dati ispravan umnoak, tj. 20 000 000 000.


Zadatak. Odredite to e se ispisati na zaslonu po izvoenju sljedeeg kda:
float a = 2.71;
float b = static_cast<int>a;
cout << b << endl;

2.4.4. Dodjeljivanje tipa brojanim konstantama

Kada se u kdu pojavljuju brojane konstante, prevoditelj ih pohranjuje u formatu nekog


od osnovnih tipova. Tako s brojevima koji sadre decimalnu toku ili slovo e, odnosno
E, prevoditelj barata kao s podacima tipa double, dok sve ostale brojeve tretira kao int.
Operatore dodjele tipa mogue primijeniti i na konstante, na primjer:

52

2. Osnovni tipovi podataka

cout << static_cast<long>(10) << endl;


cout << static_cast<unsigned>(60000) << endl;

// long int
// unsigned int

ee se za specificiranje konstanti koriste sufiksi, posebni znakovi kojima se


eksplicitno odreuje tip brojane konstante (vidi tablicu 2.6). Tako e sufiks l, odnosno
L cjelobrojnu konstantu pretvoriti u long, a konstantu s decimalnom tokom u double:
long HrvatskiDugovi = 3457630455475571952525L;
long double a = 1.602e-4583L / 645672L;
// (long double) / long

dok e sufiksi u, odnosno U cjelobrojne konstante pretvoriti u unsigned int:


cout << 65000U << endl;

// unsigned int

Sufiks f, odnosno F e konstantu s decimalnom tokom pretvoriti u float:


float b = 1.234F;

Velika i mala slova sufiksa su potpuno ravnopravna. U svakom sluaju je preglednije


koristiti veliko slovo L, da bi se izbjegla zabuna zbog slinosti slova l i broja 1.
Takoer, sufiksi L (l) i U (u) za cjelobrojne podatke mogu se meusobno kombinirati u
bilo kojem redoslijedu (LU, UL, Ul, uL, ul, lu...) rezultat e uvijek biti
unsigned long int.
Sufiksi se rijetko koriste, budui da u veini sluajeva prevoditelj obavlja sam
neophodne pretvorbe, prema ve spomenutim pravilima. Izuzetak je, naravno pretvorba
double u float koju provodi sufiks F.
Tablica 2.6. Djelovanje sufiksa na brojane konstante

broj ispred sufiksa

sufiks

rezultirajui tip

cijeli

L, l
U, u

int
long int
unsigned int

decimalni

F, f
L, l

double
float
long double

2.4.5. Simbolike konstante

U programima se redovito koriste simbolike veliine ija se vrijednost tijekom


izvoenja ne eli mijenjati. To mogu biti fizike ili matematike konstante, ali i

2.4. Tipovi podataka i operatori

53

parametri poput maksimalnog broja prozora ili maksimalne duljine znakovnog niza, koji
se namjetaju prije prevoenja kda i ulaze u izvedbeni kd kao konstante.
Zamislimo da za neki zadani polumjer elimo izraunati i ispisati opseg krunice,
povrinu kruga, oploje i volumen kugle. Pri raunanju sve etiri veliine treba nam
Ludolfov broj =3,14159...:
float Opseg = 2.
float Povrsina =
double Oplosje =
double Volumen =

* r * 3.14159265359;
r * r * 3.14159265359;
4. * r * r * 3.14159265359;
4. / 3. * r * r * r * 3.14159265359;

Naravno da bi jednostavnije i pouzdanije bilo definirati zasebnu varijablu koja e


sadravati broj :
double pi = 3.14159265359;
float Opseg = 2. * r * pi;
float Povrsina = r * r * pi;
double Oplosje = 4. * r * r * pi;
double Volumen = 4. / 3. * r * r * r * pi;

Manja je vjerojatnost da emo pogrijeiti prilikom utipkavanja samo jednog broja, a


osim toga, ako se (kojim sluajem, jednog dana) promijeni vrijednost broja , bit e
lake ispraviti ga kada je definiran samo na jednom mjestu, nego raditi pretraivanja i
zamjene brojeva po cijelom izvornom kdu.
Pretvaranjem konstantnih veliina u varijable izlaemo ih pogibelji od nenamjerne
promjene vrijednosti. Nakon izvjesnog vremena jednostavno zaboravite da dotina
varijabla predstavlja konstantu, te negdje u kdu dodate naredbu
pi = 2 * pi;

kojom ste promijenili vrijednost varijable pi. Prevoditelj vas nee upozoriti (Opet taj
prokleti kompjutor!) i dobit ete da zemaljska kugla ima dva puta vei volumen nego
to ga je imala proli puta kada ste koristili isti program, ali bez inkriminirane naredbe.
Koristite li program za odreivanje putanje svemirskog broda, ovakva pogreka sigurno
e rezultirati odailjanjem broda u bespua svemirske zbiljnosti.
Da bismo izbjegli ovakve peripetije, na raspolaganju nam je kvalifikator const
kojim se prevoditelju daje na znanje da varijabla mora biti nepromjenjiva. Na svaki
pokuaj promjene vrijednosti takve varijable, prevoditelj e javiti pogreku:
const double pi = 3.14159265359;
pi = 2 * pi;

// sada je to pogreka!

Drugi esto koriteni pristup zasniva se na pretprocesorskoj naredbi #define:


#define PI 3.14159265359

54

2. Osnovni tipovi podataka

Ona daje uputu prevoditelju da, prije nego to zapone prevoenje izvornog kda, sve
pojave prvog niza (PI) zamijeni drugim nizom znakova (3.14159265359). Stoga e
prevoditelj naredbe
double Volumen = 4. / 3. * r * r * r * PI;
PI = 2 * PI;

// pogreka

interpretirati kao da se u njima umjesto simbola PI nalazi odgovarajui broj. U drugoj


naredbi e javiti pogreku, jer se taj broj naao s lijeve strane operatora pridruivanja.
Valja napomenuti da se ove zamjene nee odraziti u izvornom kdu i on e nakon
prevoenja ostati nepromijenjen.
Na prvi pogled nema razlike izmeu pristupa oba pristupa e osigurati prijavu
pogreke pri pokuaju promjene konstante. Razlika postaje oita tek kada pokuate
program ispraviti koristei program za simboliko lociranje pogreaka (engl. debugger,
doslovni prijevod bio bi istjeriva stjenica, odnosno stjeniji terminator). Ako ste
konstantu definirali pretprocesorskom naredbom, njeno ime nee postojati u simbolikoj
tablici koju prevoditelj generira, jer je prije prevoenja svaka pojava imena
nadomjetena brojem. Ne moete ak ni provjeriti da li ste moda pogrijeili prilikom
poziva imena.
Konstante definirane pomou deklaracije const dohvatljive su i iz programa
za simboliko lociranje pogreaka.
Napomenimo da vrijednost simbolike konstante mora biti inicijalizirana prilikom
deklaracije. U protivnom emo dobiti poruku o pogreki:
const float mojaMalaKonstanta;

// pogreka

Prilikom inicijalizacije vrijednosti nismo ogranieni na brojeve moemo pridruiti i


vrijednost neke prethodno definirane varijable. Vrijednost koju pridruujemo konstanti
ne mora biti ak ni zapisana u kdu:
float a;
cin >> a;
const float DvijeTrecine = a;

2.4.6. Kvalifikator volatile

U prethodnom odsjeku smo deklarirali konstantne objekte ime smo ih zatitili od


neovlatenih promjena. Svi ostali objekti su promjenjivi (engl. volatile). Promjenjivost
objekta se moe naglasiti tako da se ispred tipa umetne kljuna rije volatile:
volatile Tip ime_promjenjivice;

2.4. Tipovi podataka i operatori

55

Time se prevoditelju daje na znanje da se vrijednost varijable moe promijeniti njemu


nedokuivim nainima, te da zbog toga mora iskljuiti sve optimizacije kda prilikom
pristupa.
Valja razjasniti koji su to naini promjene koji su izvan prevoditeljevog znanja. Na
primjer, ako razvijamo sistemski program, vrijednost memorijske adrese se moe
promijeniti unutar obrade prekida (engl. interrupt) time prekidna rutina moe
signalizirati programu da je odreeni uvjet zadovoljen. U tom sluaju prevoditelj ne
smije optimizirati pristup navedenoj varijabli. Na primjer:
int izadjiVan = 0;
while (!izadjiVan) {
// ekaj dok se vrijednost izadjiVan ne postavi na 1
}

U gornjem primjeru prevoditelj analizom petlje moe zakljuiti da se varijabla


izadjiVan ne mijenja unutar petlje, te e optimizirati izvoenje tako da se vrijednost
varijable izadjiVan uope ne testira. Prekidna rutina koja e eventualno postaviti
vrijednost izadjiVan na 1 zbog toga nee okonati petlju. Da bismo to sprijeili,
izadjiVan moramo deklarirati kao volatile:
volatile int izadjiVan;

2.4.7. Pobrojenja

Ponekad su varijable u programu elementi pojmovnih skupova, tako da je takvim


skupovima i njihovim elementima zgodno pridijeliti lakopamtljiva imena. Za takve
sluajeve obino se koriste pobrojani tipovi (engl. enumerated types, enumeration):
enum dani {ponedjeljak, utorak, srijeda,
cetvrtak, petak, subota, nedjelja};

Ovom deklaracijom uvodi se novi tip podataka dani, te sedam nepromjenjivih


identifikatora (ponedjeljak, utorak,...) toga tipa. Prvom identifikatoru prevoditelj
pridjeljuje vrijednost 0, drugom 1, itd. Sada moemo definirati varijablu tipa dani, te joj
pridruiti neku od vrijednosti iz niza:
dani HvalaBoguDanasJe = petak;
dani ZakajJaNeVolim = ponedjeljak;

Naredbom
cout << HvalaBoguDanasJe << endl;

na zaslonu se ispisuje cjelobrojni ekvivalent za petak, tj. broj 4.


Varijable tipa dani mogli smo deklarirati i neposredno uz definiciju pobrojanog
tipa:

56

2. Osnovni tipovi podataka

enum dani{ponedjeljak, utorak, srijeda, cetvrtak,


petak, subota, nedjelja} ThankGodItIs, SunnyDay;
ThankGodItIs = petak;
SunnyDay = nedjelja;

U pobrojanim nizovima podrazumijevana vrijednost prve varijable je 0. elimo li da niz


poinje nekom drugom vrijednou, treba eksplicitno pridijeliti eljenu vrijednost:
enum dani {ponedjeljak = 1, utorak, srijeda,
cetvrtak, petak, subota, nedjelja};

Identifikator utorak poprima vrijednost 2, srijeda 3, itd. U ovom sluaju, kd


dani ZecUvijekDolaziU = nedjelja;
cout << ZecUvijekDolaziU << endl;

na zaslonu ispisuje broj 7.


Eksplicitno pridjeljivanje moe se primijeniti i na bilo koji od ostalih lanova, s
time da e slijedei lan, ako njegova vrijednost nije eksplicitno definirana, imati za 1
veu vrijednost:
enum likovi {kruznica = 0,
trokut = 3,
pravokutnik = 4,
kvadrat = 4,
cetverokut = 4,
peterokut,
sedmerokut = cetverokut + 3};
cout
cout
cout
cout
cout

<<
<<
<<
<<
<<

kruznica << endl;


trokut << endl;
kvadrat << endl;
peterokut << endl;
sedmerokut << endl;

//
//
//
//
//

ispisuje
ispisuje
ispisuje
ispisuje
ispisuje

0
3
4
5
7

Ako nam ne treba vie varijabli tog tipa, ime tipa iza rijei enum moe se izostaviti:
enum {NE = 0, DA} YesMyBabyNo, ShouldIStayOrShouldIGo;
enum {TRUE = 1, FALSE = 0};

Pobrojane vrijednosti mogu se koristiti u aritmetikim izrazima. U takvim sluajevima


se prvo provodi cjelobrojna promocija (engl. integral promotion) pobrojane vrijednosti
ona se pretvara u prvi mogui cjelobrojni tip naveden u slijedu: int, unsigned int,
long ili unsigned long. Na primjer:
enum {DVOSTRUKI = 2, TROSTRUKI};
int i = 5;
float pi = 3.14159;

2.4. Tipovi podataka i operatori

cout << DVOSTRUKI * i << endl;


cout << TROSTRUKI * pi << endl;

57

// ispisuje 10
// ispisuje 9.42477

Meutim, pobrojanim tipovima ne mogu se pridruivati cjelobrojne vrijednosti, pa e


prevoditelj za sljedei primjer javiti pogreku:
dani VelikiPetak = petak;
dani DolaziZec = VelikiPetak + 2;

// pogreka

Prilikom zbrajanja pobrojeni tip VelikiPetak svodi se na tip zajedniki sa cijelim


brojem 2 (a to je int). Dobiveni rezultat tipa int treba pridruiti pobrojenom tipu, to
rezultira pogrekom prilikom prevoenja. Da bi gornja operacija prola, trebamo
operatorom dodjele tipa taj int pretvoriti u tip dani:
dani DolaziZec = static_cast<dani>(VelikiPetak + 2);

// OK!

2.4.8. Logiki tipovi i operatori

Logiki podaci su takvi podaci koji mogu poprimiti samo dvije vrijednosti, na primjer:
da/ne, istina/la, dan/no. Jezik C++ za prikaz podataka logikog tipa ima ugraen tip
bool, koji moe poprimiti vrijednosti true (engl. true tono) ili false (engl. false
pogreno):
bool JeLiDanasNedjelja = true;
bool SloboZeliIzZemlje = false;
bool NjofraMozeIzZemlje = false;

Pri ispisu logikih tipova, te pri njihovom koritenju u aritmetikim izrazima, logiki
tipovi se pravilima cjelobrojne promocije (vidi prethodno poglavlje) pretvaraju u int:
true se pretvara u cjelobrojni 1, a false u 0. Isto tako, logikim varijablama se mogu
pridruivati aritmetiki tipovi: u tom sluaju se vrijednosti razliite od nule pretvaraju u
true, a nula se pretvara u false.
Gornja svojstva tipa bool omoguavaju da se za predstavljanje logikih podataka
koriste i cijeli brojevi. Broj 0 u tom sluaju odgovara logikoj neistini, a bilo koji broj
razliit od nule logikoj istini. Iako je za logiku istinu na raspolaganju vrlo iroki
raspon cijelih brojeva (zlobnici bi rekli da ima vie istina), ona se ipak najee zastupa
brojem 1. Ovakvo predstavljanje logikih podataka je vrlo esto, budui da je tip bool
vrlo kasno uveden u standard jezika C++.

Programski jezik C dozvoljava da se pobrojanom tipu pridrui int vrijednost. Zato, radi
prenosivosti kda pisanog u programskom jeziku C, te kda pisanog u starijim varijantama
jezika C++, ANSI/ISO C++ standard dozvoljava da se u nekim implementacijama prevoditelja
omogui to pridruivanje, uz napomenu da to moe prouzroiti neeljene efekte.
Rije bool dolazi od prezimena engleskog matematiara Georgea Boolea (18151864),
utemeljitelja logike algebre.

58

2. Osnovni tipovi podataka

Za logike podatke definirana su svega


tri operatora: ! (logika negacija), &&
(logiki i), te || (logiki ili) (tablica 2.7).
!x
logika negacija
Logika negacija je unarni operator koji
x && y
logiki i
mijenja logiku vrijednost varijable: istinu
x || y
logiki ili
pretvara u neistinu i obrnuto. Logiki i daje
kao rezultat istinu samo ako su oba operanda
istinita; radi boljeg razumijevanja u tablici 2.8 dani su rezultati logikog i za sve mogue
vrijednosti oba operanda. Logiki ili daje istinu ako je bilo koji od operanada istinit
(vidi tablicu 2.9).
Tablica 2.7. Logiki operatori

Tablica 2.8. Stanja za logiki i

tono
tono
pogreno
pogreno

(1)
(1)
(0)
(0)

tono
pogreno
tono
pogreno

a .i. b

(1)
(0)
(1)
(0)

tono
pogreno
pogreno
pogreno

(1)
(0)
(0)
(0)

Razmotrimo primjenu logikih operatora na sljedeem primjeru:


enum Logicki{NEISTINA, ISTINA, DRUGAISTINA = 124};
Logicki a = NEISTINA;
Logicki b = ISTINA;
Logicki c = DRUGAISTINA;
cout <<
<<
cout <<
cout <<
cout <<

"a = " << a << ", b = " << b


", c = " << c << endl;
"Suprotno od a = " << !a << endl;
"Suprotno od b = " << !b << endl;
"Suprotno od c = " << !c << endl;

Tablica 2.9. Stanja za logiki ili

tono
tono
pogreno
pogreno

(1)
(1)
(0)
(0)

tono
pogreno
tono
pogreno

a .ili. b

(1)
(0)
(1)
(0)

tono
tono
tono
pogreno

(1)
(1)
(1)
(0)

| je znak koji je na tipkovnici oznaen prekinutom crtom . Na MS Windowsima taj se znak, uz


hrvatski raspored tipkovnice, dobiva istovremenim pritiskom na tipke <Ctrl>,<Alt> i <W>

2.4. Tipovi podataka i operatori

59

cout << "a .i. b = " << (a && b) << endl;


cout << "a .ili. c = " << (a || c) << endl;

Unato tome da smo varijabli c pridruili vrijednost DRUGAISTINA = 124, njenom


logikom negacijom dobiva se 0, tj. logika neistina. Operacija a-logiki i-b daje
neistinu (broj 0), jer operand a ima vrijednost pogreno, dok a-logiki ili-c daje istinu,
tj. 1, jer operand c ima logiku vrijednost tono.
Logiki operatori i operacije s njima uglavnom se koriste u naredbama za grananje
toka programa, pa emo ih tamo jo detaljnije upoznati.
Budui da su logiki podaci tipa bool dosta kasno uvrteni u standard C++ jezika,
stariji prevoditelji ne podravaju taj tip podataka. elite li na starijem prevoditelju
prevesti program koji je pisan u novoj verziji jezika, tip bool moete simulirati tako da
na poetak programa dodate sljedee pobrojenje:
enum bool {false, true};

2.4.9. Poredbeni operatori

Osim aritmetikih operacija, jezik C++ omoguava i usporedbe dva broja (vidi tablicu
2.10). Kao rezultat usporedbe dobiva se tip bool: ako je uvjet usporedbe zadovoljen,
rezultat je true, a ako nije rezultat je false. Tako e se izvoenjem kda
cout
cout
cout
cout
cout
cout

<<
<<
<<
<<
<<
<<

(5
(5
(5
(5
(5
(5

> 4) << endl;


>= 4) << endl;
< 4) << endl;
<= 4) << endl;
== 4) << endl;
!= 4) << endl;

//
//
//
//
//
//

je
je
je
je
je
je

li
li
li
li
li
li

5
5
5
5
5
5

vee od 4?
vee ili jednako 4?
manje od 4?
manje ili jednako 4?
jednako 4?
razliito od 4?

na zaslonu ispisati redom brojevi 1, 1, 0, 0, 0 i 1.


Tablica 2.10. Poredbeni operatori
x
x
x
x
x
x

< y
<= y
> y
>= y
== y
!= y

manje od
manje ili jednako
vee od
vee ili jednako
jednako
razliito

Poredbeni operatori (ponekad nazvani i relacijski operatori od engl. relational


operators) se koriste preteito u naredbama za grananje toka programa, gdje se, ovisno o
tome je li neki uvjet zadovoljen, izvoenje programa nastavlja u razliitim smjerovima.

60

2. Osnovni tipovi podataka

Stoga emo poredbene operatore podrobnije upoznati kod naredbi za grananje, u


poglavlju 3.
Uoimo sutinsku razliku izmeu jednostrukog znaka jednakosti (=) koji je
simbol za pridruivanje, te dvostrukog znaka jednakosti (==) koji je operator
za usporedbu!
to e se dogoditi ako umjesto operatora pridruivanja =, pogrekom u nekom izrazu
napiemo operator usporedbe ==? Na primjer:
int a = 3;
a == 5;

U drugoj naredbi e se umjesto promjene vrijednosti varijable a, ona usporediti s brojem


5. Rezultat te usporedbe je false, odnosno 0, ali to ionako nema nikakvog znaaja, jer
se rezultat usporedbe u ovom sluaju ne pridruuje niti jednoj varijabli naredba nema
nikakvog efekta. A to je najgore, prevoditelj nee prijaviti pogreku, ve moda samo
upozorenje! Kod sloenijeg izraza poput
a = 1.23 * (b == c + 5);

to upozorenje e izostati, jer ovdje poredbeni operator moe imati smisla. Za poetnike
jedno od nezgodnih svojstava jezika C++ jest da trpi i besmislene izraze, poput:
i + 5;

ili
i == 5 == 6;

Bolji prevoditelji e u gornjim primjerima prilikom prevoenja dojaviti upozorenje o


tome da kd nema efekta.
2.4.10. Znakovi

Znakovne konstante tipa char piu se uglavnom kao samo jedan znak unutar
jednostrukih znakova navodnika:
char SlovoA = 'a';
cout << 'b' << endl;

Za znakove koji se ne mogu prikazati na zaslonu koriste se posebne sekvence (engl.


escape sequence) koje poinju lijevom kosom crtom (engl. backslash) (tablica 2.11). Na
primjer, kd
cout << '\n';

// znak za novi redak

2.4. Tipovi podataka i operatori

61

Tablica 2.11. Posebni znakovi


\n
\t
\v
\b
\r
\f
\a
\\
\?
\'
\"
\0
\ddd
\xddd

novi redak
horizontalni tabulator
vertikalni tabulator
pomak za mjesto unazad (backspace)
povrat na poetak retka (carriage return)
nova stranica (form feed)
zvuni signal (alert)
kosa crta ulijevo (backslash)
upitnik
jednostruki navodnik
dvostruki navodnik
zavretak znakovnog niza
znak iji je kd zadan oktalno s 1, 2 ili 3 znamenke
znak iji je kd zadan heksadekadski

uzrokovat e pomak znake na poetak sljedeeg retka, tj. ekvivalentan je ispisu


konstante endl.
Znakovne konstante najee se koriste u znakovnim nizovima (engl. strings) za
ispis tekstova, te emo ih tamo detaljnije upoznati. Za sada samo spomenimo da se
znakovni nizovi sastoje od nekoliko znakova unutar dvostrukih navodnika. Zanimljivo je
da se char konstante i varijable mogu usporeivati, poput brojeva:
cout
cout
cout
cout

<<
<<
<<
<<

('a' < 'b') <<


('a' < 'B') <<
('A' > 'a') <<
('\'' != '\"')

endl;
endl;
endl;
<< endl;

// usporedba jednostrukog
// i dvostrukog navodnika

pri emu se u biti usporeuju njihovi brojani kdovi u nekom od standarda.


Najraireniji je ASCII niz (kratica od American Standard Code for Information
Interchange) u kojem su svim ispisivim znakovima, brojevima i slovima engleskog
alfabeta pridrueni brojevi od 32 do 127, dok specijalni znakovi imaju kdove od 0 do
31 ukljuivo. U prethodnom primjeru, prva naredba ispisuje 1, jer je ASCII kd malog
slova a (97) manji od kda za malo slovo b (98). Druga naredba ispisuje 0, jer je ASCII
kd slova B jednak 66 (nije vano to je B po abecedi iza a!). Trea naredba ispisuje 0,
jer za veliko slovo A kd iznosi 65. ASCII kdovi za jednostruki navodnik i dvostruki
navodnik su 39 odnosno 34, pa zakljuite sami to e etvrta naredba ispisati.
Znakovi se mogu usporeivati sa cijelim brojevima, pri emu se oni pretvaraju u
cjelobrojni kdni ekvivalent. Naredbom
cout << (32 == ' ') << endl;

// usporedba broja 32 i praznine

62

2. Osnovni tipovi podataka

ispisat e se broj 1, jer je ASCII kd praznine upravo 32.


tovie, na znakove se mogu primjenjivati i svi aritmetiki operatori. Budui da se
pritom znakovi cjelobrojnom promocijom pretvaraju u cijele brojeve, za njih vrijede ista
pravila kao i za operacije sa cijelim brojevima. Ilustrirajmo to sljedeim primjerom:
char a = 'h';
char b;
cout << (a + 1) << endl;
b = a + 1;
cout << b << endl;

// ASCII kd 104
// ispisuje 105
// ispisuje 'i'

Kod prvog ispisa znakovna varijabla a (koja ima vrijednost slova h) se, zbog operacije
sa cijelim brojem 1, pretvara se u ASCII kd za slovo h, tj. u broj 104, dodaje joj se 1, te
ispisuje broj 105. Druga naredba za ispis daje slovo i, jer se broj 105 pridruuje
znakovnoj varijabli b, te se 105 ispisuje kao ASCII znak, a ne kao cijeli broj.
Zadatak. Razmislite i provjerite to e se ispisati izvoenjem sljedeeg kda:
char a = 'a';
char b = a;
int asciiKod = a;
cout << a << endl;
cout << b << endl;
cout << 'b' << endl;
cout << asciiKod << endl;

Za pohranjivanje znakova iji kd ne stane u tip char moe se koristiti tip wchar_t.
Razjasnimo ukratko problem pohranjivanja znakova.
char tip podataka je duljine 1 bajta, tj. 8 bitova. Budui da se s 8 bitova moe
prikazati 28=256 razliitih brojeva (tj. brojevi od 0 do 255), to znai da e se tipom char
moi istovremeno prikazati najvie 256 znakova. ASCII je rezervirao kdove od 0 do
127 za znakove engleskog alfabeta i specijalne znakove (interpunkcija, kontrolni
kdovi) za nacionalne znakove neengleskih jezika preostali su kodovi od 127 do 255.
Taj skup je dovoljan da obuhvati jezino specifine znakove samo za nekoliko jezika.
Tako primjerice prema ISO-8859-1 kdiranju taj skup popunjavaju znakovi
zapadnoeuropskih pisama, dok ga prema ISO-8859-2 kdiranju popunjavaju znakovi
srednjeeuropskih jezika (ukljuujui Hrvatski).
Time je rijeen problem razmjene tekstova unutar podruja u kojem se koristi isto
8-bitno kodiranje. Na primjer, poaljete li datoteku s naim slovima kodiranu prema
ISO-8859-2 standardu nekom Maaru, on e sve nae znakove vidjeti korektno, jer se i
u Maarskoj koristi taj standard. Meutim, poaljete li taj dokument nekome Dancu (ili
bilo kome u zapadnoj Europi), njemu e se umjesto naih slova pojaviti potpuno
drugaiji znakovi (npr. umjesto slova , on e na ekranu imati slovo ). Uspije li

Dodue, postoje neki lokalni 7-bitni standardi koji znakove unutar ASCII skupa
nadomjetaju jeziki specifinim znakovima, no oni se danas uglavnom naputaju.

2.4. Tipovi podataka i operatori

63

promijeniti kodiranje tako da mu se prikae pravi znak, vie nee imati na raspolaganju
svoje znakove.
Da se izbjegnu ovakva ogranienja u razmjeni dokumenata, napravljen je
univerzalni svjetski standard Unicode. U taj su standard ukljueni znakovi svih
svjetskih pisama (ukljuujui irilicu, arapsko, japansko, kinesko pismo) pa e zbog toga
bilo koji dokument pisan u Unicodu biti korektno prikazan u bilo kojem dijelu svijeta.
Da bi se obuhvatili svi znakovi, kd za pojedine znakove trebalo je proirit na 2 bajta
(to daje mjesto za 65536 razliitih znakova). Koritenjem Unicoda u programima
olakava se izrada programa za jezino razliita podruja.
Na alost, da bi se Unicode mogao koristiti, treba ga podravati operacijski sustav
koji se vrti na raunalu i koji je zaduen za pretvorbu brojanih kdova u grafiki prikaz
na zaslonu. U ovom trenutku praktiki ne postoji operacijski sustav koji bi izravno
podravao Unicode, ve se obavljaju translacije iz Unicoda u neki lokalni 8-bitni
standard i onda se takvi znakovi prikazuju.
wchar_t tip omoguava pohranjivanje znakova po Unicode standardu pa tako
moemo unutar istog programa kombinirati slova razliitih pisama (naravno, uz
pretpostavku operacijski sustav podrava Unicode):
wchar_t
wchar_t
wchar_t
wchar t

DomaceJeDomace = L'';
OvakoToPisuPrekoDrine = L'';
NegdjeDalje = L'';
JosDalje = L'';

Prefix L naznaava da je znak unutar apostrofa tipa wchar_t. Duljina tipa wchar_t nije
definirana standardom jezika C++; ona mora biti jednaka duljini nekog cjelobrojnog
tipa. Na prevoditelju koji smo koristili pri pisanju knjige ona je iznosila dva bajta, tako
da smo u jedan znak tipa wchar_t mogli smjestiti dva "obina" znaka (uoite da sada
nema prefiksa L ispred apostrofa):
wchar_t podebljiZnak = 'ab';

2.4.11. Bitovni operatori

Velika prednost jezika C++ je to omoguava


izravne operacije na pojedinim bitovima
podataka. Na raspolaganju je est operatora:
bitovni komplement, bitovni i, bitovni ili,
bitovni iskljuivi ili, bitovni pomak udesno i
bitovni pomak ulijevo (tablica 2.12). Valja
napomenuti da su bitovni operatori definirani
samo za cjelobrojne (int, long int) operande.
Operator komplementiranja ~ (tilda) je
unarni operator koji mijenja stanja pojedinih
bitova, tj. sve bitove koji su jednaki nuli

Tablica 2.12. Bitovni operatori


~i
i & j
i | j
i ^ j
i << n
i >> n

komplement
binarni i
binarni ili
iskljuivi ili
pomakni ulijevo
pomakni udesno

64

2. Osnovni tipovi podataka

postavlja u 1, a sve bitove koji su 1 postavlja u 0. Tako e binarni broj 001001012


komplementiranjem prijei u 110110102, kako je prikazano na slici 2.4.
B7

B6

B5

B4

B3

B2

B1

B0

1
~00100101 = 11011010

B7

B6

B5

B4

B3

B2

B1

B0

Slika 2.4. Bitovni komplement

Zbog toga e se izvoenjem kda


unsigned char a = 0x25;
unsigned char b = ~a;

// 00100101 u heksadek.prikazu
// pridrui bitovni komplement

cout << hex << static_cast<int>(a) << endl;


// ispisuje a u hex-formatu
cout << static_cast<int>(b) << endl;
// ispisuje b u hex-formatu

ispisati heksadekadski broj 25 i njegov bitovni komplement, heksadekadski broj da (tj.


11011010 u binarnom prikazu). U gornjem kdu uoavamo hex manipulator za izlazni
tok, kojim smo osigurali da ispis svih brojeva koji slijede bude u heksadekadskom
formatu. Manipulator hex definiran je u iostream biblioteci. Operator dodjele tipa
static_cast<int> pri ispisu je neophodan, jer bi se bez njega umjesto heksadekadskih
brojeva ispisali pripadajui ASCII znakovi.
Poneki itatelj e se sigurno upitati zato smo u gornjem primjeru varijable a i b
deklarirali kao unsigned char. Varijabla tipa char ima duljinu samo jednog bajta, tj.
zauzima 8 bitova, tako da e varijabla a nakon pridruivanja vrijednosti 0x25 u memoriji
imati zaista oblik 00100101. Prilikom komplementiranja, ona se proiruje u int, tj.
dodaje joj se jo jedan bajt nula (ako int brojevi zauzimaju dva bajta), tako da ona
postaje 00000000 00100101. Komplement tog broja je 11111111 11011010 (FFDA16),
ali kako se taj rezultat pridruuje unsigned char varijabli b, vii bajt (lijevih 8 bitova) se
gubi, a preostaje samo nii bajt (DA16). Da smo varijablu b deklarirali kao int, lijevih 8
bitova bi ostalo, te bismo na zaslonu dobili ispis heksadekadskog broja ffda. Paljivi
itatelj e odmah primijetiti da je za varijablu a potpuno svejedno da li je deklarirana
kao char ili kao int ona se ionako prije komplementiranja pretvara u int. Nju smo
deklarirali kao unsigned char samo radi dosljednosti s varijablom b.
Zadatak. Razmislite (i eventualno provjerite) to se dobiva izvoenjem gornjeg kda
ako je int duljine 4 bajta, a varijable a i b se definiraju da su tipa int.

Manipulatori e biti detaljno obraeni u poglavlju 15. Ulazni i izlazni tokovi.

2.4. Tipovi podataka i operatori

65

Operator & (bitovni i) postavlja u 1 samo one bitove koji su kod oba operanda
jednaki 1 (slika 2.5); matematikom terminologijom reeno, trai se presjek bitova dvaju
brojeva.

B7

B6

B5

B4

B3

B2

B1

00100101 & 00001111 = 00000101

B0

1
Slika 2.5. Bitovni operator i

Bitovni i se najee koristi kada se ele pojedini bitovi broja postaviti u 0


(obrisati) ili ako se ele izdvojiti samo neki bitovi broja. Drugi operand je pritom maska
koja odreuje koji e se bitovi postaviti u nulu, odnosno koji e se bitovi izluiti. Za
postavljanje odreenih bitova u nulu svi bitovi maske na tim mjestima moraju biti
jednaki 0. Ako u gornjem primjeru uzmemo da je maska donji operand, tj. 000011112,
tada moemo rei da smo kao rezultat dobili gornji broj u kojem su etiri najznaajnija
(tj. lijeva) bita obrisana. etiri preostala bita su ostala nepromijenjena, jer maska na tim
mjestima ima jedinice, iz ega odmah slijedi zakljuak da u maski za izluivanje svi
bitovi koje elimo izluiti iz prvog broja moraju biti jednaki 1. Ako u gornjem primjeru
uzmemo da je maska donji operand, kao rezultat smo dobili stanja etiri najnia bita
gornjeg operanda. Zbog svojstva komutativnosti moemo rei i da je prvi broj maska
pomou koje briemo, odnosno vadimo odreene bitove drugog broja. Izvorni kd za
gornju operaciju mogli bismo napisati kao:
int a = 0x0025;
int maska = 0x000f;
cout << hex << (a & maska) << endl;

Izvoenjem se ispisuje broj 5.


Operator | (bitovni ili) postavlja u 1 sve one bitove koji su u bilo kojem od
operanada jednaki 1 (slika 2.6); matematikim rjenikom trai se unija bitova dvaju
brojeva. Bitovni ili se najee koristi za postavljanje odreenih bitova u 1. Drugi
operand je pritom maska koja mora imati 1 na onim mjestima koja elimo u broju
postaviti. U gornjem primjeru postavili smo sva etiri najnia bita lijevog broja u 1.
Stoga e niz naredbi:

66

2. Osnovni tipovi podataka

B7

B6

B5

B4

B3

B2

B1

00100101 | 00001111 = 00101111

B0

Slika 2.6. Bitovni operator ili

int a = 0x0025;
int maska = 0x000f;
cout << hex << (a | maska) << endl;

na zaslonu ispisati heksadekadski broj 2F.


Operator ^ (iskljuivi ili, ponekad nazvan i ex-ili, engl. exclusive or) postavlja u 1
samo one bitove koji su kod oba operanda meusobno razliiti (slika 2.7). On se
uglavnom koristi kada se ele promijeniti stanja pojedinih bitova. Odgovarajua maska
mora u tom sluaju imati 1 na mjestima bitova koje elimo promijeniti:
int a = 0x0025;
int maska = 0x000f;
cout << hex << (a ^ maska) << endl;

B7

B6

B5

B4

B3

B2

B1

// ispisuje 0x2a

00100101 ^ 00001111 = 00101010

B0

Slika 2.7. Bitovni operator iskljuivo ili

Zanimljivo je uoiti da ponovna primjena maske vraa broj u izvornu vrijednost:


cout << hex << (a ^ maska ^ maska) << endl;

// ispisuje 0x25

2.4. Tipovi podataka i operatori

67

Ova injenica esto se koristi za jednostavnu zatitu podataka ili kda od nepoeljnog
itanja, odnosno koritenja: primjenom iskljuivog ili na podatke pomou tajne maske
podaci se ifriraju. Ponovnom primjenom iskljuivog ili s istom maskom podaci se
vraaju u izvorni oblik.
Operatori << (pomak ulijevo, engl. shift left) i >> (pomak udesno, engl. shift right)
pomiu sve bitove lijevog operanda za broj mjesta odreen desnim operandom, kako je
prikazano na slici 2.8.

00100101 >> 2 = 00001001


00100101 << 1 = 01001010

B7

0
B7

B6

B5

B4

B3

B2

B1

B5

B4

B3

B2

B1

B5

B4

B3

B2

B1

B0

1
0

B6

B0

B7

B7

B6

B6

B5

B4

B3

B2

B1

B0

B0

0
B7

B6

B5

B4

B3

B2

B1

B0

Slika 2.8. Bitovni pomaci ulijevo, odnosno udesno

Pri pomaku ulijevo najznaajniji (tj. krajnji lijevi) bitovi se gube, dok najmanje
znaajni bitovi poprimaju vrijednost 0. Slino, pri pomaku udesno, gube se najmanje
znaajni bitovi, a najznaajniji bitovi poprimaju vrijednost 0. Uoimo da pomak bitova
u cijelim brojevima za jedno mjesto ulijevo odgovara mnoenju broja s 2 situacija je
potpuno identina dodavanju nula iza dekadskog broja, samo to je kod dekadskog broja
baza 10, a u binarnoj notaciji je baza 2. Slino, pomak bitova za jedno mjesto udesno
odgovara dijeljenju cijelog broja s 2:
int a = 20;
cout << (a << 1) << endl;
cout << (a >> 2) << endl;

// pomak za 1
//
ispisuje
// pomak za 2
//
ispisuje

bit ulijevo 40
bita udesno 5

Meutim, pri koritenju pomaka valja biti krajnje oprezan, jer se kod cjelobrojnih
konstanti s predznakom najvii bit koristi za predznak. Ako je broj negativan, tada se
pomakom ulijevo bit predznaka e se izgubiti, a na njegovo mjesto e doi najvia
binarna znamenka. Kod pomaka udesno bit predznaka ulazi na mjesto najvie znamenke.
Istina, neki prevoditelji vode rauna o bitu predznaka, ali se zbog prenosivosti kda ne
treba previe oslanjati na to.

68

2. Osnovni tipovi podataka

Mogunost izravnog pristupa pojedinim bitovima esto se koristi za stvaranje


skupova logikih varijabli pohranjenih u jednom cijelom broju, pri emu pojedini bitovi
tog broja predstavljaju zasebne logike varijable. Takvim pristupom se tedi na
memoriji, jer umjesto da svaka logika varijabla zauzima zasebne bajtove, u jednom je
bajtu pohranjeno osam logikih varijabli. Ilustrirajmo to primjerom u kojem se
definiraju parametri za prijenos podataka preko serijskog prikljuka na raunalu. Radi
lakeg praenja, izvorni kd emo ralaniti na segmente, koje emo analizirati zasebno.
Za serijsku komunikaciju treba, osim brzine prijenosa izraene u baudima, definirati
broj bitova po podatku (7 ili 8), broj stop-bitova (1 ili 2), te paritet (parni paritet, neparni
paritet ili bez pariteta). Uzmimo da na raspolaganju imamo osam brzina prijenosa: 110,
150, 300, 600, 1200, 2400, 4800 i 9600 bauda. Svakoj toj brzini pridruit emo po jedan
broj u nizu od 0 do 7:
enum {Baud110 = 0, Baud150, Baud300, Baud600,
Baud1200, Baud2400, Baud4800, Baud9600};

Budui da imamo brojeve od 0 do 7, moemo ih smjestiti u tri najnia bita B0 - B2 (vidi


sliku 2.9). Podatak o broju bitova po podatku pohranit emo u B3; ako se prenosi 7
bitova po podatku bit B3 je jednak 0, a ako se prenosi 8 bitova po podatku onda je 1.
Binarni broj koji ima trei bit postavljen odgovara broju 08 u heksadekadskom prikazu
(0000 10002 = 0816):
enum {Bitova7 = 0x00, Bitova8 = 0x08};

Broj stop-bitova pohranit emo u B4 i B5. Ako se trai jedan stop-bit, tada e B4 biti 1,
a za dva stop-bita B5 je jednak 1:
enum {StopB1 = 0x10, StopB2 = 0x20};

Konano, podatke o paritetu emo pohraniti u dva najvia bita (B6 - B7):
enum {ParitetNjet = 0x00, ParitetNeparni = 0x40,
ParitetParni = 0x80};

Uoimo da smo sva gornja pobrojenja mogli saeti u jedno.


elimo li sada definirati cjelobrojnu varijablu SerCom u kojoj e biti sadrani svi
parametri, primijenit emo bitovni operator ili:
int SerCom = Baud1200 | Bitova8 | StopB2 | ParitetNjet;

kojim se odreeni bitovi postavljaju u stanje 1. Rezultirajui raspored bitova prikazan je


na slici 2.9.
Kako iz nekog zadanog bajta s parametrima izluiti relevantne informacije? Za to
trebamo na cijeli bajt primijeniti masku kojom emo odstraniti sve nerelevantne bitove.
Na primjer, za brzinu prijenosa vani su nam samo bitovi B0 - B3, tako da emo

2.4. Tipovi podataka i operatori

B7

0
B7

0
B7

0
B7

B6

B5

0
B6

0
B5

0
B6

0
B5

0
B6

1
B5

bez
pariteta
$"%"&
B7

B6

69

B4

0
B4

0
B4

0
B4

B3

0
B3

1
B3

0
B3

B2

B1

1
B2

0
B1

0
B2

0
B1

0
B2

0
B1

B0

Baud1200 |

B0

Bitova8 |

B0

StopB2 |

B0

ParitetNjet

8 bitova
podataka
$%&

B5

B4

"

"!

B3

B2

B1

""

2 stop-bita

B0

0
""!

1200 bauda

Slika 2.9. Primjer rasporeda bitovnih parametara za serijsku komunikaciju

bitovnim i operatorom s brojem koji u binarnom prikazu ima 1 na tim mjestima (tj. s 07
heksadekadsko), izluiti podatak o brzini (vidi sliku 2.10):
int Speed = SerCom & 0x07;

// dobiva se 4

Prenosi li se osam bitova podataka provjerit emo sljedeom bitovnom ili operacijom:
int JeLiOsamBita = SerCom & 0x08;

// dobiva se 8

budui da 816 ima u binarnom prikazu 1 samo na mjestu B3. Ako je bit B3 postavljen, tj.
ako ima vrijednost 1, varijabla JeLiOsamBita e poprimiti vrijednost dekadsko (i
heksadekadsko!) 8; u protivnom e biti 0.
Analogno, za izluivanje broja stop-bitova posluit emo se maskom 3016 koja na
mjestima B4 i B5 ima 1:
B7

0
B7

0
B7

B6

0
B6

0
B6

B5

0
B5

1
B5

B4

0
B4

0
B4

B3

0
B3

1
B3

B2

1
B2

1
B2

B1

1
B1

0
B1

B0

00000111 &

B0

SerCom

B0

00000100

Slika 2.10. Primjena bitovne maske i operatora i

70

2. Osnovni tipovi podataka

1
B7

B6

"""

B5

B4

B3

"""!

B2

B1

B0

00100000 >> 4

$"""%"""&
B7

B6

B5

B4

B3

B2

B1

B0

00000010

Slika 2.11. Pomak udesno za etiri bita

int BrojStopBita = SerCom & 0x30;

// dobiva se 32

U naem primjeru kao rezultat emo dobiti 32. Ako rezultantu bitovnu strukturu
pomaknemo udesno za 4 mjesta tako da B4 i B5 dou na B0 odnosno B1 (slika 2.11):
BrojStopBita = BrojStopBita >> 4;

dobit emo upravo broj stop-bitova, tj. broj 2.


Zadatak. Napiite kd u kojem e se int varijabla nekiBroj mnoiti s 4 pomakom
bitova ulijevo. Prije pomaka pohranite bit predznaka u cjelobrojnu varijablu predznak,
a nakon pomaka vratite predznak rezultatu! Napravite to isto i za dijeljenje s 2.
2.4.12. Operatori pridruivanja (2 )

Osim ve obraenog operatora =, jezik C++ za aritmetike i bitovne operatore podrava


i operatore obnavljajueg pridruivanja (engl. update assignment) koji se sastoje se od
znaka odgovarajueg aritmetikog ili bitovnog operatora i znaka jednakosti. Operatori
obnavljajueg pridruivanja omoguavaju krai zapis naredbi. Na primjer, naredba
a += 5;

ekvivalentna je naredbi
a = a + 5;

U tablici 2.13 dani su svi operatori pridruivanja. Primjenu nekolicine operatora


ilustrirat emo sljedeim kdom

Tablica 2.13. Operatori pridruivanja


=

+=

-=

*=

/=

%=

>>=

<<=

^=

&=

|=

2.4. Tipovi podataka i operatori

int n = 10;
n += 5;
cout << n <<
n -= 20;
cout << n <<
n *= -2;
cout << n <<
n %= 3;
cout << n <<

71

//
//
//
//
//
//
//
//

endl;
endl;
endl;
endl;

isto kao: n =
ispisuje: 15
isto kao: n =
ispisuje: -5
isto kao: n =
ispisuje: 10
isto kao: n =
ispisuje 1

n + 5
n - 20
n * (-2)
n % 3

Pri koritenju operatora obnavljajueg pridruivanja valja znati da operator


pridruivanja ima nii prioritet od svih aritmetikih i bitovnih operatora. Stoga, elimo li
naredbu
a = a - b - c;

napisati krae, neemo napisati


a -= b - c;

// to je zapravo a = a - (b - c)

ve kao
a -= b + c;

// a = a - (b + c)

Operator -= ima nii prioritet od ostalih aritmetikih operatora. Izraz s desne


strane je zapravo izraz u zagradi ispred znaka oduzimanja.

2.4.13. Alternativne oznake operatora

Na nekim starijim operacijskim sustavima (npr. starije inaice MS DOS-a) koristilo se 7bitno kodiranje, gdje za prikaz svih znakova stoji na raspolaganju samo 128 kdova. Da
bi se s takvim kodiranjem mogli prikazati nacionalni znakovi, neki rjee koriteni
specijalni znakovi poput [, ], {, }, |, \, ~ i ^ nadomjeteni su u pojedinim europskim
jezicima nacionalnim znakovima kojih nema u engleskom alfabetu. Tako su u hrvatskoj
inaici (udomaenoj pod nazivom CROSCII) ti znakovi nadomjeteni slovima , , , ,
, , , odnosno . Oito je da e na raunalu koje podrava samo takav sustav znakova
biti nemogue pregledno napisati ak i najjednostavniji C++ program. Na primjer, na
zaslonu bi kd nekog trivijalnog programa mogao izgledati ovako (onaj tko deifrira
kd, zasluuje bronani Velered Bjarnea Stroustrupa, bez pletera):
int main()
int a = 5;
char b = '0';
int c = a b;
return 0;

72

2. Osnovni tipovi podataka

Budui da prevoditelj interpretira kdove pojedinih znakova, a ne njihove grafike


prezentacije na zaslonu, program e biti preveden korektno. Meutim, za ovjeka je kd
neitljiv. Osim toga, ispis programa neete moi poslati svom prijatelju u Njemakoj,
koji ima svojih briga jer umjesto vitiastih zagrada ima znakove i .
Da bi se izbjegla ogranienja ovakve vrste, ANSI komitet je predloio alternativne
oznake za operatore koji sadre problematine znakove (tablica 2.14). Uz to, za istu

Tablica 2.14. Alternativne oznake operatora

osnovna

alternativa

osnovna

{
}
[
]
#
##

<%
%>
<:
:>
%:
%:%:

&&
||
!
&
|
^

alternativa
and
or
not
bitand
bitor
xor

osnovna
~
!=
&=
|=
^=

alternativa
compl
not_eq
and_eq
or_eq
xor_eq

namjenu je u jeziku C++ dozvoljena i upotreba nizova od tri znaka (engl. trigraph),
naslijeenih iz programskog jezika C (tablica 2.15). Sreom, dananji operacijski sustavi
za predstavljanje znakova koriste neki 8-bitni standard (npr. kodna stranica 852 pod
DOS-om ili kodna stranica 1250 pod Windows-ima) pa omoguavaju istovremeno
koritenje nacionalnih znakova i specijalnih znakova neophodnih za pisanje programa u
jeziku C++, tako da veini korisnika tablice 2.14 i 2.15 nee nikada zatrebati. Ipak za
ilustraciju pogledajmo kako bi izgledao neki program napisan pomou alternativnih
oznaka (itatelju preputamo da deifrira kd):
%:include <iostream>
using namespace std;
int main() <%
bool prva = true;
bool druga = false;
bool treca = prva and druga;
cout << treca << endl;
cout << not treca << endl;
cout << prva or druga << endl;
return 1;
%>

Tablica 2.15. Trigraf nizovi

trigraf

zamjena za

trigraf

zamjena za

trigraf

zamjena za

??=
??/
??'

#
\
^

??(
??)
??!

[
]
|

??<
??>
??-

{
}
~

2.4. Tipovi podataka i operatori

73

2.4.14. Korisniki definirani tipovi i operatori

Osim standardno ugraenih tipova podataka koje smo u prethodnim odjeljcima upoznali,
te operatora koji su za njih definirani, u programskom jeziku C++ na raspolaganju su
izvedeni tipovi podataka kao to su polja, pokazivai i reference (njih emo upoznati u
sljedeem poglavlju). Meutim, ono to programski jezik C++ ini naroito monim su
razredi koji omoguavaju uvoenje potpuno novih, korisniki definirani tipova
podataka. Tako programer vie nije sputan osnovnim tipovima koji su ugraeni u jezik,
ve ih moe po volji dopunjavati i definirati operacije na novostvorenim tipovima.
Detaljnije o razredima bit e govora u poglavlju 6.
2.4.15. Deklaracija typedef

Kljuna rije typedef omoguava uvoenje novog imena za ve postojei ugraeni ili
korisniki definirani tip podataka. Na primjer, deklaracijom:
typedef float broj;

identifikator broj postaje sinonimom za tip float. Nakon gornje deklaracije


novopeeni identifikator tipa broj moe se ravnopravno koristiti u deklaracijama
objekata:
broj pi = 3.14159;

Budui da deklaracija typedef ne uvodi novi tip podataka, niti mijenja standardna
pravila pretvorbe podataka, sljedea pridruivanja su dozvoljena i nee prouzroiti
nikakve promjene u tonosti:
float a = pi;
typedef float pliva;
pliva = pi;

Osnovni razlog za primjenu deklaracije typedef jesu jednostavnije promjene kda.


Pretpostavimo da smo napisali program za neki numeriki proraun tako da su nam svi
brojani podaci tipa float. Nakon nekog vremena utvrdili smo da nam float ne
zadovoljava uvijek glede tonosti, te da ponekad neke brojeve moramo deklarirati kao
double. U najgorem sluaju to znai pretraivanje kda i runu zamjenu odgovarajuih
deklaracija float u deklaracije double ili obrnuto (ako se predomislimo).
// prije
float a,
float k,
// ...
float x,

promjene:
b;
h;
y;

// nakon promjene:
double a, b;
float k, h;
// ...
double x, y;

Kada je broj objekata mali to i nije teko, ali za veliki broj deklaracija te zamjene mogu
biti naporne i podlone pogrekama. Posao emo si bitno olakati, ako u gornjem
primjeru dodamo deklaraciju typedef za podatke iji tip emo povremeno mijenjati:

74

2. Osnovni tipovi podataka

typedef float brojevi;


brojevi a, b;
float k, h;
// ...
brojevi x, y;

elimo li sada promijeniti tipove, dovoljno je samo gornju deklaraciju typedef


zamijeniti sljedeom:
typedef double brojevi;

Sada e svi podaci tipa brojevi biti prevedeni kao double podaci, bez potrebe daljnjih
izmjena u izvornom kdu.
Osim u ovakvim jednostavnim sluajevima, kljuna rije typedef se esto koristi
prilikom deklaracija pokazivaa i referenci na objekte, pokazivaa na funkcije i kod
deklaracija polja. Naime, sintaksa kojom se ti tipovi opisuju moe esto biti vrlo
sloena. Zbog toga, ako esto koristimo pokaziva na neki tip, programski kd moe
postati vrlo neitljiv. U tom sluaju, jednostavnije je pomou kljune rijei typedef
definirati novi tip, koji oznaava esto koriteni tip pokaziva na objekt. Takav tip
postaje ravnopravan svim ostalim ugraenim tipovima, te se moe pojaviti na svim
mjestima na kojima se moe pojaviti ugraeni tip: prilikom deklaracije objekata,
specificiranja parametara funkcije, kao parametar sizeof operatoru i sl. Primjena
typedef kljune rijei na takve tipove bit e objanjena u kasnijim poglavljima.

2.5. Operator sizeof


Operator sizeof je unarni operator koji kao rezultat daje broj bajtova to ih operand
zauzima u memoriji raunala:
cout << "Duljina podataka tipa int je " << sizeof(int)
<< " bajtova" << endl;

Valja naglasiti da standard jezika C++ ne definira veliinu bajta, osim u smislu rezultata
to ga daje sizeof operator; tako je sizeof(char) jednak 1. Naime, duljina bajta (broj
bitova koji ine bajt) ovisi o arhitekturi raunala. Mi emo u knjizi uglavnom
podrazumijevati da bajt sadri 8 bitova, to je najei sluaj u praksi.
Operand sizeof operatora moe biti identifikator tipa (npr. int, float, char) ili
konkretni objekt koji je ve deklariran:
float f;
cout << sizeof(f) << endl;
int i;
cout << sizeof(i) << endl;

// duljina float-a
// duljina int-a

2.6. Operator razdvajanja

75

Operator sizeof se moe primijeniti i na izraz, koji se u tom sluaju ne izraunava ve


se odreuje duljina njegova rezultata. Zbog toga e sljedee naredbe ispisati duljine
float, odnosno int rezultata:
float f;
int i;
cout << sizeof(f * i) << endl;
// duljina float
cout << sizeof(static_cast<int>(i * f)) << endl;
// duljina int

Operator sizeof se moe primijeniti i na pokazivae, reference, polja, korisniki


definirani razredi, strukture, unije i objekte (s kojima emo se upoznati u sljedeim
poglavljima). Ne moe se primijeniti na funkcije (na primjer, da bi se odredilo njihovo
zauzee memorije), ali se moe primijeniti na pokazivae na funkcije. U svim
sluajevima on vraa ukupnu duljinu tih objekata izraenu u bajtovima.
Rezultat operatora sizeof je tipa size_t, cjelobrojni tip bez predznaka koji ovisi o
implementaciji prevoditelja, definiran u zaglavlju cstddef.
Operator sizeof se uglavnom koristi kod dinamikog alociranja memorijskog
prostora kada treba izraunati koliko memorije treba osigurati za neki objekt, o emu e
biti govora u kasnije u knjizi.

2.6. Operator razdvajanja


Operator razdvajanja , (zarez) koristi se za razdvajanje izraza u naredbama. Izrazi
razdvojeni zarezom se izvode postepeno, s lijeva na desno. Tako e nakon naredbe
i = 10, i + 5;

varijabli i biti pridruena vrijednost 15. Prilikom koritenja operatora razdvajanja u


sloenijim izrazima valja biti vrlo oprezan, jer on ima najnii prioritet (vidi sljedei
odjeljak o hijerarhiji operatora). To se posebice odnosi na pozive funkcija u kojima se
zarez koristi za razdvajanje argumenata. Ovaj operator se vrlo esto koristi u sprezi s
uvjetnim operatorom (poglavlje 3.3) te za razdvajanje vie izraza u parametrima for
petlje (poglavlje 3.5).

2.7. Hijerarhija i redoslijed izvoenja operatora


U matematici postoji utvrena hijerarhija operacija prema kojoj neke operacije imaju
prednost pred drugima. Podrazumijevani slijed operacija je slijeva nadesno, ali ako se
dvije operacije razliitog prioriteta nau jedna do druge, prvo se izvodi operacija s viim
prioritetom. Na primjer u matematikom izrazu
a + b c / d
mnoenje broja b s brojem c ima prednost pred zbrajanjem s brojem a, tako da se ono
izvodi prvo. Umnoak se zatim dijeli s d i tek se tada pribraja broj a.

76

2. Osnovni tipovi podataka

I u programskom jeziku C++ definirana je hijerarhija operatora. Prvenstveni razlog


tome je kompatibilnost s matematikom hijerarhijom operacija, to omoguava pisanje
raunskih izraza na gotovo identian nain kao u matematici. Stoga gornji izraz u jeziku
C++ moemo pisati kao
y = a + b * c / d;

Redoslijed izvoenja operacija e odgovarati matematiki oekivanom. Operacije se


izvode prema hijerarhiji operacija, poevi s operatorima najvieg prioriteta. Ako dva
susjedna operatora imaju isti prioritet, tada se operacije izvode prema slijedu izvoenja
operatora. U tablici 2.16 na stranici 77 dani su svi operatori svrstani po hijerarhiji od
najvieg do najnieg. Operatori s istim prioritetom smjeteni su u zajednike blokove.
Striktno definiranje hijerarhije i slijeda izvoenja je neophodno i zato jer se neki
znakovi koriste za vie namjena. Tipian primjer je znak - (minus) koji se koristi kao
binarni operator za oduzimanje, kao unarni operator za promjenu predznaka, te u
operatoru za umanjivanje (--). Takva vieznanost moe biti uzrokom estih pogreaka.
Ilustrirajmo to sljedeim primjerom. Neka su zadana dva broja a i b; elimo od broja a
oduzeti broj b prethodno umanjen za 1. Neopreznom programeru moe se dogoditi da
umjesto
c = a - --b;

za to napie naredbu
c = a---b;

to e stvarno ta naredba uraditi pouzdano emo saznati ako ispiemo vrijednosti svih
triju varijabli nakon naredbe:
int main() {
int a = 2;
int b = 5;
int c;
c = a---b;
cout << "a = " << a << ", b = " << b << ", c = " << c << endl;
return 1;
}

Izvoenjem ovog programa na zaslonu e se ispisati


a = 1, b = 5, c = -3

to znai da je prevoditelj naredbu interpretirao kao


c = a-- - b;

tj. uzeo je vrijednost varijable a, od nje oduzeo broj b te rezultat pridruio varijabli c, a
varijablu a je umanjio (ali tek nakon to je upotrijebio njenu vrijednost).

2.7. Hijerarhija i redoslijed izvoenja operatora

77

Tablica 2.16. Hijerarhija operatora

operator

znaenje

primjer

::
::
::

globalno podruje
podruje razreda
podruje imenika

::ime
razred::ime
imenik::ime

.
->
[]
()
()
++
-typeid
typeid
const_cast
dynamic_cast
static_cast
reinterpret_cast

izbor lana
izbor lana
indeksiranje
poziv funkcije
stvori tip
uveaj nakon
umanji nakon
identifikacija tipa
identifikacija tipa tijekom izvoenja
pretvorba nepromjenjivosti tipa
pretvorba tipa tijekom izvoenja
pretvorba tipa tijekom prevoenja
neprovjerena pretvorba tipa

objekt.clan
pokazivac->clan
varijabla[indeks]
funkcija(argumenti)
tip(argumenti)
lvrijednost++
lvrijednost-typeid(tip)
typeid(izraz)
const_cast<tip>(izraz)
dynamic_cast<tip>(izraz)
static_cast<tip>(izraz)
reinterpret_cast<tip>(izraz)

sizeof
sizeof
++
-+ - ! ~
*
&
new
new
new
new
delete
delete
()

veliina objekta
veliina tipa
uveaj prije
umanji prije
unarni operatori
dereferenciranje
adresa objekta
stvori (alociraj) objekt
stvori (i inicijaliziraj) objekt
stvori (smjesti) objekt
stvori (smjesti i inicijaliziraj) objekt
uniti (dealociraj) objekt
uniti (dealociraj) poljet
dodjela tipa
izbor lana
izbor lana
mnoenja
zbrajanja
bitovni pomaci
poredbeni operatori
operatori jednakosti

sizeof izraz
sizeof(tip)
++lvrijednost
--lvrijednost
~lvrijednost
*izraz
&lvrijednost
new tip
new tip(argumenti)
new(argumenti) tip
new(argumenti) tip(argumenti)
delete pokazivac
delete[] pokazivac
(tip) izraz

.*
->*
* / %
+ << >>
< > <= >=
== !=

objekt.*pokazivac_na_clan
pokazivac->*pokazivac_na_clan
izraz % izraz
izraz izraz
izraz >> izraz
izraz <= izraz
izraz != izraz
(nastavlja se)

78

2. Osnovni tipovi podataka

Tablica 2.16 (nastavak)

operator

znaenje

primjer

&

bitovni i
bitovno iskljuivo ili
bitovni ili
logiki i
logiki ili
uvjetni izraz
pridruivanja

izraz & izraz

baci iznimku
razdvajanje

throw izraz

^
|
&&
||
?:
= *= /= += -= &=
^= |= %= >>= <<=
throw
,

izraz ^ izraz
izraz | izraz
izraz && izraz
izraz || izraz
izraz ? izraz : izraz
lvrijednost += izraz

izraz , izraz

Kao i u matematici, okruglim zagradama se moe zaobii ugraena hijerarhija


operatora, budui da one imaju vii prioritet od svih operatora. Tako e se u kdu
d = a * (b + c);

prvo zbrojiti varijable b i c, a tek potom e se njihov zbroj mnoiti s varijablom a. esto
je zgodno zagrade koristiti i radi itljivosti kda kada one nisu neophodne. Na primjer, u
gore razmatranom primjeru mogli smo za svaki sluaj pisati
c = a - (--b);

Dobra je navada stavljati zagrade i praznine svugdje gdje postoji dvojba o


hijerarhiji operatora i njihovom pridruivanju. Time kd postaje pregledniji i
razumljiviji. Pritom valja paziti da broj lijevih zagrada u naredbi mora biti
jednak broju desnih zagrada u protivnom e prevoditelj javiti pogreku.

79

3. Naredbe za kontrolu toka programa


Tko kontrolira prolost, glasio je slogan
Stranke, kontrolira i budunost: tko kontrolira
sadanjost kontrolira prolost.
George Orwell (19031950), 1984

U veini realnih problema tok programa nije pravocrtan i jedinstven pri svakom
izvoenju. Redovito postoji potreba da se pojedini odsjeci programa ponavljaju
programski odsjeci koji se ponavljaju nazivaju se petljama (engl. loops). Ponavljanje
moe biti unaprijed odreeni broj puta, primjerice elimo li izraunati umnoak svih
cijelih brojeva od 1 do 100. Meutim, broj ponavljanja moe ovisiti i o rezultatu neke
operacije. Kao primjer za to uzmimo uitavanje podataka iz neke datoteke datoteka se
ita podatak po podatak, sve dok se ne uita znak koji oznaava kraj datoteke (end-offile). Duljina datoteke pritom moe varirati za pojedina izvoenja programa.
Gotovo uvijek se javlja potreba za grananjem toka, tako da se ovisno o
postavljenom uvjetu u jednom sluaju izvodi jedan dio programa, a u drugom sluaju
drugi dio. Na primjer, elimo izraunati realne korijene kvadratne jednadbe. Prvo emo
izraunati diskriminantu ako je diskriminanta vea od nule, izraunat emo oba
korijena, ako je jednaka nuli izraunat emo jedini korijen, a ako je negativna ispisat
emo poruku da jednadba nema realnih korijena. Grananja toka i ponavljanja dijelova
kda omoguavaju posebne naredbe za kontrolu toka.

3.1. Blokovi naredbi


Dijelovi programa koji se uvjetno izvode ili ije se izvoenje ponavlja grupiraju se u
blokove naredbi jednu ili vie naredbi koje su omeene parom otvorena-zatvorena
vitiasta zagrada {}. Izvana se taj blok ponaa kao jedinstvena cjelina, kao da se radi
samo o jednoj naredbi. S blokom naredbi susreli smo se ve u prvom poglavlju, kada
smo opisivali strukturu glavne funkcije main(). U prvim primjerima na stranicama 21 i
25 cijeli program sastojao se od po jednog bloka naredbi. Blokovi naredbi se redovito
piu uvueno. To uvlaenje radi se iskljuivo radi preglednosti, to je naroito vano
ako imamo blokove ugnijeene jedan unutar drugog.
Vano svojstvo blokova jest da su varijable deklarirane u bloku vidljive samo
unutar njega. Zbog toga e prevoenje kda
#include <iostream>
using namespace std;
int main() {
79

80

3. Naredbe za kontrolu toka programa

{
int a = 1;
cout << a << endl;
}
return 0;

// poetak bloka naredbi


// lokalna varijabla u bloku
// kraj bloka naredbi

proi uredno, ali ako naredbu za ispis lokalne varijable a prebacimo izvan bloka
#include <iostream>
using namespace std;
int main() {
{
int a = 1;
}
cout << a << endl;
return 0;
}

// pogreka: a vie ne postoji!

dobit emo poruku o pogreki da varijabla a koju pokuavamo ispisati ne postoji.


Ovakvo ogranienje podruja lokalne varijable (engl. scope domet, doseg) omoguava
da se unutar blokova deklariraju varijable s istim imenom kakvo je ve upotrijebljeno
izvan bloka. Lokalna varijabla e unutar bloka zakloniti istoimenu varijablu prethodno
deklariranu izvan bloka, u to se najbolje moemo uvjeriti sljedeim primjerom
#include <iostream>
using namespace std;
int main() {
int a = 5;
{
int a = 1;
cout << a << endl;
}
cout << a << endl;
return 0;
}

// ispisuje 1
// ispisuje 5

Prva naredba za ispis dohvatit e lokalnu varijablu a = 1, budui da ona ima prednost
pred istoimenom varijablom a = 5 koja je deklarirana ispred bloka. Po izlasku iz bloka,
lokalna varijabla a se gubi te je opet dostupna samo varijabla a = 5. Naravno da bi
ponovna deklaracija istoimene varijable bilo u vanjskom, bilo u unutarnjem bloku
rezultirala pogrekom tijekom prevoenja. Podrujem dosega varijable pozabavit emo
se detaljnije u kasnijim poglavljima.
Ako se blok u naredbama za kontrolu toka sastoji samo od jedne naredbe, tada se
vitiaste zagrade mogu i izostaviti.

3.2. Grananje toka naredbom if

81

3.2. Grananje toka naredbom if


Naredba if omoguava uvjetno grananje toka programa ovisno o tome da li je ili nije
zadovoljen uvjet naveden iza kljune rijei if. Najjednostavniji oblik naredbe za
uvjetno grananje je:
if ( logiki_izraz )
// blok_naredbi

Ako je vrijednost izraza iza rijei if logika istina (true), izvodi se blok naredbi koje
slijede iza izraza. U protivnom se taj blok preskae i izvoenje nastavlja od prve
naredbe iza bloka. Na primjer:
if (a < 0) {
cout << "Broj a je negativan!" << endl;
}

U sluaju da blok sadri samo jednu naredbu, vitiaste zagrade koje omeuju blok mogu
se i izostaviti, pa smo gornji primjer mogli pisati i kao:
if (a < 0)
cout << "Broj a je negativan!" << endl;

ili
if (a < 0) cout << "Broj a je negativan!" << endl;

Zbog preglednosti kda i nedoumica koje mogu nastati prepravkama,


poetniku preporuujemo redovitu uporabu vitiastih zagrada i pisanje
naredbi u novom retku.
U protivnom se moe dogoditi da nakon dodavanja naredbe u blok programer zaboravi
omeiti blok zagradama i time dobije nepredviene rezultate:
if (a < 0)
cout << "Broj a je negativan!" << endl;
cout << "Njegova apsolutna vrijednost je " << -a
<< endl;

Druga naredba ispod if uvjeta izvest e se i za pozitivne brojeve, jer vie nije u bloku,
pa e se za pozitivne brojeve ispisati pogrena apsolutna vrijednost! Inae, u primjerima
emo izbjegavati pisanje vitiastih zagrada gdje god je to mogue radi utede na
prostoru.
elimo li da se ovisno u rezultatu izraza u if uvjetu izvode dva nezavisna
programska odsjeka, primijenit emo sljedei oblik uvjetnog grananja:

82

3. Naredbe za kontrolu toka programa

if ( logiki_izraz )
// prvi_blok_naredbi
else
// drugi_blok_naredbi

Kod ovog oblika, ako izraz u if uvjetu daje kao rezultat logiku istinu (true), izvest e
se prvi blok naredbi. Po zavretku bloka, izvoenje programa nastavlja se od prve
naredbe iza drugog bloka. Ako izraz daje kao rezultat logiku neistinu (false), preskae
se prvi blok, a izvodi samo drugi blok naredbi, nakon ega se nastavlja izvoenje
naredbi koje slijede. Evo jednostavnog primjera u kojem se raunaju presjecita pravca s
koordinatnim osima. Pravac je zadan jednadbom a x + b y + c = 0.
#include <iostream>
using namespace std;
int main() {
cout << "Upii koeficijente pravca:" << endl;
float a, b, c;
// koeficijenti pravca
cout << "a = ";
cin >> a;
// uitaj koeficijent a
cout << "b = ";
cin >> b;
// uitaj koeficijent b
cout << "c = ";
cin >> c;
// uitaj koeficijent c
cout << "Koeficijenti: " << a << ","
<< b << "," << c << endl; // ispii ih
cout << "Presjecite s apscisom: ";
if (a != 0)
cout << -c / a << ", ";
else
cout << "nema, ";
// pravac je horizontalan
cout << "presjecite s ordinatom: ";
if (b != 0)
cout << -c / b << endl;
else
cout << "nema" << endl; // pravac je vertikalan
return 0;
}

Kada prevedete i pokrenete gornji program, ne zaboravite nakon upisa svake vrijednosti
pritisnuti tipku Enter.
Zadatak. Napiite program kojim ete (pomou operatora modulo) ispitati da li je
upisani broj paran ili neparan i shodno tome ispisati poruku.

3.2. Grananje toka naredbom if

83

Blokovi if naredbi se mogu nadovezivati:


if ( logiki_izraz1 )
// prvi_blok_naredbi
else if ( logiki_izraz2 )
// drugi_blok_naredbi
else if ( logiki_izraz3 )
// trei_blok_naredbi
...
else
// zadnji_blok_naredbi

Ako je logiki_izraz1 toan, izvest e se prvi blok naredbi, a zatim se izvoenje


nastavlja od prve naredbe iza zadnjeg else bloka u nizu, tj. iza bloka
zadnji_blok_naredbi. Ako logiki_izraz1 nije toan, izraunava se logiki_izraz2
i ovisno o njegovoj vrijednosti izvodi se drugi_blok_naredbi, ili se program nastavlja
iza njega. Ilustrirajmo to primjerom u kojem traimo realne korijene kvadratne
jednadbe:
#include <iostream>
using namespace std;
int main() {
float a, b, c;

cout << "Unesi koeficijente kvadratne jednadbe:"


<< endl;
cout << "a = ";
cin >> a;
cout << "b = ";
cin >> b;
cout << "c = ";
cin >> c;
float diskr = b * b - 4. * a * c;

// diskriminanta

cout << "Jednadba ima ";


if (diskr == 0)
cout << "dvostruki realni korijen." << endl;
else if (diskr > 0)
cout << "dva realna korijena." << endl;
else
cout << "dva kompleksna korijena." << endl;
return 0;
}

Blokovi if naredbi mogu se ugnjeivati jedan unutar drugoga. Ilustrirajmo to


primjerom u kojem gornji kd poopujemo i na sluajeve kada je koeficijent a
kvadratne jednadbe jednak nuli, tj. kada se kvadratna jednadba svodi na linearnu
jednadbu:

84

3. Naredbe za kontrolu toka programa

#include <iostream>
using namespace std;
int main() {
float a, b, c;
cout << "Unesi koeficijente kvadratne jednadzbe:"
<< endl;
cout << "a = ";
cin >> a;
cout << "b = ";
cin >> b;
cout << "c = ";
cin >> c;
if (a) {
float diskr = b * b - 4. * a * c;
cout << "Jednadba ima ";
if (diskr == 0)
cout << "dvostruki realni korijen." << endl;
else if (diskr > 0)
cout << "dva realna korijena." << endl;
else
cout << "kompleksne korijene." << endl;
}
else
cout << "Jednadba je linearna." << endl;
return 0;
}

Za logiki izraz u prvom if uvjetu postavili smo samo vrijednost varijable a ako e
ona biti razliita od nule, uvjet e biti zadovoljen (pravilima pretvorbe vrijednost
varijable svest e se na logiku istinu) i izvest e se naredbe u prvom if bloku. Taj blok
sastoji se od niza if-else blokova identinih onima iz prethodnog primjera. Ako
poetni uvjet nije zadovoljen, tj. ako varijabla a ima vrijednost 0 (to rezultira logikom
neistinom nakon pretvorbe), preskae se cijeli prvi blok i ispisuje poruka da je
jednadba linearna. Uoimo u gornjem primjeru dodatno uvlaenje ugnijeenih
blokova.
Zadatak. Proirite prethodni zadatak za provjeru parnosti tako da za neparne brojeve
dodatno ispitate djeljivost s 3 ako je broj djeljiv s 3, ispiite dodatnu poruku o tome.

Pri definiranju logikog izraza u naredbama za kontrolu toka poetnik treba biti
oprezan. Na primjer, elimo li da se dio programa izvodi samo za odreeni opseg
vrijednosti varijable b, naredba
if (-10 < b < 0) //...

nee raditi onako kako bi se prema ustaljenim matematikim pravilima oekivalo. Ovaj
logiki izraz u biti se sastoji od dvije usporedbe: prvo se ispituje je li 10 manji od b, a
potom se rezultat te usporedbe usporeuje s 0, tj.

3.3. Uvjetni operator ? :

85

if ((-10 < b) < 0) //...

Kako rezultat prve usporedbe moe biti samo true ili false, odnosno 1 ili 0, druga
usporedba dat e uvijek logiku neistinu. Da bi program poprimio eljeni tok, usporedbe
moramo razdvojiti i logiki izraz formulirati ovako: ako je 10 manji od b i ako je b
manji od 0:
if (-10 < b && b < 0) //...

Druga nezgoda koja se moe dogoditi jest da se umjesto operatora za usporedbu ==, u
logikom izrazu napie operator pridruivanja =. Na primjer:
if (k = 0)
k++;
else
k = 0;

// pridruivanje, a ne usporedba!!!

Umjesto da se varijabla k usporeuje s nulom, njoj se u logikom izrazu pridjeljuje


vrijednost 0. Rezultat logikog izraza jednak je vrijednosti varijable k (0 odnosno
false), tako da se prvi blok naredbi nikada ne izvodi. Bolji prevoditelj e na takvom
mjestu korisniku prilikom prevoenja dojaviti upozorenje.

3.3. Uvjetni operator ? :


Iako ne spada meu naredbe za kontrolu toka programa, uvjetni operator po strukturi je
slian if-else bloku, tako da ga je zgodno upravo na ovom mjestu predstaviti. Sintaksa
operatora uvjetnog pridruivanja je:
uvjet ? izraz1 : izraz2 ;

Ako izraz uvjet daje logiku istinu, izraunava se izraz1, a u protivnom izraz2. U
primjeru
x = (x < 0) ? -x : x;

// x = abs(x)

ako je x negativan, izraunava se prvi izraz, te se varijabli x na lijevoj strani znaka


jednakosti pridruuje njegova pozitivna vrijednost, tj. varijabla x mijenja svoj predznak.
Naprotiv, ako je x pozitivan, tada se izraunava drugi izraz i varijabli x na lijevoj strani
pridruuje njegova nepromijenjena vrijednost.
Izraz u uvjetu mora kao rezultat vraati logiki tip (ili tip koji se moe svesti na
bool). Alternativni izrazi desno od znaka upitnika moraju davati rezultat meusobno
istog tipa ili se moraju dati svesti na isti tip preko ugraenih pravila pretvorbe.
Uvjetni operator koristite samo za jednostavna ispitivanja kada naredba stane
u jednu liniju. U protivnom kd postaje nepregledan.

86

3. Naredbe za kontrolu toka programa

Koliko itatelja odmah shvaa da u sljedeem primjeru zapravo raunamo korijene


kvadratne jednadbe?
((diskr = b * b -4 * a * c) >= 0) ?
(x1 = (-b + diskr) / 2 / a, x2 = (-b + diskr) / 2 / a)
(cout << "Ne valja ti korijen!", x1 = x2 = 0);

Zadatak. Koristei uvjetni operator, ispitajte parnost unesenog broja i ako je broj
neparan poveajte mu vrijednost za 1.

3.4. Grananje toka naredbom switch


Kada izraz uvjeta daje vie razliitih cjelobrojnih rezultata, a za svaki od njih treba
provesti razliite odsjeke programa, tada je umjesto if grananja esto preglednije
koristiti switch grananje. Kod tog grananja se prvo izraunava neki izraz koji daje
cjelobrojni rezultat. Ovisno o tom rezultatu, tok programa se preusmjerava na neku od
grana unutar switch bloka naredbi. Openita sintaksa switch grananja izgleda ovako:
switch ( cjelobrojni_izraz ) {
case konstantan_izraz1 :
// prvi_blok_naredbi
case konstantan_izraz2 :
// drugi_blok_naredbi
break;
case konstantan_izraz3 :
case konstantan_izraz4 :
// trei_blok_naredbi
break;
default:
// etvrti_blok_naredbi
}

Prvo se izraunava cjelobrojni_izraz, koji mora davati cjelobrojni rezultat. Ako je


rezultat tog izraza jednak nekom od konstantnih izraza u case uvjetima, tada se izvode
sve naredbe koje slijede pripadajui case uvjet sve do prve break naredbe. Nailaskom
na break naredbu, izvoenje kda u switch bloku se prekida i nastavlja se od prve
naredbe iza switch bloka. Ako izraz daje rezultat koji nije naveden niti u jednom od
case uvjeta, tada se izvodi blok naredbi iza kljune rijei default. Razmotrimo tokove
programa za sve mogue sluajeve u gornjem primjeru. Ako cjelobrojni_izraz kao
rezultat daje:
konstantan_izraz1, tada e se prvo izvesti prvi_blok_naredbi, a zatim
drugi_blok_naredbi. Nailaskom na naredbu break prekida se izvoenje naredbi u
switch bloku. Program iskae iz bloka i nastavlja od prve naredbe iza bloka.
konstantan_izraz2, izvodi se drugi_blok_naredbi. Nailaenjem na naredbu break
prekida se izvoenje naredbi u switch bloku i program nastavlja od prve naredbe iza
bloka.

3.4. Grananje toka naredbom switch

87

konstantan_izraz3 ili konstantan_izraz4 izvodi se trei_blok_naredbi.


Naredbom break prekida se izvoenje naredbi u switch bloku i program nastavlja od
prve naredbe iza bloka.
Ako rezultat nije niti jedan od navedenih konstantnih_izraza, izvodi se
etvrti_blok_naredbi iza default naredbe.

Evo i konkretnog primjera switch grananja (algoritam je prepisan iz prirunika za jedan


stari programirljivi kalkulator):
#include <iostream>
using namespace std;
int main() {
cout << "Upii datum u formatu DD MM GGGG:";
int dan, mjesec;
long int godina;
cin >> dan >> mjesec >> godina;
long datum;
if (mjesec < 3) {
datum = 365 * godina + dan + 31 * (mjesec - 1)
+ (godina - 1) / 4
- 3 * ((godina - 1) / 100 + 1) / 4;
}
else {
// uoimo operator dodjele tipa static_cast<int>:
datum = 365 * godina + dan + 31 * (mjesec - 1)
- static_cast<int> (0.4 * mjesec + 2.3)
+ godina / 4 - 3 * (godina / 100 + 1) / 4;
}
cout << dan << "." << mjesec << "." << godina
<< ". pada u ";
switch (datum % 7) {
case 0:
cout << "subotu." << endl;
break;
case 1:
cout << "nedjelju." << endl;
break;
case 2:
cout << "ponedjeljak." << endl;
break;
case 3:
cout << "utorak." << endl;
break;
case 4:
cout << "srijedu." << endl;
break;
case 5:
cout << "etvrtak." << endl;

88

3. Naredbe za kontrolu toka programa

break;
default:
cout << "petak." << endl;
}
return 0;
}

Algoritam se zasniva na cjelobrojnim dijeljenjima, tako da sve varijable treba deklarirati


kao cjelobrojne. tovie, godina se mora definirati kao long int, jer se ona u raunu
mnoi s 365. U protivnom bi vrlo vjerojatno dolo do brojanog preljeva, osim ako
bismo se ograniili na datume iz ivota Kristovih suvremenika. Uoimo u gornjem kdu
operator dodjele tipa static_cast<int>()
/*...*/ static_cast<int>(0.4 * mjesec + 2.3)

/*...*/

kojim se rezultat mnoenja i zbrajanja brojeva s pominim zarezom pretvara u cijeli


broj, tj. odbacuju decimalna mjesta. U switch naredbi se rezultat prethodnih rauna
normira na neki od sedam dana u tjednu pomou operatora % (modulo).
U gornjem primjeru svaki case je zakljuen break naredbom pa se netko moe
zapitati zato je uope neophodan break zar ne bi bilo jednostavnije definirati da se
program podrazumijevano izvrava samo do sljedee naredbe case? Pogledajmo
protuprimjer: u gornjem programu emo switch blok nadomjestiti sljedeim kdom:
switch (datum % 7) {
case 0:
case 1:
cout << "dane weekenda." << endl;
break;
default:
cout << "radne dane." << endl;
}

Budui da odmah iza naredbe case 0: slijedi case 1:, blok naredbi do naredbe break
e se izvravati i za sluaj kada je rezultat izraza u switch jednak 0. default blok e se
izvoditi za sve ostale sluajeve.
Zadatak. U gornjem primjeru pomaknite default blok naredbi ispred case naredbi i
pokrenite program. Nemojte zaboraviti dodati naredbu break na kraj default bloka!
to bi se dogodilo da taj break izostavite?

Blok default moe biti smjeten bilo gdje unutar switch bloka, no zbog
preglednosti je preporuljivo staviti ga na kraj. On se smije i izostaviti, ali ga je redovito
zgodno imati da bi kroz njega program proao za vrijednosti koje nisu obuhvaene case
blokovima. Ovo je naroito vano tijekom razvijanja programa, kada se u default blok
moe staviti naredba koja e ispisivati upozorenje da je cjelobrojni_izraz u switch
poprimio neku nepredvienu vrijednost.
Zadatak. Zadnji primjer modificirajte tako da dodatno ispitujete da li zadani datum
pada na neki blagdan (za poetak ispitajte samo za 25.12.). Ako pada na blagdan ili

3.5. Petlja for

89

ako pada u dane weekenda, ispiite da je taj dan neradni, inae da je radni. Uputa: na
poetku programa definirajte bool varijablu DaLiJePraznik i postavite ju poetno na
false. Vrijednost te varijable promijenite ako je zadovoljen uvjet ispitivanja za
blagdane ili ako se unutar switch-a ispostavi da datum pada u subotu ili nedjelju. Na
kraju programa ispitajte vrijednost varijable i ispiite odgovarajuu poruku.

3.5. Petlja for


esto u programima treba ponavljati dijelove kda. Ako je broj ponavljanja poznat prije
ulaska u petlju, najprikladnije je koristiti for petlju. To je najopenitija vrsta petlje i ima
sljedei oblik:
for ( poetni_izraz ; uvjet_izvoenja ; izraz_prirasta )
// blok_naredbi

Iza kljune rijei for, unutar okruglih zagrada () navode se tri grupe naredbi,
meusobno odvojenih znakom toka-zarez ;. Postupak izvoenja for-bloka je sljedei:
1. Izraunava se poetni_izraz. Najee je to pridruivanje poetne vrijednosti
brojau kojim e se kontrolirati ponavljanje petlje.
2. Izraunava se uvjet_izvoenja, izraz iji rezultat mora biti tipa bool. Ako je rezultat
jednak logikoj neistini, preskae se blok_naredbi i program se nastavlja prvom
naredbom iza bloka.
3. Ako je uvjet_izvoenja jednak logikoj istini, izvodi se blok_naredbi.
4. Na kraju se izraunava izraz_prirasta (npr. poveavanje brojaa petlje). Program
se vraa na poetak petlje, te se ona ponavlja od toke 2.
Programski odsjeak se ponavlja sve dok uvjet_izvoenja na poetku petlje daje
logiku istinu; kada rezultat tog izraza postane logika neistina, programska petlja se
prekida.
Kao primjer za for petlju, napiimo program za raunanje faktorijela (faktorijela od
n je umnoak svih brojeva od 1 do n):
n! = 1 2 (n 2) (n 1) n

Pogledajmo kd:
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Upii prirodni broj: ";
cin >> n;
long int fjel = 1;
for (int i = 2; i <= n; i++)
fjel *= i;

// manji od 13!?

90

3. Naredbe za kontrolu toka programa

cout << n << "! = " << fjel << endl;


return 0;
}

Prije ulaska u petlju trebamo definirati poetnu vrijednost varijable fjel u koju emo
gomilati umnoke. Na ulasku u petlju deklariramo broja petlje, varijablu i tipa int te
joj pridruujemo poetnu vrijednost 2 (poetni_izraz: int i = 2). Unutar same petlje
mnoimo fjel s brojaem petlje, a na kraju tijela petlje uveavamo broja
(izraz_prirasta: i++). Petlju ponavljamo sve dok je broja manji ili jednak unesenom
broju (uvjet_izvoenja: i <= n). Pri testiranju programa pazite da uneseni broj ne
smije biti vei od 12, jer e inae doi do brojanog preljeva varijable fjel.
Zanimljivo je uoiti to e se dogoditi ako za n unesemo brojeve manje od 2. Ve
pri prvom ulasku u petlju nee biti zadovoljen uvjet ponavljanja petlje te e odmah biti
preskoeno tijelo petlje i ona se nee izvesti niti jednom! Ovo nam odgovara, jer je 1! =
1 i (po definiciji) 0! = 1. Naravno da smo petlju mogli napisati i na sljedei nain:
for (int i = n; i > 1; i--)
fjel *= i;

Rezultat bi bio isti. Iskusni programer bi gornji program mogao napisati jo saetije
(vidi poglavlje 3.11), no u ovom trenutku to nam nije bitno.
Moe se dogoditi da je uvjet izvoenja uvijek zadovoljen, pa e se petlja izvesti
neogranieni broj puta. Program e uletjeti u slijepu ulicu iz koje nema izlaska, osim
pomou tipki Power ili Reset na kuitu vaeg raunala. Na primjer:
// ovaj primjer pokreete na vlastitu odgovornost!
cout << "Beskonana petlja";
for (int i = 5; i > 1; )
cout << "a";

Varijabla i je uvijek vea od 1, tako da ako se i usudite pokrenuti ovaj program, ekran
e vam vrlo brzo biti preplavljen slovom a. Iako naizgled banalne, ovakve pogreke
mogu poetniku zadati velike glavobolje.
Uoimo da smo u gornjem kdu izostavili izraz_prirasta. Openito, moe se
izostaviti bilo koji od tri izraza u for naredbi jedino su oba znaka ; obavezna.
Izostavi li se uvjet_izvoenja, podrazumijevana vrijednost e biti true i
petlja e biti beskonana!
tovie, mogu se izostaviti i sva tri izraza:
for ( ; ; )

// opet beskonana petlja!

ali itatelju preputamo da sam zakljui koliko je to smisleno.

3.5. Petlja for

91

Koristan savjet (ali ne apsolutno pravilo) je izbjegavati mijenjanje vrijednosti


kontrolne varijable unutar bloka naredbi for petlje. Sve njene promjene bolje
je definirati iskljuivo u izrazu prirasta.
U protivnom se lako moe dogoditi da petlja postane beskonana, poput sljedeeg
primjera:
for (int i = 0; i < 5; i++)
i--;
// opet beskonana petlja!

Naredba unutar petlje potpuno potire izraz prirasta, te varijabla i alternira izmeu 1 i 0.
Poetni izraz i izraz prirasta mogu se sastojati i od vie izraza odvojenih operatorom
nabrajanja , (zarez) . To nam omoguava da program za raunanje faktorijela napiemo
i (neto) krae:
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Upii prirodni broj: ";
cin >> n;
long fjel;
int i;
for (i = 2, fjel = 1; i <= n; fjel *= i, i++) ;
cout << n << "! = " << fjel;
return 0;
}

U poetnom izrazu postavljaju se broja i varijabla fjel na svoje inicijalne vrijednosti.


Naredba za mnoenje s brojaem prebaena je iz bloka naredbi u izraz prirasta, tako da
je od bloka ostala prazna naredba, tj. sam znak ;. Njega ne smijemo izostaviti, jer bi
inae prevoditelj prvu sljedeu naredbu (a to je naredba za ispis rezultata) obuhvatio u
petlju. Sada je i deklaracija brojaa prebaena ispred for naredbe, jer poetni izraz ne
trpi viestruke deklaracije. Da smo for naredbu napisali kao:
for (int i = 2, long fjel = 1; i <= n; fjel *= i, i++) ;

prevoditelj bi javio da je deklaracija varijable i okonana nepravilno, jer bi iza zareza,


umjesto imena varijable naiao na kljunu rije long.
Ako for naredba sadri deklaraciju varijable, tada se podruje te varijable prostire
samo do kraja petlje . Na primjer:

Tijekom razvoja Standarda to pravilo se mijenjalo (zanimljivi lanak o tome izaao je u


asopisu C++ Report od veljae 1993, pod naslovom Identifier Scope in C++ for statement
autora A. Koeniga). Tako e neki prevoditelji ostaviti varijablu i ivom i iza for petlje.

92

3. Naredbe za kontrolu toka programa

#include <iostream>
using namespace std;
int main() {
int i = -1;
for (int i = 1; i <= 10; i++)
cout << i << endl;
cout << i << endl;
// ispisuje -1
return 0;
}

Zadatak. Napiite program s dvije uzastopne petlje koje e ispisati tablicu sa slovima
engleskog alfabeta. Tablica neka ima dva stupca: u prvom stupcu neka je ASCII kd (od
65 do 90 ukljuivo za velika slova, odnosno 97 do 122 ukljuivo za mala slova). Uputa:
slovo ispiite koristei dodjelu tipa static_cast<char>. Potom preuredite program
tako da imate samo jednu petlju i ispis u etiri stupca.
for petlje mogu biti ugnijeene jedna unutar druge. Ponaanje takvih petlji
razmotrit emo na sljedeem programu:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
for (int redak = 1; redak <= 10; redak++) {
for (int stupac = 1; stupac <= 10; stupac++)
cout << setw(5) << redak * stupac;
cout << endl;
}
return 0;
}

Nakon prevoenja i pokretanja programa, na zaslonu e se ispisati ve pomalo


zaboravljena, ali generacijama pukokolaca omraena tablica mnoenja do 10:
1
2
3
4
5
6
7
8
9
10

2
4
6
8
10
12
14
16
18
20

3
6
9
12
15
18
21
24
27
30

4
8
12
16
20
24
28
32
36
40

5
10
15
20
25
30
35
40
45
50

6
12
18
24
30
36
42
48
54
60

7
14
21
28
35
42
49
56
63
70

8
16
24
32
40
48
56
64
72
80

9
18
27
36
45
54
63
72
81
90

10
20
30
40
50
60
70
80
90
100

Kako se gornji program izvodi? Pri ulasku u vanjsku petlju, inicijalizira se broja redaka
na vrijednost 1 te se s njom ulazi u unutarnju petlju. U unutarnjoj petlji se broja stupaca
mijenja od 1 do 10 i za svaku pojedinu vrijednost izraunava se njegov umnoak s

3.6. Naredba while

93

brojaem redaka (potonji je cijelo to vrijeme redak = 1). Po zavrenoj unutarnjoj petlji
ispisuje se znak za novi redak, ime zavrava blok naredbi vanjske petlje. Slijedi prirast
brojaa redaka (redak = 2) i povrat na poetak vanjske petlje. Unutarnja petlja se
ponavlja od stupac = 1 do stupac = 10 itd. Kao to vidimo, za svaku vrijednost brojaa
vanjske petlje izvodi se cjelokupna unutarnja petlja.
Da bismo dobili ispis brojeva u pravilnim stupcima, u gornjem primjeru smo rabili
operator za rukovanje (manipulator) setw(). Argument tog manipulatora (tj. cijeli broj
u zagradi) odreuje koliki e se najmanji prostor predvidjeti za ispis podatka koji slijedi
u izlaznom toku. Ako je podatak krai od predvienog prostora, preostala mjesta bit e
popunjena prazninama. Manipulator setw() definiran je u datoteci zaglavlja iomanip.
Zadatak. Preuredite prethodni primjer tako da ispie samo lanove u donjem lijevom
trokutu:
1
2
3
4
...

4
6
8

9
12

16

Uputa: u unutarnjoj petlji kao uvjet izvoenja postavite da je stupac manji ili jednak
retku.
Zadatak. Kd iz prethodnog zadatka modificirajte tako da se ispiu samo lanovi u
gornjem desnom trokutu. Uputa: unutar vanjske petlje smjestite dvije petlje po
stupcima, s time da prva treba ispisivati odgovarajui broj praznina, a druga traene
brojeve.

3.6. Naredba while


Druga od tri petlje kojima jezik C++ raspolae jest while petlja. Ona se koristi
uglavnom za ponavljanje segmenta kda kod kojeg broj ponavljanja nije unaprijed
poznat. Sintaksa while bloka je
while ( uvjet_izvoenja )
// blok_naredbi
uvjet_izvoenja je izraz iji je rezultat tipa bool. Tok izvoenja for-bloka je sljedei:

1. Izraunava se logiki izraz uvjet_izvoenja.


2. Ako je rezultat jednak logikoj neistini, preskae se blok_naredbi i program se
nastavlja od prve naredbe iz bloka.
3. Ako je uvjet_izvoenja jednak logikoj istini izvodi se blok_naredbi. Potom se
program vraa na while naredbu i izvodi od toke 1.

94

3. Naredbe za kontrolu toka programa

Konkretnu primjenu while bloka dat emo programom kojim se ispisuje sadraj
datoteke s brojevima. U donjem kdu je to datoteka brojevi.dat, ali uz promjene
odgovarajueg imena, to moe biti i neka druga datoteka.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream ulazniTok("brojevi.dat");
cout << "Sadraj datoteke:" << endl << endl;
float broj;
while ((ulazniTok >> broj) != 0)
cout << broj << endl;
return 0;
}

Brojevi u datoteci brojevi.dat moraju biti upisani u tekstovnom obliku, razdvojeni


prazninama, tabulatorima ili napisani u zasebnim recima (moemo ih upisati pomou
najjednostavnijeg programa za upis teksta te ih pohraniti na disk).
Na poetku programa se stvara objekt ulTok tipa (razreda) ifstream. Iako e
razredi biti detaljnije objanjene kasnije, za sada je dovoljno rei da je objekt ulTok
slian ulaznom toku cin kojeg smo do sada koristili za unos podataka s tipkovnice.
Osnovna razlika je u tome to je cin povezan na tipkovnicu, dok se ulTok vee za
datoteku iji je naziv zadan u dvostrukim navodnicima u zagradama. elimo li koristiti
tokove u naem programu, potrebno je ukljuiti datoteku zaglavlja fstream pomou
pretprocesorske naredbe #include.
Usredotoimo se na blok while naredbe. Na poetku while-petlje, u uvjetu
izvoenja se naredbom
ulTok >> broj

ita podatak. Ako je uitavanje bilo uspjeno, ulTok e biti razliit od nule (neovisno o
vrijednosti uitanog broja), te se izvodi blok naredbi u while-petlji ispisuje se broj na
izlaznom toku cout. Nakon to se izvede naredba iz bloka, izvoenje se vraa na
ispitivanje uvjeta petlje. Ako ulTok poprimi vrijednost 0, to znai da nema vie brojeva
u datoteci, petlja se prekida. Blok petlje se preskae, te se izvoenje nastavlja prvom
naredbom iza bloka.
Primijetimo zgodno svojstvo petlje while: ako je datoteka prazna, ulazni tok e
odmah poprimiti vrijednost 0 te e uvjet odmah prilikom prvog testiranja biti
neispunjen. Blok petlje se tada nee niti jednom izvesti, to u naem sluaju i trebamo.
Zadatak. Dopunite gornji program tako da nakon sadraja datoteke ispie i broj
iitanih brojeva i njihovu srednju vrijednost.

Ulazni i izlazni tokovi te razred fstream detaljno su obraeni u 15. poglavlju.

3.7. Blok do-while

95

Zanimljivo je uoiti da nema sutinske razlike izmeu for- i while-bloka naredbi


svaki for-blok se uz neznatne preinake moe napisati kao while-blok i obrnuto. Da
bismo se u to osvjedoili, napisat emo program za raunanje faktorijela iz prethodnog
poglavlja koritenjem while naredbe:
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Upii prirodni broj: ";
cin >> n;
long int fjel = 1;
int i = 2;
while (i <= n) {
fjel *= i;
i++;
}
cout << n << "! = " << fjel;
return 0;
}

Trebalo je samo poetni izraz (int i = 2) izluiti ispred while naredbe, a izraz prirasta
(i++) prebaciti u blok naredbi.
Zadatak. Program za ispis datoteke napiite tako da umjesto while-bloka upotrijebite
for-blok naredbi.
Koji e se pristup koristiti (for-blok ili while-blok) prvenstveno ovisi o
sklonostima programera. Ipak, zbog preglednosti i razumljivosti kda for-blok je
preporuljivo koristiti kada se broj ponavljanja petlje kontrolira cjelobrojnim brojaem.
U protivnom, kada je uvjet ponavljanja odreen nekim logikim uvjetom, praktinije je
koristiti while naredbu.

3.7. Blok do-while


Zajedniko for i while naredbi jest ispitivanje uvjeta izvoenja prije izvoenja naredbi
bloka. Zbog toga se moe dogoditi da se blok naredbi ne izvede niti jednom. Meutim,
esto je neophodno da se prvo izvede neka operacija te da se, ovisno o njenom ishodu,
ta operacija eventualno ponavlja. Za ovakve sluajeve svrsishodnija je do-while petlja:
do
// blok_naredbi
while ( uvjet_ponavljanja );

Svakako treba uoiti da:


while uvjet ponavljanja mora biti zakljuen znakom toka-zarezom ; (za
razliku od naredbe while koju je neposredno slijedio blok naredbi)

96

3. Naredbe za kontrolu toka programa

Primjenu do-while bloka ilustrirat emo programom-igricom u kojem treba pogoditi


sluajno generirani trazeniBroj. Nakon svakog naeg pokuaja ispisuje se samo poruka
da li je broj vei ili manji od traenog. Petlja se ponavlja sve dok je pokuaj (mojBroj)
razliit od traenog broja.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
int raspon = 100;
srand(time(0));
// inicijalizira generator slu.brojeva
// generira sluajni broj izmeu 1 i raspon
int trazeniBroj = static_cast<float>(rand()) / RAND_MAX
* (raspon - 1) + 1;
cout << "Treba pogoditi broj izmeu 1 i "
<< raspon << endl;
int mojBroj;
int brojPokusa = 0;
do {
cout << ++brojPokusa << ". pokuaj: ";
cin >> mojBroj;
if (mojBroj > trazeniBroj)
cout << "MANJE!" << endl;
else if (mojBroj < trazeniBroj)
cout << "VIE!" << endl;
} while(mojBroj != trazeniBroj);
cout << "BINGO!!!" << endl;
return 0;
}

Za generiranje sluajnih brojeva upotrijebljena je funkcija rand() iz zaglavlja cstdlib.


Ona kao rezultat vraa sluajni broj izmeu 0 i RAND_MAX, pri emu je RAND_MAX broj
takoer definiran u cstdlib biblioteci. Da bismo generirali broj u rasponu izmeu 1 i
raspon, broj koji vraa funkcija rand() podijelili smo s RAND_MAX (ime smo normirali
broj na interval od 0 do 1), pomnoili s raspon - 1 i uveali za 1. Prilikom dijeljenja
primijenili smo operator dodjele tipa static_cast<float>, jer bi se u protivnom
izgubila decimalna mjesta i rezultat bi bili samo brojevi 0 ili 1.
Uzastopni pozivi funkcije rand() uvijek generiraju isti slijed sluajnih brojeva, a
prvi poziv te funkcije daje uvijek isti rezultat. Da bi se izbjegle katastrofalne posljedice
takvog svojstva na neizvjesnost igre, prije poziva funkcije rand() pozvali smo funkciju
srand() koja inicijalizira klicu generatora sluajnog broja, tj. postavlja poetni
sluajno generirani broj to ga daje rand() na neku drugu vrijednost. Funkciji
srand() treba kao argument navesti neki cijeli broj na osnovu kojeg e se izraunati
vrijednost klice. Iako bismo tu vrijednost mogli sami zadavati, radi fair-playa smo to
prepustili raunalu: pomou funkcije time(), definirane u standardnoj biblioteci ctime,

3.8. Naredbe break i continue

97

uitava se trenutno sistemsko vrijeme (broj sekundi to ih odbrojava interni sat u


raunalu od referentnog trenutka) i ono se koristi kao osnovica za klicu. Budui da
nema anse da program pokrenete vie puta unutar iste sekunde (pa ak i na razliitim
raunalima), tako generirani brojevi e biti doista sluajni.
Zadatak. Izbacite iz gornjeg primjera naredbu srand() i provjerite sluajnost
generiranih brojeva. Dodajte u gornji primjer provjeru je li broj pokuaja vei od 10
u tom sluaju ispiite koliko je pokuaj daleko od traenog broja.
Zadatak. Napiite program u kojem se rauna priblina vrijednost funkcije sinus
pomou reda potencija

(1)i
i =0

x 2i +1
x 3 x5 x 7 x 9
= x +
+
K
(2i + 1)!
3! 5! 7! 9 !

Petlju za raunanje lanova reda treba ponavljati sve dok je apsolutna vrijednost
zadnjeg izraunatog lana reda vea od nekog zadanog broja (npr. 107). Uputa: ispred
do-while petlje definirajte realnu varijablu zbrojReda (poetno 0), te cjelobrojne
varijable red i preznak koje poetno postavite na +1. Unutar do-while petlje
definirajte realnu varijablu NtiClan i inicijalizirajte ju na vrijednost uitanog x, iza
ega slijedi for petlja. Indeks petlje j ide od 1 do red i unutar nje se NtiClan mnoi s
kvocijentom x/j. Na izlasku iz for petlje pomnoite tako izmnoeni NtiClan s predznak,
dodajte to u zbrojReda, promijenite predznak i na kraju ispitajte da li je NtiClan vei
od postavljene granice ako jest, petlju ponovite.

3.8. Naredbe break i continue


Naredba break moe se koristiti samo u petljama te u switch grananjima. Njenu
funkciju u switch grananjima upoznali smo u odjeljku 3.4, dok se u petljama njome
prekida izvoenje okolne for, while ili do-while petlje. Na primjer, elimo da se
izvoenje naeg program za ispis brojeva iz datoteke brojevi.dat (na str. 94) prekine
kada se uita 0. Tada emo while-petlju modificirati na sljedei nain:
// ...
while ((ulazniTok >> broj) != 0) {
if (broj == 0)
break;
// prekida petlju uitavanja
cout << broj << endl;
}
// ...

Nailaskom na znak broj 0 program iskae iz while-petlje te se prekida daljnje itanje


datoteke i ispis njena sadraja.

Na IBM kompatibilnim osobnim raunalima referentno vrijeme je pono (0:00 sati) 1. sijenja
1970. godine.

98

3. Naredbe za kontrolu toka programa

Naredba continue takoer uzrokuje skok programa na kraj petlje, ali se potom
njeno ponavljanje nastavlja. Na primjer, elimo li da na program za ispis sadraja
datoteke ispisuje samo one znakove koji se mogu prikazati na zaslonu, jedna mogua
varijanta bila bi:
// ...
while ((znak = fgetc(ulazniTok)) != EOF) {
if (znak < ' ' && znak != '\r')
continue;
// preskae naredbe do kraja petlje
cout << znak;
}
// ...

Nailaskom na znak iji je kd manji od kda za prazninu i nije jednak znaku za novi
redak, izvodi se naredba continue preskau se sve naredbe do kraja petlje (u ovom
sluaju je to naredba za ispis znaka), ali se ponavljanje petlje dalje nastavlja kao da se
nita nije dogodilo.
Ako je vie petlji ugnijeeno jedna unutar druge, naredba break ili naredba
continue prouzroit e prekid ponavljanja, odnosno nastavak okolne petlje u kojoj se
naredba nalazi.
Valja izbjegavati esto koritenje break i continue naredbi u petljama, jer
one naruavaju strukturiranost programa.
Koristite ih samo za izvanredna stanja, kada ne postoji drugi prikladan nain da se
izvoenje naredbi u petlji prekine. Naredba continue redovito se moe izbjei ifblokom.
Kao ilustraciju nesvrhovitog koritenja break naredbe pogledajmo primjer kakav se
nerijetko moe vidjeti kod samozvanih C++ gurua:
while (1) {
int i;
cin >> i;
if (i == 0)
break;
}

// beskonana petlja!
// ako je uitani broj 0,
// tada prekini petlju

Budui da je uvjet izvoenja petlje uvijek 1 (tj. true), petlja je beskonana; prekida se
tek izvoenjem break naredbe. Ljepe napisana petlja bi izgledala ovako:
int i;
do {
cin >> i;
} while(i != 0);

Za razliku od poetnog rjeenja, u ovako napisanom kdu uvjet izvoenja petlje je


odmah uoljiv.

3.9. Ostale naredbe za skok

99

3.9. Ostale naredbe za skok


Naredba goto omoguava bezuvjetni skok na neku drugu naredbu unutar iste funkcije.
Opi oblik je:
goto ime_oznake ;
ime_oznake je simboliki naziv koji se mora nalaziti ispred naredbe na koju se eli
prenijeti kontrola, odvojen znakom : (dvotoka). Na primjer
if (a < 0)
goto negativniBroj;
//...
negativniBroj:
//naredba

Naredba na koju se eli skoiti moe se nalaziti bilo gdje (ispred ili iza naredbe goto)
unutar iste funkcije. ime_oznake mora biti jedinstveno unutar funkcije, ali moe biti
jednako imenu nekog objekta ili funkcije. Ime oznake jest identifikator, pa vrijede
pravila navedena u poglavlju 0.
U pravilno strukturiranom programu naredba goto uope nije potrebna, te ju
velika veina programera uope ne koristi.
Zadnju naredbu za kontrolu toka koju emo ovdje spomenuti upoznali smo na samom
poetku knjige. To je naredba return kojom se prekida izvoenje funkcija te emo se
njome pozabaviti u poglavlju 5 posveenom funkcijama.

3.10. O strukturiranju izvornog kda


Uvlaenje blokova naredbi i pravilan raspored vitiastih zagrada doprinose preglednosti
i itljivosti izvornog kda. Programeri koji tek zapoinju pisati u programskim jezicima
C ili C++ esto se nau u nedoumici koji stil strukturiranja koristiti. Obino preuzimaju
stil knjige iz koje pretipkavaju svoje prve programe ili od kolege preko ijeg ramena
kriomice stjeu prve programerske vjetine, ne sagledavajui nedostatke i prednosti tog
ili nekog drugog pristupa. Nakon to im taj stil ue u krv, teko e prijei na drugi bez
obzira koliko je on bolji (u to su se uvjerili i sami autori knjige tijekom njena pisanja!).
Prvi problem jest raspored vitiastih zagrada koje oznaavaju poetak i kraj blokova naredbi. Navedimo nekoliko najeih pristupa (redoslijed navoenja je sluajan):
1. vitiaste zagrade uvuene i meusobno poravnate:
for ( /*...*/ )
{
// blok naredbi
// ...
}

100

3. Naredbe za kontrolu toka programa

2. poetna zagrada izvuena, zavrna uvuena:


for ( /*...*/ )
{
// blok naredbi
// ...
}

3. zagrade izvuene, meusobno poravnate:


for ( /*...*/ )
{
// blok naredbi
// ...
}

4. poetna zagrada na kraju naredbe za kontrolu, zavrna izvuena:


for ( /*...*/ ) {
// blok naredbi
// ...
}

Pristupi 2. i 3. imaju jo podvarijante u kojima se redak s poetnom zagradom ostavlja


prazan, bez naredbe. Meutim, taj prazan redak ne doprinosi bitno preglednosti i
nepotrebno zauzima prostor. Ista zamjerka moe se uputiti prvom pristupu.
Ve letiminim pogledom na etiri gornja pristupa itatelj e uoiti da izvuena
zavrna zgrada u 3. odnosno 4. pristupu bolje istie kraj bloka. U 3. pristupu zagrade u
paru otvorena-zatvorena vitiasta zagrada meusobno su poravnate, tako da je svakoj
zagradi lako uoiti njenog partnera, to moe biti vrlo korisno prilikom ispravljanja
programa. Meutim, u mnogim knjigama koristi se pristup 4 kod kojeg je poetna
vitiasta zagrada smjetena na kraj naredbe za kontrolu toka. Budui da ona zapoinje
blok te je vezana uz njega, ovaj pristup je logian. U ostalim pristupima povezanost
bloka naredbi s naredbom za kontrolu toka nije vizualno tako oita i moe se stei dojam
da blok naredbi predstavlja potpuno samostalnu cjelinu. Zbog navedenih razloga (Kud
svi Turci, tuda i mali Mi), u knjizi koristimo 4. pristup. Uostalom, pronalaenja para,
odnosno provjera uparenosti vitiastih zagrada u urednicima teksta (editorima) koji se
koriste za pisanje i ispravljanje izvornog kda ne predstavlja problem, jer veina njih
ima za to ugraene funkcije.
Druga nedoumica jest koliko duboko uvlaiti blokove. Za uvlaenje blokova
najprikladnije je koristiti tabulatore. Obino editori imaju poetno ugraeni pomak
tabulatora od po 8 znakova, meutim za iole sloeniji program s vie blokova
ugnijeenih jedan unutar drugoga, to je previe. Najee se za izvorni kd koristi
uvlaenje po 4 ili samo po 2 znaka. Uvlaenje po 4 znaka je dovoljno duboko da bi se i
poetnik mogao lagano snalaziti u kdu, pa smo ga zato i mi koristimo u knjizi.
Iskusnijem korisniku dovoljno je uvlaenje i po samo 2 znaka, to ostavlja dovoljno
prostora za dugake naredbe. Naravno da kod definiranja tabulatora treba voditi rauna
o tipu znakova (fontu) koje se koristi u editoru. Za pravilnu strukturiranost kda
neophodno je koristiti neproporcionalno pismo kod kojeg je irina svih znakova jednaka.

3.11. Kutak za budue C++ gurue

101

Trei estetski detalj vezan je uz praznine oko operatora. Poetniku u svakom


sluaju preporuujemo umetanje praznina oko binarnih operatora, ispred prefiksoperatora i iza postfiks operatora, te umetanje zagrada kada je god u nedoumici oko
hijerarhije operatora. U protivnom osim estetskih, moete imati i sintaktikih problema.
Uostalom, neka sam itatelj procijeni koji je kd je itljiviji:
a = b * c - d / (2.31 + e) + e / 8.21e-12 * 2.43;

ili
a=b*c-d/(2.31+e)+e/8.21e-12*2.43;

Koji ete pristup preuzeti ovisi iskljuivo o vaoj odluci, ali ga onda svakako
koristite dosljedno.

3.11. Kutak za budue C++ gurue


Jedna od odlika programskog jezika C++ jest mogunost saetog pisanja naredbi.
Podsjetimo se samo naredbe za inkrementiranje koja umjesto
i = i + 1;

omoguava jednostavno napisati


i++;

Takoer, mogunost viekratne uporabe operatora pridruivanja u istoj naredbi,


dozvoljava da se primjerice umjesto dviju naredbi
a = b + 25.6;
c = e * a - 12;

napie samo jedna


c = e * (a = b + 25.6) - 12;

s potpuno istim efektom. Ovakvo saimanje kda ne samo da zauzima manje prostora u
editoru i izvornom kdu, ve esto olakava prevoditelju generiranje kraeg i breg
izvedbenog kda. tovie, mnoge naredbe jezika C++ (poput naredbe za
inkrementiranje) vrlo su bliske strojnim instrukcijama mikroprocesora, pa se njihovim
prevoenjem dobiva maksimalno efikasan kd. Pri saimanju kda posebno valja paziti
na hijerarhiju operatora (vidi tablicu 2.16). esto se zaboravlja da logiki operatori
imaju nii prioritet od poredbenih operatora, a da operatori pridruivanja imaju najnii
prioritet. Zbog toga nakon naredbe

102

3. Naredbe za kontrolu toka programa

c = 4 * (a = b - 5);

varijabla a nee imati istu vrijednost kao nakon naredbe


c = 4 * ((a = b) - 5);

ili nakon naredbi


a = b;
c = 4 * (b - 5);

U prvom primjeru e se prvo izraunati b - 5 te e rezultat dodijeliti varijabli a, to je


oito razliito od drugog, odnosno treeg primjera gdje se prvo varijabli a dodijeli
vrijednost od b, a zatim se provede oduzimanje.
Kod C-gurua su uobiajena saimanja u kojima se umjesto eksplicitne usporedbe
s nulom, kao na primjer
if (a != 0) {
// ...
}

pie implicitna usporedba


if (a) {
// ...
}

Iako e oba kda raditi potpuno jednako, sutinski gledano je prvi pristup ispravniji (i
itljiviji) izraz u if ispitivanju po definiciji mora davati logiki rezultat (tipa bool). U
drugom (saetom) primjeru se, sukladno ugraenim pravilima pretvorbe, aritmetiki tip
pretvara u tip bool (tako da se brojevi razliiti od nule pretvaraju u true, a nula se
pretvara u false), pa je konani ishod isti.
Slina situacija je prilikom ispitivanja da li je neka varijabla jednaka nuli. U
dosljednom pisanju ispitivanje bismo pisali kao:
if (a == 0) {
// ...
}

dok bi nerijetki gurui to krae napisali kao


if (!a) {
// ...
}

I u ovom sluaju e oba ispitivanja poluiti isti izvedbeni kd, ali e neiskusnom
programeru iitavanje drugog kda biti zasigurno tee. tovie, neki prevoditelji e
prilikom prevoenja ovako saetih ispitivanja ispisati upozorenja.

3.11. Kutak za budue C++ gurue

103

Mogunost saimanja izvornog kda (s eventualnim popratnim zamkama) ilustrirat


emo programom u kojem traimo zbroj svih cijelih brojeva od 1 do 100. Budui da se
radi o trivijalnom raunu, izvedbeni program e i na najsporijim suvremenim strojevima
rezultat izbaciti za manje od sekunde. Stoga neemo koristiti Gaussov algoritam za
rjeenje problema, ve emo (zdravo-seljaki) napraviti petlju koja e zbrojiti sve
brojeve unutar zadanog intervala. Krenimo s prvom verzijom:
// ver. 1.0
#include <iostream>
using namespace std;
int main() {
int zbroj = 0;
for(int i = 1; i <= 100; i++)
zbroj = zbroj + i;
cout << zbroj << endl;
return 0;
}

Odmah uoavamo da naredbu za zbrajanje unutar petlje moemo napisati krae:


// ver. 2.0
//...
for (int i = 1; i <= 100; i++) {
zbroj += i;
//...

tovie, zbrajanje moemo ubaciti u uvjet za poveavanje kontrolne varijable for petlje:
// ver. 3.0
//...
for (int i = 1; i <= 100; zbroj += i, i++) ;
//...

Blok naredbi u petlji je sada ostao prazan, ali ne smijemo izbaciti znak ;. U dosadanjim
realizacijama mogli smo broja petlje i poveavati i prefiks-operatorom:
// ver. 3.1
//...
for (int i = 1; i <= 100; zbroj += i, ++i) ;
//...

Efekt je potpuno isti u izrazu prirasta for-naredbe izrazi odvojeni znakom , (zarezom)
se izraunavaju postupno, slijeva na desno. Naravno, da su izrazi napisani obrnutim
redoslijedom
for (int i = 1; i <= 100; i++, zbroj += i)

konani zbroj bi bio pogrean prvo bi se uveao broja, a zatim tako uvean dodao
zbroju kao rezultat bismo dobili zbroj brojeva od 2 do 101. Meutim, kada stopimo
oba izraza za prirast

104

3. Naredbe za kontrolu toka programa

// ver. 4.0
//...
for (int i = 1; i <= 100; zbroj += i++) ;
//...

vie nije svejedno koristi li se postfiks- ili prefiks-operator inkrementiranja, tj. da li se


prvo dohvaa vrijednost brojaa, dodaje zbroju i zatim poveava broja, ili se prvo
poveava broja, a tek potom dohvaa njegova vrijednost:
for (int i = 1; i <= 100; zbroj += ++i)

Usporedimo li zadnju inaicu (4.0) s prvom, skraenje kda je oevidno. Ali je isto tako
oito da je kd postao nerazumljiviji: prebacivanjem naredbe za pribrajanje brojaa u
for-naredbu, zakamuflirali smo osnovnu naredbu zbog koje je uope petlja napisana.
Budui da veina dananjih prevoditelja ima ugraene postupke optimizacije
izvedbenog kda, pitanje je koliko e i hoe li uope ovakva saimanja rezultirati brim
i efikasnijim programom. Stoga vam preporuujemo:
Ne troite previe energije na ovakva saimanja, jer e najvjerojatnije
rezultat biti neproporcionalan uloenom trudu, a izvorni kd postati
neitljiv(iji).

You might also like