You are on page 1of 18

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)

Akademska 2014/2015
Enil Paji

OSNOVE RAUNARSTVA
DODATAK:
Prefiksni, postfiksi i ostali operatori u C-u
(Dio 1)
Sadraj: (Kliknuti za navigaciju po dokumentu)
Tabela svih operatora u C-u ..............................................................................................
Tabela prioriteta i asocijativnosti operatora ......................................................................
Operatori +, , *, /, % ......................................................................................................
Primjer: razbijanja broja na cifre ...................................................................................
Postfiksni operatori ...........................................................................................................
Boni efekti u C-u .............................................................................................................
Prefiksni operatori .............................................................................................................
Ternarni (kondicionalni) operator ......................................................................................
Kombinovani operatori dodjele, zarez operator i operator unarni minus .........................
Konverzioni operator ........................................................................................................

2
4
5
6
7
9
10
12
15
17

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
Vrlo je vano upoznati se sa operatorima koje nam jezik C nudi. Neki su dosta intuitivni
(poput sabiranja a + b, oduzimanja a b, mnoenja a * b i slino), dok su drugi
neintuitivni nekome ko nema iskustva pri radu sa njima (prefiksni i postfiksni operatori ++a i
a++, operator pristupa a.b, operator dereferenciranja *a i slino veinom neintuitivni zbog
svoga prioriteta i asocijativnosti). Mi emo ovdje nabrojati najee koritene operatore,
klasificirajui ih po svrsi, binarnosti i po prioritetu, sa naglaskom na prefiksne i postfiksne
(sufiksne) operatore dekrementiranja i inkrementiranja. Takoer emo skrenuti panju na tzv.
bone efekte koji se mogu javiti.
Ovo je prvi dio dokumenta, i on govori generalno o operatorima, dok e drugi dio biti
fokusiran na prefiksne i postfiksne operatore nad pokazivakim varijablama, gdje u igru ulazi
i operator dereferenciranja.
Navedimo tabelu svih operatora u C-u sa njihovim veoma kratkim objanjenjima:
Operator
+

*
/
%
+ (unarno)
(unarno)
++ (prefiks)
++ (postfiks)
-- (prefiks)
-- (postfiks)
&&
||
!
>
<
>=
<=
==
!=
~
&
|
^
>>
<<

+=

Znaenje
Sabiranje: a + b
Oduzimanje: a b
Mnoenje: a * b
Dijeljenje: a / b
Ostatak pri cjelobrojnom
dijeljenjeu modulo
dijeljenje: a % b
Unarni plus: +a
Unarni minus: -a
Prefiksno inkrementiranje:
++a
Postfiksno
inkrementiranje: a++
Prefiksno dekrementiranje:
--a
Postfiksno
dekrementiranje: a-Logiko I (engl. and):
a && b
Logiko ILI (enlg. or):
a || b
Logiko NE (engl. not): !a
Vee od: a > b
Manje od: a < b
Vee ili jednako od: a >= b
Manje ili jednako od:
a <= b
Jednako: a == b
Nije jednako: a != b
Binarno NE (not): ~a
Binarno I (and): a & b
Binarno ILI (or): a | b
Binarno iskljuivo ILI
(xor): a ^ b
Binarno desno shiftanje
Binarno lijevo shiftanje

-=
*=
/=
%=
&=
|=
^=
<<=
>>=
=
*
(dereferenciranje)
&
(adresni operator)
[]
->
.
,
?:
sizeof
(tip) - konverzije

