You are on page 1of 9

Željko Jurić: Principi programiranja /kroz programski jezik C++/

9. Logički izrazi i operatori

Do sada smo isključivo koristili aritmetičke izraze, u kojima su se pojavljivali brojevi, brojčane
promjenljive, i aritmetičke operacije poput sabiranja, itd. Njihov rezultat je uvijek bio neka brojčana
vrijednost. Sada ćemo se upoznati sa logičkim izrazima. To su izrazi za koje jedino možemo utvrditi da
su tačni (engl. true) ili netačni (engl. false). Drugim riječima, jedine vrijednosti koje ima smisla pripisati
logičkim izrazima su vrijednosti “tačno” odnosno “netačno”. Logički izrazi se još nazivaju i uvjeti (engl.
conditions).

Najjednostavniji uvjeti formiraju se poređenjem dvije vrijednosti, koje možemo izvršiti korištenjem
relacionalnih operatora (koji spadaju u grupu tzv. logičkih operatora). Jezik C++ poznaje sljedeće
relacione operatore:

== jednako
!= nije jednako (različito)
< manje od
> veće od
<= manje od ili jednako
>= veće od ili jednako

Na primjer, uvjet “2 > 3” je netačan (tj. njegova vrijednost je “netačno”), dok je uvjet “ 1 <= 4” tačan
(njegova vrijednost je “tačno”). Uvjeti mogu sadržavati promjenljive, i tada njihova tačnost ovisi od
trenutnih vrijednosti promjenljivih upotrijebljenih unutar uvjeta. Na primjer, uz pretpostavku da su
deklarirane sljedeće promjenljive:

int stanje_kase, porez;


double broj;
char inicijal;

možemo formirati uvjete poput sljedećih:

stanje_kase == 100
porez < 1000
broj > 5.2
inicijal == 'P'

Prvi uvjet je tačan samo ukoliko je vrijednost promjenljive “ stanje_kase” jednaka 100, inače je
netačan. Analogno vrijedi za preostala tri uvjeta. Naročito obratite pažnju na razliku između operatora
“==” sa značenjem “da li je jednako” i operatora dodjele “=” sa značenjem “postaje”. Na ovu razliku
ćemo detaljno ukazati nešto kasnije jer je ona Ahilova peta jezika C++ i čest je uzrok veoma ozbiljnim
greškama u programima, koje se teško uočavaju.

Najveću primjenu logički izrazi imaju za formiranje naredbi grananja i naredbi ponavljanja, koje
ćemo upoznati u narednim poglavljima. Na ovom mjestu ćemo razmotriti logičke promjenljive (ili
Booleove promjenljive, u čast Georga Boolea, osnivača matematičke logike), koje pamte da li je neki
uvjet bio ispunjen ili nije. Da bismo vidjeli kako se formiraju ovakve promjenljive, moramo prvo vidjeti
šta je tačno vrijednost nekog uvjeta. U jeziku C vrijedi konvencija da je vrijednost svakog tačnog uvjeta
jednaka jedinici, dok je vrijednost svakog netačnog uvjeta jednaka nuli (drugim riječima, vrijednosti
“tačno” i “1” odnosno vrijednosti “netačno” i “0” su poistovjećene). Dugo vremena (sve do pojave ISO
C++98 standarda) ista konvencija je vrijedila i u jeziku C++. Međutim standard ISO C++98 uveo je
dvije nove ključne riječi “true” i “false” koje respektivno predstavljaju vrijednosti “tačno” odnosno
“netačno”. Tako je vrijednost svakog tačnog izraza “ true”, a vrijednost svakog netačnog izraza

IX – 1
Željko Jurić: Principi programiranja /kroz programski jezik C++/

“false”. Uvedena je i ključna riječ “ bool” kojom se mogu deklarirati promjenljive koje mogu imati
samo vrijednosti “true” odnosno “false”. Na primjer, ako imamo sljedeće deklaracije:
bool u_dugovima, punoljetan, polozio_ispit;