Sjedinjeno sabiranje: a +=
b isto kao a = a + b
a -= b isto kao a = a b
a *= b isto kao a = a * b
a /= b isto kao a = a / b
a %= b isto kao a = a % b
Sjedinjeno binarno I: a &=
b isto kao a = a & b
Binarno ILI: a |= b isto kao
a=a|b
Binarno iskljuivo ILI
(xor): a ^= b isto kao a = a
^b
Binarno lijevo shiftanje: a
<<= b isto kao a = a << b
Binarno desno shiftanje: a
>>= b isto kao a = a >> b
Operator dodjele: a = b (a
postaje b)
Dereferenciranje
pokazivake varijable: *a
Uzimanje adrese varijable:
&a
Indeksiranje nizova:
a[broj]
Strukturno
derefenerciranje: a->b
Operator pristupa (kod
struktura): a.b
Zarez operator: a, b
Ternarni operator:
uslov ? tacno : netacno
Operator koji vraa
veliinu promjenljive
Pretvaranje tipova: (a) b
npr. (int) 4.54

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
Prva klasifikacija operatora koju emo objasniti jeste klasifikacija po asocijativnosti.
Operatori u C-u mogu biti lijevo asocijativni i desno asocijativni. Neka je neki operator, te
neka a b c predstavlja a operator b operator c. Operator je lijevo asocijativan ukoliko
se a b c parsira kao ((a b) c), dok je navedeni operator desno asocijativan
ukoliko se parsira kao (a (b c)).
Kao primjer navedimo da je operator < lijevo asocijativan: if (a < b < c) se tretira kao
if ((a < b) < c). Konkretan primjer: if (10 < 5 < 3), e uvijek biti taan, jer se
tretira kao if ((10 < 5) < 3) , a (10 < 5)ima vrijednost 0 (netano) pa je cijeli uslov
ovakav: if (0 < 3) to je uvijek tano.
Operator dodjele (=) je desno asocijativan, pa se konstrukcije poput a = b = c = 12
tretiraju kao a = (b = (c = 12)). Operator dodjele je morao biti desno asocijativan, jer
da nije, onda konstrukcija iznad ne bi bila mogua, tj. bilo bi tretirano (u sluaju da je lijevo
asocijativan) kao: ((a = b) = c) = 12, to nije mogue zbog toga to izraz (a = b) nije
l-vrijednost (ne moe se njemu dodjeljivati).
Za razliku od operatora dodjele (=) koji je desno asocijativan, operator poreenja (==) je
lijevo asocijativan. Zbog toga se konstrukcija a == b == c tretira tako da prvo poredi a i b,
pa onda rezultat toga poreenja (koji moe biti 1 ili 0) poredi sa c: ((a == b) == c)) .
Sada navedimo zanimljiv primjer: if (7 == 7 == 7), ovaj uslov e uvijek biti netaan,
tretira se kao if ((7 == 7) == 7). 7 == 7 e biti tano, tj. bie 1, i onda se to poredi sa
7: if (1 == 7) to je uvijek netano. Sa druge strane, ovo e biti tano, i kd uslov e se
izvriti: if (7 == 7 == 1).
Operatori se takoer mogu klasificirati po prioritetu. Vano je da znamo prioritet pojedinih
operatora kako ne bismo imali neispravan rad programa. Pogledajmo izraz a + b * c.
Ovdje je intitivno jasno da se izraz tretira kao a + (b * c), jer operator mnoenja ima vei
prioritet od operatora sabiranja. Jasno je i da e izraz a * -b c * 12.4 biti evaluiran
ovako: (a * (-b)) (c * 12.4). Gdje se vidi da operator unarni minus (-b) ima
najvei prioritet od svih navedenih u izrazu. Znaenje operatora unarni minus emo objasniti
kasnije. ta ukoliko imamo vie operatora sa istim prioritetom? Pogledajmo sljedei primjer:
b / 2.5 * a. Da li e biti tretirano kao b / (2.5 * a) ili kao (b / 2.5) * a? Eh,
ukoliko imamo operatore istog prioriteta, onda se gleda njihova asocijativnost. Operatori
dijeljenja (/), mnoenja (*) su lijevo asocijativni, ba kao i modulo operator (%). Stoga e se
izraz iznad tretirati kao (b / 2.5) * a. Operator oduzimanja () je lijevo asocijativan, pa
se izraz 1025 tretira kao (102)5, to daje rezultat 3, a ne kao 10(25), to bi dalo
pogrean rezultat 13.
Tabelu asocijativnosti i prioriteta operatora emo dati na sljedeoj stranici. Tabela takoer
ukljuuje i informaciju o binarnosti operatora, tj. sa koliko operanada operator radi (unarni
operatori sa jednim operandom, binarni sa dva i ternarni sa tri).

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
Prioritet

1
(najvei)

4
5

6
7
8
9
10
11
12
13

14

15
(najmanji)

Operator
++
-[]
.
->
()
++
-+
!
~
(tip)
*
&
sizeof
*
/
%
+
>>
<<
<
<=
>
>=
==
!=
&
^
|
&&
||
?:
=
+=
-=
*=
/=
%=
<<=
>>=
&=
^=
|=
,

Opis (generalni primjer koritenja)


Postfiksni inkrement (a++)
Postifksni dekrement (a)
Indeksiranje nizova (a[b])
Operator pristupa kod struktura (a.b)
Operator indirektnog pristupa (a->b)
Funkcijski operator (F(), F(a, b...))
Prefiksni inkrement (++a)
Prefiksni dekrement (a)
Unarno plus (+a)
Unarno minus (a)
Negacija (!a)
Binarno NE (not) (~a)
Konverzijski operator ((a)b)
Operator dereferenciranja (*a)
Adresni operator (&a)
Veliina (u bajtima) varijable (sizeof a)
Mnoenje (a * b)
Dijeljenje (a / b)
Cjelobrojno dijeljenje modulo (a % b)
Sabiranje (a + b)
Oduzimanje (a b)
Binarno desno shiftanje (a >> b)
Binarno lijevo shiftanje (a << b)
Manje od (a < b)
Manje ili jednako od (a <= b)
Vee od (a > b)
Vee ili jednako od (a >= b)
Jednako (a == b)
Nije jednako (a != b)
Binarno I (bin. and) (a & b)
Binarno iskljuivo ILI (xor) (a ^ b)
Binarno ILI (bin. or) (a | b)
Logiko I (log. and) (a && b)
Logiko ILI (log. or) (a || b)
Kondicionalni operator (a ? b : c)
Dodjela (a = b)
Dodjela i sabiranje (a += b)
Dodjela i oduzimanje (a = b)
Dodjela i mnoenje (a *= b)
Dodjela i dijeljenje (a *= b)
Dodjela i modulo (a %= b)
Dodjela i bin. lijevo shiftanje (a <<= b)
Dodjela i bin. desno shiftanje (a =>> b)
Dodjela i binarno I (and) (a &= b)
Dodjela i bin. isklj. ILI (xor) (a ^= b)
Dodjela i binarno ILI (or) (a |= b)
Zarez operator (a, b)

Asocijativnost

Lijevo

Desno

Lijevo

Lijevo
Lijevo

Lijevo

Lijevo
Lijevo
Lijevo
Lijevo
Lijevo
Lijevo
Desno

Desno

Lijevo

Binarni?
Ne
Ne
Da
Da
Ne
Da/Ne
Ne
Ne
Ne
Ne
Ne
Ne
Ne
Ne
Ne
Ne
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Ternarni
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da
Da

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
Sada emo da opiemo neke od navedenih operatora. U ovom dokumentu nee biti opisani svi
navedeni operatori iz tri razloga: neke neemo koristiti na ovom predmetu, dok emo se sa
nekima upoznati tek kasnije (ti e operatori biti vjerovatno opisani u drugom dijelu ovog
dodatka koji e se pojaviti kasnije) i trei razlog je to su neki ve opisani u prethodnim
dokumentima (npr. logiki operatori).