tada su sasvim ispravne slijedeće dodjele (uz pretpostavku da također imamo deklarirane brojčane
promjenljive “stanje_kase” i “starost”):

u_dugovima = stanje_kase < 0;


punoljetan = starost >= 18;
polozio_ispit = true;

Za logičke izraze kažemo da su logičkog tipa, odnosno “ bool”. Međutim, kako je dugo vremena
vrijedila konvencija da su logički izrazi numeričkog tipa, preciznije cjelobrojnog tipa “ int” (s obzirom
da im je pripisivana cjelobrojna vrijednost 1 ili 0), uvedena je automatska pretvorba logičkih vrijednosti
u numeričke i obratno, koja se vrši po potrebi, i koja omogućava miješanje aritmetičkih i logičkih
operatora u istom izrazu, na isti način kako je to bilo moguće i prije uvođenja posebnog logičkog tipa.
Pri tome vrijedi pravilo da se, u slučaju potrebe za pretvorbom logičkog tipa u numerički, vrijednost
“true” konvertira u cjelobrojnu vrijednost “1”, dok se vrijednost “ false” konvertira u cjelobrojnu
vrijednost “0”. U slučaju potrebe za obrnutom konverzijom, nula se konvertira u vrijednost “ false” dok
se svaka numerička vrijednost (cjelobrojna ili realna) različita od nule (a ne samo jedinica) konvertira u
vrijednost “true”. Posljedice ove činjenice razmotrićemo u poglavljima koji slijede. Na ovom mjestu
ćemo navesti jedan jednostavan primjer. Razmotrimo sljedeći programski isječak:

bool a;
a = 5;
cout << a;

Ovaj isječak će ispisati na ekran vrijednost “1”. Pri dodjeli “ a = 5” izvršena je automatska
konverzija cjelobrojne vrijednosti “5” u logičku vrijednost “ true”. Konverzija je izvršena zbog
činjenice da je odredište (promjenljiva “ a”) u koju smještamo vrijednost logičkog tipa. Prilikom ispisa
na ekran, logička vrijednost “ true” konvertira se u cjelobrojnu vrijednost “1”, tako da pri ispisu
dobijamo jedinicu. Naravno, ovaj primjer je potpuno vještački formiran, ali pomaže da se lakše shvati šta
se zapravo dešava.

Zbog činjenice da je podržana automatska dvosmjerna konverzija između numeričkih tipova i


logičkog tipa, moguće je kombinirati aritmetičke i logičke operatore u istom izrazu. Na primjer, ukoliko
se kao neki od operanada operatora sabiranja “+” upotrijebi logička vrijednost (ili logički izraz), ona će
biti konvertirana u cjelobronu vrijednost, s obzirom da operator sabiranja nije prirodno definiran za
operande koji su logičke vrijednosti. Stoga je izraz

5 + (2 < 3) * 4

potpuno legalan, i ima vrijednost “9”, s obzirom da se vrijednost izraza “ 2 < 3” koja iznosi “true”
konvertira u vrijednost “1” prije nego što se na nju primijeni operacija množenja. Ova osobina se često
može korisno upotrijebiti. Na primjer, uz pretpostavku da su “a” i “b” cjelobrojne promjenljive, naredba

a = a + (b < 5);

ili, ekvivalentno, naredba

a += b < 5;

uvećava sadržaj promjenljive “a” za 1 pod uvjetom da je vrijednost promjenljive “b” manja od 5, inače
je ostavlja nepromijenjenom (s obzirom da tada izraz “ b < 5” ima vrijednost “false”, koja se
konvertira u nulu). Razlog zašto smo u prvom slučaju upotrijebili zagradu a u drugom nismo,
uvidjećemo uskoro (u pitanju je prioritet odgovarajućih operatora).

IX – 2
Željko Jurić: Principi programiranja /kroz programski jezik C++/

U nekim slučajevima na prvi pogled nije jasno da li se treba izvršiti pretvorba iz logičkog u
numerički tip ili obrnuto. Na primjer, neka je “a” logička promjenljiva čija je vrijednost “ true”, a “b”
cjelobrojna promjenljiva čija je vrijednost “5”. Postavlja se pitanje da li je uvjet “ a == b” tačan.
Odgovor zavisi od toga kakva će se pretvorba izvršiti. Ako se vrijednost promjenljive “ a” pretvori u
cjelobrojnu vrijednost “1”, uvjet neće biti tačan. S druge strane, ako se vrijednost promjenljive “ b”
pretvori u logičku vrijednost “true”, uvjet će biti tačan. U jeziku C++ uvijek vrijedi pravilo da se u
slučaju kada je moguće više različitih pretvorbi, uvijek uži tip (po opsegu vrijednosti) pretvara u širi tip.
Dakle, ovdje će logička vrijednost promjenljive “ a” biti pretvorena u cjelobrojnu vrijednost, tako da
uvjet neće biti tačan.

S obzirom na automatsku konverziju koja se vrši između logičkog tipa i numeričkih tipova,
promjenljive “u_dugovima”, “punoljetan” i “polozio_ispit” iz jednog od ranijih primjera mogle
su se deklarirati i kao obične cjelobrojne promjenljive (tipa “ int”). Do uvođenja tipa “bool”, tako se i
moralo raditi. Međutim, takvu praksu danas treba strogo izbjegavati, jer se na taj način povećava
mogućnost zabune, i program čini nejasnijim. Stoga, ukoliko je neka promjenljiva zamišljena da čuva
samo logičke vrijednosti, nju treba deklarirati upravo kao takvu.

Već smo upoznali na desetine različitih operatora u jeziku C++. Iz matematike je jasno da množenje
i dijeljenje ima veći prioritet u odnosu na sabiranje i oduzimanje, ali se postavlja pitanje kakav je
prioritet ostalih operatora. Na primjer, može se postaviti pitanje da li će se izraz “ a + b < c + d“
interpretirati kao

(a + b) < (c + d)

ili kao

a + (b < c) + d

Iako su obe varijante u jeziku C++ principijelno dozvoljene, druga varijanta izgleda nelogično. Jezik C+
+ je dodijelio takve prioritete operatorima da je (osim u slučajevima kada upotrebom zagrada naznačimo
drugačije) obično logičnija varijanta ispravna (mada je sam pojam “logičan” dosta upitan). U jeziku C++
postoji čak 17 nivoa prioriteta. Da ne bi bilo zabune, ovdje navodimo potpunu tablicu prioriteta svih C+
+ operatora (mnoge od njih nismo još upoznali, a neke nećemo ni upoznati):

Prioritet: Operatori:

1. (najviši) :: :: (unarni)
2. () [] -> :: ++ (postfiks) –– (postfiks)
3. ! ~ + (unarni) - (unarni) & (unarni) * (unarni)
++ (prefiks) –– (prefiks) new delete sizeof typeof
4. .* ->* (tip)
5. * / %
6. + -
7. << >>
8. < <= > >=
9. == !=
10. &
11. ^
12. |
13. &&
14. ||
15. ?:
16. = += -= *= /= %=

IX – 3
Željko Jurić: Principi programiranja /kroz programski jezik C++/

&= ^= |= <<= >>=


17. (najniži) ,

Množenje i dijeljenje imaju prioritet 5, a sabiranje i oduzimanje prioritet 6. Znaci “+” i “–“
spomenuti pod prioritetom 3 (uz napomenu “unarni” u zagradi) predstavljaju operatore za predznak (npr.
“–7”, “+3” ili “–(2*a)”). Operatori “+” i “–“ su primjeri operatora koji postoje i u unarnoj i u binarnoj
varijanti. Takvi su također i operatori “*”, “ &“ i “::” (u binarnoj varijanti, operator “*” predstavlja
množenje, dok ćemo se sa značenjem njegove unarne varijante upoznati kasnije). Kao što smo ranije
vidjeli, unarni operatori “++” i “ ––” postoje u prefiksnoj i postfiksnoj verziji (“ ++a“ odnosno “a++“),
koje imaju neznatno različite prioritete.