Operatori sabiranja (+), oduzimanja (), mnoenja (*), dijeljenja (/) i


modulo operator (%)
Ovi operatori se ubrajaju u klasu binarnih operatora (rade sa dva operanda); prva dva
operatora imaju manji prioritet od preostala tri. Veinom nam je poznata njihova
funkcionalnost (ili intuitivno ili ve opisano ranije npr. modulo operator). Operatori + i -
imaju isti prioritet i on je manji od prioritet operator *, / i % koji meusobno imaju
isti prioritet. Svi navedeni operatori su lijevo asocijativni, tj. izrazi poput a b c se
tretiraju na sljedei nain: (a b) c.
Jo da napomenemo da dijeljenje sa nulom rezultira drugaijim ponaanjem programa ukoliko
dijelimo cijele brojeve i ukoliko dijelimo realne brojeve. Standard C-a preporuuje da se za
realne tipove koristi IEEE754 reprezentacija brojeva, koja ima definisane nenormalne
brojeve poput inf, -inf (odnosno INF i -INF), kao i ne-broj nan. Broj inf je
specijalna reprezentacija beskonanosti.
Ukoliko uradimo neto poput sljedeeg, program e raditi ispravno i trebao bi ispisati inf
(da smo koristili %F umjesto %f, bilo bi ispisano INF).
double br = 1 / 0.0;
printf ("%f", br);

Ovo je ispravan program, i vrijednost inf je ispravna vrijednost. Moemo ispisati i


negativnu beskonanost, tj. INF sa sljedeim kdom (stavili smo %F pri ispisu):
double br = 1 / 0.0;
printf ("%F", -br);

Ali, ukoliko pokuamo podijeliti cijele brojeve, tada ve dolazimo do nedefinisanog


ponaanja i na program nije ispravan. Sljedei isjeak e vjerovatno dovesti do toga da nam
program krahira:
int br = 1 / 0;
printf ("%d", br);

Stoga, treba posebno obratiti panju pri cjelobrojnom dijeljenju. I modulo dijeljenje sa nulom
isto tako stavlja program u nedefinisano stanje (najvjerovatnije e se desiti krahiranje
programa). Npr. int br = 1 % 0; e dovesti program u nedefinisano stanje.
Pokaimo i zanimljiv nain kako saznati cifre nekog broja koritenjem modulo operatora.
Modulo operator daje ostatak pri cjelobrojnom dijeljenju (npr. 10 % 3 = 1, gdje je 1 ostatak),

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
to znai da, ukoliko neki broj cjelobrojno podijelimo modulo operatorom sa 10, dobiemo
njegovu zadnju cifru. Npr. 321 % 10 je 1; 457 % 10 je 7, i tako dalje. Ukoliko broj pomou
modulo operatora podijelimo sa 100, dobiemo njegove posljednje dvije cifre, npr. 3241 %
100 je 41. Ovo nam govori da moemo razviti algoritam za razbijanje cijelog broja na njegove
cifre. Napomenimo da modulo operator radi iskljuivo sa cijelim brojevima. Za realne brojeve
se mogu koristiti neke bibliotene funkcije, poput fmod iz <math.h> biblioteke. Pogledajmo
zanimljiv primjer koji e ispisati sve cifre nekog broja:
#include <stdio.h>
int main()
{
int broj;
printf ("Unesite broj: ");
scanf ("%d", &broj);
printf ("\nCifre broja %d su: \n", broj);
if (broj == 0) printf ("0\n");
/* Isto kao: broj = broj * -1; ili kao broj = -broj; */
if (broj < 0) broj *= -1;

while (broj > 0)


{
int cifra = broj % 10;
printf ("%d\n", cifra);
broj /= 10; /* Isto kao: broj = broj / 10; */
}
printf ("\n");
return 0;
}

Program iznad nakon kompajliranja, pokretanja i unosa broja izgleda ovako:

Primijetimo da smo posebno testirali da li je broj jednak nuli. To smo uradili zbog toga to
uslov u while petlji ispod ne bi bio taan i za broj nula ne bi bile ispisane cifre. Takoer smo
broj testirali na pozitivnost i ako nije pozitivan, pomnoili smo ga sa -1. Moe se sada rei a
ta da je uslov u while petlji bio broj != 0 umjesto broj > 0?. Tano, da je takav uslov
bio, program bi radio i ispisao negativne cifre (npr. za broj 137 bilo bi ispisano -7, -3 i -1,
svaki u novom redu, to je malo runo). Jo je vano da smo u while petlji broj dijelili sa 10,
kako bismo svaki put dobili novu cifru (npr 123 / 10 je 12, pa onda kada uradimo 12 % 10
dobiemo 2, tj. drugu cifru). A to dijeljenje je pomoglo da naa while petlja nije beskonana
(onda broj nikad ne bi bio manji od 0 da ga nismo smanjivali dijeljenjem). Takoer se moe
primijetiti da su cifre ispisane u obrnutom redoslijedu (to je, ako se analizira kd i logino).
Ovo se moe iskoristiti da cifre nekog broja obrnemo, tj. zamjenimo njihov redoslijed.

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji

Postfiksni operatori inkrementiranja (++) i dekrementiranja (--)


Posebnu panju u ovom dokumentu emo posvetiti postifksnim i prefiksnim operatorima
inkrementiranja i dekrementiranja. Oni za zadatak imaju izmjenu varijable, ali da dozvole
njeno koritenje neposredno ili prije izmjene (postfiksni operatori) ili neposredno nakon
izmjene (prefiksni operatori).
Postfiksni (ili sufiksni) operatori inkrementiranja/dekrementiranja (u nastavku samo
postfiksni operatori) slue da vrate vrijednost varijable i nakon toga je inkrementiraju ili
dekrementiraju. Nazivaju se postfiksni zato to se piu nakon imena varijable (npr. a++), te
predstavljaju sufiks.
Ukoliko se posfiksni operator nalazi samo u jednoj naredbi (a ne izrazu), onda je on jednak i
prefiksnom operatoru i normalnim operatorima sabiranja (a += b, a = a + b). Pogledajmo
primjer:
int broj = 10;
/* Isto kao ++broj, kao i broj += 1 tj. broj = broj + 1 */
broj++;

Kd iznad sadi naredbu koja sa sastoji samo od broj++; tj. jedne komande, pa se isti efekat
moe postii i konstrukcijama napisanim u komentaru. Napomenimo da ovo vrijedi jedino
ukoliko se postfiksni operator ne koristi u nekom izrazu.
int a = 10;
int b = a++;
printf ("a = %d, b = %d", a, b);

U isjeku iznad je koriten postfiksni operator u izrazu. Bie ispisano a = 11, b = 10. Znai,
u varijablu b smo prvo smjestili vrijednost varijable a, pa smo tek onda poveali vrijednost
varijable a za 1. Stoga se postfiksi operatori mogu itati kao daj mi vrijednost varijable, pa
onda izmijeni njenu vrijednost. Isjeak iznad funkcionalno je ekvivalentan sljedeem kdu:
int a = 10;
int b = a;
a++;
printf ("a = %d, b = %d", a, b);

Gdje se jasno vidi da smo u varijblu b smjestili vrijednost varijable a, pa smo tek onda
poveali varijablu a (u novoj naredbi). Pogledajmo i sljedei isjeak:
int a = 10;
printf ("a = %d\n", a++);
printf ("a = %d\n", a);

Bie ispisano a = 10 pa u novom redu a = 11.

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
Napomenimo da nije dozvoljeno imati vie izmjena jedne te iste varijable u istoj naredbi ili
izrazu. To je nedefinisano ponaanje i na program nije ispravan (naziva se i 'sick' to znai
bolestan; nee svima isto raditi i slino). Mijenjanje varijable vie od jednom u nekom izrazu
izaziva bone efekte (engl. side effects) koji su, kao to je ve reeno, nedefinisano
ponaanje. Pogledajmo jedan neispravnan isjeak:
int a = 5;
int b = a++ + 10 - 2 * a++;
printf ("a = %d, b = %d", a, b);

U drugoj liniji imamo bone efekte jer varijablu a mijenjamo vie od jednom (i ne zna se ta
e prvo biti izvreno, to nije definirano standardom i dato je kompajleru da izvri kako mu je
lake). Moda e kod vas ispisati a = 7, b = 5, ali to ne mora biti tako prilikom drugih
pokretanja i kompajliranja. Takoer, ne moraju izrazi ovako komplikovani biti da bi
izazvali bone efekte. Navedimo jedan prost primjer (koji se inae najee u literaturi koristi
kao primjer bonih efekata).
int a = 5;

a = a++;
Ovdje u jednoj liniji (izrazu) varijablu mijenjamo a dva puta i to prouzrokuje bone efekte.
Ni za operatore poput +, *, / i slino mi ne znamo koji od izraza e biti izvren prvi,
pogledajmo npr.
if (naredba1 == naredba2)

Mi ovdje ne znamo da li e biti prvo izvrena naredba1 ili naredba2, ali ono to sigurno
znamo jeste da e obje biti izvrene prije nego se meusobno porede. Jedini operatori za koje
sigurno znamo koja strana e prva biti izvrena, tj. imamo garanciju da e biti izvrena prvo
lijeva pa onda desna strana su operator logiko I (&&), logiko ILI (||) i zarez operator (,)
kojem je jedna od glavnih primjena i bila navedeno. Stoga ako imamo
if (naredba1 && naredba2);
if (naredba1 || naredba2);
int x = (naredba1, naredba2);

Garantirano znamo da e u svim navedenim konstrukcijama biti izvrena prvo naredba1, pa


tek onda naredba 2 (u sluaju && i || operatora, naredba2 nee biti ni izvrena ukoliko je
naredba1 zadovoljena odnosno nije zadovoljena), dok su u treem sluaju stavljene zagrade
(jer operator zarez ima najmanji prioritet). Takoer i ternarni operator (jo se naziva i
kondicionalni operator) sigurno e izvriti prvi dio, tzv. uslovni dio, o emu emo govoriti
kasnije.
Pokaimo i jedan zanimljiv primjer koji se esto koristi za trikove u kojima se poetnike vara
govorei da postoje i neki novi operatori. U stvari, primjer izgleda neobino samo zbog toga

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
to kompajler C jezika ignorira razmake izmeu naredbi. Primjer o kojemu priamo je
sljedei:
int x = 10;
while (x --> 0)
printf ("Zdravo, OR-ovci\n");

Ovo e ispisati Zdravo, OR-ovci 10 puta, svaki u novom redu. Iako na prvi pogled
programerima izgleda udno, ljudima koji se tek susreu sa programiranjem izgleda
prirodno i tumae uslov kao radi, dokle x tei ka nuli. Ovaj isjeak iznad je potpuno
ispravan i legalan, a izgleda udo zbog stavljanja razmaka na pogreno mjesto. Naime,
itljivije se moglo napisati ovako:
int x = 10;
while (x-- > 0)
printf ("Zdravo, OR-ovci\n");

Gdje se jasno vidi ta se zapravo deava. Prvo poredimo x sa nulom, pa ga onda