Treba primijetiti da svi relacioni operatori (poput “<” itd.) imaju prioritet niži od aritmetičkih
operatora (poput “+”, “–“ itd.), pa se, zbog toga, izrazi poput

a + b < c + d

grupiraju “ispravno” kao

(a + b) < (c + d)

Operatori dodjele (“=”, “+=” itd.) imaju veoma nizak prioritet (što je sasvim logično), tako da će
ranije spomenute dodjele poput

u_dugovima = stanje_kase < 0;

biti ispravno shvaćene kao

u_dugovima = (stanje_kase < 0);

a ne kao

(u_dugovima = stanje_kase) < 0;

Šta bi radila ova druga varijanta? Ona bi izvršila dodijelu promjenljivoj “ u_dugovima” vrijednost
promjenljive “stanje_kase”, a zatim ispitala da li je rezultat te dodjele manji od nule, i ovisno od toga,
vratila rezultat “true” ili “false”. Ovo vrlo vjerovatno nije ono što smo željeli, tako da kompajler,
posve logično, podrazumijeva prvu varijantu. Naravno, ukoliko je baš to ono što želimo, uvijek možemo
upotrijebiti zagrade da eksplicitno naznačimo redoslijed izvođenja operacija.

Jedini operator koji ima niži prioritet od dodjele je zarez. Značenje zareza kao operatora uvidjećemo
u poglavlju o naredbama ponavljanja. Na ovom mjestu ćemo samo reći da je tako nizak prioritet
operatora “zarez” u skladu sa intuitivnim shvatanjem da konstrukcije poput

int a = 5, b = 10;

ne treba da budu “besmisleno” grupirane kao

int a = (5, b) = 10;

S druge strane, operatori “++” i “––“ i u prefiksnoj i u postfiksnoj formi imaju veoma visok
prioritet, tako da se “otkačena” naredba, koju smo pisali u jednom od ranijih poglavlja

b = 3 + 2 * (a++);

mogla pisati i bez zagrade kao

IX – 4
Željko Jurić: Principi programiranja /kroz programski jezik C++/

b = 3 + 2 * a++;

Naravno, ako Vas već “boli glava” od razmišljanja o prioritetima operatora, ništa loše nema u tome da
sami pomoću zagrada eksplicitno odredite kakav redoslijed operacija želite, čak i ako se takav redoslijed
podrazumijevao i bez zagrada.

Izbor prioriteta pojedinih operatora nije baš “najsretnije” odabran. Na primjer, ako želimo da se
“svojim očima” uvjerimo kolika je vrijednost izraza “ 2 < 3”, imaćemo problema ako napišemo naredbu

cout << 2 < 3;

Naime, operator “<<” kojim vršimo ispis na ekran (napomenimo ovo nije jedina funkcija ovog
operatora) ima veći prioritet u odnosu na operator “<”, pa se gornja naredba besmisleno grupira kao

(cout << 2) < 3;

Posljednji izraz je sintaksno neispravan, jer se rezultat izraza “ cout << 2” (koji zapravo predstavlja sam
objekat “cout”, što u ovom trenutku nije bitno) ne može upotrijebiti kao lijevi operand operatora “ <”.
Rješenje ovog problema je, naravno, u korištenju zagrada:

cout << (2 < 3);

Složeniji logički izrazi mogu se formirati korištenjem logičkih operatora. Programski jezik C++
poznaje sljedeće logičke operatore:

&& konjukcija (logičko “i”)


|| disjunkcija (logičko “ili”)
! logička negacija

Ovi operatori kao svoje operande očekuju logičke vrijednosti, ali će prihvatiti i numeričke vrijednosti,
koje će tom prilikom biti pretvorene u logičke, po već opisanim pravilima. Interpretacija ovih operatora
predstavljena je sljedećom tablicom:

false && false = false false || false = false !false = true


false && true = false false || true = true !true = false
true && false = false true || false = true
true && true = true true || true = true