dekrementiramo.
Napomenimo takoer da je sm izraz x++ zapravo r-value, tj. neka vrijednost (privremena
varijabla) kojoj mi ne moemo nita dodjeljivati. U tome sluaju, nije dozvoljeno raditi
sljedee:
int x = 10;
x++ = 15;

Kompajler e javiti greku C:\Users\...\main.c |6|error: lvalue required as left operand of


assignment gdje opisuje ono to smo maloprije napisali. Zbog svega ovoga, nije dozvoljeno
ni sljedee raditi:
int x = 10;
x++++;

Jer, izraz x++ je r-value, pa onda na njega ne moemo (ponovo) primijeniti operator ++. U
jeziku C++, za obine (ugraene ) tipove, vrijedi isto pravilo. Ali u C++-u, za razliku od C-a,
mi moemo definisati znaenje pojedinih operatora za nae tipove, pa moemo (mada ne
smisleno) napraviti da varijabla x, tipa kojeg smo mi definisali, ipak moe biti postfiskno vie
puta inkrementirana (npr. x++++++). Ovo nije preporuljivo raditi (jer e programske
konstrukcije biti neintuitivne), i ovdje je spomenuto samo radi kompletnosti.

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji

Prefiksni operatori inkrementiranja (++) i dekrementiranja (--)

Ve smo, u prethodnom dijelu dokumenta, objasnili da postiksni (sufiksni) operatori prvo


vrate vrijednost pa onda izmijene varijablu (dekrementiraju ili inkrementiraju). Sa prefiksnim
operatorima je obratna situacija: oni prvo izmijene varijablu pa onda vrate njenu vrijednost.
Pokaimo na primjeru kako radi prefiksni operator ++:
int x = 10;
int y = ++x;
printf ("x = %i, y = %i", x, y);

Isjeak iznad e ispisati x = 11, y = 11. To je zbog zoga to je varijabla x prvo poveana za
1, pa onda dodijeljena varijabli y. Isjeak iznad je ekvivalentan sljedeem:
int x = 10;
x++; /* Isto kao '++x', kao i 'x += 1' tj. 'x = x + 1' */
int y = x;
printf ("x = %i, y = %i", x, y);

Sada nam je jasno zato je vrijednost obje varijable 11, U komentaru u isjeku iznad pie da
su ovi izrazi ekvivalentni, to je tano, ali jedino ukoliko se nalazi taj izraz sm (tj. kao jedna
naredba je).
Kao i postfiksni operatori inkrementiranja i dekrementiranja (++ i --), i prefiksni operatori
vraaju r-value objekat. Zbog toga, u jeziku C, sljedea konstrukcija nije ispravna i kompajler
e javiti greku.
int x = 10;
++++x;

Napomenimo da su ovakve konstrukcije u jeziku C++ dozvoljene (i ispravne), ali u jeziku C


nisu, pa treba obratiti panju na ovo.

Pogledajmo sada kakve e vrijednosti imati a, b i c, nakon koritenja i prefiksnih i postfiksnih


operatora.
int a = 5;
int b = ++a;
int c = a++;
printf ("a = %i, b = %i, c = %i\n", a, b, c);
b = a++;
c = ++a;
printf ("a = %i, b = %i, c = %i\n", a, b, c);

10

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
ta e biti ispisano? Analizirajmo malo isjeak. Postavili smo varijablu a na 5, b smo
inicijalizirali sa ++a (tj. prvo poveali a na 6, pa je dodijelili b varijabli), a c sa a++ (prvo u c
stavili vrijednost varijable a tj. stavili smo 6, pa smo onda poveali vrijednost varijable a na
7). Sve navedeno je uraeno posebno, svako u novoj naredbi navedenim redoslijedom. Prvi
poziv printf funkcije e ispisati a = 7, b = 6, c = 6, to smo i opisali iznad.
Nastavimo sa analiziranjem. Sada u b varijablu stavljamo vrijednost varijable a tj. vrijednost
7, pa onda varijablu a poveavamo za 1 (na 8). Onda, u novoj naredbi poveavamo varijablu a
za 1, tj. na 9, pa je onda dodjeljujemo varijabli c koja takoer poprima vrijednost 9. Drugi
poziv printf funkcije e ispisati a = 9, b = 7, c = 9.
Isjeak iznad emo sada malo pojednostaviti i napisati na malo itljiviji nain, kako bismo
dobili uvid ta se zapravo dogaalo i da potvrdimo opisano u prethodna dva paragrafa.
int a = 5;
a++; /* Ili ++a; svejedno je kad je poziv zaseban */
int b = a;
int c = a;
a++;
printf ("a = %i, b = %i, c = %i\n", a, b, c); /* a: 7, b: 6, c: 6 */
b = a;
a++;
a++;
c = a;
printf ("a = %i, b = %i, c = %i\n", a, b, c); /* a: 9, b: 7, c: 9 */

Sa ovim smo izvrili izlaganje o prefiksnim i postfiksnim operatorima inkrementiranja


odnosno dekrementiranja u jeziku C.

11

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji

Ternarni (kondicionalni) operator (?:)