Logički operatori se najčešće koriste za formiranje kombiniranih uvjeta. Na primjer, sljedeća dva
uvjeta koriste logičke operatore:

starost >= 16 && starost < 65


starost < 16 || starost >= 65

Prvi od ova dva izraza je tačan ukoliko je vrijednost promjenljive “ starost” veća ili jednaka 16 i
manja od 65, a drugi je tačan ukoliko je vrijednost promjenljive “ starost” manja od 16 ili veća ili
jednaka 65. Obratite pažnju da su ova dva izraza uvijek suprotna po vrijednosti (ako je prvi tačan, drugi
je netačan, i obrnuto). Također, u oba izraza dodatne zagrade nisu potrebne, zbog toga što operatori
“&&” i “||” imaju niži prioritet od operatora poređenja. Naravno, ništa ne bi bilo loše da smo napisali:

(starost >= 16) && (starost < 65)


(starost < 16) || (starost >= 65)

Uvođenje dodatnih zagrada je korisna praksa ako nismo sigurni u prioritet operacija, a ono nam također
pomaže i da “olakšamo život” onima koji pokušavaju da shvate šta i kako program radi.

IX – 5
Željko Jurić: Principi programiranja /kroz programski jezik C++/

Neko bi se mogao zapitati da li bi se prvi od prethodna dva uvjeta mogao napisati na sljedeći način,
koji je uobičajen u matematici, a koji je podržan u nekim specijalističkim matematičkim programskim
jezicima (npr. u programskom paketu Mathematica):

16 <= starost < 65

Odgovor je odrečan. Na žalost, gornji izraz je sintaksno potpuno ispravan, ali ne obavlja onu funkciju
koju bismo očekivali. Zapravo, prethodni izraz je uvijek tačan, bez obzira na vrijednost promjenljive
“starost”! Da bismo ovo pokazali, razmotrimo kako se ovaj izraz tačno interpretira. S obzirom da su
operatori “<=” i “<” istog prioriteta, ovaj izraz se izračunava redom, slijeva nadesno, odnosno
interpretira se kao

(16 <= starost) < 65

Šta se sad dešava? Vrijednost izraza “ 16 <= starost” je “true” ili “false”, zavisno kakva je
vrijednost promjenljive “starost”. Ta vrijednost se sada upoređuje sa brojem 65, pri čemu dolazi do
njene pretvorbe iz logičke vrijednosti u cjelobrojnu vrijednost “0” ili “1”. Međutim, ma koja od ove
dvije vrijednosti manja je od 65, tako da je cjelokupan izraz na kraju tačan! Kao pouku, možemo izvesti
zaključak da gotovo nikada nema smisla u istom izrazu koristiti više od jednog relacionog operatora,
osim u slučaju kada se između njih nalazi neki od logičkih operatora “ &&” ili “||”.

Operator “!” može se koristiti za negiranje uvjeta, ali zbog njegovog veoma visokog prioriteta,
dodatne zagrade su skoro uvijek neophodne. Na primjer:

!(starost > 65)

Ovaj uvjet je tačan samo ukoliko vrijednost promjenljive “ starost” nije veća od 65. Međutim, da smo
izostavili zagrade, tj. da smo napisali uvjet

!starost > 65

on bi bio interpretiran pogrešno. Naime, operator “!” bio bi primijenjen samo na promjenljivu
“starost”. Kako je ona cjelobrojna promjenljiva, a operator “ !” očekuje logičku vrijednost, njena
vrijednost bi bila konvertirana u “true” odnosno “false” (zavisno da li joj je vrijednost različita od
nule ili jednaka nuli). Nakon negacije, ta vrijednost bi postala “ false” odnosno “true” respektivno.
Konačno, ta bi se vrijednost poredila sa brojem 65. Kako se logička vrijednost ne može direktno porediti
sa brojem, ona bi bila pretvorena u brojčanu vrijednost “0” ili “1”, koja bi se poredila sa brojem 65.
Rezultat poređenja bi u svakom slučaju bio netačan, tako da bi konačna vrijednost ovog uvjeta bila
“false”. To sigurno nije ono što smo željeli.