Svi do sada opisani operatori su bili ili unarni ili binarni, tj. imali su jedan ili dva operanda
nad kojima operiraju. U ovom odjeljku e biti opisan operator koji radi sa tri operanda, tj.
ternarni operator.
Prije svega da napomenemo da ternarni operator (u literalnom znaenju) znai operator koji
operira nad tri operanda. Stoga je operator kojeg emo opisati malo neispravno zvati ternarni
(jer njih moe biti vie); ispravan njegov naziv je kondicionalni operator. Poto u jeziku C
postoji samo jedan ternarni operator, to se vrlo esto za kondicionalni operator koristi naziv
ternarni operator. U izlaganju koje slijedi, mi emo koristiti oba naziva i odnosie se na
kondicionalni operator. Ovaj operator se jo naziva i jednolinijski if (inline if iif) zbog toga
to simulira if else konstrukciju, ali veinom u jednom redu.
ta radi ternarni operator i kako se koristi? On se sastoji iz tri dijela. Prvi dio je uslov, drugi
dio je kd koji se izvrava ako je uslov taan, a trei dio je kd koji se izvrava ako uslov nije
taan. Pogledajmo generalnu sintaksu operatora:
uslov ? uslov_tacan : uslov_netacan

Kao to vidimo, specifian je po tome to koristi znakove ? i :. Prvo ide uslov koji se
evaluira, nakon toga znak ? pa onda dio kda koji e biti izvren ako je uslov taan. Nakon
toga slijedi znak : i nakon njega dio kda koji e biti izvren ako uslov nije taan. Opisani
redoslijed mora biti ispotovan i mi ne moemo na mjesto znaka ? staviti znak : i
obrnuto (bie javljena greka). Ono to je jo zanimljivo, jeste da e ternarni operator
zapravio vratiti vrijednost. Pogledajmo prost primjer. Neka je potrebno u varijablu b staviti
vrijednost 10 ako je vrijednost varijable a manja od 5, u suprotnom emo u varijablu b staviti
vrijednost 11:
int a = 2;
int b = a < 5 ? 10 : 11;
printf ("B = %i", b);

Isjeak iznad e ispisati B = 10. Analizirajmo sada isjeak. U varijablu b emo staviti ili
vrijednost 10 ili vrijednost 11, u zavisnosti od toga da li je vrijednost varijable a manja od 5 ili
ne. Uslov je bio da testiramo da li je vrijednost varijable manja od 5. Ukoliko jeste, onda mi,
pomou kondicionalnog operatora (?:) vraamo vrijednost 10. To je drugi dio, tj. dio ako je
uslov taan. Ukoliko uslov nije taan, onda mi vraamo vrijednost 11 (trei dio). Eh, tu
vrijednost koju je operator ?: vratio mi smjetamo u varijablu b. Ovaj kd iznad se mogao
napisati preko if else konstrukcija:
int a = 2;
int b;
if (a < 5)
12

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
{
b = 10;
}
else
{
b = 11;
}

Pogledajmo sada zanimljiv primjer koji ilustrira upotrebu kondicionalnog operatora pri
ispitivanju koji je broj vei, a koji manji.
#include <stdio.h>
int main ()
{
int a, b;
printf ("Unesite brojeve a i b, razdvojite ih razmakom: ");
scanf ("%i %i", &a, &b);
int max = a > b ? a : b;
int min = a < b ? a : b;
printf ("Veci od ova dva broja je broj: %i\n", max);
printf ("Manji od ova dva broja je broj: %i\n", min);
return 0;
}

Ovo se moglo jo krae napisati:


#include <stdio.h>
int main ()
{
int a, b;
printf ("Unesite brojeve a i b, razdvojite ih razmakom: ");
scanf ("%i %i", &a, &b);
printf ("Veci od ova dva broja je broj: %i\n", a > b ? a : b);
printf ("Manji od ova dva broja je broj: %i\n", a < b ? a : b);
return 0;
}