Treba razmotriti još neke greške koje početnici mogu učiniti pri korištenju logičkih operatora.
Zamislimo da želimo da formiramo uvjet koji je tačan ako i samo ako je vrijednost promjenljive “a”
jednaka 2 ili 3. Ispravno bi bilo napisati sljedeću konstrukciju:

a == 2 || a == 3

Međutim, početnik bi, ponesen analogijom sa govornim jezikom, mogao napisati sljedeći uvjet:

a == 2 || 3

Problem je što je ovaj uvjet sintaksno ispravan, ali ne radi ono što treba (zapravo, on je uvijek tačan).
Naime, prvi operand operatora “||” je izraz “a == 2”, koji je tačan ili netačan, ovisno od vrijednosti
promjenljive “a” (operator “==” ima veći prioritet u odnosu na operator “ ||”), dok je njegov drugi
operand cijeli broj “3”. Kako “3” nije logička vrijednost, ona se konvertira u logičku vrijednost “ true”.

IX – 6
Željko Jurić: Principi programiranja /kroz programski jezik C++/

Kako je vrijednost disjunkcije jednaka “ true” ukoliko barem jedan od operanada ima vrijednost
“true”, to i cijeli izraz ima vrijednost “ true”, neovisno od vrijednosti promjenljive “ a”. Još
besmisleniju interpretaciju ćemo dobiti ukoliko napišemo:

a == (2 || 3)

Ovaj izraz će biti tačan ako i samo ako je vrijednost promjenljive “ a” jednaka jedinici (razmislite zašto).
Problem je, u suštini, veoma sličan problemu koji smo imali pri interpretaciji sintaksno ispravnog ali
logički nekorektnog izraza “16 <= starost < 65”. Ako Vam sve ovo djeluje konfuzno, zapamtite
barem slijedeće: ne pravite ovakve greške.

Standard ISO C++98 jezika C++ predvidio je da se kao alternativa za oznake operatora “ &&”, “||” i
“!” mogu koristiti i ključne riječi “ and”, “or” i “not”. Tako smo maloprije napisane uvjete mogli
napisati i na sljedeći način:

starost >= 16 and starost < 65


starost < 16 or starost >= 65
not(starost > 65)

Ipak, ovaj način pisanja nije uobičajen. Prvo, uveden je u jezik C++ tek nedavno, a drugo, smatra se da
nije “u duhu” jezika C++.

Budite na oprezu: pored logičkih operatora “&&” i “||”, jezik C++ posjeduje i operatore “&” i “|” sa
sasvim drugačijim značenjem (koji uopće nisu logički operatori). Tako ako greškom napišete izraz

starost >= 16 & starost < 65

kompajler neće prijaviti nikakvu grešku, jer se također radi o legalnom sintaksno ispravnom izrazu, ali
koji ne predstavlja ono što smo (vjerovatno) zamislili. Ovdje se opet susrećemo sa problemom da
prilikom izvršavanja programa računar nažalost ne izvršava ono što smo zamislili nego ono što smo
napisali.

Interesantna osobina operatora “&&” i “||” je da se u nekim slučajevima njihov desni operand uopće
ne izračunava. Ukoliko pretpostavimo da “x” i “y” predstavljaju neke logičke ili numeričke izraze, tačna
interpretacija izraza “x && y ” i “x || y ” je sljedeća:

x && y Ako x ima vrijednost “0” ili “false”, vrijednost čitavog izraza je “false”, pri
čemu se y uopće i ne pokušava izračunati. U suprotnom se izračunava i y. Ako
je njegova vrijednost “0” ili “false”, vrijednost čitavog izraza je “ false”. U
suprotnom, vrijednost čitavog izraza je “true”.

x || y Ako x ima vrijednost “true” ili brojnu vrijednost različitu od “0” ili, vrijednost
čitavog izraza je “true”, pri čemu se y uopće i ne pokušava izračunati. U
suprotnom se izračunava i y. Ako je njegova vrijednost “true” ili brojna
vrijednost različita od “0”, vrijednost čitavog izraza je “ true”. U suprotnom,
vrijednost čitavog izraza je “false”.

Ako pažljivo razmotrimo ove interpretacije, vidjećemo da ćemo na kraju kao rezultat dobiti upravo
ono što očekujemo. Međutim, karakteristično je da se vrijednost izraza “y” uopće ne računa ukoliko se
rezultat može predvititi samo na osnovu operanda “x”. Ovakav princip naziva se skraćeno izračunavanje
(engl. short evaluation). Programer uglavnom ne treba da brine o ovome, ali su izvjesna iznenađenja
ipak moguća ukoliko izraz “y” sadrži bočne efekte. Naime, pod određenim uvjetima ovaj izraz uopće
neće biti izračunat, pa ni odgovarajući bočni efekti neće biti izvršeni. Zamislimo, na primjer, da želimo

IX – 7
Željko Jurić: Principi programiranja /kroz programski jezik C++/

da uvećamo sadržaj promjenljivih “a” i “b” za 1, a zatim da formiramo uvjet koji će testirati da li su obje
promjenljive dostigle vrijednost 10. Neko bi mogao sve ovo da napiše u formi jednog izraza oblika

++a == 10 && ++b == 10

Međutim, izraz “++b == 10” uopće se neće izračunavati ukoliko se izraz “ ++a == 10” pokaže netačnim,
tako da ni vrijednost promjenljive “ b” neće biti uvećana. Naravno da pisanje ovakvih izraza treba
izbjegavati. U ovom slučaju je bilo mnogo preglednije prvo uvećati promjenljive posebnim naredbama, a
tek onda formirati izraz koji obavlja njihovo poređenje.

Treba obratiti pažnju da operatori “&&” i “||” nisu istog prioriteta, nego operator “&&” ima viši
prioritet od operatora “||”. Tako, ako želimo da formiramo uvjet koji je tačan ukoliko je vrijednost
promjenljive “a” jednaka 2 ili 3, a vrijednost promjenljive “b” jednaka 5, moramo pisati

(a == 2 || a == 3) && b == 5

a ne samo

a == 2 || a == 3 && b == 5

jer će ovakav uvjet, zbog prioriteta, biti interpretiran kao

a == 2 || (a == 3 && b == 5)

Od logičkih izraza, samih za sebe, nema neke osobite koristi. Već smo rekli da je njihova glavna
primjena u naredbama izbora i ponavljanja, koje ćemo upoznati u poglavljima koji slijede. Međutim,
prije toga ćemo upoznati operator “ ? :” koji omogućava da se logički izrazi veoma elegantno iskoriste.
Ovaj operator ima tri operanda, i prema tome, predstavlja ternarni operator (jedini takve vrste u jeziku
C++). Forma u kojoj se koristi ovaj operator ima sljedeći oblik:
x ? y : z

Ovdje su, u općem slučaju, “x”, “y” i “z” također izrazi. Izraz “x” bi trebao imati logičku vrijednost, a
dopuštena je i proizvoljna numerička vrijednost (koja će biti automatski konvertirana u logičku, prema
već objašnjenim pravilima). Interpretacija ovog izraza je sljedeća: ukoliko je izraz “x” tačan, tada je
vrijednost čitavog izraza jednaka vrijednosti izraza “y”, pri čemu se izraz “z” uopće ne pokušava
izračunati. S druge strane, ukoliko je izraz “x” netačan, tada je vrijednost čitavog izraza jednaka
vrijednosti izraza “z”, pri čemu se vrijednost izraza “y” uopće ne pokušava izračunati. Na primjer,
naredba

b = (a > 0) ? a : -a;

dodjeljuje promjenljivoj “b” vrijednost promjenljive “a” ukoliko je ona pozitivna, a vrijednost “ –a”
ukoliko nije (drugim riječima, dodjeljuje promjenljivoj “ b” apsolutnu vrijednost promjenljive “a”).
Kako operator “? :” ima veoma nizak prioritet, zagrade oko operanada “x”, “y” i “z” gotovo nikad nisu
potrebne, ali se preporučuju zbog čitljivosti. Tako smo prethodnu naredbu mogli napisati i kao