Pogledajmo jo jedan primjer: neka je potrebno unijeti tri realna broja, a, b i c. I neka je
potrebno izraunati max {a, b} c b / min {a, c}. Da ovo radimo preko if
konstrukcija, na kd bi bio vei... ali preko ternarnog operatora (koji e automatski vratiti ili
dio nakon ? ili dio nakon :) mi to moemo krae napisati:
#include <stdio.h>
int main ()
{
double a, b, c;
printf ("Unesite brojeve a, b
scanf ("%lf %lf %lf", &a, &b,
printf ("Rezultat onog izraza
(a > b ? a : b) * c
return 0;
}

i c: ");
&c);
je: %f",
- b / (a < c ? a : c));

Ono to nam standard C jezika garantira jeste da e se prvi dio operatora ?: tj. dio koji
predstavlja uslov, sigurno izvriti prije drugog i treeg dijela. Stoga, u sljedeem izrazu nema
bonih efekata (o kojima smo govorili u pretdhodnim poglavljima).

13

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
int a = 3;
int b = a++ < 5 ? 10 * a++ : 10 * ++a;
printf ("b = %i, a = %i", b, a);

Isjeak iznad je ispravan (nema bonih efekata) zbog toga to e sigurno biti prvo izvren dio
kda a++ < 5, pa e onda biti izvreno ili 10 * a++, ili 10 * ++a (ali ne oboje).
Analizirajmo malo detaljnije isjeak. Varijablu a smo inicijalizirali brojem 3. Onda smo u
izrazu a++ < 5 poredili da li je a manje od 5, te onda inkrementirali varijablu (znai,
poreenje je uraeno sa prijanjom vrijednosti varijable, tj. poreenje je izgledalo kao 3 < 5
ali je nakon toga varijabla a poprimila vrijednost 4). Uslov 3 < 5 je taan, te je u varijablu b
smjetena vrijednost izraza 10 * a++. A ta vrijednost je zapravo 40, jer je varijabla a (sa
vrijednosti 4) pomnoena sa brojem 10 i smjetena u varijablu b. Nakon toga je i varijabla a
inkrementirana na 5 (podizraz a++). Konano, isjeak e ispisati b = 40, a = 5.
Da smo uslov promijenili, tj. da je u drugoj liniji isjeka pisalo ovako: int b = a++ > 5 ?
10 * a++ : 10 * ++a; onda bi varijabla b imala vrijednost 50, jer je izvren trei dio ?:
operatora, a on je prvo poveao varijablu a na 5 (++a), pa je onda pomnoio sa 10 i rezultat
toga cijelog izraza smjestio u b varijablu.
Jo napomenemo da je ternarni operator desno asocijativan, tj. izrazi poput
x = a ? b : c ? d : e

e biti evaluirani kao


x = a ? b : (c ? d : e)

a ne kao
x = (a ? b : c) ? d : e

Ovo je uraeno iz razloga da se mogu graditi sloenije if else if else konstrukcije


koritenjem vie kondicionalnih operatora.

14

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji

Operatori dodjele sa prateim funkcionalnostima (+=, -=, *=, %=, ....),


unarni minus (-) i operator zarez (,)

Kao to smo ve par puta spominjali, izraze poput a = a b (gdje je neki binarni operator)
moemo napisati krae, tj. kao a = b. Pokaimo na nekoliko primjera, za razliite operatore,
kako krae moemo pisati neke konstrukcije.
a
b
c
3

+=
*=
%=
/=

12; /* Isto kao a = a + 12 */


-1; /* Isto kao i b = b * -1 */
a * b; /* Isto kao i c = c % (a * b) */
b; /* NEISPRAVNO, isto kao 3 = 3 / b, sto ne moze! */

Ovi operatori su desno asocijativni. U tabeli prioriteta i asocijativnosti operatora su navedeni


svi operatori koji imaju iznad opisanu asocijativnost.
Da sada objasnimo unarni operator minus (-). On operira nad jednim operandom, i mijenja
predznak varijable. Ono to je vano napomenuti jeste to da on ne mijenja varijablu, nego
kreira novu, privremenu, koja ima vrijednost negirane varijable.
int a = 10;
printf ("Negirano a = %i", -a);
printf ("Normalno a = %i", a);

Isjeak e ispisati Negirano a = 10 i Normalno a = 10. Moemo primijetiti da varijablu


a nismo promijenili, nego smo joj samo privremeno promijenili predznak. Da smo htjeli da
promijenimo predznak varijable, uradili bismo ovo: a = -a.
Jo samo da kaemo koju rije o zarez operatoru, vie zbog toga to se prave greke njegovim
(neispravnim) koritenjem. Zarez operator je uveden u jezik C kako bi omoguio da mi, u
jednom izrazu, evaluiramo neki podizraz, i onda ga kasnije upotrijebimo u tome istom izrazu.
Zbog toga su mogue konstrukcije poput for (a = 0, b = 10; b >= 3 && a < 14;
a++, b -= 2). Ovdje smo mi, pomou sporednih efekata postavili a na 0 i b na 10, te
poveavali a za 1 i smanjivali b za 2. U ovim situacijama je zarez operator koristan, ali
mogue je vrlo esto napraviti greku njegovim koritenjem. Npr if (a < 2, b < 10).
Ova konstrukcija e evaluirati a < 2 (i ne uraditi nita sa njim), pa onda evaluirati izraz b <
10 i onda to staviti kao uslov u if konstrukciji i onda isjeak bude samo if (b < 10).
Znaenje operatora zarez moemo pojednostavljeno tumaiti kao evaluiraj lijevu stranu i
vrati mi desnu stranu. Primjer:
int a = (5, 6);

Ovaj isjeak e u varijablu a smjestiti vrijednost 6. Moemo, isto tako, u jednoj naredbi i
unijeti i ispisati uneseni broj, zahvaljujui zarez operatoru koji, ponavljamo, kae evaluiraj
lijevo i daj mi desno. Pogledajmo:

15

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
int n;
printf ("Unesite broj: ");
printf ("Uneseni broj je: %i", (scanf("%i", &n), n));

Sa zelenom bojom je oznaen zarez operator koji e evaluirati lijevu stranu (unos broja
pomou scanf funkcije) i vratiti (proslijediti printf funkciji) desnu stranu (tj. uneseni broj n).
Vano je ovdje da e sigurno biti prvo izvrena lijeva strana (tj. unos broja) pa onda desna.
Tu garanciju imamo samo kod zarez operatora i logikih operatora I (&&) i ILI (||). Sa utom
bojom nije oznaen zarez operator, tj. znak zarez oznaen utom bojom se nije koristio kao
operator nego kao separator. Vano je ne mijeati ove dvije funkcionalnosti!
Spomenimo jo i to da zarez operator ima najmanji prioritet od svih operatora u jeziku C, pa
ak manji prioritet i od operatora dodjele (=). Pogledajmo primjer:
int a, b;
a = (5, 6);
/* a je sada
b = 5, 6; /*
/* b je sada
printf ("a =

6 */
Isto kao: "(b = 5), 6" */
5 */
%d, b = %d", a, b);

Operator zarez moemo iskoristiti i za odvajanje izraza C jezika. Ovo moe biti korisno kada
imamo dvije ili vie naredbe u tijelu if, for, while i slinih konstrukcija, pa ne moramo pisati
vitiaste zagrade. Npr.
if (c < 10)
a = 1, b = 0; /* Umjesto {a = 1; b = 0;} */
else
a = 0, b = 1; /* Umjesto {a = 0; b = a;} */

Operator zarez se naziva ejtan operatorom, upravo zbog toga to prouzroukuje vie problema
nego koristi prilikom njegovog (neopreznog) koritenja. Stoga se ne preporuuje koritenje
ovog operatora osim kada se sigurno zna ta se radi.

16

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji

Operator konverzije

Ve smo, u prethodnim dokumentima, spominjali da sve varijable i konstante u C jeziku


imaju svoj tip. Tako, ukoliko napiemo broj 5 (izvan konteksta teksta literala) on je tipa int.
Broj 5.1 je tipa double. Ukoliko elimo konstantu tipa float, dodajemo onda sufiks f ili F
tj. 5.1f ili 5.1F. Spomenuto je i to da se nula moe zanemariti, pa je broj 5. tipa double i
ima istu vrijednost kao 5.0. Isto vrijedi i za vodee nule: 0.6 se moe napisati kao .6, oboje
je tipa double.
Spomenuli smo i da treba obratiti panju pri cjelobrojnom dijeljenju, gdje oekujemo da e
rezultat biti realan broj, a zapravo rezultat bude cijeli broj koji kasnije bude konvertovan u
realni tip (ali sa gubljenjem decimala). Kao primjer smo uzimali prosto dijeljenje:
double x = 3 / 2;
printf ("x = %f", x);

Gdje e biti ispisano x = 1.000000. Ovo je zbog toga to su i broj 3 i broj 2 cijeli brojevi,
pa imamo cjelobrojno dijeljenje 3 / 2 koje daje rezultat 1. Onda se taj broj konvertuje i
smjeta u varijablu x. Ovo moemo izbjei eksplicitnim stavljanjem realnih brojeva u izraz,
npr. na jedan od sljedeih naina:
double x1 = 3.0 / 2;
double x2 = 3 / 2.0;
double x3 = 3. / 2;

Dovoljno je samo da jedan od operanada bude realnog tipa kako bismo imali realno dijeljenje
tj. dijeljenje sa realnim brojevima. Sve je do sada ilo normalno kada smo koristi konstante,
pa smo mogli ekspilicitno rei kojeg e tipa biti. Ali ta ako imamo samo varijable na
raspolaganju? Kako onda da dobijemo eljeni efekat? Odgovor je: konverzijom. Pogledajmo
primjer koji e raunati sumu koliinik broja i njegovog kvadrata.
int i;
double suma = 0.0;
for (i = 1; i <= n; i++)
suma += i / (i * i);

Rezultat ovog raunanja sume e uvijek biti 1, za ma kakvo n. Razlog tome jeste to smo
imali cjelobrojno dijeljenje u sljedeem izrazu (varijabla i je tipa int): i / (i * i). Sada ne
moemo dodati .0 kako bismo dijeljenje uinili realnim. Moemo se snai pa pomnoiti
varijablu i sa 1.0 kako bismo dobili realno dijeljenje, tj.
suma += (i * 1.0) / (i * i);

Ovo radi, ali ipak nije preporuljivo ovako raditi iz vie razloga. Meu glavnim razlozima
zbog ega ne treba ovako raditi jeste taj da mi neemo uvijek raditi sa brojevima. Moemo
17

Osnove Raunarstva Dodatak: prefiksni, postfiksni i ostali operatori u C-u (dio 1)


Akademska 2014/2015
Enil Paji
raditi sa drugim objektima (koje sami definiemo), pa u tome sluaju ovakva rjeenja nisu
mogua. Isto tako ovakvo rjeenje se ne moe primijeniti na konverzije pokazivaa, koje
emo kasnije uiti. Ostaje nam da je jedino pravo rjeenje koristiti konverzioni operator.
Konverzioni operator spada u operatore sa drugim najveim prioritetom. Njegova generalna
sintaksa je sljedea:
(tip)izraz

Gdje tip predstavlja tip u koji elimo izvriti konverziju, a izraz predstavlja ono nad ime
vrimo konverziju, tj. ono to pretvaramo u tip. Pogledajmo sada kako emo rijeiti
prthodni problem cjelobrojnog dijeljenja.
int i;
double suma = 0.0;
for (i = 1; i <= n; i++)
suma += (double)i / (i * i);

Podizraz kojeg smo markirali je poziv konverzinogo operatora, tj. konverzija varijable i (tipa
int) u tip double. Nakon ovoga, na isjeak e pravilno raunati sumu jer imamo realno
dijeljenje (ve smo napomenuli da je potrebno da samo jedan od operanada bude realnog tipa
da bi dijeljenje bilo realno). Ovdje treba primijetiti da je ova konverzija napravila novu
privremenu varijablu koja je tipa double i u nju smjestila vrijednost varijable i, tj. mi ovom
konverzijom nismo (zauvijek) promijenili niti tip niti vrijednost varijable i. Tip varijable
naknadno ne moemo ni mijenjati. Isto tako treba primijetiti da je prvo izvrena konverzija,
pa mnonje (jer je u zagradama) pa onda dijeljenje, tj. konverzioni operator je imao prioritet u
odnosu na dijeljenje i mnoenje.
Konverzoni operator se moe iskoristiti i za uklanjanje decimala kod realnih brojeva. Npr.
neka je potrebno uzeti cijeli dio nekog realnog broja:
double x = 12.34;
int cijeli = x;

Ovdje varijabla cijeli ima vrijednost 12. Primijetimo da je ovdje izvrena automatska
konverzija tipa double u tip int. Isjeak iznad je ekvivalentan sljedeem:
double x = 12.34;
int cijeli = (int)x;

Vama se za vjebu ostavlja da uradite sljedei zadatak (sluite se konverzionim operatorom,


tj. ukljanjajte decimale brojevima):
Napiite program koji e od korisnika traiti da unese realni broj koji predstavlja sate (u
decimalnom formatu). Program treba da rastavi uneseni broj i ispie ga u malo itljivijem
formatu (sati, minute i sekunde). Primjer:
Unesite broj sati: 2.11
Uneseno je: 2h 6m 36s

18

You might also like