b = a > 0 ? a : -a;

S druge strane, također zbog veoma niskog prioriteta, zagrade oko čitavog izraza oblika “x ? y : z ”
praktično su uvijek potrebne kad god se on upotrijebi kao sastavni dio nekog složenijeg izraza. Na
primjer, ukoliko bismo na ekran željeli ispisati apsolutnu vrijednost promjenljive “a” uz upotrebu
operatora “? :”, morali bismo pisati

cout << ((a > 0) ? a : -a);

IX – 8
Željko Jurić: Principi programiranja /kroz programski jezik C++/

a ne samo

cout << (a > 0) ? a : -a;


jer bi u tom slučaju napisani izraz bio interpretiran kao

(cout << (a > 0)) ? a : -a;

Što je najgore, ovako interpretirani izraz je također sintaksno ispravan. Naime, rezultat izraza u zagradi
prije znaka “?” je upravo objekat izlaznog toka “ cout”, a vidjećemo kasnije da se on pod izvjesnim
okolnostima može upotrijebiti kao logička vrijednost! Zapravo, jedan od najvećih problema jezika C++
je njegova velika sloboda, koja omogućava da mnoge konstrukcije, koje ne rade ono što bi na prvi
pogled trebalo da rade, budu sintaksno ispravne, i prema tome, savršeno legalne! Interesantno je
napomenuti da sličan izraz bez ijedne zagrade, tj. izraz

cout << a > 0 ? a : -a;

nije sintaksno ispravan, jer se on interpretira kao

((cout << a) > 0) ? a : -a;

a rezultat izraza “cout << a“ ne može se porediti sa nulom!

Izrazi “y” i “z” u opisu operatora “? :” mogu biti i stringovi, tako da je sljedeća konstrukcija
savršeno ispravna:

cout << ((x >= 0) ? "Broj je nenegativan" : "Broj je negativan");

Ova konstrukcija ispisuje na ekran tekst “Broj je nenegativan” odnosno “Broj je negativan” u zavisnosti
kakva je vrijednost promjenljive “x”. U sljedećem poglavlju vidjećemo kako se isti efekat na jasniji
način može ostvariti uz pomoć naredbi grananja.

Nema nikakve prepreke da se kao izrazi “y” i “z” u opisu operatora “? :” pojave ponovo izrazi koji
sadrže operator “? :”. Na taj način dobijaju se dosta konfuzne konstrukcije. Na primjer, sljedeća
naredba

sgn = (x > 0) ? 1 : ((x == 0) ? 0 : -1);

dodjeljuje promjenljivoj “sgn” vrijednost “1”, “0” ili “–1”, zavisno od toga da li je vrijednost
promjenljive “x” veća od nule, jednaka nuli ili manja od nule respektivno. Zbog prioriteta operacija, ista
konstrukcija se mogla napisati bez ikakvih zagrada, tj. u obliku

sgn = x > 0 ? 1 : x == 0 ? 0 : -1;

za koji možemo reći sve osim da je jasan. Nemojte se mnogo uzbuđivati ako ne razumijete ovu
konstrukciju. Nije velika šteta, s obzirom da će u sljedećem poglavlju biti pokazano kako se isti efekat
može postići na mnogo razumljiviji način, korištenjem naredbi grananja.

Operator “? :” naslijeđen je iz jezika C, i korišten je jako mnogo u danima kada je jezik C nastajao,
jer su tada primarni zahtjevi bili efikasnost i kratkoća programa. Danas, kada su jasnost i čitljivost
programa primarni zahtjevi, prevelika upotreba ovih operatora se ne preporučuje, jer obično dovode do
veoma nečitljivih programa. Efekat ovog operatora uvijek se može simulirati primjenom naredbi
grananja, na mnogo čitljiviji način, a obično uz sasvim neznatan ili nikakav gubitak efikasnosti.

IX – 9

You might also like