You are on page 1of 378

le

E
ro
n

kt
sk
o
d

iz
an
je

(2
01
5)

le

E
ro
n

kt
sk
o
d

iz
an
je

(2
01
5)

Predrag Janii

(2
01
5)

Filip Mari

je

PROGRAMIRANJE 1

le

kt

ro
n

sk
o

iz

an

Osnove programiranja kroz programski jezik C

Beograd
2015.

Autori:
dr Filip Mari, docent na Matematikom fakultetu u Beogradu
dr Predrag Janii, redovni profesor na Matematikom fakultetu u Beogradu
PROGRAMIRANJE 1
Izdava: Matematiki fakultet Univerziteta u Beogradu

(2
01
5)

Studentski trg 16, 11000 Beograd


Za izdavaa: prof. dr Zoran Raki, dekan
Recenzenti:

dr Gordana Pavlovi-Laeti, redovni profesor na Matematikom fakultetu u


Beogradu

dr Miodrag ivkovi, redovni profesor na Matematikom fakultetu u Beogradu


dr Dragan Uroevi, nauni savetnik na Matematikom institutu SANU

kt

ro
n

sk
o

iz

an

je

Obrada teksta, crtei i korice: autori

le

ISBN 978-86-7589-100-0

c 2015.

Filip Mari i Predrag Janii

Ovo delo zatieno je licencom Creative Commons CC BY-NC-ND 4.0 (AttributionNonCommercial-NoDerivatives 4.0 International License).
videti na veb-adresi

Detalji licence mogu se

http://creativecommons.org/licenses/by-nc-nd/4.0/.

Do-

zvoljeno je umnoavanje, distribucija i javno saoptavanje dela, pod uslovom da se


navedu imena autora. Upotreba dela u komercijalne svrhe nije dozvoljena. Prerada,
preoblikovanje i upotreba dela u sklopu nekog drugog nije dozvoljena.

(2
01
5)
je

Sadraj

Osnovni pojmovi raunarstva i programiranja

an

Sadraj

10
11

iz

1 Raunarstvo i raunarski sistemi

Rana istorija raunarskih sistema . . . . . . . . . . . . . . . . .

12

1.2

Raunari fon Nojmanove arhitekture . . . . . . . . . . . . . . .

16

1.3

Oblasti savremenog raunarstva . . . . . . . . . . . . . . . . . .

21

1.4

Hardver savremenih raunara . . . . . . . . . . . . . . . . . . .

22

1.5

Softver savremenih raunara . . . . . . . . . . . . . . . . . . . .

26

sk
o

1.1

38

ro
n

2 Reprezentacija podataka u raunarima


Analogni i digitalni podaci i digitalni raunari . . . . . . . . . .

38

2.2

Zapis brojeva . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

2.3

Zapis teksta . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

2.4

Zapis multimedijalnih sadraja

55

kt

2.1

. . . . . . . . . . . . . . . . . .

61

le

3 Algoritmi i izraunljivost
Formalizacije pojma algoritma

. . . . . . . . . . . . . . . . . .

61

3.2

er-Tjuringova teza . . . . . . . . . . . . . . . . . . . . . . . .

63

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

3.1
3.3

ur maine

3.4

Enumeracija

3.5

Neizraunljivost i neodluivost

3.6

Vremenska i prostorna sloenost izraunavanja

urm programa

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . .

4 Vii programski jezici

69
71
73

78

4.1

Kratki pregled istorije programskih jezika

. . . . . . . . . . . .

79

4.2

Klasifikacije programskih jezika . . . . . . . . . . . . . . . . . .

80

4.3

Leksika, sintaksa, semantika programskih jezika . . . . . . . . .

80

4.4

Pragmatika programskih jezika

. . . . . . . . . . . . . . . . . .

II Jezik C

83

90

5 Osnovno o programskom jeziku C

91

Standardizacija jezika

. . . . . . . . . . . . . . . . . . . . . . .

91

5.2

Prvi programi . . . . . . . . . . . . . . . . . . . . . . . . . . . .

93

(2
01
5)

5.1

6 Predstavljanje podataka i operacije nad njima

101

6.1

Promenljive i deklaracije . . . . . . . . . . . . . . . . . . . . . .

101

6.2

Osnovni tipovi podataka . . . . . . . . . . . . . . . . . . . . . .

104

6.3

Konstante i konstantni izrazi

109

6.4

Operatori i izrazi . . . . . . . . . . . . . . . . . . . . . . . . . .

112

6.5

Konverzije tipova . . . . . . . . . . . . . . . . . . . . . . . . . .

126

6.6

Nizovi i niske

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

132

6.7

Korisniki definisani tipovi . . . . . . . . . . . . . . . . . . . . .

140

an

je

. . . . . . . . . . . . . . . . . . .

7 Naredbe i kontrola toka


Naredba izraza

7.2

Sloene naredbe (blokovi)

7.3

Naredbe grananja . . . . . . . . . . . . . . . . . . . . . . . . . .

152

7.4

Petlje

156

. . . . . . . . . . . . . . . . . . . . . . . . . . .

151

7.1

iz

. . . . . . . . . . . . . . . . . . . . .

8 Funkcije

sk
o

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

151
152

168

Primeri definisanja i pozivanja funkcije . . . . . . . . . . . . . .

168

8.2

Deklaracija i definicija funkcije

170

8.3

Parametri funkcije

. . . . . . . . . . . . . . . . . . . . . . . . .

171

8.4

Prenos argumenata . . . . . . . . . . . . . . . . . . . . . . . . .

172

8.5

Konverzije tipova argumenata funkcije . . . . . . . . . . . . . .

174

8.6

Povratna vrednost funkcije

ro
n

8.1

. . . . . . . . . . . . . . . . . .

175

8.7

Nizovi i funkcije . . . . . . . . . . . . . . . . . . . . . . . . . . .

175

8.8

Korisniki definisani tipovi i funkcije . . . . . . . . . . . . . . .

178

8.9

Rekurzija

kt

. . . . . . . . . . . . . . . . . . . .

179

8.10 Funkcije sa promenljivim brojem argumenata . . . . . . . . . .

179

le

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9 Organizacija izvornog i izvrnog programa


. . . . . . . . . . . . . . . .

186

9.1

Od izvornog do izvrnog programa

9.2

Organizacija izvornog programa . . . . . . . . . . . . . . . . . .

193

9.3

Organizacija izvrnog programa . . . . . . . . . . . . . . . . . .

219

10 Pokazivai i dinamika alokacija memorije


10.1 Pokazivai i adrese

187

234

. . . . . . . . . . . . . . . . . . . . . . . . .

234

10.2 Pokazivai i argumenti funkcija . . . . . . . . . . . . . . . . . .

239

10.3 Pokazivai i nizovi

. . . . . . . . . . . . . . . . . . . . . . . . .

241

10.4 Pokazivaka aritmetika . . . . . . . . . . . . . . . . . . . . . . .

244

10.5 Pokazivai i niske . . . . . . . . . . . . . . . . . . . . . . . . . .

247

10.6 Nizovi pokazivaa i viedimenzioni nizovi . . . . . . . . . . . . .

251

10.7 Pokazivai i strukture

. . . . . . . . . . . . . . . . . . . . . . .

254

10.8 Pokazivai na funkcije

. . . . . . . . . . . . . . . . . . . . . . .

255

10.9 Dinamika alokacija memorije . . . . . . . . . . . . . . . . . . .

258

11 Pregled standardne biblioteke


11.2 Zaglavlje
11.3 Zaglavlje
11.4 Zaglavlje
11.5 Zaglavlje

string.h
stdlib.h
ctype.h
math.h .
assert.h

269

. . . . . . . . . . . . . . . . . . . . . . . . .

269

. . . . . . . . . . . . . . . . . . . . . . . . .

272

. . . . . . . . . . . . . . . . . . . . . . . . .

274

(2
01
5)

11.1 Zaglavlje

. . . . . . . . . . . . . . . . . . . . . . . . .

275

. . . . . . . . . . . . . . . . . . . . . . . . .

276

12 Ulaz i izlaz programa

277

12.2 Ulaz iz niske i izlaz u nisku

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .

an

12.3 Ulaz iz datoteka i izlaz u datoteke

le

kt

ro
n

sk
o

Indeks

iz

B Reenja zadataka

12.4 Argumenti komandne linije programa

A Tabela prioriteta operatora

je

12.1 Standardni tokovi . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . .

277

285
286
294

300
301
373

(2
01
5)

Predgovor

je

Ova knjiga pisana je kao udbenik za predmet Programiranje 1 na smeru

Informatika Matematikog fakulteta u Beogradu. U ovom predmetu i u ovoj

an

knjizi, centralno mesto ima programski jezik C, ali predmet i knjiga nisu samo
kurs ovog jezika, ve pokuavaju da dju ire osnove programiranja, ilustrovane

kroz jedan konkretan jezik.

Knjiga je nastala na osnovu materijala za predavanja koja smo na ovom

iz

predmetu drali od 2005. godine. Ipak, vremenom je materijal proiren i delovima koji se u okviru tog predmeta ne predaju ili se predaju u vrlo ogranie-

sk
o

nom obimu. Zahvaljujui tome, ova knjiga i njen nastavak (Programiranje 2

Osnove programiranja kroz programski jezik C) mogu se koristiti kao udbenici


za vie razliitih kurseva.

Za predmet na studijama na kojima nema drugih

(ili nema mnogo drugih) raunarskih predmeta, predlaemo obraivanje i-

ro
n

tave knjige, s tim to obraivanje glave 4 preporuujemo samo za studije sa


jakom matematikom orijentacijom. itaocima (studentima) koji poznaju osnove raunarstva i programiranja, a ne znaju jezik C, preporuujemo itanje

kt

samo drugog dela knjige (Jezik C). Za kurs Programiranje 1 na smeru Informatika preporuujemo samo ubrzano upoznavanje sa glavama 1 i 2 (jer se ti
Za ovaj kurs

le

sadraji izuavaju u okviru drugih predmeta na prvoj godini).

preporuujemo i upoznavanje sa glavama 3 i 4, a upoznavanje sa glavama 10 i

12 preporuujemo za drugi semestar.


Na kraju veine poglavlja naveden je vei broj pitanja i zadataka koji mogu

da slue za proveru znanja.

Meu ovim pitanjima su praktino sva pitanja

koja su zadata na testovima i ispitima iz predmeta Programiranje 1 u periodu od pet godina. Odgovori na pitanja nisu eksplicitno navoeni, jer su ve
implicitno sadrani u osnovnom tekstu knjige.

Na kraju knjige navedena su

reenja zadataka, te se moe smatrati da ova knjiga obuhvata i potpunu prateu


zbirku zadataka. Za zadatka tipa ta ispisuje naredni program? nisu navoeni
odgovori jer italac to moe da proveri na svom raunaru (i knjiga pokuava
da ohrabri itaoca da itanje knjige kombinuje sa radom na raunaru).
U pripremi knjige koristili smo mnoge izvore, pre svega sa interneta. Od

izvora o jeziku C, pomenimo ovde znamenitu knjigu Programski jezik C (The


C Programming Language, K&R) Brajana Kernigana i Denisa Riija koja je
dugo sluila kao nezvanini standard jezik, knjigu Knjiga o C-u (The C Book)
Majka Banahana, Deklana Brejdija i Marka Dorana, kao i ISO standarde jezika
C. Za pripremu glave Algoritmi i izraunljivost koristili smo knjigu Teorija al-

goritama, jezika i automata - zbirka zadataka, Irene Spasi i Predraga Janiia.


Na veoma paljivom itanju i brojnim korisnim savetima zahvaljujemo re-

(2
01
5)

cenzentima Gordani Pavlovi-Laeti, Miodragu ivkoviu i Draganu Uroe-

viu. Na brojnim sugestijama i ispravkama zahvalni smo i nastavnicima Matematikog fakulteta Mileni Vujoevi-Janii, Nenadu Mitiu i Mladenu Nikoliu,

kao i studentima Nikoli Premevskom, Mladenu Canoviu, Nemanji Mioviu,

Vojislavu Grujiu, Stefanu oreviu, Petru Vukmiroviu, Bobanu Piskuliu,

Jani Proti, Ljubici Peleksi, Ivanu Baleviu, Danielu Doi, Milou Samardiji,
Stefanu Saviu, Petru Kovrliji i Tomislavu Milovanoviu.

je

Ova knjiga dostupna je (besplatno) u elektronskom obliku preko internet


strana autora.

Sadraj tampanog i elektronskog izdanja je identian.

Be-

an

splatna dostupnost elektronskog oblika knjige odraava stav autora o otvorenim

sk
o

iz

sadrajima kdu programa i sadraju knjiga.

le

kt

ro
n

Beograd, april 2015. godine

Autori

(2
01
5)

Deo I

le

kt

ro
n

sk
o

iz

an

je

Osnovni pojmovi raunarstva i


programiranja

10

(2
01
5)

Glava 1

je

Raunarstvo i raunarski sistemi

Raunarstvo i informatika predstavljaju jednu od najatraktivnijih i najivot u savremenom drutvu ne moe se zamis-

an

vanijih oblasti dananjice.

liti bez korienja razliitih raunarskih sistema : stonih i prenosnih raunara,


tableta, pametnih telefona, ali i raunara integrisanih u razliite maine (au-

tomobile, avione, industrijske maine, itd). Definicija raunarskog sistema je

iz

prilino iroka. Moe se rei da se danas pod digitalnim raunarskim sistemom


(raunarom) podrazumeva maina koja moe da se programira da izvrava razliite zadatke svoenjem na elementarne operacije nad brojevima.

Brojevi

sk
o

se, u savremenim raunarima, zapisuju u binarnom sistemu, kao nizovi nula


i jedinica tj. binarnih cifara, tj. bitova (engl. bit, od binary digit ). Koristei

bitova, moe se zapisati

ro
n

Na primer, jedan bajt (B)

razliitih vrednosti.

oznaava osam bitova i moe da reprezentuje

28 ,

tj. 256 razliitih vrednosti.

Raunarstvo se bavi izuavanjem raunara, ali i optije, izuavanjem teorije


i prakse procesa raunanja i primene raunara u raznim oblastima nauke,

tehnike i svakodnevnog ivota .

kt

Raunari u dananjem smislu nastali su polovinom XX veka, ali koreni


raunarstva su mnogo stariji od prvih raunara.

Vekovima su ljudi stvarali

le

mehanike i elektromehanike naprave koje su mogle da reavaju neke numerike zadatke. Dananji raunari su programabilni, tj. mogu da se isprogrami-

raju da vre razliite zadatke.

Stoga je oblast programiranja , kojom se ova

knjiga bavi, jedna od najznaajnijih oblasti raunarstva.


modernih raunara neophodni su i hardver i softver.

Za funkcionisanje

Hardver (tehniki sis-

tem raunara) ine opipljive, fizike komponente raunara: procesor, memo-

1 Koliina

podataka i kapacitet memorijskih komponenti savremenih raunara obino se

iskazuje u bajtovima ili izvedenim jedinicama. Obino se smatra da je jedan kilobajt (KB)
jednak 1024 bajtova (mada neke organizacije podrazumevaju da je jedan KB jednak 1000
bajtova). Slino, jedan megabajt (MB) je jednak 1024 KB ili

10242

B, jedan gigabajt (GB)

je jednak 1024 MB, a jedan teraabajt (TB) je jednak 1024 GB.

2 esto

se kae da se raunarstvo bavi raunarima isto onoliko koliko se astronomija bavi

teleskopima, a biologija mikroskopima. Raunari nisu sami po sebi svrha i samo su sredstvo
koje treba da pomogne u ostvarivanju razliitih zadataka.

11

12

1. Raunarstvo i raunarski sistemi

rija, matina ploa, hard disk, DVD ureaj, itd. Softver (programski sistem
raunara) ine raunarski programi i pratei podaci koji odreuju izraunavanja koja vri raunar. Raunarstvo je danas veoma iroka i dobro utemeljena
nauna disciplina sa mnotvom podoblasti.

(2
01
5)

1.1 Rana istorija raunarskih sistema


Programiranje u savremenom smislu postalo je praktino mogue tek krajem Drugog svetskog rata, ali je njegova istorija znatno starija.

Prvi pre-

cizni postupci i sprave za reavanje matematikih problema postojali su jo


u vreme antikih civilizacija.

Na primer, kao pomo pri izvoenju osnovnih

matematikih operacija koriene su raunaljke zvane abakus . U IX veku persijski matematiar Al Horezmi

3 precizno je opisao postupke raunanja u indo-

arapskom dekadnom brojevnom sistemu (koji i danas predstavlja najkorieniji

4 doneo je ovaj nain zapi-

je

brojevni sistem). U XIII veku Leonardo Fibonai

sivanja brojeva iz Azije u Evropu i to je bio jedan od kljunih preduslova za

an

razvoj matematike i tehnikih disciplina tokom renesanse. Otkrie logaritma


omoguilo je svoenje mnoenja na sabiranje, dodatno olakano raznovrsnim

analognih spravama (npr. klizni lenjir iber ) . Prve mehanike sprave koje

su mogle da potpuno automatski izvode aritmetike operacije i pomau u rea-

iz

vanju matematikih zadataka su napravljene u XVII veku. Blez Paskal

6 kon-

struisao je 1642. godine mehanike sprave, kasnije nazvane Paskaline , koje su


sluile za sabiranje i oduzimanje celih brojeva. Gotfrid Lajbnic

7 konstruisao je

sk
o

1672. godine mainu koja je mogla da izvrava sve etiri osnovne aritmetike
operacije (sabiranje, oduzimanje, mnoenje i deljenje) nad celim brojevima.
Ova maina bila je zasnovana na dekadnom brojevnom sistemu, ali Lajbnic je

le

kt

ro
n

prvi predlagao i korienje binarnog brojevnog sistema u raunanju.

Slika 1.1: Abakus. iber. Paskalina

3 Muhammad ibn Musa al-Khwarizmi (780850), persijski matematiar.


4 Leonardo Pisano Fibonacci, (11701250), italijanski matematiar iz Pize.
5 Zanimljivo je da su klizni lenjiri noeni na pet Apolo misija, ukljuujui i onu

na Mesec,

da bi astronautima pomagali u potrebnim izraunavanjima.

6 Blaise

Pascal (16231662), francuski filozof, matematiar i fiziar. U njegovu ast jedan

programski jezik nosi ime PASCAL.

7 Gottfried

Wilhelm Leibniz (16461716), nemaki filozof i matematiar.

13

1. Raunarstvo i raunarski sistemi

Mehanike maine.

ozef Mari akard

8 konstruisao je 1801. godine prvu

programabilnu mainu mehaniki tkaki razboj koji je koristio buene kartice kao svojevrsne programe za generisanje kompleksnih ara na tkanini. Svaka
rupa na kartici odreivala je jedan pokret maine, a svaki red na kartici odgovarao je jednom redu are.
U prvoj polovini XIX veka, arls Bebid

9 dizajnirao je, mada ne i real-

izovao, prve programabilne raunske maine.

Godine 1822. zapoeo je rad

(2
01
5)

na diferencijskoj maini koja je trebalo da rauna vrednosti polinomijalnih

funkcija (i eliminie este ljudske greke u tom poslu) u cilju izrade to preciznijih logaritamskih tablica. Ime je dobila zbog toga to je koristila tzv. metod

konanih razlika da bi bila eliminisana potreba za mnoenjem i deljenjem.

Maina je trebalo da ima oko 25000 delova i da se pokree runo, ali nije
nikada zavrena

10 . Ubrzo nakon to je rad na prvom projektu utihnuo bez

rezultata, Bebid je zapoeo rad na novoj maini nazvanoj analitika maina .

je

Osnovna razlika u odnosu na sve prethodne maine, koje su imale svoje specifine namene, bila je u tome to je analitika maina zamiljena kao raun-

an

ska maina opte namene koja moe da se programira (programima zapisanim


na buenim karticama, slinim akardovim karticama).

Program zapisan na

karticama kontrolisao bi mehaniki raunar (pokretan parnom mainom) i

omoguavao sekvencijalno izvravanje naredbi, grananje i skokove, slino pro-

iz

gramima za savremene raunare. Osnovni delovi raunara trebalo je da budu


mlin (engl. mill) i skladite (engl. store), koji po svojoj funkcionalnosti sasvim
odgovaraju procesoru i memoriji dananjih raunara.

Ada Bajron

11 zajedno

sk
o

sa Bebidem napisala je prve programe za analitiku mainu i, da je maina


uspeno konstruisana, njeni programi bi mogli da raunaju odreene sloene nizove brojeva (takozvane Bernulijeve brojeve). Zbog ovoga se ona smatra prvim

ro
n

programerom u istoriji (i njoj u ast jedan programski jezik nosi ime Ada ).
Ona je bila i prva koja je uvidela da se raunske maine mogu upotrebiti i za
nematematike namene, ime je na neki nain anticipirala dananje namene

kt

digitalnih raunara.

Elektromehanike maine.

Elektromehanike maine za raunanje koristili

le

su se od sredine XIX veka do vremena Drugog svetskog rata.

Jedna od prvih je maina za itanje buenih kartica koju je konstruisao

Herman Holerit

12 . Ova maina koriena je 1890. za obradu rezultata popisa

stanovnitva u SAD. Naime, obrada rezultata popisa iz 1880. godine trajala


je vie od 7 godina, a zbog naglog porasta broja stanovnika procenjeno je

8 Joseph Marie Jacquard (17521834), francuski trgovac.


9 Charles Babbage (17911871), engleski matematiar, filozof i pronalaza.
10 Dosledno sledei Bebidev dizajn, 1991. godine (u nauno-popularne svrhe)

uspeno

je konstruisana diferencijska maina koja radi besprekorno. Neto kasnije, konstruisan je i


tampa koji je Bebid dizajnirao za diferencijsku mainu, tj. tamparska presa povezana
sa parnom mainom koja je tampala izraunate vrednosti.

11 Augusta

Ada King (ro. Byron), Countess of Lovelace, (18151852), engleska matem-

atiarka. U njenu ast nazvan je programski jezik ADA.

12 Herman

Hollerith (18601929), ameriki pronalaza.

1. Raunarstvo i raunarski sistemi

(2
01
5)

14

je

Slika 1.2: akardov razboj. Bebidova diferencijska maina.

an

da bi obrada rezultata iz 1890. godine trajala vie od 10 godina, to je bilo


neprihvatljivo mnogo. Holerit je sproveo ideju da se podaci prilikom popisa zapisuju na mainski itljivom medijumu (na buenim karticama), a da se kasnije

obrauju njegovom mainom. Koristei ovaj pristup obrada rezultata popisa


nastala uvena kompanija IBM.
Godine 1941, Konrad Cuze

iz

uspeno je zavrena za godinu dana. Od Holeritove male kompanije kasnije je

13 konstruisao je 22-bitnu mainu raunanje Z3

sk
o

koji je imao izvesne mogunosti programiranja (podrane su bile petlje, ali


ne i uslovni skokovi), te se esto smatra i prvim realizovanim programabilnim

14 . Cuzeove maine tokom Drugog svetskog rata naile su samo na

raunarom

ro
n

ograniene primene. Cuzeova kompanija proizvela je oko 250 razliitih tipova


raunara do kraja ezdesetih godina, kada je postala deo kompanije Simens
(nem. Siemens).

U okviru saradnje kompanije IBM i univerziteta Harvard, tim Hauarda

15 zavrio je 1944. godine mainu Harvard Mark I . Ova maina itala je

kt

Aikena

instrukcije sa buene papirne trake, imala je preko 760000 delova, duinu 17m,

le

visinu 2.4m i masu 4.5t. Mark I mogao je da pohrani u memoriji (korienjem


elektromehanikih prekidaa) 72 broja od po 23 dekadne cifre.

Sabiranje i

oduzimanje dva broja trajalo je treinu, mnoenje est, a deljenje petnaest


sekundi.

Elektronski raunari.

Elektronski raunari koriste se od kraja 1930-ih do

danas.
Jedan od prvih elektronskih raunara ABC (specijalne namene reavanje

13 Konrad Zuse (19101995), nemaki inenjer.


14 Maini Z3 prethodile su jednostavnije maine
15 Howard Hathaway Aiken (19001973).

Z1 i Z2, izgraeni 1938. i 1940. godine.

1. Raunarstvo i raunarski sistemi

Slika 1.3:

Holeritova maina.

je

(2
01
5)

15

Harvard Mark I. ENIAC (proces reprogrami-

an

ranja).

sistema linearnih jednaina) napravili su 1939. godine Atanasov

16 i Beri 17 .

iz

Maina je prva koristila binarni brojevni sistem i elektrine kondenzatore (engl.


capacitor) za skladitenje bitova sistem koji se u svojim savremenim varigramabilna.

sk
o

jantama koristi i danas u okviru tzv. DRAM memorije. Maina nije bila proKrajem Drugog svetskog rada, u Engleskoj, u Bleli parku (engl. Bletchley Park) u kojem je radio i Alan Tjuring

18 , konstruisan je raunar Kolos

ro
n

(engl. Colossus ) namenjen deifrovanju nemakih poruka. Raunar je omoguio


razbijanje nemake ifre zasnovane na maini Enigma , zahvaljujui emu su
saveznici bili u stanju da prate komunikaciju nemake podmornike flote, to

kt

je znaajno uticalo na ishod Drugog svetskog rata.


U periodu izmeu 1943. i 1946. godine od strane amerike vojske i tima

le

univerziteta u Pensilvaniji koji su predvodili Don Mokli

19 i Dej Ekert 20 kon-

struisan je prvi elektronski raunar opte namene ENIAC (Electronic Nu-

merical Integrator and Calculator) .


30m i masu 30t.

Imao je 1700 vakuumskih cevi, duinu

Raunske operacije izvravao je hiljadu puta bre od elek-

tromehanikih maina. Osnovna svrha bila mu je jedna specijalna namena


raunanje trajektorije projektila. Bilo je mogue da se maina preprogramira i
za druge zadatke ali to je zahtevalo intervencije na preklopnicima i kablovima
koje su mogle da traju danima.

16 John Vincent Atanasoff (19031995).


17 Clifford Edward Berry (19181963).
18 Alan Turing (19121954), britanski matematiar.
19 John William Mauchly (19071980).
20 J. Presper Eckert (19191995).

16

1. Raunarstvo i raunarski sistemi

1.2 Raunari fon Nojmanove arhitekture


Rane maine za raunanje nisu bile programabilne ve su radile po unapred fiksiranom programu, odreenom samom konstrukcijom maine. Takva
arhitektura se i danas koristi kod nekih jednostavnih maina, na primer, kod
kalkulatora (digitrona). Da bi izvravali nove zadatke, rani elektronski raunari nisu programirani u dananjem smislu te rei, ve su sutinski redizajniTako su, na primer, operaterima bile potrebne nedelje da bi prespojili

(2
01
5)

rani.

kablove u okviru kompleksnog sistema ENIAC i tako ga instruisali da izvrava


novi zadatak.

Potpuna konceptualna promena dola je kasnih 1940-ih, sa pojavom raunara koji programe na osnovu kojih rade uvaju u memoriji zajedno sa podacima

raunara sa skladitenim programima (engl. stored program computers) . U


okviru ovih raunara, postoji jasna podela na hardver i softver.

Iako ideje

je

za ovaj koncept datiraju jo od arlsa Bebida i njegove analitike maine i

nastavljaju se kroz radove Tjuringa, Cuzea, Ekerta, Moklija, za rodonaelnika

an

ovakve arhitekture raunara smatra se Don fon Nojman

21 . Fon Nojman se u

ulozi konsultanta prikljuio timu Ekerta i Moulija i 1945. godine je u svom


izvetaju EDVAC (Electronic Discrete Variable Automatic Computer) opisao

arhitekturu koja se i danas koristi u najveem broju savremenih raunara i u

iz

kojoj se programi mogu uitavati isto kao i podaci koji se obrauju.

Rau-

nar EDVAC, naslednik raunara ENIAC, koristio je binarni zapis brojeva, u


memoriju je mogao da upie hiljadu 44-bitnih podataka i bio je jedan od prvih

sk
o

raunara koji su mogli da uitaju programe u memoriju. Iako je dizajn raunara EDVAC bio prvi opis fon Nojmanove arhitekture, pre 1951. godine - kada
je EDVAC puten u rad, ve je nekoliko raunara sline arhitekture bilo kon-

ro
n

struisano i funkcionalno njega (Mark 1 i EDSAC - 1949. godine i MESM u


tadanjem SSSR, 1950. godine).
Osnovni elementi fon Nojmanove arhitekture raunara su procesor (koji
ine aritmetiko-logika jedinica, kontrolna jedinica i registri) i glavna memo-

kt

rija , koji su meusobno povezani. Ostale komponente raunara (npr. ulaznoizlazne jedinice, spoljanje memorije, . . . ) smatraju se pomonim i povezuju

le

se na centralni deo raunara koji ine procesor i glavna memorija. Sva obrada
podataka vri se u procesoru. U memoriju se skladite podaci koji se obrauju,

ali i programi, predstavljeni nizom elementarnih instrukcija (kojima se procesoru zadaje koju akciju ili operaciju da izvri). I podaci i programi se zapisuju
obino kao binarni sadraj i nema nikakve sutinske razlike izmeu zapisa programa i zapisa podataka. Tokom rada, podaci i programi se prenose izmeu
procesora i memorije. S obzirom na to da i skoro svi dananji raunari imaju
fon Nojmanovu arhitekturu, nain funkcionisanja ovakvih raunara bie opisan
detaljnije u poglavlju o savremenim raunarskim sistemima.
Moderni programabilni raunari se, po pitanju tehnologije koju su koristili,
mogu grupisati u etiri generacije, sve zasnovane na fon Nojmanovoj arhitek-

21 John

Von Neumann (19031957), ameriki matematiar.

17

1. Raunarstvo i raunarski sistemi

Slika 1.4:

(2
01
5)

turi.

Osnovni gradivni elementi korieni u etiri generacije raunara:

vakuumska cev, tranzistor, integrisano kolo i mikroprocesor

I generacija raunara

(od kraja 1930-ih do kraja 1950-ih) koristila je vaku-

Za programiranje su korieni mainski jezik i asembler a glavne

primene su bile vojne i naune.

Raunari su uglavnom bili unikatni (tj. za

an

memoriju.

je

umske cevi kao logika kola i magnetne doboe (a delom i magnetne trake) za

veinu nije postojala serijska proizvodnja). Prvi realizovani raunari fon Nojmanove arhitekture bili su Manesterska Beba (engl. Manchester Baby)

eksperimentalna maina, razvijena 1949. na Univerzitetu u Manesteru, na

iz

kojoj je testirana tehnologija vakuumskih cevi i njen naslednik Manesterski

Mark 1 (engl. Manchester Mark 1) , EDSAC razvijen 1949. na Univerzitetu


u Kembridu, MESM razvijen 1950. na Kijevskom elektrotehnikom institutu

sk
o

i EDVAC koji je prvi dizajniran, ali napravljen tek 1951. na Univerzitetu u


Pensilvaniji. Tvorci raunara EDVAC, poeli su 1951. godine proizvodnju prvog komercijalnog raunara UNIVAC UNIVersal Automatic Computer koji

ro
n

je prodat u, za to doba neverovatnih, 46 primeraka.

II generacija raunara

(od kraja 1950-ih do polovine 1960-ih) koristila je

kt

tranzistore umesto vakuumskih cevi. Iako je tranzistor otkriven jo 1947. godine, tek sredinom pedesetih poinje da se koristi umesto vakuumskih cevi kao
osnovna elektronska komponenta u okviru raunara. Tranzistori su izgraeni

le

od tzv. poluprovodnikih elemenata (obino silicijuma ili germanijuma).

poreenju sa vakuumskih cevima, tranzistori su manji, zahtevaju manje energije te se manje i greju. Tranzistori su unapredili ne samo procesore i memoriju ve i spoljanje ureaje. Poeli su da se iroko koriste magnetni diskovi
i trake, zapoelo je umreavanja raunara i ak korienje raunara u zabavne
svrhe (implementirana je prva raunarska igra Spacewar za raunar PDP-1 ).
U ovo vreme razvijeni su i prvi jezici vieg nivoa (FORTRAN, LISP, ALGOL,
COBOL). U to vreme kompanija IBM dominirala je tritem samo raunar

IBM 1401, prodat u vie od deset hiljada primeraka, pokrivao je oko treinu
tada postojeeg trita.

III generacija raunara

(od polovine 1960-ih do sredine 1970-ih) bila je za-

snovana na integrisanim kolima smetenim na silicijumskim (mikro)ipovima .

18

1. Raunarstvo i raunarski sistemi

Prvi raunar koji je koristio ovu tehnologiju bio je IBM 360, napravljen 1964. go-

Slika 1.5:

(2
01
5)

dine.

Integrisana kola dovela su do minijaturizacije i kompleksni iani

spojevi su mogli biti realizovani na izuzetno maloj povrini.

je

Nova tehnologija omoguila je poslovnu primenu raunara u mnogim oblastima. U ovoj eri dominirali su mejnfrejm (engl. mainframe)mejnfrejm raunari

an

raunari koji su bili izrazito moni za to doba, ija se brzina merila milionima
instrukcija u sekundi (engl. MIPS; na primer, neki podmodeli raunara IBM

360 imali su brzinu od skoro 1 MIPS) i koji su imali mogunost skladitenja i


obrade velike koliine podataka te su korieni od strane vlada i velikih korpo-

iz

racija za popise, statistike obrade i slino. Kod raunara ove generacije uveden je sistem deljenja vremena (engl. timesharing) koji dragoceno procesorsko

sk
o

vreme raspodeljuje i daje na uslugu razliitim korisnicima koji istovremeno


rade na raunaru i komuniciraju sa njim putem specijalizovanih terminala . U
ovo vreme uvedeni su prvi standardi za jezike vieg nivoa (npr. ANSI FORTRAN). Korieni su razliiti operativni sistemi, uglavnom razvijeni u okviru

ro
n

kompanije IBM. Sa udelom od 90%, kompanija IBM je imala apsolutnu dominaciju na tritu ovih raunara.
Pored mejnfrejm raunara, u ovom periodu iroko su korieni i mini rau-

kt

nari (engl. minicomputers) koji se mogu smatrati prvim oblikom linih (personalnih) raunara. Procesor je, uglavnom, bio na raspolaganju iskljuivo jednom
korisniku.

Obino su bili veliine ormana i retko su ih posedovali pojedinci

le

(te se ne smatraju kunim raunarima). Tritem ovih raunara dominirala je

kompanija DEC Digital Equipment Corporation sa svojim serijama raunara

poput PDP-8 i VAX. Za ove raunare, obino se vezuje operativni sistem Unix
i programski jezik C razvijeni u Belovim laboratorijama (engl. Bell Laborato-

ries), a esto i hakerska

22 kultura nastala na univerzitetu MIT (engl. Mas-

sachusetts Institute of Technology).

IV generacija raunara

(od ranih 1970-ih) zasnovana je na visoko inte-

grisanim kolima kod kojih je na hiljade kola smeeno na jedan silikonski ip.

22 Termin

haker se obino koristi za osobe koje neovlaeno pristupaju raunarskim sis-

temima, ali hakeraj kao programerska podkultura podrazumeva anti-autoritaran pristup


razvoju softvera, obino povezan sa pokretom za slobodan softver.

U oba sluaja, hakeri

su pojedinici koji na inovativan nain modifikuju postojee hardverske i softverske sisteme.

1. Raunarstvo i raunarski sistemi

(2
01
5)

19

Slika 1.6: Mejnfrejm raunar: IBM 7094. Mini raunar: DEC PDP 7

U kompaniji Intel 1971. godine napravljen je prvi mikroprocesor Intel 4004


celokupna centralna procesorska jedinica bila je smetena na jednom ipu. Iako

prvobitno namenjena za ugradnju u kalkulatore, ova tehnologija omoguila je

je

razvoj brzih a malih raunara pogodnih za linu tj. kunu upotrebu.


asopis Popular electronics nudio je 1975. godine itaocima mogunost

an

naruivanja delova za sklapanje mikroraunara MITS Altair 8800 zasnovanog


na mikroprocesoru Intel 8080 (nasledniku mikroprocesora Intel 4004 ).

In-

teresovanje meu onima koji su se elektronikom bavili iz hobija bio je izuzetno

pozitivan i samo u prvom mesecu prodato je nekoliko hiljada ovih uradi-sm


Smatra se da je Altair 8800 bio inicijalna kapisla za revoluciju

iz

raunara.

mikroraunara koja je usledila narednih godina.

Altair se vezuje i za nas-

tanak kompanije Microsoft danas jedne od dominantnih kompanija u oblasti

sk
o

proizvodnje softvera. Naime, prvi proizvod kompanije Microsoft bio je interpretator za programski jezik BASIC za Altair 8800.
Nakon Altaira pojavljuje se jo nekoliko raunarskih kompleta na skla-

ro
n

panje. Prvi mikroraunar koji je prodavan ve sklopljen bio je Apple, na ijim


temeljima je nastala istoimena kompanija, danas jedan od lidera na tritu
raunarske opreme.

Kuni raunari koristili su se sve vie uglavnom od strane entuzijasta

kt

za jednostavnije obrade podataka, uenje programiranja i igranje raunarskih igara. Kompanija Commodore je 1977. godine predstavila svoj rau-

le

narom Commodore PET koji je zabeleio veliki uspeh. Commodore 64, jedan
od najuspenijih raunara za kunu upotrebu, pojavio se 1982. godine.

Iz

iste kompanije je i serija Amiga raunara sa kraja 1980-ih i poetka 1990-ih.


Pored kompanije Commodore, znaajni proizvoai raunara toga doba bili su

i Sinclair (sa veoma popularnim modelom ZX Spectrum ), Atari, Amstrad, itd.


Kuni raunari ove ere bili su obino jeftini, imali su skromne karakteristike i
najee koristili kasetofone i televizijske ekrane kao ulazno-izlazne ureaje.
Najznaajnija raunarska kompanija toga doba IBM ukljuila se na
trite kunih raunara 1981. godine, modelom IBM PC 5150, poznatijem jednostavno kao IBM PC ili PC (engl. Personal computer ).

Zasnovan na In-

telovom mikroprocesoru Intel 8088, ovaj raunar veoma brzo je zauzeo trite
raunara za linu poslovnu upotrebu (obrada teksta, tabelarna izraunavanja,
. . . ). Pratei veliki uspeh IBM PC raunara, pojavio se odreen broj klonova

1. Raunarstvo i raunarski sistemi

je

(2
01
5)

20

Slika 1.7: Prvi mikroprocesor: Intel 4004. Naslovna strana asopisa Popular

an

electronics sa Altair 8800. Commodore 64. IBM PC 5150.

raunara koji nisu proizvedeni u okviru kompanije IBM, ali koji su kompat-

iz

ibilni sa IBM PC raunarima. PC arhitektura vremenom je postala standard


za kune raunare. Sredinom 1980-ih, pojavom naprednijih grafikih (VGA) i
zvunih (SoundBlaster) kartica, IBM PC i njegovi klonovi stekli su mogunost
proizvoae.

sk
o

naprednih multimedijalnih aplikacija i vremenom su sa trita istisli sve ostale


I naslednici originalnog IBM PC raunara (IBM PC/XT, IBM

PC/AT, . . . ) bili su zasnovani na Intelovim mikroprocesorima, pre svega na

ro
n

x86 seriji (Intel 80286, 80386, 80486) i zatim na seriji Intel Pentium. Operativni sistem koji se tradicionalno vezuju uz PC raunare dolaze iz kompanije

Microsoft prvo MS DOS, a zatim MS Windows. PC arhitektura podrava i


korienje drugih operativnih sistema (na primer, GNU/Linux).

kt

Jedini veliki konkurent IBM PC arhitekturi koji se sve vreme odrao na


tritu (pre svega u SAD) je serija raunara Macintosh kompanije Apple. Mac-

le

intosh, koji se pojavio 1984., je prvi komercijalni kuni raunar sa grafikim


korisnikim interfejsom i miem. Operativni sistem koji se i danas koristi na

Apple raunarima je Mac OS.


Iako su prva povezivanja udaljenih raunara izvrena jo krajem 1960-ih

godina, pojavom interneta (engl. internet) i veba (engl. World Wide Web

WWW), veina raunara postaje meusobno povezana sredinom 1990-ih godina. Danas se veliki obim poslovanja izvrava u internet okruenju, a domen
korienja raunara je veoma irok. Dolo je do svojevrsne informatike revolucije koja je promenila savremeno drutvo i svakodnevni ivot. Na primer, tokom
prve decenije XXI veka dolo je do pojave drutvenih mrea (engl. social net-

works) koje postepeno preuzimaju ulogu osnovnog medijuma za komunikaciju.


Tritem dananjih raunara dominiraju raunari zasnovani na PC arhitekturi i Apple Mac raunari.

Pored stonih (engl. desktop) raunara popularni

1. Raunarstvo i raunarski sistemi

Slika 1.8: Stoni raunar.

je

(2
01
5)

21

Prenosni raunar: IBM ThinkPad.

Tablet: Apple

an

Ipad 2. Pametni telefon: Samsung Galaxy S2.

su i prenosni (engl. notebook ili laptop) raunari.

U najnovije vreme, javlja

iz

se trend tehnoloke konvergencije koja podrazumeva stapanje razliitih ureaja u jedinstvene celine, kao to su tableti (engl. tablet) i pametni telefoni

(engl. smartphone). Operativni sistemi koji se danas uglavnom koriste na ovim

sk
o

ureajima su IOS kompanije Apple, kao i Android kompanije Google.


Pored linih raunara u IV generaciji se i dalje koriste mejnfrejm raunari
(na primer, IBM Z serija) i superraunari (zasnovani na hiljadama procesora).

ro
n

Na primer, kineski superraunar Tianhe-2 radi brzinom od preko 30 petaflopsa

23

(dok proseni lini raunar radi brzinom reda 10 gigaflopsa).

kt

1.3 Oblasti savremenog raunarstva


Savremeno raunarstvo ima mnogo podoblasti, kako praktinih, tako i teori-

le

jskih. Zbog njihove isprepletenosti nije jednostavno sve te oblasti sistematizoU nastavku je dat spisak nekih od oblasti savremenog

vati i klasifikovati.

raunarstva (u skladu sa klasifikacijom amerike asocijacije ACM Associa-

tion for Computing Machinery, jedne od najveih i najuticajnijih raunarskih


zajednica):

Algoritmika (procesi izraunavanja i njihova sloenost);

Strukture podataka (reprezentovanje i obrada podataka);

23 Flops

je mera raunarskih performansi, posebno pogodna za izraunavanja nad broje-

vima u pokretnom zarezu (i pogodnija nego generika mera koja se odnosi na broj instrukcija
u sekundi). Broj flopsa govori koliko operacija nad brojevima u pokretnom zarezu moe da
izvri raunar u jednoj sekundi. Brzina dananjih raunara se obino izraava u gigaflopsima
(109 flopsa), teraflopsima (1012 flopsa) i petaflopsima (1015 flopsa).

22

1. Raunarstvo i raunarski sistemi

Programski jezici (dizajn i analiza svojstava formalnih jezika za opisivanje


algoritama);

Programiranje (proces zapisivanja algoritama u nekom programskom jeziku);

Softversko inenjerstvo (proces dizajniranja, razvoja i testiranja pro-

(2
01
5)

grama);

Prevoenje programskih jezika (efikasno prevoenje viih programskih


jezika, obino na mainski jezik);

Operativni sistemi (sistemi za upravljanje raunarom i programima);

Mreno raunarstvo (algoritmi i protokoli za komunikaciju izmeu rau-

je

nara);

Primene (dizajn i razvoj softvera za svakodnevnu upotrebu);

Istraivanje podataka (pronalaenje relevantnih informacija u velikim sku-

an

Vetaka inteligencija (reavanje problema u kojima se javlja kombinatorna eksplozija);

iz

povima podataka);

Robotika (algoritmi za kontrolu ponaanja robota);

Raunarska grafika (analiza i sinteza slika i animacija);

Kriptografija (algoritmi za zatitu privatnosti podataka);

ro
n

sk
o

Teorijsko raunarstvo (teorijske osnove izraunavanja, raunarska matematika, verifikacija softvera, itd).

kt

1.4 Hardver savremenih raunara

le

Hardver ine opipljive, fizike komponente raunara. Iako je u osnovi savre-

menih raunarskih sistema i dalje fon Nojmanova maina (procesor i memorija), oni se danas ne mogu zamisliti bez niza hardverskih komponenti koje
olakavaju rad sa raunarom.
Iako na prvi pogled deluje da se jedan uobiajeni stoni raunar sastoji od
kuita, monitora, tastature i mia, ova podela je veoma povrna, podlona
promenama (ve kod prenosnih raunara, stvari izgledaju znatno drugaije) i
nikako ne ilustruje koncepte bitne za funkcionisanje raunara. Mnogo znaajnija je podela na osnovu koje raunar ine:

procesor tj. centralna procesorska jedinica (engl. Central Processing Unit,


CPU), koja obrauje podatke;

23

1. Raunarstvo i raunarski sistemi

glavna memorija (engl. main memory), u kojoj se istovremeno uvaju i


podaci koji se obrauju i trenutno pokrenuti programi (takoe zapisani
binarno, u obliku podataka);

razliiti periferijski ureaji ili ulazno-izlazne jedinice (engl. peripherals,


input-output devices, IO devices), kao to su mievi, tastature, ekrani,
za trajno skladitenje podataka i programa.

(2
01
5)

tampai, diskovi, a koje slue za komunikaciju korisnika sa sistemom i

Sve nabrojane komponente meusobno su povezane i podaci se tokom rada

raunara prenose od jedne do druge. Veza izmeu komponenti uspostavlja se


hardverskim sklopovima koji se nazivaju magistrale (engl. bus).

Magistrala

obuhvata provodnike koji povezuju ureaje, ali i ipove koji kontroliu protok
podataka. Svi periferijski ureaji se sa memorijom, procesorom i magistralama
povezuju hardverskim sklopovima koji se nazivaju kontroleri .

Matina ploa

je

(engl. motherboard) je tampana ploa na koju se prikljuuju procesor, memorijski ipovi i svi periferijski ureaji. Na njoj se nalaze ipovi magistrale, a
Osnovu hardvera savremenih

an

danas i mnogi kontroleri periferijskih ureaja.

Procesor je jedna od dve centralne komponente svakog rau-

iz

Procesori.

raunara, dakle, ine sledee komponente:

narskog sistema fon Nojmanove arhitekture.

Svi delovi procesora su danas

objedinjeni u zasebnu jedinicu (CPU) realizovanu na pojedinanom ipu

sk
o

mikroprocesoru. Procesor se sastoji od kontrolne jedinice (engl. Control Unit)


koja upravlja njegovim radom i aritmetiko-logike jedinice (engl. Arithmetic

Logic Unit) koja je zaduena za izvoenje aritmetikih operacija (sabiranje,


oduzimanje, mnoenje, poreenje, . . . )

i logikih operacija (konjunkcija, ne-

ro
n

gacija, . . . ) nad brojevima. Procesor sadri i odreeni, manji broj, registara


koji privremeno mogu da uvaju podatke. Registri su obino fiksirane irine
(8 bitova, 16 bitova, 32 bita, 64 bita). Komunikacija sa memorijom se ranije

kt

vrila iskljuivo preko specijalizovanog registra koji se nazivao akumulator. Aritmetiko logika jedinica sprovodi operacije nad podacima koji su smeteni u

le

registrima i rezultate ponovo smeta u registre. Kontrolna jedinica procesora


ita instrukciju po instrukciju programa zapisanog u memoriji i na osnovu njih

odreuje sledeu akciju sistema (na primer, izvri prenos podataka iz procesora na odreenu memorijsku adresu, izvri odreenu aritmetiku operaciju
nad sadrajem u registrima procesora, uporedi sadraje dva registra i ukoliko
su jednaki izvri instrukciju koja se nalazi na zadatoj memorijskoj adresi i
slino). Brzina procesora meri se u milionima operacija u sekundi (engl. Million Instructions Per Second, MIPS) tj. poto su operacije u pokretnom zarezu
najzahtevnije, u broju operacija u pokretnom zarezu u sekundi (engl. FLoating Point Operations per Second, FLOPS). Dananji standardni procesori rade
oko 10 GFLOPS (deset milijardi operacija u pokretnom zarezu po sekundi).
Dananji procesori mogu da imaju i nekoliko jezgara (engl. core) koja istovremeno izvravaju instrukcije i time omoguuju tzv. paralelno izvravanje.

24

1. Raunarstvo i raunarski sistemi

CPU
Kontrolna

Aritmetiko

jedinica

logika jedinica

registri

Memorija

(2
01
5)

magistrala

Ulazni

Izlazni

ureaji

ureaji

an

je

Slika 1.9: Shema raunara fon Nojmanove arhitekture

Vane karakteristike procesora danas su broj jezgara (obino 1, 2 ili 4),


irina rei (obino 32 bita ili 64 bita) i radni takt (obino nekoliko gigaherca
u jedinici vremena.

Druga centralna komponenta fon Nojmanove arhi-

sk
o

Memorijska hijerarhija.

iz

(GHz)) vei radni takt obino omoguava izvravanje veeg broja operacija

tekture je glavna memorija u koju se skladite podaci i programi. Memorija je


linearno ureeni niz registara (najee bajtova), pri emu svaki registar ima
svoju adresu. Kako se kod ove memorije sadraju moe pristupati u sluajnom

ro
n

redosledu (bez unapred fiksiranog redosleda), ova memorija se esto naziva


i memorija sa slobodnim pristupom (engl. random access memory, RAM).
Osnovni parametri memorija su kapacitet (danas obino meren gigabajtima

kt

(GB)), vreme pristupa koje izraava vreme potrebno da se memorija pripremi


za itanje odnosno upis podataka (danas obino mereno u nanosekundama
(ns)), kao i protok koji izraava koliinu podataka koji se prenose po jedinici

le

merenja (danas obino mereno u GBps).

U savremenim raunarskim sistemima, uz glavnu memoriju uspostavlja se

itava hijerarhija memorija koje slue da unaprede funkcionisanje sistema.


Memorije neposredno vezane za procesor koje se koriste iskljuivo dok je raunar ukljuen nazivaju se unutranje memorije, dok se memorije koje se koriste za skladitenje podataka u trenucima kada raunar nije ukljuen nazivaju

spoljne memorije . Procesor obino nema naina da direktno koristi podatke


koji se nalaze u spoljnim memorijama (jer su one znatno sporije od unutranjih), ve se pre upotrebe svi podaci prebacuju iz spoljnih u unutranju memoriju.
Memorijska hijerarhija predstavlja se piramidom. Od njenog vrha ka dnu
opadaju kvalitet i brzina memorija, ali zato se smanjuje i cena, pa se kapacitet
poveava.

25

1. Raunarstvo i raunarski sistemi

via cena/manji kapacitet


nia cena/vei kapacitet
manja veliina/vea brzina vea veliina/manja brzina

CPU

pod napajanjem

registri

Ke memorija

(2
01
5)

RAM

ROM/BIOS

bez napajanja

USB diskovi

je

hard diskovi

an

CD, DVD, Blu-ray, magnetne trake

iz

Slika 1.10: Memorijska hijerarhija

sk
o

Registri procesora predstavljaju najbru memoriju jer se sve aritmetike i


logike operacije izvode upravo nad podacima koji se nalaze u njima.

Ke (engl. cache) je mala koliina brze memorije (nekoliko hiljada puta


manjeg kapaciteta od glavne memorije; obino nekoliko megabajta) koja se

ro
n

postavlja izmeu procesora i glavne memorije u cilju ubrzanja rada raunara.


Ke se uvodi jer su savremeni procesori postali znatno bri od glavnih memorija. Pre pristupa glavnoj memoriji procesor uvek prvo pristupa keu. Ako

kt

traeni podatak tamo postoji, u pitanju je tzv. pogodak kea (engl. cache hit) i
podatak se dostavlja procesoru. Ako se podatak ne nalazi u keu, u pitanju je
tzv. promaaj kea (engl. cache miss) i podatake se iz glavne memorije prenosi

le

u ke zajedno sa odreenim brojem podataka koji za njim slede (glavni fak-

tor brzine glavne memorije je njeno kanjenje i praktino je svejedno da li se


prenosi jedan ili vie podataka jer je vreme prenosa malog broja bajtova mnogo
manje od vremena kanjenja). Motivacija ovog pristupa je u tome to programi
esto pravilno pristupaju podacima (obino redom kojim su podaci smeteni u
memoriji), pa je velika verovatnoa da e se naredni traeni podaci i instrukcije
nai u ke-memoriji.

Glavna memorija uva sve podatke i programe koje procesor izvrava. Mali
deo glavne memorije ini ROM (engl. read only memory) nepromenljiva memorija koja sadri osnovne programe koji slue za kontrolu odreenih komponenata raunara (na primer, osnovni ulazno-izlazni sistem BIOS). Znatno vei
deo glavne memorije ini RAM privremena promenljiva memorija sa slobodnim pristupom.

Terminoloki, podela glavne memorije na ROM i RAM nije

26

1. Raunarstvo i raunarski sistemi

najpogodnija jer ove vrste memorije nisu sutinski razliite nepromenljivi


deo (ROM) je takoe memorija sa slobodnim pristupom (RAM). Da bi RAM
memorija bila to bra, izrauje se uvek od poluprovodnikih (elektronskih)
elemenata.

Danas se uglavnom realizuje kao sinhrona dinamika memorija

(SDRAM). To znai da se prenos podataka izmeu procesora i memorije vri


u intervalima odreenim otkucajima sistemskog sata (esto se u jednom otkucaju izvri nekoliko prenosa). Dinamika memorija je znatno jeftinija i jednos-

(2
01
5)

tavnija, ali zato sporija od statike memorije od koje se obino gradi ke.

Spoljne memorije uvaju podatke trajno, i kada raunar ostane bez elektrinog napajanja. Kao centralna spoljna skladita podataka uglavnom se ko-

riste hard diskovi (engl. hard disk) koji uvaju podatke korienjem magnetne
tehnologije, a u novije vreme se sve vie koriste i SSD ureaji (engl. solid state

drive) koji uvaju podatke korienjem elektronskih tzv. fle memorija (engl.
flash memory). Kao prenosne spoljne memorije koriste se uglavnom USB fle-

je

memorije (izraene u slinoj tehnologiji kao i SSD) i optiki diskovi (CD, DVD,

Ulazni ureaji.

an

Blu-ray).

Osnovni ulazni ureaji dananjih raunara su tastature i

koristiti tzv.

taped (engl.

mievi. Prenosni raunari imaju ugraenu tastaturu, a umesto mia moe se


touchpad).

Tastature i mievi se sa raunarom

iz

povezuju ili kablom (preko PS/2 ili USB prikljuaka) ili beino (najee korienjem BlueTooth veze). Ovo su uglavnom standardizovani ureaji i nema

sk
o

velikih razlika meu njima. Skeneri sliku sa papira prenose u raunar. Princip
rada je slian digitalnom fotografisanju, ali prilagoen slikanju papira.

Izlazni ureaji.

Osnovni izlazni ureaji savremenih raunara su monitori.

ro
n

Danas dominiraju monitori tankog i ravnog ekrana (engl. flat panel display),
zasnovani obino na tehnologiji tenih kristala (engl. liquid crystal display,
LCD) koji su osvetljeni pozadinskim LED osvetljenjem.

Ipak, jo uvek su

kt

ponegde u upotrebi i monitori sa katodnom cevi (engl. cathode ray tube, CRT).
Grafiki kontroleri koji slue za kontrolu slike koja se prikazuje na monitoru

le

ili projektoru danas su obino integrisani na matinoj ploi, a ponekad su i na


istom ipu sa samim procesorom (engl. Accelerated Processing Unit, APU).

to se tehnologije tampe tie, danas su najzastupljeniji laserski tampai

i inkdet tampai (engl. inkjet). Laserski tampai su ee crno-beli, dok su


ink-det tampai obino u boji. Sve su dostupniji i 3D tampai.

1.5 Softver savremenih raunara


Softver ine raunarski programi i pratei podaci koji odreuju izraunavanja koje vri raunar.

Na prvim raunarima moglo je da se programira

samo na mainski zavisnim programskim jezicima na jezicima specifinim


za konkretnu mainu na kojoj program treba da se izvrava. Polovinom 1950ih nastali su prvi jezici vieg nivoa i oni su drastino olakali programiranje.

27

1. Raunarstvo i raunarski sistemi

Danas se programi obino piu u viim programskim jezicima a zatim prevode


na mainski jezik jezik razumljiv raunaru. Bez obzira na to kako je nastao,
da bi mogao da se izvri na raunaru, program mora da budu smeten u memoriju u obliku binarno zapisanih podataka (tj. u obliku niza nula i jedinica)
koji opisuju instrukcije koje su neposredno podrane arhitekturom raunara.
U ovom poglavlju bie prikazani osnovni principa rada raunara kroz nekoliko

1.5.1

(2
01
5)

jednostavnih primera programa.

Primeri opisa izraunavanja

Program specifikuje koje operacije treba izvriti da bi se reio neki zadatak.

Principi rada programa mogu se ilustrovati na primeru nekoliko jednostavnih


izraunavanja i instrukcija koje ih opisuju. Ovi opisi izraunavanja dati su u

vidu prirodno-jezikog opisa ali direktno odgovaraju i programima na viim

je

programskim jezicima.

Kao prvi primer, razmotrimo izraunavanje vrednosti

2 + 3

za datu vred-

U programiranju (slino kao i u matematici) podaci se predstavljaju

an

nost

promenljivama. Meutim, promenljive u programiranju (za razliku od matematike) vremenom mogu da menjaju svoju vrednost (tada kaemo da im se

dodeljuje nova vrednost). U programiranju, svakoj promenljivoj pridrueno je

iz

(jedno, fiksirano) mesto u memoriji i tokom izvravanja programa promenljiva


moe da menja svoju vrednost, tj. sadraj dodeljenog memorijskog prostora.
Ako je promenljiva ija je vrednost ulazni parametar oznaena sa

sk
o

ljiva ija je vrednost rezultat izraunavanja oznaena sa

a promen-

onda se pomenuto

izraunavanje moe opisati sledeim jednostavnim opisom.

Simbol

ro
n

y := 2*x + 3

* oznaava mnoenje, + sabiranje, a := oznaava da se promenljivoj

sa njene leve strane dodeljuje vrednost izraza sa desne strane.

kt

Kao naredni primer, razmotrimo odreivanje veeg od dva data broja. Raunari (tj. njihovi procesori) obino imaju instrukcije za poreenje brojeva, ali

le

odreivanje vrednosti veeg broja zahteva nekoliko koraka. Pretpostavimo da


promenljive

sadre dve brojevne vrednosti, a da promenljiva

dobije vrednost vee od njih.

treba da

Ovo izraunavanje moe da se izrazi sledeim

opisom.

ako je x >= y onda


m := x
inae
m := y
Kao malo komplikovaniji primer razmotrimo stepenovanje. Procesori skoro
uvek podravaju instrukcije kojima se izraunava zbir i proizvod dva cela broja,
ali stepenovanje obino nije podrano kao elementarna operacija.

Sloenije

28

1. Raunarstvo i raunarski sistemi

operacije se mogu ostvariti korienjem jednostavnijih.

pen broja

(tj. vrednost

mnoenja: ako se krene od broja


e biti

Na primer,

-ti

ste-

mogue je izraunati uzastopnom primenom

puta sa pomnoi brojem

rezultat

Da bi moglo da se osigura da e mnoenje biti izvreno tano

puta, koristi se brojaka promenljiva

koja na poetku dobija vrednost

0,

zatim se, prilikom svakog mnoenja, uveava sve dok ne dostigne vrednost

(2
01
5)

Ovaj postupak moemo predstaviti sledeim opisom.

s := 1, i := 0
dok je i < n radi sledee:
s := sx, i := i+1
Kada se ovaj postupak primeni na vrednosti

i := 0,

n(=2),

poto je

i := i+1 = 1+1 = 2,

n(=2),

i(=0)

manje od

vre se dalje ope-

racije

an

i := i+1 = 0+1 = 1,

i(=1)

manje od

vre se dalje ope-

racije

poto i(=2) nije manje od


n(=2), ne vre se dalje
operacije.

sk
o

iz

s := sx = 33 = 9,

poto je

s := sx = 13 = 3,

1.5.2

= 3 i = 2, izvodi se naredni

je

niz koraka.
s := 1,

Mainski programi

Mainski programi su neposredno vezani za procesor raunara na kojem se

ro
n

koriste procesor je konstruisan tako da moe da izvrava odreene elementarne naredbe.

Ipak, razvoj najveeg broja procesora usmeren je tako da se

isti mainski programi mogu koristiti na itavim familijama procesora.

kt

Primitivne instrukcije koje podrava procesor su veoma malobrojne i jednostavne (na primer, postoje samo instrukcije za sabiranje dva broja, kon-

le

junkcija bitova, instrukcija skoka i slino) i nije lako kompleksne i apstraktne


algoritme izraziti korienjem tog uskog skupa elementarnih instrukcija. Ipak,

svi zadaci koje raunari izvravaju svode se na ove primitivne instrukcije.

Asemblerski jezici.

Asemblerski (ili simboliki) jezici su jezici koji su veoma

bliski mainskom jeziku raunara, ali se, umesto korienja binarnog sadraja
za zapisivanje instrukcija koriste (mnemotehnike, lako pamtljive) simbolike
oznake instrukcija (tj. programi se unose kao tekst). Ovim se, tehniki, olakava
unos programa i programiranje (programer ne mora da direktno manipulie binarnim sadrajem), pri emu su sve mane mainski zavisnog programiranja i
dalje prisutne. Kako bi ovako napisan program mogao da se izvrava, neophodno je izvriti njegovo prevoenje na mainski jezik (tj. zapisati instrukcije
binarnom azbukom) i uneti na odgovarajue mesto u memoriji. Ovo prevoenje

29

1. Raunarstvo i raunarski sistemi

je jednostavno i jednoznano i vre ga jeziki procesori koji se nazivaju asem-

bleri .
Sva izraunavanja u primerima iz poglavlja 1.5.1 su opisana neformalno,
kao uputstva oveku a ne raunaru.

Da bi se ovako opisana izraunavanja

mogla sprovesti na nekom raunaru fon Nojmanove arhitekture neophodno je


opisati ih preciznije. Svaka elementarna operacija koju procesor moe da izvri
u okviru programa zadaje se procesorskom instrukcijom svaka instrukcija

(2
01
5)

instruie procesor da izvri odreenu operaciju. Svaki procesor podrava unapred fiksiran, konaan skup instrukcija (engl. instruction set). Svaki program

raunara predstavljen je nizom instrukcija i skladiti se u memoriji raunara.


Naravno, raunari se razlikuju (na primer, po tome koliko registara u proce-

soru imaju, koje instrukcije moe da izvri njihova aritmetiko-logika jedinica,


koliko memorije postoji na raunaru, itd). Meutim, da bi se objasnili osnovni
principi rada raunara nije neophodno razmatrati neki konkretan raunar, ve
tri registra oznaena sa

ax, bx i cx

je

se moe razmatrati neki hipotetiki raunar. Pretpostavimo da procesor sadri


i jo nekoliko izdvojenih bitova (tzv. zas-

an

tavica). Dalje, pretpostavimo da procesor moe da izvrava naredne aritmetike

instrukcije (zapisane ovde u asemblerskom obliku):

add ax, bx

oznaava operaciju sabiranja vrednosti brojeva

Operacija

ax i bx, pri emu se rezultat sabiranja smeta


add moe se primeniti na bilo koja dva registra.

mul ax, bx

oznaava operaciju mnoenja vrednosti brojeva

ax.

Instrukcija

sk
o

u registar

Instrukcija

koji se nalaze u registrima

iz

Operacija

ax i bx, pri emu se rezultat mnoenja smeta


mul moe se primeniti na bilo koja dva registra.

cmp ax, bx

oznaava operaciju poreenja vrednosti brojeva

koji se nalaze u registrima


u registar

Instrukcija

ro
n

ax.

ax i bx i rezultat pamti postavljanjem zastavice


cmp se moe primeniti na bilo koja dva registra.

koji se nalaze u registrima

kt

u procesoru. Operacija

Program raunara je niz instrukcija koje se obino izvravaju redom, jedna


za drugom. Meutim, poto se javlja potreba da se neke instrukcije ponove vei

le

broj puta ili da se odreene instrukcije preskoe, uvode se instrukcije skoka.

Da bi se moglo specifikovati na koju instrukciju se vri skok, uvode se labele


oznaena mesta u programu. Pretpostavimo da na procesor moe da izvrava
sledee dve vrste skokova (bezuslovne i uslovne):

Instrukcija

jmp label,

gde je

label

neka labela u programu, oznaava

bezuslovni skok koji uzrokuje nastavak izvravanja programa od mesta u


programu oznaenog navedenom labelom.

Uslovni skokovi prouzrokuju nastavak izvravanja programa od instrukcije oznaene navedenom labelom, ali samo ako je neki uslov ispunjen.
Ukoliko uslov nije ispunjen, izvrava se naredna instrukcija.
tavku e se razmatrati samo instrukcija

U nas-

jge label, koja uzrokuje uslovni

30

1. Raunarstvo i raunarski sistemi

skok na mesto oznaeno labelom

label

ukoliko je vrednost prethodnog

poreenja brojeva bila vee ili jednako.


Tokom izvravanja programa, podaci se nalaze u memoriji i u registrima
procesora. S obzirom na to da procesor sve operacije moe da izvri iskljuivo
nad podacima koji se nalaze u njegovim registrima, svaki procesor podrava
i instrukcije prenosa podataka izmeu memorije i registara procesora (kao i
Pretpostavimo da na procesor podrava sledeu

(2
01
5)

izmeu samih registara).


instrukciju ove vrste.

Instrukcija

mov

oznaava operaciju prenosa podataka i ima dva parame-

tra prvi odreuje gde se podaci prenose, a drugi koji odreuje koji
se podaci prenose.

Parametar moe biti ime registra (to oznaava da

se pristupa podacima u odreenom registru), broj u zagradama (to oznaava da se pristupa podacima u memoriji i to na adresi odreenoj

je

brojem u zagradama) ili samo broj (to oznaava da je podatak ba taj

mov ax bx oznaava da se sadraj


bx prepisuje u registar ax, instrukcija mov ax, [10] oznaava da
se sadraj iz memorije sa adrese 10 prepisuje u registar ax, instrukcija
mov ax, 1 oznaava da se u registar ax upisuje vrednost 1, dok instrukcija oznaava mov [10], ax da se sadraj registra ax upisuje u memoriju
na adresu 10.

an

navedeni broj). Na primer, instrukcija

iz

registra

2 + 3

sk
o

Sa ovakvim procesorom na raspolaganju, izraunavanje vrednosti

moe se ostvariti na sledei nain. Pretpostavimo da se ulazni podatak (broj

) nalazi u glavnoj memoriji i to na adresi 10, a da rezultat treba smestiti na


adresu 11 (ovo su sasvim proizvoljno odabrane adrese). Izraunavanje se onda

ax, [10]
bx, 2
ax, bx
bx, 3
ax, bx
[11], ax

le

kt

mov
mov
mul
mov
add
mov

ro
n

moe opisati sledeim programom (nizom instrukcija).

mov ax, [10] prepisuje vrednost promenljive (iz memorije sa


ax. Instrukcija mov bx, 2 upisuje vrednost 2 u registar
bx. Nakon instrukcije mul ax, bx vri se mnoenje i registar ax sadri vrednost
2. Instrukcija mov bx, 3 upisuje vrednost 3 u registar bx, nakon instrukcije
add ax, bx se vri sabiranje i u registru ax se nalazi traena vrednost 2 + 3.
Na kraju se ta vrednost instrukcijom mov [11], ax upisuje u memoriju na
adresu 11.
Instrukcija

adrese

10)

u registar

Odreivanje veeg od dva broja moe se ostvariti na sledei nain. Pretpostavimo da se ulazni podaci nalaze u glavnoj memoriji i to broj

na adresi

31

10,

1. Raunarstvo i raunarski sistemi

broj

na adresi

11,

dok rezultat

treba smestiti na adresu

12.

Program

(niz instrukcija) kojima moe da se odredi maksimum je sledei:

(2
01
5)

mov ax, [10]


mov bx, [11]
cmp ax, bx
jge vecix
mov [12], bx
jmp kraj
vecix:
mov[12], ax
kraj:

iz

an

je

Nakon prenosa vrednosti oba broja u registre procesora (instrukcijama mov


ax, [10] i mov bx, [11]), vri se njihovo poreenje (instrukcija cmp ax, bx).
Ukoliko je broj vei od ili jednak broju prelazi se na mesto oznaeno labelom vecix (instrukcijom jge vecix) i na mesto rezultata upisuje se vrednost
promenljive (instrukcijom mov[12], ax). Ukoliko uslov skoka jge nije ispunjen (ako nije vee ili jednako ), na mesto rezultata upisuje se vrednost
promenljive (instrukcijom mov [12], bx) i bezuslovno se skae na kraj programa (instrukcijom jmp kraj) (da bi se preskoilo izvravanje instrukcije koja
na mesto rezultata upisuje vrednost promenljive ).
Izraunavanje stepena moe se ostvariti na sledei nain. Pretpostavimo da
na adresi
adresu

11,

12.

sk
o

se ulazni podaci nalaze u glavnoj memoriji i to broj

na adresi

Pretpostavimo da e pomone promenljive

ro
n

ax, a promenljiva u registru bx.

koja se sabira sa promenljivom

kt

mov ax, 1
mov bx, 0
petlja:
mov cx, [11]
cmp bx, cx
jge kraj
mov cx, [10]
mul ax, cx
mov cx, 1
add bx, cx
jmp petlja
kraj:
mov [12], ax

u registru

i , kao i konstanta

Niz instrukcija kojim opisani hipotetiki

raunar moe da izrauna stepen je sledei:

le

Poto postoji jo samo jedan registar (cx), u

njega e naizmenino biti smetane vrednosti promenljivih

a broj

koje se koriste u

postupku biti smetene sve vreme u procesoru, i to promenljiva

10,

i da konaan rezultat treba da bude smeten u memoriju i to na

32

1. Raunarstvo i raunarski sistemi

32 . Inici10 u memoriji nalazi vrednost = 3,

Ilustrujmo izvravanje ovog programa na izraunavanju vrednosti


jalna konfiguracija je takva da se na adresi
na adresi

11

vrednost

= 2.

Poetna konfiguracija (tj. vrednosti memorijskih

lokacija i registara) moe da se predstavi na sledei nain:

ax: ?
bx: ?
cx: ?

Nakon izvravanja prve dve instrukcije (mov


se vrednost registara

ax: 1
bx: 0
cx: ?

Sledea instrukcija (mov

ax: 1
bx: 0
cx: 2

10: 3
11: 2
12: ?

cx, [11]) kopira vrednost 2 sa adrese 11 u regis-

an

cx:

iz

tar

ax, 1 i mov bx, 0), postavlja

i prelazi se u sledeu konfiguraciju:

je

10: 3
11: 2
12: ?

ax i bx

(2
01
5)

10: 3
11: 2
12: ?

bx (cmp bx, cx) i kako uslov skoka (jge kraj)


2 u cx), nastavlja se dalje. Nakon kopiranja vrednosti 3 sa adrese 10 u registar cx (instrukcijom mov cx, [10]), vri se mnoenje vrednosti u registrima ax i cx
(instrukcijom mul ax, cx) i dolazi se u sledeu konfiguraciju:
Vri se poreenje sa registrom

bx

nije vea ili jednaka od vrednosti

ax: 3
bx: 0
cx: 3

kt

10: 3
11: 2
12: ?

ro
n

sk
o

nije ispunjen (vrednost

cx se upisuje 1 (instrukcijom mov cx, 1) i vri se sabiranje


bx i cx (instrukcijom add bx, cx) ime se vrednost u regza 1.

Nakon toga, u

le

vrednosti registara
istru

bx

10: 3
11: 2
12: ?

uveava

ax: 3
bx: 1
cx: 1

Bezuslovni skok (jmp

cx

petlja)

ponovo vraa kontrolu na poetak petlje,

2 sa adrese 11 (mov cx, [11]).


bx (cmp bx, cx) i kako uslov skoka (jge kraj)
nije ispunjen (vrednost 1 u bx nije vea ili jednaka vrednosti 2 u cx), nastavlja

nakon ega se u

opet prepisuje vrednost

Vri se poreenje sa registrom

se dalje. Nakon jo jednog mnoenja i sabiranja dolazi se do konfiguracije:

33

1. Raunarstvo i raunarski sistemi

10: 3
11: 2
12: ?

ax: 9
bx: 2
cx: 1

Bezuslovni skok ponovo vraa kontrolu na poetak petlje, nakon ega se

cx opet prepisuje vrednost 2 sa adrese 11. Vri se poreenje sa registrom


bx, no, ovaj put je uslov skoka ispunjen (vrednost 2 u bx je vea ili jednaka
vrednosti 2 u cx) i skae se na mesto oznaeno labelom kraj, gde se poslednjom instrukcijom (mov [12], ax) konana vrednost iz registra ax kopira u
memoriju na dogovorenu adresu 12, ime se stie u zavrnu konfiguraciju:
ax: 9
bx: 2
cx: 1

je

10: 3
11: 2
12: 9

(2
01
5)

Mainski jezik.

an

Fon Nojmanova arhitektura podrazumeva da se i sam pro-

gram (niz instrukcija) nalazi u glavnoj memoriji prilikom njegovog izvravanja.


Potrebno je svaki program (poput tri navedena) predstaviti nizom nula i je-

dinica, na nain razumljiv procesoru na mainskim jeziku.

Na primer,

mogue je da su binarni kdovi za instrukcije uvedeni na sledei nain:

sk
o

iz

001
010
011
100
101
110

ro
n

mov
add
mul
cmp
jge
jmp

Takoe, poto neke instrukcije primaju podatke razliite vrste (neposredno


navedeni brojevi, registri, apsolutne memorijske adrese), uvedeni su posebni
kdovi za svaki od razliitih vidova adresiranja. Na primer:

kt

neposredno
registarsko

le

apsolutno

00
01
10

Pretpostavimo da registar

registar

cx oznaku 10.

ax

ima oznaku

00,

registar

bx

ima oznaku

01,

Pretpostavimo i da su sve adrese osmobitne. Pod nave-

mov [10], ax se, u ovom hipotetikom


001 10 01 00010000 00. Kd 001 dolazi
10 i 01 koji ukazuju da prvi argument pred-

denim pretpostavkama, instrukcija

mainskom jeziku, moe kodirati kao


od instrukcije

mov,

zatim slede

stavlja memorijsku adresu, a drugi oznaku registra, za im sledi memorijska


adresa

(10)16

binarno kodirana sa

00010000

i na kraju oznaka

00

registra

ax.

Na slian nain, celokupan prikazani mainski kd navedenog asemblerskog


programa koji izraunava

001 01 10 00 00010000
001 01 00 01 00000010
011 00 01

2 + 3

je mogue binarno kodirati kao:

// mov ax, [10]


// mov bx, 2
// mul ax, bx

34

1. Raunarstvo i raunarski sistemi

001 01 00 01 00000011
010 00 01
001 10 01 00010001 00

// mov bx, 3
// add ax, bx
// mov [11], ax

Izmeu prikazanog asemblerskog i mainskog programa postoji veoma direktna i jednoznana korespondencija (u oba smera) tj. na osnovu datog mainskog
kda mogue je jednoznano rekonstruisati asemblerski kd.

(2
01
5)

Specifini hardver koji ini kontrolnu jedinicu procesora dekodira jednu po


jednu instrukciju i izvrava akciju zadatu tom instrukcijom. Kod realnih procesora, broj instrukcija i naini adresiranja su mnogo bogatiji a prilikom pisanja
programa potrebno je uzeti u obzir mnoge aspekte na koje se u navedenim
jednostavnim primerima nije obraala panja.

Ipak, mainske i asemblerske

instrukcije stvarnih procesora veoma su sline navedenim hipotetikim instruk-

Klasifikacija savremenog softvera

an

1.5.3

je

cijama.

Raunarski programi veoma su sloeni.

Hardver raunara sainjen je od

elektronskih kola koja mogu da izvre samo elementarne operacije i, da bi rau-

nar mogao da obavi i najjednostavniji zadatak zanimljiv korisniku, neophodno

iz

je da se taj zadatak razloi na mnotvo elementarnih operacija.

Napredak

raunara ne bi bio mogu ako bi programeri morali svaki program da opisuju


i razlau do krajnjeg nivoa elementarnih instrukcija. Zato je poeljno da pro-

sk
o

grameri naredbe raunaru mogu zadavati na to apstraktnijem nivou. Raunarski sistemi i softver se grade slojevito i svaki naredni sloj oslanja se na
funkcionalnost koju mu nudi sloj ispod njega. U skladu sa tim, softver savre-

ro
n

menih raunara se obino deli na aplikativni i sistemski .

Osnovni zadatak

sistemskog softvera je da posreduje izmeu hardvera i aplikativnog softvera


koji krajnji korisnici koriste.

Granica izmeu sistemskog i aplikativnog soft-

vera nije kruta i postoje programi za koje se moe smatrati da pripadaju obema

kt

grupama (na primer, editori teksta).

le

Aplikativni softver.

Aplikativni softver je softver koji krajnji korisnici rau-

nara direktno koriste u svojim svakodnevnim aktivnostima. To su pre svega


pregledai Veba, zatim klijenti elektronske pote, kancelarijski softver (programi za kucanje teksta, izradu slajd-prezentacija, tabelarna izraunavanja),
video igre, multimedijalni softver (programi za reprodukciju i obradu slika,
zvuka i video-sadraja) itd.

Sistemski softver.

je softver ija je uloga da kontrolie hardver i prua

usluge aplikativnom softveru.

Najznaajniji skup sistemskog softvera, danas

prisutan na skoro svim raunarima, ini operativni sistem (OS). Pored OS,
sistemski softver sainjavaju i razliiti usluni programi : editori teksta, alat za
programiranje (prevodioci, dibageri, profajleri, integrisana okruenja) i slino.

35

1. Raunarstvo i raunarski sistemi

Korisnici OS esto identifikuju sa izgledom ekrana tj. sa programom koji


koriste da bi pokrenuli svoje aplikacije i organizovali dokumente.

Meutim,

ovaj deo sistema koji se naziva korisniki interfejs (engl. user interface UI)
ili koljka (engl. shell) samo je tanak sloj na vrhu operativnog sistema i OS je
mnogo vie od onoga to krajnji korisnici vide. Najvei i najznaajni deo OS
naziva se jezgro (engl. kernel). Osim to kontrolie i apstrahuje hardver, operativni sistem tj. njegovo jezgro sinhronizuje rad vie programa, rasporeuje
orijama itd.

(2
01
5)

procesorsko vreme i memoriju, brine o sistemu datoteka na spoljanjim memNajznaanjni operativni sistemi danas su Microsoft Windows,

sistemi zasnovani na Linux jezgru (na primer, Ubuntu, RedHat, Fedora, Suse)
i Mac OS X.

OS upravlja svim resursima raunara (procesorom, memorijom, periferi-

jskim ureajima) i stavlja ih na raspolaganje aplikativnim programima. OS je


u veoma tesnoj vezi sa hardverom raunara i veliki deo zadataka se izrvrava uz

je

direktnu podrku specijalizovanog hardvera namenjenog iskljuivo izvravanju


OS. Nekada se hardver i operativni sistem smatraju jedinstvenom celinom i

an

umesto podele na hardver i softver razmatra se podela na sistem (hardver i


OS) i na aplikativni softver.

Programer ne bi trebalo da misli o konkretnim detaljima hardvera, tj. po-

eljno je da postoji odreena apstrakcija hardvera. Na primer, mnogo je pogod-

iz

nije ako programer umesto da mora da kae Neka se zavrti ploa diska, neka
se glava pozicionira na odreenu poziciju, neka se zatim tu upie odreeni bajt
itd. moe da kae Neka se u datu datoteku na disku upie odreeni tekst.

sk
o

OS je taj koji se brine o svim detaljima, dok se programer (tanije, aplikacije


koje on isprogramira), kada god mu je potrebno obraa sistemu da mu tu
uslugu prui. Konkretni detalji hardvera poznati su u okviru operativnog sis-

ro
n

tema i komande koje programer zadaje izvravaju se uzimajui u obzir ove


specifinosti. Operativni sistem, dakle, programeru prua skup funkcija koje
on moe da koristi da bi postigao eljenu funkcionalnost hardvera, sakrivajui
pritom konkretne hardverske detalje.

kt

ski interfejs za pisanje aplikacija

Ovaj skup funkcija naziva se program-

24 (engl. Aplication Programming Interface,

API ). Funkcije se nazivaju i sistemski pozivi (jer se OS poziva da izvri odreeni

le

zadatak).

Programer nema mogunost direktnog pristupa hardveru i jedini

nain da se pristupi hardveru je preko sistemskih poziva. Ovim se osigurava

odreena bezbednost celog sistema.


Postoji vie nivoa na kojima se moe realizovati neka funkcionalnost. Pro-

gramer aplikacije je na vrhu hijerarhije i on moe da koristi funkcionalnost


koju mu prua programski jezik koji koristi i biblioteke tog jezika.

Izvrni

programi esto koriste funkcionalnost specijalne rantajm biblioteke (engl. run-

time library) koja koristi funkcionalnost operativnog sistema (preko sistemskih


poziva), a zatim operativni sistem koristi funkcionalnost samog hardvera.

24 Ovaj

termin se ne koristi samo u okviru operativnih sistema, ve i u irem kontekstu,

da oznai skup funkcija kroz koji jedan programski sistem koristi drugi programski sistem.

36

1. Raunarstvo i raunarski sistemi

Pitanja za vebu
Pitanje 1.1.

Nabrojati osnovne periode u razvoju raunara i navesti njihove

osnovne karakteristike i predstavnike.

Pitanje 1.2.

Ko je i u kom veku konstruisao prvu mehaniku spravu na kojoj

je bilo mogue sabirati prirodne brojeve, a ko je i u kom veku konstruisao prvu

Pitanje 1.3.

(2
01
5)

mehaniku spravu na kojoj je bilo mogue sabirati i mnoiti prirodne brojeve?

Kojoj spravi koja se koristi u dananjem svetu najvie odgovaraju

Paskalove i Lajbnicove sprave?

Pitanje 1.4.

Kakva je veza izmeu tkakih razboja i raunara s poetka XIX

veka?

Pitanje 1.5.

Koji je znaaj arlsa Bebida za razvoj raunarstva i programi-

U kom veku je on dizajnirao svoje raunske maine?

je

ranja?

zovu i koja od njih je trebalo da bude programabilna?

an

programerom?

Kako se one

Ko se smatra prvim

Pitanje 1.6.

Na koji nain je Herman Holerit doprineo izvravanju popisa

stanovnika u SAD 1890?

Kako su bili uvani podaci sa tog popisa?

Koja

iz

uvena kompanija je nastala iz kompanije koju je Holerit osnovao?

Pitanje 1.7.

Kada su nastali prvi elektronski raunari?

Pitanje 1.8.

Nabrojati nekoliko

sk
o

najznaajnijih.

Na koji nain je programiran raunar ENIAC, a na koji raunar

ro
n

EDVAC?

Pitanje 1.9.

Koje su osnovne komponente raunara fon Nojmanove arhitek-

ture? ta se skladiti u memoriju raunara fon Nojmanove arhitekture? Gde se

kt

vri obrada podataka u okviru raunara fon Nojmanove arhitekture? Od kada


su raunari zasnovani na fon Nojmanovoj arhitekturi?

le

Pitanje 1.10.

ta su to raunari sa skladitenim programom? ta je to hard-

ver a ta softver?

Pitanje 1.11.

ta su procesorske instrukcije? Navesti nekoliko primera.

Pitanje 1.12.

Koji su uobiajeni delovi procesora? Da li se u okviru samog

procesora nalazi odreena koliina memorije za smetanje podataka? Kako se


ona naziva?

Pitanje 1.13.

Ukratko opisati osnovne elektronske komponente svake gen-

eracije raunara savremenih elektronskih raunara? ta su bile osnovne elektronske komponente prve generacije elektronskih raunara? Od koje generacije
raunara se koriste mikroprocesori? Koji tipovi raunara se koriste u okviru
III generacije?

37

1. Raunarstvo i raunarski sistemi

Pitanje 1.14.

U kojoj deceniji dolazi do pojave raunara za kunu upotrebu?

Koji je najprodavaniji model kompanije Commodore? Da li je IBM proizvodio raunare za kunu upotrebu? Koji komercijalni kuni raunar prvi uvodi
grafiki korisniki interfejs i mia?

Pitanje 1.15.

Koja serija Intelovih procesora je bila dominantna u PC rau-

Pitanje 1.16.

ta je to tehnoloka konvergencija?

pametni telefoni?

Pitanje 1.17.

(2
01
5)

narima 1980-ih i 1990-ih godina?


ta su to tableti, a ta

Koje su osnovne komponente savremenog raunara?

ta je

memorijska hijerarhija? Zato se uvodi ke-memorija? Koje su danas najkorienije spoljne memorije?

U koju grupu jezika spadaju mainski jezici i asemblerski jezici?

Pitanje 1.19.

Da li je kd na nekom mainskom jeziku prenosiv sa jednog na

je

Pitanje 1.18.

Pitanje 1.20.

an

sve druge raunare? Da li asembler zavisi od maine na kojoj se koristi?


Ukoliko je raspoloiv asemblerski kd nekog programa, da li

je mogue jednoznano konstruisati odgovarajui mainski kd?

Ukoliko je

iz

raspoloiv mainski kd nekog programa, da li je mogue jednoznano konstruisati odgovarajui asemblerski kd?

Zadatak 1.1.

Na opisanom asemblerskom jeziku opisati izraunavanje vred-

x := x*y + y + 3.

sk
o

nosti izraza
gram.

Zadatak 1.2.

Generisati i mainski kd za napisani pro-

ro
n

Na opisanom asemblerskom jeziku opisati izraunavanje:

kt

ako je (x < 0)
y := 3*x;
inace
x := 3*y;

Zadatak 1.3.

le

Na opisanom asemblerskom jeziku opisati izraunavanje:

dok je (x <= 0) radi


x := x + 2*y + 3;

Zadatak 1.4.
Na
se izraunava

opisanom asemblerskom jeziku opisati izraunavanje kojim

[ ],

pri emu se

nalazi na adresi 100, a rezultat smeta na

adresu 200.

Pitanje 1.21.

Koji su osnovni razlozi slojevite organizacije softvera? ta je

sistemski, a ta aplikativni softver?

Pitanje 1.22.

Koji su osnovni zadaci operativnog sistema? ta su sistemski

pozivi? Koji su operativni sistemi danas najkorieniji?

(2
01
5)

Glava 2

an

je

Reprezentacija podataka u
raunarima

Dananji raunari su digitalni . To znai da su svi podaci koji su u njima


zapisani, zapisani kao nizovi celih brojeva. Dekadni brojevni sistem koji ljudi

koriste u svakodnevnom ivotu nije pogodan za zapis brojeva u raunarima jer

iz

zahteva azbuku od 10 razliitih simbola (cifara). Bilo da se radi o elektronskim,


magnetnim ili optikim komponentama, tehnologija izrade raunara i medijuma
za zapis podataka koristi elemente koji imaju dva diskretna stanja, to za

sk
o

zapis podataka daje azbuku od samo dva razliita simbola. Tako, na primer,
ukoliko izmeu dve take postoji napon vii od odreenog praga, onda se smatra
da tom paru taaka odgovara vrednost

1,

a inae mu odgovara vrednost

ro
n

Takoe, polje hard diska moe biti ili namagnetisano to odgovara vrednosti
ili razmagnetisano to odgovara vrednosti

0.

0.
1

Slino, laserski zrak na povrini

kompakt diska bui rupice kojim je odreen zapis podataka pa polje koje
nije izbueno predstavlja vrednost

1.

0,

a ono koje jeste izbuesno predstavlja

U nastavku e biti pokazano da je azbuka od samo dva simbola

kt

vrednost

dovoljna za zapisivanje svih vrsta brojeva, pa samim tim i za zapisivanje svih

le

vrsta digitalnih podataka.

2.1 Analogni i digitalni podaci i digitalni raunari


Kontinualna priroda signala.

Veina podataka koje raunari koriste nas-

taje zapisivanjem prirodnih signala.

Najznaajniji primeri signala su zvuk i

slika, ali se pod signalima podrazumevaju i ultrazvuni signali, EKG signali,


zraenja razliite vrste itd.
Signali koji nas okruuju u prirodi u veini sluajeva se prirodno mogu predstaviti neprekidnim funkcijama. Na primer, zvuni signal predstavlja promenu
pritiska vazduha u zadatoj taki i to kao neprekidnu funkciju vremena. Slika se
moe opisati intenzitetom svetlosti odreene boje (tj. odreene talasne duine)
u datom vremenskom trenutku i to kao neprekidna funkcija prostora.

38

39

2. Reprezentacija podataka u raunarima

Analogni zapis.

Osnovna tehnika koja se primenjuje kod analognog zapisa

signala je da se kontinualne promene signala koji se zapisuje opiu kontinualnim


promenama odreenog svojstva medijuma na kojem se signal zapisuje. Tako,
na primer, promene pritiska vazduha koji predstavlja zvuni signal direktno
odgovaraju promenama nivoa namagnetisanja na magnetnoj traci na kojoj se
zvuk analogno zapisuje. Koliina boje na papiru direktno odgovara intenzitetu
svetlosti u vremenskom trenutku kada je fotografija bila snimljena.

Dakle,

(2
01
5)

analogni zapis uspostavlja analogiju izmeu signala koji je zapisan i odreenog


svojstva medijuma na kome je signal zapisan.

Osnovna prednost analogne tehnologije je da je ona obino veoma jednos-

tavna ukoliko se zadovoljimo relativno niskim kvalitetom (jo su drevni narodi

mogli da naprave nekakav zapis zvuka uz pomo jednostavne igle prikaene na


trepereu membranu).

Osnovni problem analogne tehnologije je to je izrazito teko na medijumu

je

napraviti veran zapis signala koji se zapisuje i izrazito je teko napraviti dva
identina zapisa istog signala. Takoe, problem predstavlja i inherentna nestal-

an

nost medijuma, njegova promenljivost tokom vremena i podlonost spoljanjim


uticajima. S obzirom na to da varijacije medijuma direktno dovode do varijacije zapisanog signala, vremenom neizbeno dolazi do pada kvaliteta analogno

zapisanog signala. Obrada analogno zapisanih signala je obino veoma komp-

iz

likovana i za svaku vrstu obrade signala, potrebno je da postoji ureaj koji je

Digitalni zapis.

sk
o

specijalizovan za tu vrste obrade.

Osnovna tehnika koja se koristi kod digitalnog zapisa po-

dataka je da se vrednost signala izmeri u odreenim vremenskim trenucima ili


odreenim takama prostora i da se onda na medijumu zapiu izmerene vred-

ro
n

nosti. Ovim je svaki digitalno zapisani signal predstavljen nizom brojeva koji
se nazivaju odbirci ili semplovi (engl. sample) .

Svaki od brojeva predstavlja

vrednost signala u jednoj taki diskretizovanog domena. S obzirom na to da

kt

izmerene vrednosti takoe pripadaju kontinualnoj skali, neophodno je izvriti i


diskretizaciju kodomena, odnosno dopustiti zapisivanje samo odreenog broja
nivoa razliitih vrednosti.

le

Digitalni zapis predstavlja diskretnu aproksimaciju polaznog signala. Vano

pitanje je koliko esto je potrebno vriti merenje da bi se polazni kontinualni signal mogao verno rekonstruisati.

Odgovor daje tvrenje o odabiranju

(tzv. Najkvist-enonova teorema), koje kae da je signal dovoljno meriti dva


puta ee od najvie frekvencije koja sa u njemu javlja.

Na primer, poto

ovekovo uho uje frekvencije do 20KHz, dovoljno je da frekvencija odabiranja


(sempliranja) bude 40KHz.

Dok je za analogne tehnologije za postizanje vi-

sokog kvaliteta zapisa potrebno imati medijume visokog kvaliteta, kvalitet reprodukcije digitalnog zapisa ne zavisi od toga kakav je kvalitet medija na kome
su podaci zapisani, sve dok je medijum dovoljnog kvaliteta da se zapisani brojevi mogu razaznati.

Dodatno, kvarljivost koja je inherentna za sve medije

postaje nebitna. Na primer, papir vremenom uti to uzrokuje pad kvaliteta


analognih fotografija tokom vremena. Meutim, ukoliko bi papir sadrao za-

2. Reprezentacija podataka u raunarima

(2
01
5)

40

je

Slika 2.1: Digitalizacija zvunog signala

an

pis brojeva koji predstavljaju vrednosti boja u takama digitalno zapisane fotografije, injenica da papir uti ne bi predstavljala problem dok god se brojevi
mogu razaznati.

Digitalni zapis omoguava kreiranje apsolutno identinih kopija to dalje

iz

omoguava prenos podataka na daljinu. Na primer, ukoliko izvrimo fotokopiranje fotografije, napravljena fotokopija je daleko loijeg kvaliteta od originala.
Meutim, ukoliko umnoimo CD na kojem su zapisani brojevi koji ine za-

sk
o

pis neke fotografije, kvalitet slike ostaje apsolutno isti. Ukoliko bi se dva CD-a
pregledala pod mikroskopom, oni bi izgledali delimino razliito, ali to ne predstavlja problem sve dok se brojevi koji su na njima zapisani mogu razaznati.

ro
n

Obrada digitalno zapisanih podataka se svodi na matematiku manipulaciju


brojevima i ne zahteva (za razliku od analognih podataka) korienje specijalizovanih maina.

Osnovni problem implementacije digitalnog zapisa predstavlja injenica da

kt

je neophodno imati veoma razvijenu tehnologiju da bi se uopte stiglo do iole


upotrebljivog zapisa.

Na primer, izuzetno je komplikovano napraviti ureaj

le

koji je u stanju da 40 hiljada puta izvri merenje intenziteta zvuka.

Jedna

sekunda zvuka se predstavlja sa 40 hiljada brojeva, za iji je zapis neophodna

gotovo cela jedna sveska.


istorijski javio kasno.

Ovo je osnovni razlog zbog ega se digitalni zapis

Kada se dolo do tehnolokog nivoa koji omoguava

digitalni zapis, on je doneo mnoge prednosti u odnosu na analogni.

2.2 Zapis brojeva


Proces digitalizacije je proces reprezentovanja (raznovrsnih) podataka brojevima.

Kako se svi podaci u raunarima reprezentuju na taj nain bro-

jevima, neophodno je precizno definisati zapisivanje razliitih vrsta brojeva.


Osnovu digitalnih raunara, u skladu sa njihovom tehnolokom osnovom, predstavlja binarni brojevni sistem (sistem sa osnovom 2) . U raunarstvu se koriste

41

2. Reprezentacija podataka u raunarima

i heksadekadni brojevni sistem (sistem sa osnovom 16) a i, neto ree, oktalni


brojevni sistem (sistem sa osnovom 8), zbog toga to ovi sistemi omoguavaju
jednostavnu konverziju izmeu njih i binarnog sistema. Svi ovi brojevni sistemi,
kao i drugi o kojima e biti rei u nastavku teksta, su pozicioni. U pozicionom
brojnom sistemu, udeo cifre u celokupnoj vrednosti zapisanog broja zavisi od
njene pozicije.
Treba naglasiti da je zapis broja samo konvencija a da su brojevi koji se

(2
01
5)

zapisuju apsolutni i ne zavise od konkretnog zapisa. Tako, na primer, zbir dva

prirodna broja je uvek jedan isti prirodni broj, bez obzira na to u kom sistemu
su ova tri broja zapisana.

S obzirom na to da je svaki zapis broja u raunaru ogranien, ne mogu biti


zapisani svi celi brojevi. Ipak, za cele brojeve zapisive u raunaru se obino gov-

ori samo celi brojevi, dok su ispravnija imena oznaeni celi brojevi (engl. signed

integers) i neoznaeni celi brojevi (engl. unsigned integers), koji podrazumevaju


zapisom) ne mogu biti zapisani u raunaru.

je

konaan zapis. Ni svi realni brojevi (sa potencijalno beskonanim decimalnim


Za zapis zapisivih realnih bro-

an

jeva (koji su uvek racionalni) obino se koristi konvencija zapisa u pokretnom


zarezu. Iako je jedino precizno ime za ove brojeve brojevi u pokretnom zarezu
(engl. floating point numbers), esto se koriste i imena realni ili racionalni bro-

jevi. Zbog ogranienog zapisa brojeva, rezultati matematikih operacija nad

iz

njima sprovedenih u raunaru, nee uvek odgovarati rezultatima koji bi se dobili bez tih ogranienja (zbog takozvanih prekoraenja ).

Naglasimo jo i da,

za razliku od matematike gde se skup celih brojeva smatra podskupom skupa

sk
o

realnih brojeva, u raunarstvu, zbog razliitog naina zapisa, izmeu zapisa

2.2.1

ro
n

ovih vrsta brojeva ne postoji direktna veza.

Neoznaeni brojevi

Pod neoznaenim brojevima podrazumeva se neoznaeni zapis nenegativnih

kt

celih brojeva i znak se izostavlja iz zapisa.

Odreivanje broja na osnovu datog zapisa.

le

pozicioni brojevni sistem sa osnovom

gde je

Pretpostavimo da je dat

prirodan broj vei od 1. Niz

( 1 . . . 1 0 ) predstavlja zapis1 broja u osnovi , pri emu za svaku


cifru vai 0 < .
Vrednost broja zapisanog u osnovi definie se na sledei nain:

cifara

( 1 . . . 1 0 ) =

= + 1 1 + . . . 1 + 0

=0
Na primer:

(101101)2 = 1 25 + 0 24 + 1 23 + 1 22 + 0 2 + 1 = 32 + 8 + 4 + 1 = 45,
(3245)8 = 383 +282 +48+5 = 3512+264+48+5 = 1536+128+32+5 =
1701.
1 Ako

u zapisu broja nije navedena osnova, podrazumeva se da je osnova

10.

42

2. Reprezentacija podataka u raunarima

Navedena definicija daje i postupak za odreivanje vrednosti datog zapisa:

:= 0
za svako od 0 do
:= +

(2
01
5)

ili, malo modifikovano:

:= 0
za svako od 1 do
:= +

+ 1)-tocifrenog zapisa drugim nave(+1)


denim postupkom potrebno je sabiranja i + ( 1) + . . . + 1 =
2

mnoenja. Zaista, da bi se izraunalo potrebno je mnoenja, da bi se


1
izraunalo 1
potrebno je 1 mnoenja, itd. Meutim, ovo izrauna
vanje moe da se izvri i efikasnije. Ukoliko se za izraunavanje lana iskoristi
1
ve izraunata vrednost
, broj mnoenja se moe svesti na 2. Ovaj nain

an

je

Za izraunavanje vrednosti nekog (

iz

izraunavanja primenjen je u sledeem postupku:

ro
n

sk
o

:= 0
:= 1
za svako od 1 do
:=
:= +

Jo efikasniji postupak izraunavanja se moe dobiti korienjem Hornerove

sheme:

kt

( 1 . . . 1 0 ) = (. . . (( + 1 ) + 2 ) . . . + 1 ) + 0

le

Korienjem ove sheme, dolazi se do sledeeg postupka za odreivanje vred-

nosti broja zapisanog u nekoj brojevnoj osnovi:

:= 0
za svako od unazad do 0
:= +
Naredni primer ilustruje primenu Hornerovog postupka na zapis

3
9
0 10 + 9 = 9

2
8
9 10 + 8 = 98

1
7
98 10 + 7 = 987

(9876)10 .

0
6
987 10 + 6 = 9876

43

2. Reprezentacija podataka u raunarima

Meurezultati dobijeni u ovom raunu direktno odgovaraju prefiksima zapisa ija se vrednost odreuje, a rezultat u poslednjoj koloni je traeni broj.
Navedeni postupak moe se primeniti na proizvoljnu brojevnu osnovu. Sledei
primer ilustruje primenu postupka na zapis

3
3
08+3=3

2
2
3 8 + 2 = 26

1
4
26 8 + 4 = 212

0
5
212 8 + 5 = 1701

(2
01
5)

(3245)8 .

Navedena tabela moe se krae zapisati na sledei nain:

3
3

2
26

4
212

5
1701

je

Hornerov postupak je efikasniji u odnosu na poetni postupak, jer je u


sabiranja i

+1

mnoenja).

+1

an

svakom koraku dovoljno izvriti samo jedno mnoenje i jedno sabiranje (ukupno

Odreivanje zapisa datog broja.

u
osnovom ,
ostatak je 0 a celobrojni kolinik je broj iji je zapis ( 1 . . . 1 ) . Dakle,
izraunavanjem celobrojnog kolinika i ostatka pri deljenju sa , odreena je
poslednja cifra broja i broj koji se dobija uklanjanjem poslednje cifre iz zapisa.
vai da je

0 < .

Za svaku cifru

u zapisu broja

iz

Dodatno, pri deljenju broja

sk
o

osnovi

Ukoliko se isti postupak primeni na dobijeni kolinik, dobija se postupak koji

ro
n

omoguava da se odrede sve cifre u zapisu broja

Postupak se zaustavlja kada

tekui kolinik postane 0. Ako se izraunavanje ostatka pri deljenju oznai sa

mod,

a celobrojnog kolinika sa

div,

postupak kojim se odreuje zapis broja

se moe formulisati na sledei nain:

kt

u datoj osnovi

le

:= 0
dok je razliito od 0
:= mod
:= div
:= + 1
Na primer, 1701 = (3245)8 jer je 1701 = 212 8 + 5 = (26 8 + 4) 8 + 5 =
((3 8 + 2) 8 + 4) 8 + 5 = (((0 8 + 3) 8 + 2) 8 + 4) 8 + 5. Ovaj postupak se

moe prikazati i tabelom:

1701
1701

1
1701 div 8 = 212
1701 mod 8 = 5

2
212 div 8 = 26
212 mod 8 = 4

3
26 div 8 = 3
26 mod 8 = 2

3 div 8 = 0
3 mod 8 = 3

44

2. Reprezentacija podataka u raunarima

Prethodna tabela moe se krae zapisati na sledei nain:

1701
5

212
4

26
2

3
3

Druga vrsta tabele sadri celobrojne kolinike, a trea ostatke pri deljenju
sa osnovom

tj. traene cifre. Zapis broja se formira tako to se dobijene cifre

(2
01
5)

itaju unatrag.

Ovaj algoritam i Hornerov algoritam su meusobno simetrini u smislu da


se svi meurezultati poklapaju.

Direktno prevoenje izmeu heksadekadnog i binarnog sistema.


Osnovni razlog korienja heksadekadnog sistema

je mogunost jednostavnog

prevoenja brojeva izmeu binarnog i heksadekadnog sistema. Pri tome, hek-

je

sadekadni sistem omoguava da se binarni sadraj memorije zapie kompaktnije (uz korienje manjeg broja cifara). Prevoenje se moe izvriti tako to

an

se grupiu etiri po etiri binarne cifre, krenuvi unazad, i svaka etvorka se


zasebno prevede u odgovarajuu heksadekadnu cifru na osnovu sledee tabele:
binarno

heksa

binarno

0000

0100

heksa

binarno

heksa

binarno

1000

0001

1100

0101

1001

0010

1101

0110

1010

0011

1110

0111

1011

1111

sk
o

iz

heksa

Na primer, proizvoljni 32-bitni sadraj moe se zapisati korienjem osam

ro
n

heksadekadnih cifara:

(1011 0110 0111 1100 0010 1001 1111 0001)2 = (6729 1)16

Zapisi fiksirane duine

U raunarima se obino koristi fiksirani broj bina-

kt

rnih cifara (sauvanih u pojedinanim bitovima) za zapis svakog broja. Takve


zapise oznaavamo sa

(. . .) ,

ako se koristi

cifara.

Ukoliko je broj cifara

le

potrebnih za zapis broja krai od zadate duine zapisa, onda se broj proiruje
vodeim nulama. Na primer,

55 = (0011 0111)82 .

Ograniavanjem broja cifara

ograniava se i raspon brojeva koje je mogue zapisati (u binarnom sistemu)


i to na raspon od

do

2 1.

U sledeoj tabeli su dati rasponi za najee

koriene duine zapisa:


broj bitova

raspon

od 0 do 255

16

od 0 do 65535

32

od 0 do 4294967295

45

2. Reprezentacija podataka u raunarima

2.2.2

Oznaeni brojevi

Oznaeni brojevi su celi brojevi iji zapis ukljuuje i zapis znaka broja

).

(+ ili

S obzirom na to da savremeni raunari koriste binarni brojevni

sistem, bie razmatrani samo zapisi oznaenih brojeva u binarnom brojevnom


sistemu. Postoji vie naina zapisivanja oznaenih brojeva od kojih su najee

Oznaena apsolutna vrednost.

Zapis broja se formira tako to se na prvu

poziciju zapisa unapred fiksirane duine

(2
01
5)

u upotrebi oznaena apsolutna vrednost i potpuni komplement.

upie znak broja, a na preostalih

pozicija upie zapis apsolutne vrednosti broja. Poto se za zapis koriste

samo dva simbola (0 i


a znak

simbolom

1.

1),

konvencija je da se znak

zapisuje simbolom

0,

Ovim se postie da pozitivni brojevi imaju identian

+100 = (0 1100100)82 ,
8
100 = (1 1100100)2 .
Osnovni problem zapisa u obliku oznaene apsolutne vrednosti je injenica

je

zapis kao da su u pitanju neoznaeni brojevi. Na primer,

an

da se osnovne aritmetike operacije teko izvode ukoliko su brojevi zapisani na


ovaj nain.

Potpuni komplement.

Zapis u potpunom komplementu (engl. twos com-

iz

plement) oznaenih brojeva zadovoljava sledee uslove:


1. Nula i pozitivni brojevi se zapisuju na isti nain kao da su u pitanju

sk
o

neoznaeni brojevi, pri emu u njihovom zapisu prva cifra mora da bude

0.

2. Sabiranje se sprovodi na isti nain kao da su u pitanju neoznaeni brojevi,

ro
n

pri emu se prenos sa poslednje pozicije zanemaruje.

+100 se u potpunom komplementu zapisuje kao (0 1100100)82 .


8
8
Nula se zapisuje kao (0 0000000)2 . Zapis broja 100 u obliku (. . .)2 se moe
odrediti na sledei nain. Zbir brojeva 100 i +100 mora da bude 0.

kt

Na primer, broj

le

binarno

1


dekadno

????????

-100

01100100

+100

00000000

Analizom traenog sabiranja cifru po cifru, poevi od poslednje, sledi

da se

100

mora zapisati kao

(10011100)82 .

Do ovoga je mogue doi i na

, zapis njemu suprotnog broja


+1
je mogue odrediti iz uslova da je + () = (1 00 . . . 00)2
. Poto je
+1

(1 00 . . . 00)2 = (11 . . . 11)2 + 1, zapis broja () je mogue odrediti tako to

se izrauna (11 . . . 11)2 +1. Izraunavanje razlike (11 . . . 11)2 se svodi na


komplementiranje svake pojedinane cifre broja . Tako se odreivanje zapisa
broja 100 moe opisati na sledei nain:
sledei nain.

Ukoliko je poznat zapis broja

46

2. Reprezentacija podataka u raunarima

01100100

+100

10011011

komplementiranje

1
10011100

Kao to je traeno, zapisi svih pozitivnih brojeva i nule poinju cifrom


dok zapisi negativnih brojeva poinju sa

21

je jedini izuzetak u optem postupku odreivanja zapisa u pot-

punom komplementu. Zapis broja


poto poinje cifrom

1,

(100 . . . 00)2

je sam sebi komplementaran, a

(2
01
5)

Broj

1.

uzima se da on predstavlja zapis najmanjeg zapisivog

21 . Zahvaljujui ovoj konvenciji, u zapisu pot


1
1
punog komplementa (. . .)2 mogue je zapisati brojeve od 2
do 2
1. U
sledeoj tabeli su dati rasponi za najee koriene duine zapise u potpunom

negativnog broja, tj. broja

komplementu:
raspon

128
od 32768
2147483648
od

16
32

od

do
do
do

+127
+32767
+2147483647

je

an

broj bita

Kao to je reeno, za sabiranje brojeva zapisanih u potpunom komplementu


moe se koristiti opti postupak za sabiranje neoznaenih brojeva (pri emu se

podrazumeva da moe doi do prekoraenja, tj. da neke cifre rezultata ne mogu

iz

biti upisane u raspoloiv broj mesta). To ne vai samo za sabiranje, ve i za


oduzimanje i mnoenje. Ovo pogodno svojstvo vai i kada je jedan od argumenata broj

21

(koji se je jedini izuzetak u optem postupku odreivanja

sk
o

zapisa). Sve ovo su vani razlozi za korienje potpunog komplementa u raunarima.

Zapis realnih brojeva

ro
n

2.2.3

Pored celobrojnih dostupni u programskim jezicima su po pravilu podrani


i realni brojevni tipovi. Realne brojeve je u raunaru mnogo komplikovanije

kt

predstaviti nego cele brojeve.

Obino je mogue predstaviti samo odreeni

podskup skupa realnih brojeva i to podskup skupa racionalnih brojeva. Interni

le

zapis celog broja i njemu odgovarajueg realnog se ne poklapaju (nule i jedinice


kojima se oni zapisuju nisu iste), ak i kada se isti broj bitova koristi za njihov

zapis.

Fiksiranjem bitova koji e se odvojiti za zapis nekog realnog broja,

odreuje se i broj moguih razliitih brojeva koji se mogu zapisati.

Svakoj

kombinaciji nula i jedinica pridruuje se neki realan broj. Kod celih brojeva
odluivano je da li e se takvim kombinacijama pridruivati samo pozitivni ili
i pozitivni i negativni brojevi i kada je to odlueno, u principu je jasno koji
skup celih brojeva moe biti zapisan (taj skup vrednosti je uvek neki povezan
raspon celih brojeva).

U zapisu realnih brojeva stvari su komplikovanije jer

je potrebno napraviti kompromis izmeu irine raspona brojeva koji se mogu


zapisati (slino kao i kod celih brojeva), ali i izmeu preciznosti brojeva koji
se mogu zapisati. Dakle, kao i celobrojni tipovi, realni tipovi imaju odreen
raspon vrednosti koji se njima moe predstaviti, ali i odreenu preciznost zapisa

47

2. Reprezentacija podataka u raunarima

(nju obino doivljavamo kao broj decimala, mada to tumaenje, kao to emo
uskoro videti, nije uvek u potpunosti tano).
Osnovni naini zapisivanja realnih brojeva su zapis u fiksnom zarezu i zapis
u pokretnom zarezu . Zapis u fiksnom zarezu podrazumeva da se posebno zapisuje znak broja, zatim ceo deo broja i zatim njegov razlomljeni deo (njegove
decimale). Broj cifara za zapis celog dela i za zapis realnog dela je fiksiran i
jednak je za sve brojeve u okviru istog tipa koji koristi zapis u fiksnom zarezu.

Vrednost

je osnova

(2
01
5)

Zapis u pokretnom zarezu podrazumeva oblik

koja se podrazumeva (danas je to obino 2, mada se nekada koristila i vrednost

16, dok se u svakodnevnoj matematikoj praksi esto brojevi izraavaju na


ovaj nain uz korienje osnove 10),

se naziva mantisa, a vrednost

naziva

se eksponent. Broj cifara (obino binarnih) za zapis mantise i broj cifara za

zapis eksponenta je fiksiran i jednak je za sve brojeve u okviru istog tipa koji
koristi zapis u pokretnom zarezu. Zapisivanje brojeva u pokretnom zarezu pro-

je

pisano je standardom IEEE 754 iz 1985. godine, meunarodne asocijacije In-

stitut inenjera elektrotehnike i elektronike, IEEE (engl. Institute of Electrical


Ovaj standard predvia da se odreene kombi-

an

and Electronics Engineers).

nacije bitova odvoje za zapis tzv. specijalnih vrednosti (beskonanih vrednosti,


greaka u izraunavanju i slino).

Ilustrujmo osnovne principe zapisa realnih brojeva na dekadnom zapisu

iz

nenegativnih realnih brojeva (kao to smo rekli, u raunaru se ovakav zapis interno ne koristi, ve se koristi binarni zapis). Zamislimo da imamo tri dekadne
cifre koje moemo iskoristiti za zapis. Dakle, imamo 1000 brojeva koji se mogu

sk
o

zapisati. Prva mogunost je da se odreeni broj cifara upotrebi za zapis celog


dela, a odreeni broj cifara za zapis decimala i takav nain zapisa predstavlja
zapis u fiksnom zarezu.

Na primer, ako se jedna cifra upotrebi za decimale

ro
n

moi emo zapisivati vrednosti

00,0, 00,1,

...,

99,8

99,9.

male odvoje dva mesta, onda moemo zapisivati vrednosti


i

9,99.

Ako se se za deci-

0,00, 0,01,

...,

9,98

Ovim smo dobili bolju preciznost (svaki broj je zapisan sa dve, umesto

sa jednom decimalom), ali smo to platili mnogo uim rasponom brojeva koje

kt

moemo zapisati (umesto irine oko 100, dobili smo raspono irine oko 10). U
raunaru se fiksni zarez esto ostvaruje binarno (odreeni broj bitova kodira

le

ceo, a odreeni broj bitova kodira razlomljeni deo), pri emu se uvek jedan bit
ostavlja za predstavljanje znaka broja ime se omoguava zapis i pozitivnih i

negativnih vrednosti.
Umesto fiksnog zareza, u raunarima se mnogo ee koristi pokretni zarez.

U takvom zapisu, nae tri dekadne cifre podeliemo tako da dve odlaze za zapis
mantise, a jednu za zapis eksponenta (pa e zapis biti oblika
prve dve cifre
u zapisu

1 i 2 ,

tumaiemo da je mantisa

0, 1 2 .

1 2 3 ).

Ako su

Ako je trea cifra

3 , tumaiemo da eksponent = 3 4 (ovim postiemo da vrednosti


4 i 5 tj. da mogu da budu i pozitivne i

eksponenta mogu da budu izmeu

negativne). Pogledajmo neke zapise koje na taj nain dobijamo.

48

2. Reprezentacija podataka u raunarima

zapis

vrednost

010
020
980
990

0,01 104
0,02 104
0,98 104
0,99 104

= 0,000001
= 0,000002
= 0,000098
= 0,000099

zapis

vrednost

011
021
981
991

0,01 103
0,02 103
0,98 103
0,99 103

Raspon je prilino irok (od

10

= 0,00001
= 0,00002
= 0,00098
= 0,00099

...

zapis

vrednost

...

018
028
988
998

0,01 104
0,02 104
0,98 104
0,99 104

do

99 000, 0

...
...
...

0, 000001

= 100,0
= 200, 0
= 9800,0
= 9900,0

zapis

vrednost

019
029
989
999

0,01 105
0,02 105
0,98 105
0,99 105

tj. od oko

= 1 000,0
= 2 000,0
= 98 000,0
= 99 000,0

106

do oko

) i mnogo iri nego to je to bilo kod fiksnog zareza, ali gustina zapisa je

neravnomerno rasporeena, to nije bio sluaj kod fiksnog zareza. Kod malih

(2
01
5)

brojeva preciznost zapisa je mnogo vea nego kod velikih. Na primer, kod malih
brojeva moemo zapisivati veliki broj decimala, ali nijedan broj izmeu
i

99 000

98 000

nije mogue zapisati (brojevi iz tog raspona bi se morali zaokruiti na

neki od ova dva broja). Ovo nije preveliki problem, jer nam obino kod velikih

brojeva preciznost nije toliko bitna koliko kod malih (matematiki gledano,
relativna greka koja nastaje usled zaokruivanja se ne menja puno kroz ceo
raspon).

Dve vane komponente koje karakteriu svaki zapis u pokretnom

oko

106

do oko

je

zarezu su raspon brojeva koji se mogu zapisati (u naem primeru to je bilo od

105 ) i on je skoro potpuno odreen irinom eksponentna, kao i

an

broj dekadnih znaajnih cifara (u naem primer, imamo dve dekadne znaajne
cifre) i on je skoro potpuno odreeno irinom mantise.

iz

2.3 Zapis teksta

Meunarodna organizacija za standardizaciju, ISO (engl. International Stan-

sk
o

dard Organization) definie tekst (ili dokument) kao informaciju namenjenu


ljudskom sporazumevanju koja moe biti prikazana u dvodimenzionalnom obliku. Tekst se sastoji od grafikih elemenata kao to su karakteri, geometrijski ili
fotografski elementi ili njihove kombinacije, koji ine sadraj dokumenta. Iako

ro
n

se tekst obino zamilja kao dvodimenzioni objekat, u raunarima se tekst predstavlja kao jednodimenzioni (linearni) niz karaktera koji pripadaju odreenom
unapred fiksiranom skupu karaktera.

U zapisu teksta, koriste se specijalni

kt

karakteri koji oznaavaju prelazak u novi red, tabulator, kraj teksta i slino.
Osnovna ideja koja omoguava zapis teksta u raunarima je da se svakom
karakteru pridrui odreen (neoznaeni) ceo broj (a koji se interno u rau-

le

narima zapisuje binarno) i to na unapred dogovoreni nain.

Ovi brojevi se

Tehnika ogranienja

nazivaju kdovima karaktera (engl. character codes).

ranih raunara kao i neravnomeran razvoj raunarstva izmeu razliitih zemalja, doveli su do toga da postoji vie razliitih standardnih tabela koje dodeljuju numerike kdove karakterima. U zavisnosti od broja bitova potrebnih
za kodiranje karaktera, razlikuju se 7-bitni kdovi, 8-bitni kdovi, 16-bitni kdovi, 32-bitni kdovi, kao i kodiranja promenljive duine koja razliitim karakterima dodeljuju kdove razliite duine. Tabele koje sadre karaktere i njima
pridruene kdove obino se nazivaju kdne strane (engl. code page).
Postoji veoma jasna razlika izmeu karaktera i njihove grafike reprezentacije.
Elementi pisanog teksta koji najee predstavljaju grafike reprezentacije pojedinih karaktera nazivaju se glifovi (engl. glyph), a skupovi glifova nazivaju
se fontovi (engl. font).

Korespondencija izmeu karaktera i glifova ne mora

49

2. Reprezentacija podataka u raunarima

biti jednoznana. Naime, softver koji prikazuje tekst moe vie karaktera predstaviti jednim glifom (to su takozvane ligature, kao na primer glif za karaktere
f i i:

fi), dok jedan isti karakter moe biti predstavljen razliitim glifovima

u zavisnosti od svoje pozicije u rei. Takoe, mogue je da odreeni fontovi ne


sadre glifove za odreene karaktere i u tom sluaju se tekst ne prikazuje na eljeni nain, bez obzira to je ispravno kodiran. Fontovi koji se obino instaliraju
uz operativni sistem sadre glifove za karaktere koji su popisani na takozvanoj

(2
01
5)

WGL4 listi (Windows Glyph List 4 ) koja sadri uglavnom karaktere koriene

u evropskim jezicima, dok je za ispravan prikaz, na primer, kineskih karaktera,


potrebno instalirati dodatne fontove. Specijalnim karakterima se najee ne
pridruuju zasebni grafiki likovi.

Englesko govorno podruje.

Tokom razvoja raunarstva, broj karaktera

koje je bilo poeljno kodirati je postajao sve vei. Poto je raunarstvo u ranim

an

je potrebno predstaviti sledee karaktere:

je

fazama bilo razvijano uglavnom u zemljama engleskog govornog podruja, bilo

a, b, ... , z

Mala slova engleskog alfabeta:

Velika slova engleskog alfabeta:

Cifre

Interpunkcijske znake:

Specijalne znake: kraj reda, tabulator, . . .

A, B, ... , Z

iz

0, 1, ..., 9

...

sk
o

, . : ; + * - _ ( ) [ ] { }

Standardne tabele kdova ovih karaktera su se pojavile jo tokom 1960-ih


godina. Najrasprostranjenije od njih su:

EBCDIC - IBM-ov standard, korien uglavnom na mainframe rau-

ro
n

narima, pogodan za buene kartice.

ASCII - standard iz koga se razvila veina danas korienih standarda za

kt

zapis karaktera.

le

ASCII.

ASCII (American Standard Code for Information Interchange) je

standard uspostavljen 1968. godine od strane Amerikog nacionalnog instituta

za standarde, (engl. American National Standard Institute) koji definie sed-

mobitan zapis kda svakog karaktera to daje mogunost zapisivanja ukupno


128 razliitih karaktera, pri emu nekoliko kdova ima dozvoljeno slobodno korienje. ISO takoe delimino definie ASCII tablicu kao deo svog standarda

ISO 646 (US).


Osnovne osobine ASCII standarda su:

Prva 32 karaktera od

Ukupno 95 karaktera ima pridruene grafike likove (engl. printable characters).

(00)16 do (1 )16 su specijalni kontrolni karakteri.

50

2. Reprezentacija podataka u raunarima

NUL

STX

SOT

ETX

EOT

ENQ

ACK

BEL

BS

HT

LF

VT

FF

CR

SO

SI

DLE

DC1

DC2

DC3

DC4

NAK

SYN

ETB

CAN

EM

SUB

ESC

FS

GS

RS

US

"

&

'

2
0

<

>

DEL

Slika 2.2: ASCII tablica

Cifre 0-9 predstavljene su kdovima

(30)16

do

(2
01
5)

(39)16 , tako da se njihov


011 na njihov bina-

ASCII zapis jednostavno dobija dodavanjem prefiksa

je

rni zapis.

Kdovi velikih i malih slova se razlikuju u samo jednom bitu u binarnoj

se kodira brojem (41)16 odnosno (100 0001)2 ,


(61)16 odnosno (110 0001)2 . Ovo omoguava da

kodira brojem

an

reprezentaciji. Na primer,
dok se

Slova su poreana u kolacionu sekvencu, u skladu sa engleskim alfabetom.

iz

se konverzija veliine slova u oba smera moe vriti efikasno.

Razliiti operativni sistemi predviaju razliito kodiranje oznake za prelazak


Tako operativni sistem Windows podrazumeva da se prelazak u

sk
o

u novi red.

novi red kodira sa dva kontrolna karaktera i to


stavljen kdom

(0)16 i

(carriage return) pred-

(line feed) predstavljen kodom

(0)16 ,

operativni

ro
n

sistem Unix i njegovi derivati (pre svega Linux) podrazumevaju da se koristi


samo karakter

dok MacOS podrazumeva korienje samo karaktera

Nacionalne varijante ASCII tablice i ISO 646.

Tokom 1980-ih, Ju-

kt

goslovenski zavod za standarde definisao je standard YU-ASCII (YUSCII, JUS


I.B1.002, JUS I.B1.003) kao deo standarda ISO 646, tako to su kdovi koji

le

imaju slobodno korienje (a koji u ASCII tabeli uobiajeno kodiraju zagrade

i odreene interpunkcijske znakove) dodeljeni naim dijakriticima:


YUSCII

ASCII

kd

YUSCII

ASCII

kd

@
[
\
]
^

(40)16
(5)16
(5)16
(5)16
(5)16

{
|
}
~

(60)16
(7)16
(7)16
(7)16
(7)16

Osnovne mane YUSCII kodiranja su to to ne potuje abecedni poredak,


kao i to da su neke zagrade i vani interpunkcijski znaci izostavljeni.

8-bitna proirenja ASCII tabele.

Podaci se u raunaru obino zapisuju

bajt po bajt. S obzirom na to da je ASCII sedmobitni standard, ASCII karak-

51

2. Reprezentacija podataka u raunarima

teri se zapisuju tako to se njihov sedmobitni kd proiri vodeom nulom. Ovo


znai da jednobajtni zapisi u kojima je vodea cifra
do

( )16

nisu iskorieni.

1,

tj. raspon od

(80)16

Meutim, ni ovih dodatnih 128 kdova nije do-

voljno da se kodiraju svi karakteri koji su potrebni za zapis tekstova na svim


jezicima (ne samo na engleskom). Zbog toga je, umesto jedinstvene tabele koja
bi proirivala ASCII na 256 karaktera, standardizovano nekoliko takvih tabela,
pri emu svaka od tabela sadri karaktere potrebne za zapis odreenog jezika
Praktian problem je to postoji dvostruka

(2
01
5)

odnosno odreene grupe jezika.

standardizacija ovako kreiranih kdnih strana i to od strane ISO (International

Standard Organization) i od strane znaajnih korporacija, pre svega kompanije

Microsoft.

ISO je definisao familiju 8-bitnih kdnih strana koje nose zajedniku oznaku

ISO/IEC 8859 (kdovi od

(00)16

do

(1 )16 , (7 )16

i od

(80)16

do

(9 )16

ostali

su nedefinisani ovim standardom, iako se esto u praksi popunjavaju odreenim

je

kontrolnim karakterima):
Latin 1

veina zapadno-evropskih jezika

ISO-8859-2

Latin 2

centralno i istono-evropski jezici

ISO-8859-3

Latin 3

juno-evropski jezici

ISO-8859-4

Latin 4

severno-evropski jezici

ISO-8859-5

Latin/Cyrillic

irilica veine slovenskih jezika

ISO-8859-6

Latin/Arabic

ISO-8859-7

Latin/Greek

ISO-8859-8

Latin/Hebrew

an

ISO-8859-1

iz

najee korieni arapski

moderni grki alfabet


moderni hebrejski alfabet

sk
o

Kompanija Microsoft definisala je familju 8-bitnih strana koje se oznaavaju


kao Windows-125x (ove strane se nekada nazivaju i ANSI ). Za srpski jezik,
znaajne su kdne strane:

centralno i istono-evropski jezici

ro
n

Windows-1250
Windows-1251

irilica veine slovenskih jezika

Windows-1252

(esto se neispravno naziva i ANSI) zapadno-

kt

evropski jezici

le

NBSP

SHY

Slika 2.3: ISO-8859-1 tablica

Unicode.

Iako navedene kdne strane omoguavaju kodiranje tekstova koji

nisu na engleskom jeziku, nije mogue, na primer, u istom tekstu koristiti i

52

2. Reprezentacija podataka u raunarima

NBSP

SHY

Slika 2.4: ISO-8859-2 tablica

(2
01
5)

iz

an

je

NBSP

sk
o

Slika 2.5: Windows-1250 tablica

SHY

le

kt

ro
n

irilicu i latinicu.
svih karaktera.

Slika 2.6: ISO-8859-5 tablica

Takoe, za azijske jezike nije dovoljno 256 mesta za zapis

Poto je kapacitet raunara vremenom rastao, postepeno se

krenulo sa standardizacijom skupova karaktera koji karaktere kodiraju sa vie


od jednog bajta. Kasnih 1980-ih, dve velike organizacije zapoele su standardizaciju tzv. univerzalnog skupa karaktera (engl. Universal Character Set
UCS). To su bili ISO, kroz standard 10646 i projekat Unicode , organizovan i
finansiran uglavnom od strane amerikih kompanija koje su se bavile proizvodnjom viejezikog softvera (Xerox Parc, Apple, Sun Microsystems, Microsoft,
. . . ).
ISO 10646 zamiljen je kao etvorobajtni standard.

Prvih 65536 karak-

53

2. Reprezentacija podataka u raunarima

0
8

(2
01
5)

Slika 2.7: Windows-1251 tablica

tera koristi se kao osnovni viejezini skup karaktera, dok je preostali prostor
ostavljen kao proirenje za drevne jezike, naunu notaciju i slino.

je

Unicode je za cilj imao da bude:

Univerzalan (UNIversal) sadri sve savremene jezike sa pismom;

jedinstven (UNIque) bez dupliranja karaktera - kodiraju se pisma, a

an

uniforman (UNIform) svaki karakter sa istim brojem bitova.

iz

ne jezici;

Poetna verzija Unicode standarda svakom karakteru dodeljuje dvobajtni

sk
o

kd (tako da kd svakog karaktera sadri tano 4 heksadekadne cifre). Dakle,


mogue je dodeliti kdove za ukupno

216 = 65536

razliitih karaktera. S vre-

menom se shvatilo da dva bajta nee biti dovoljno za zapis svih karaktera

ro
n

koji se koriste na planeti, pa je odlueno da se skup karaktera proiri i Unicode danas dodeljuje kdove od

(000000)16 do (10 )16 podeljenih u 16


65536 karaktera. U najeoj upotrebi

tzv. ravni, pri emu svaka ravan sadri

je osnovna viejezina ravan (engl. basic multilingual plane) koja sadri veinu

kt

danas korienih karaktera (ukljuujui i CJK Chinese, Japanese, Korean


karaktere koji se najee koriste) iji su kdovi izmeu

(0000)16 i ( )16 .

le

Vremenom su se pomenuta dva projekta UCS i Unicode zdruila i danas

postoji izuzetno preklapanje izmeu ova dva standarda.

U sledeoj tabeli je naveden raspored odreenih grupa karaktera u osnovnoj

viejezikoj ravni:

54

2. Reprezentacija podataka u raunarima

0020-007E

ASCII printable

00A0-00FF

Latin-1

0100-017F

Latin extended A (osnovno proirenje latinice,

0180-027F

Latin extended B

sadri sve nae dijakritike)

grki alfabet

0400-04FF

irilica

(2
01
5)

...
0370-03FF
...
2000-2FFF

specijalni karakteri

3000-3FFF

CJK (Chinese-Japanese-Korean) simboli

...

Unicode standard u sutini predstavlja veliku tabelu koja svakom karakteru


dodeljuje broj. Standardi koji opisuju kako se niske karaktera prevode u nizove

ISO definie UCS-2 standard koji svaki Unicode karakter osnovne

an

UCS-2.

je

bajtova se definiu dodatno.

Latinini tekstovi kodirani korienjem UCS-2 standarda sadre ve-

liki broj nula.

Ne samo to te nule zauzimaju dosta prostora, ve zbog njih

iz

UTF-8.

viejezike ravni jednostavno zapisuje sa odgovarajua dva bajta.

softver koji je razvijen za rad sa dokumentima u ASCII formatu ne moe da

sk
o

radi bez izmena nad dokumentima kodiranim korienjem UCS-2 standarda.

Unicode Transformation Format (UTF-8) je algoritam koji svakom dvobajtnom Unicode karakteru dodeljuje odreeni niz bajtova ija duina varira od 1
do najvie 3. UTF je ASCII kompatibilan, to znai da se ASCII karakteri za-

ro
n

pisuju pomou jednog bajta, na standardni nain. Konverzija se vri na osnovu

kt

sledeih pravila:

raspon

binarno zapisan Unicode kd

binarno zapisan UTF-8 kd

00000000 0xxxxxxx

0xxxxxxx

00000yyy yyxxxxxx

110yyyyy 10xxxxxx

0800-FFFF

zzzzyyyy yyxxxxxx

1110zzzz 10yyyyyy 10xxxxxx

le

0000-007F

0080-07FF

Na primer, karakter A koji se nalazi u ASCII tabeli ima Unicode kd

(0041)16 = (0000 0000 0100 0001)2 ,

pa se na osnovu prvog reda prethodne

(01000001)2 = (41)16 . Karakter ima


(0160)16 = (0000 0001 0110 0000)2 . Na njega se primenjuje drugi
red prethodne tabele i dobija se da je njegov UTF-8 zapis (1100 0101 1010 0000)2
tj. (50)16 . Opisani konverzioni algoritam omoguava da se itanje samo
tabele u UTF-8 kodiranju zapisuje kao

Unicode kd

poetka jednog bajta odredi da li je u pitanju karakter zapisan korienjem


jednog, dva ili tri bajta.

55

2. Reprezentacija podataka u raunarima

2.4 Zapis multimedijalnih sadraja


Raunari imaju sve veu ulogu u veini oblasti svakodnevnog ivota. Od
maina koje su pre svega sluile za izvoenje vojnih i naunih izraunavanja,
raunari su postali i sredstvo za kunu zabavu (gledanje filmova, sluanje
muzike), izvor informacija (internet) i nezaobilazno sredstvo u komunikaciji
(elektronska pota (engl. e-mail), askanje (engl. chat, instant messaging), video
Nagli razvoj i

(2
01
5)

konferencije, telefoniranje korienjem interneta (VoIP), . . . ).

proirivanje osnovne namene raunara je posledica iroke raspoloivosti velike


koliine multimedijalnih informacija (slika, zvuka, filmova, . . . )

koje su za-

pisane u digitalnom formatu. Sve ovo je posledica tehnolokog napretka koji

je omoguio jednostavno i jeftino digitalizovanje signala, skladitenje velike


koliine digitalno zapisanih informacija, kao i njihov brz prenos i obradu.

Zapis slika

je

2.4.1

an

Slike se u raunaru zapisuju koristei vektorski zapis, rasterski zapis ili kom-

binovani zapis..

U vektorskom obliku, zapis slike sastoji se od konanog broja geometri-

jskih figura (taaka, linija, krivih, poligona), pri emu se svaka figura pred-

iz

stavlja koncizno svojim koordinatama ili jednainom u Dekartovoj ravni. Slike


koje raunari generiu esto koriste vektorsku grafiku. Vektorski zapisane slike
esto zauzimaju manje prostora, dozvoljavaju uveavanje (engl. zooming) bez

sk
o

gubitaka na kvalitetu prikaza i mogu se lake preureivati, s obzirom na to


da se objekti mogu nezavisno jedan od drugoga pomerati, menjati, dodavati i

le

kt

ro
n

uklanjati.

Slika 2.8: Primer slike u rasterskoj (levo) i vektorskoj (desno) grafici

U rasterskom zapisu, slika je predstavljena pravougaonom matricom komponenti koje se nazivaju pikseli (engl. pixel - PICture ELement). Svaki piksel je
individualan i opisan jednom bojom. Raster nastaje kao rezultat digitalizacije
slike. Rasterska grafika se jo naziva i bitmapirana grafika. Ureaji za prikaz
(monitori, projektori), kao i ureaji za digitalno snimanje slika (fotoaparati,
skeneri) koriste rasterski zapis.

56

2. Reprezentacija podataka u raunarima

Modeli boja.

Za predstavljanje crno-belih slika, dovoljno je boju predstaviti

intenzitetom svetlosti. Razliite koliine svetlosti se diskretizuju u konaan broj


nivoa osvetljenja ime se dobija odreeni broj nijansi sive boje. Ovakav model
boja se naziva grayscale.

Ukoliko se za zapis informacije o koliini svetlosti

koristi 1 bajt, ukupan broj nijansi sive boje je 256.

U sluaju da se slika

predstavlja sa ukupno dve boje (na primer, crna i bela, kao kod skeniranog
predstavlja jednim bitom.

(2
01
5)

teksta nekog dokumenta) koristi se model pod nazivom Duotone i boja se tada
U RGB modelu boja, kombinovanjem crvene (R), zelene (G) i plave (B)
komponente svetlosti reprezentuju se ostale boje. Tako se, na primer, kombi-

novanjem crvene i zelene boje reprezentuje uta boja. Bela boja se reprezentuje

maksimalnim vrednosti sve tri osnovne komponente, dok se crna boja reprezentuje minimalnim vrednostima osnovnih komponenti.

U ovom modelu, zapis

boje ini informacija o intenzitetu crvene, plave i zelene komponente.

RGB

je

model boja se koristi kod ureaja koji boje prikazuju kombinovanjem svetlosti
(monitori, projektori, . . . ). Ukoliko se za informaciju o svakoj komponenti komogue koristiti

224 = 16777216

an

risti po jedan bajt, ukupan broj bajtova za zapis informacije o boji je 3, te je


razliitih boja. Ovaj model se esto naziva i

TrueColor model boja.

Za razliku od aditivnog RGB modela boja, kod kojeg se bela boja dobija

iz

kombinovanjem svetlosti tri osnovne komponente, u tampi se koristi subtraktivni CMY (Cyan-Magenta-Yellow) model boje kod kojeg se boje dobijaju kombinovanjem obojenih pigmenata na belom papiru. Kako se potpuno crna teko

sk
o

dobija meanjem drugih pigmenata, a i kako je njena upotreba obino daleko


najea, obino se prilikom tampanja uz CMY pigmente koristi i crni pigment
ime se dobija model CMYK.

ro
n

Za obradu slika pogodni su HSL ili HSV (poznat i kao HSB) model boja.
U ovom modelu, svaka boja se reprezentuje Hue (H) komponentom (koja predstavlja ton boje), Saturation (S) komponentom (koja predstavlja zasienost
boje odnosno njenu jarkost) i Lightness (L), Value (V) ili Brightness (B)

kt

komponentom (koja predstavlja osvetljenost).

le

Formati zapisa rasterskih slika.

Rasterske slike su reprezentovane ma-

tricom piksela, pri emu se za svaki piksel uva informacija o njegovoj boji.
Dimenzije ove matrice predstavljaju tzv. apsolutnu rezoluciju slike. Apsolutna
rezolucija i model boja koji se koristi odreuju broj bajtova potrebnih za zapis slike. Na primer, ukoliko je apsolutna rezolucija slike 800x600 piksela, pri
emu se koristi RGB model boje sa 3 bajta po pikselu, potrebno je ukupno

800 600 3 = 1440000 1.373

za zapis slike. Da bi se smanjila koliina

informacija potrebnih za zapis slike, koriste se tehnike kompresije i to (i) kompresije bez gubitka (engl. lossless), i (ii) kompresije sa gubitkom (engl. lossy).
Najee korieni formati u kojima se koristi tehnike kompresije bez gubitka
danas su GIF i PNG (koji se koriste za zapis dijagrama i slinih raunarski
generisanih slika), dok je najee korieni format sa gubitkom JPEG (koji se
obino koristi za fotografije).

57

2. Reprezentacija podataka u raunarima

2.4.2

Zapis zvuka

Zvuni talas predstavlja oscilaciju pritiska koja se prenosi kroz vazduh ili
neki drugi medijum (tenost, vrsto telo). Digitalizacija zvuka se vri merenjem i zapisivanjem vazdunog pritiska u kratkim vremenskim intervalima. Osnovni parametri koji opisuju zvuni signal su njegova amplituda (koja odgovara
glasnoi) i frekvencija (koja odgovara visini). Poto ljudsko uho obino uje

(2
01
5)

raspon frekvencija od 20Hz do 20KHz, dovoljno je koristiti frekvenciju odabi-

ranja 40KHz, tj. dovoljno je izvriti odabiranje oko 40 000 puta u sekundi.
Na primer, AudioCD standard koji se koristi prilikom snimanja obinih audio

kompakt diskova, propisuje frekvenciju odabiranja 44.1KHz. Za postizanje jo


veeg kvaliteta, neki standardi (miniDV, DVD, digital TV) propisuju odabiranje na frekvenciji 48KHz.

Ukoliko se snima ili prenosi samo ljudski govor

(na primer, u mobilnoj telefoniji), frekvencije odabiranja mogu biti i znatno

manje. Drugi vaan parametar digitalizacije je broj bita kojim se zapisuje svaki
dobija mogunost zapisa

216 = 65536

je

pojedinani odbirak. Najee se koristi 2 bajta po odbirku (16 bita), ime se


razliitih nivoa amplitude.

snimanja zvuka.

an

Da bi se dobio prostorni oseaj zvuka, primenjuje se tehnika viekanalnog


U ovom sluaju, svaki kanal se nezavisno snima posebnim

mikrofonom i reprodukuje na posebnom zvuniku. Stereo zvuk podrazumeva


snimanje zvuka sa dva kanala. Surround sistemi podrazumevaju snimanje sa

iz

vie od dva kanala (od 3 pa ak i do 10), pri emu se esto jedan poseban kanal
izdvaja za specijalno snimanje niskofrekvencijskih komponenti zvuka (tzv. bas).

sk
o

Najpoznatiji takvi sistemi su 5+1 gde se koristi 5 regularnih i jedan bas kanal.
Kao i slika, nekomprimovan zvuk zauzima puno prostora. Na primer, jedan
minut stereo zvuka snimljenog u AudioCD formatu zauzima

60 2
= 10584000 10.1 .

2 44100

Zbog toga se koriste tehnike kom-

ro
n

presije, od kojeg je danas najkorienija tehnika kompresije sa gubitkom MP3


(MPEG-1 Audio-Layer 3). MP3 kompresija se zasniva na tzv. psiho-akustici
koja prouava koje je komponente mogue ukloniti iz zvunog signala, a da

kt

pritom ljudsko uho ne oseti gubitak kvaliteta signala.

le

Pitanja i zadaci

Pitanje 2.1.

Kako su u digitalnom raunaru zapisani svi podaci? Koliko se

cifara obino koristi za njihov zapis?

Pitanje 2.2.

Koje su osnovne prednosti digitalnog zapisa podataka u odnosu

na analogni? Koji su osnovni problemi u korienju digitalnog zapisa podataka?

Pitanje 2.3.

ta je Hornerova shema?

Opisati Hornerova shemu pseudo-

kdom.

Pitanje 2.4.

Koje su prednosti zapisa u potpunom komplementu u odnosu na

zapis u obliku oznaene apsolutne vrednosti?

Pitanje 2.5.

ta je to IEEE 754?

58

2. Reprezentacija podataka u raunarima

Pitanje 2.6.

ta je to glif, a ta font?

Da li je jednoznana veza izmeu

karaktera i glifova? Navesti primere.

Pitanje 2.7.

Koliko bitova koristi ASCII standard? ta ini prva 32 karaktera

ASCII tabele? Kako se odreuje binarni zapis karaktera koji predstavljaju cifre?

Pitanje 2.8.

Navesti barem dve jednobajtne kdne strane koje sadre iriline

Pitanje 2.9.

(2
01
5)

karaktere.
Nabrojati bar tri kdne sheme u kojima moe da se zapie re

raunarstvo.

Pitanje 2.10.

Koliko bitova koristi ASCII tabela karaktera, koliko YUSCII

tabela, koliko ISO-8859-1, a koliko osnovna UNICODE ravan? Koliko razliitih


karaktera ima u ovim tabelama?

Koja kodiranja teksta je mogue koristiti ukoliko se u okviru is-

je

Pitanje 2.11.

tog dokumenta eli zapisivanje teksta koji sadri jedan pasus na srpskom (pisan

an

latinicom), jedan pasus na nemakom i jedan pasus na ruskom (pisan irilicom)?

U emu je razlika izmeu Unicode i UTF-8 kodiranja?

Pitanje 2.13.

Prilikom prikazivanja filma, neki program prikazuje titlove tipa

"raunari e biti...".

iz

Pitanje 2.12.

Objasniti u emu je problem.

ta je to piksel? ta je to sempl?

Zadatak 2.1.

Prevesti naredne brojeve u dekadni brojevni sistem:

sk
o

Pitanje 2.14.

(b) (34)16
(c) (734)8
Zadatak uraditi klasinim postupkom, a zatim i korienjem Hornerove sheme.

(10111001)2

ro
n

(a)

Zapisati dekadni broj

254

u osnovama

2, 8

16.

kt

Zadatak 2.2.

Zadatak 2.3.

(a)

le

Registar ima sadraj

1010101101001000111101010101011001101011101010101110001010010011.

Zapisati ovaj broj u heksadekadnom sistemu.

(b) Registar ima sadraj

3 46189237.

narnom sistemu.

Zadatak 2.4.

Zapisati ovaj sadraj u bi-

Na Vebu se boje obino predstavljaju estocifrenim heksadekad-

nim kdovima u RGB sistemu: prve dve cifre odgovaraju koliini crvene boje,
naredne dve koliini zelene i poslednje dve koliini plave. Koja je koliina RGB
komponenti (na skali od 0-255) za boju

#35A7DC?

Kojim se kdom predstavlja

ista uta boja ako se zna da se dobija meanjem crvene i zelene? Kako izgledaju kdovi za nijanse sive boje?

59

2. Reprezentacija podataka u raunarima

Zadatak 2.5.

U registru se zapisuju neoznaeni brojevi. Koji raspon brojeva

moe da se zapie ukoliko je irina registra:


(a)

bita

(b)

Zadatak 2.6.

bita

(c)

16

bita

(d)

24

bita

32

(e)

Ukoliko se koristi binarni zapis neoznaenih brojeva irine

bita, zapisati brojeve:

12

(b)

Zadatak 2.7.

123

(c)

255

(d)

300

U registru se zapisuju brojevi u potpunom komplementu. Koji

raspon brojeva moe da se zapie ukoliko je irina registra:


(a)

bita

(b)

Zadatak 2.8.
mentu irine
(a)

12

(2
01
5)

(a)

bita

bita

(c)

16

bita

(d)

24

bita

32

(e)

bita

Odrediti zapis narednih brojeva u binarnom potpunom komple-

bita:

(b)

Zadatak 2.9.

123

(c)

18

(d)

(e)

128

(f )

200

je

Odrediti zapis brojeva -5 i 5 u potpunom komplementu duine

an

6 bita. Odrediti, takoe u potpunom komplementu duine 6 bita, zapis zbira i


proizvoda ova dva broja.

Zadatak 2.10.
(a)
(e)

Ukoliko se zna da je korien binarni potpuni komplement

bita, koji su brojevi zapisani?

11011010
01111111

(b)
(f )

01010011
00000000

(c)

10000000

iz

irine

(d)

11111111

ta predstavljaju dati zapisi ukoliko se zna da je korien zapis neoznaenih

tera.

Odrediti broj bitova neophodan za kodiranje 30 razliitih karak-

ro
n

Zadatak 2.11.

sk
o

brojeva?

Zadatak 2.12.
rani zapis rei

Znajui da je dekadni kd za karakter A 65, navesti kodi-

FAKULTET ASCII kdovima u heksadekadnom zapisu.

Dekodirati

45.

kt

sledeu re zapisanu u ASCII kdu heksadekadno: 44 49 53 4B 52 45 54 4E

le

Zadatak 2.13.

tekst:

Korienjem ASCII tablice odrediti kdove kojima se zapisuje

"Programiranje 1".

Kdove zapisati heksadekadno, oktalno, dekadno i

binarno. ta je sa kodiranjem teksta

Zadatak 2.14.

Za rei

Matematiki fakultet?

raunarstvo, informatika, navesti da li ih je mogue

kodirati narednim metodima i, ako jeste, koliko bajtova zauzimaju:


(a) ASCII

(b) Windows-1250

(c) ISO-8859-5

(d) ISO-8859-2

(e) Unicode (UCS-2)

(f ) UTF-8

Zadatak 2.15.
pisuje tekst

Odrediti (heksadekadno predstavljene) kdove kojima se za-

krui u UCS-2 i UTF-8 kodiranjima.

jem HEX editora.

Rezultat proveriti korien-

60

2. Reprezentacija podataka u raunarima

Zadatak 2.16.

HEX editori su programi koji omoguavaju direktno pregledanje,

kreiranje i auriranje bajtova koji sainjavaju sadraja datoteka. Korienjem


HEX editora pregledati sadraj nekoliko datoteka razliite vrste (tekstualnih,
izvrnih programa, slika, zvunih zapisa, video zapisa, . . . ).

Zadatak 2.17.

Uz pomo omiljenog editora teksta (ili nekog naprednijeg, uko-

liko editor nema traene mogunosti) kreirati datoteku koja sadri listu imena
tika). Datoteka treba da bude kodirana kodiranjem:
(a) Windows-1250

(b) ISO-8859-2

(2
01
5)

10 vaih najomiljenijih filmova (pisano latinicom uz ispravno korienje dijakri(c) Unicode (UCS-2)

(d) UTF-8

Otvoriti zatim datoteku iz nekog pregledaa Veba i prouiti ta se deava kada


se menja kodiranje koje pregleda koristi prilikom tumaenja datoteke (obino
meni

View->Character encoding).

Objasniti i unapred pokuati predvideti

ishod (uz pomo odgovarajuih tabela koje prikazuju kdne rasporede).

Za datu datoteku kodiranu UTF-8 kodiranjem, korienjem

je

Zadatak 2.18.

editora teksta ili nekog od specijalizovanih alata (na primer,

iconv)

rekodirati

Zadatak 2.19.

an

ovu datoteku u ISO-8859-2. Eksperimentisati i sa drugim kodiranjima.


Korienjem nekog naprednijeg grafikog programa (na primer,

GIMP ili Adobe Photoshop) videti kako se boja

le

kt

ro
n

sk
o

iz

HSB modelima.

#B58A34

predstavlja u CMY i

(2
01
5)

Glava 3

Neformalno govorei, algoritam

1 je precizan opis postupka za reavanje


Algoritmi postoje u svim ljud-

an

nekog problema u konanom broju koraka.


skim delatnostima.

je

Algoritmi i izraunljivost

U matematici, na primer, postoje algoritmi za sabiranje

i za mnoenje prirodnih brojeva. U raunarstvu, postoje algoritmi za odreivanje najmanjeg elementa niza, ureivanje elemenata po veliini i slino. Da bi

iz

moglo da se diskutuje o tome ta se moe a ta ne moe izraunati algoritamski,


potrebno je najpre precizno definisati pojam algoritma.

sk
o

3.1 Formalizacije pojma algoritma


Precizni postupci za reavanje matematikih problema postojali su u vreme

ro
n

starogrkih matematiara (na primer, Euklidov algoritam za odreivanje najveeg zajednikog delioca dva broja), pa i pre toga.

Ipak, sve do poetka

dvadesetog veka nije se uviala potreba za preciznim definisanjem pojma al-

kt

goritma. Tada je, u jeku reforme i novog utemeljivanja matematike, postavljeno pitanje da li postoji algoritam kojim se (pojednostavljeno reeno) mogu

le

dokazati sve matematike teoreme . Da bi se ovaj problem uopte razmatrao,


bilo je neophodno najpre definisati (matematiki precizno) ta je to algoritam.

1 Re

algoritam ima koren u imenu persijskog astronoma i matematiara Al-Horezmija

(engl. Muhammad ibn Musa al-Khwarizmi). On je 825. godine napisao knjigu, u meuvremenu nesauvanu u originalu, verovatno pod naslovom O raunanju sa indijskim brojevima.
Ona je u dvanaestom veku prevedena na latinski, bez naslova, ali se na nju obino pozivalo
njenim poetnim reima Algoritmi de numero Indorum, to je trebalo da znai Al-Horezmi
o indijskim brojevima (pri emu je ime autora latinizovano u Algoritmi). Meutim, veina
italaca je re Algoritmi shvatala kao mnoinu od nove, nepoznate rei algoritam koja se
vremenom odomaila sa znaenjem metod za izraunavanje.

2 Ovaj

1928.

problem, poznat pod imenom Entscheidungsproblem, postavio je David Hilbert

godine.

Poznato je da je jo Gotfrid Lajbnic u XVII veku, nakon to je napravio

mainu za raunanje, verovao da e biti mogue napraviti mainski postupak koji e, manipulisanjem simbolima, biti u stanju da d odgovor na sva matematika pitanja. Ipak, 1930-ih,
rezultatima era, Tjuringa i Gedela pokazano je da ovakav postupak ne moe da postoji.

61

62

3. Algoritmi i izraunljivost

U tome, bilo je dovoljno razmatrati algoritme za izraunavanje funkcija iji su


i argumenti i rezultujue vrednosti prirodni brojevi (a drugi matematiki i nematematiki algoritmi se, digitalizacijom, mogu svesti na taj sluaj). Formalno
zasnovan pojam algoritma omoguio je da kasnije budu identifikovani problemi
za koje postoje algoritmi koji ih reavaju, kao i problemi za koje ne postoje
algoritmi koji ih reavaju.
Pitanjem formalizacije pojma algoritma 1920-ih i 1930-ih godina nezavisno

(2
01
5)

se bavilo nekoliko istaknutih matematiara i uvedeno je nekoliko raznorodnih


formalizama, tj. nekoliko raznorodnih sistema izraunavanja.
meu njima su:

Tjuringove maine (Tjuring),

rekurzivne funkcije (Gedel

3 i Klini4 ),

-raun

(er ),

Najznaajniji

Postove maine (Post ),

Markovljevi algoritmi (Markov ),

maine sa beskonano mnogo registara (engl. Unlimited Register Ma-

je

urm)8 .

chines

an

iz

Navedeni sistemi nastali su pre savremenih raunara i veina njih podrazumeva odreene apstraktne maine. I u to vreme bilo je jasno da je opis postupka
dovoljno precizan ukoliko je mogue njime instruisati neku mainu koja e taj

sk
o

postupak izvriti. U tom duhu, i savremeni programski jezici predstavljaju precizne opise algoritama i mogue ih je pridruiti gore navedenoj listi. Znaajna
razlika je u tome to nabrojani formalizmi tee da budu to jednostavniji tj. da

ro
n

koriste to manji broj operacija i to jednostavije modele maina, dok savremeni programski jezici tee da budu to udobniji za programiranje te ukljuuju
veliki broj operacija (koje, sa teorijskog stanovita, nisu neophodne jer se mogu
definisati preko malog broja osnovnih operacija).

kt

Blok dijagrami (kae se i algoritamske eme, dijagrami toka, tj. tokovnici )


mogu se smatrati poluformalnim nainom opisa algoritama. Oni nee biti raz-

le

matrani u teorijskom kontekstu ali e biti korieni u reenjima nekih zadataka,


radi lakeg razumevanja.

Za sistem izraunavanja koji je dovoljno bogat da moe da simulira Tjuring-

ovu mainu i tako da izvri sva izraunavanja koja moe da izvri Tjuringova

3 Kurt Gdel (1906-1978), austrijsko-ameriki matematiar.


4 Stephen Kleene (1909-1994), ameriki matematiar.
5 Alonzo Church (1903-1995), ameriki matematiar.
6 Emil L. Post (1897-1954), ameriki matematiar.
7 Andrej Andrejevi Markov (1856-1922), ruski matematiar.
8 Postoji vie srodnih formalizama koji se nazivaju
. Prvi

urm

opisi mogu da se nau u

radovima eperdsona i Sturdisa (engl. Sheperdson and Sturgis), dok je opis koji e biti dat
u nastavku preuzet od Katlanda (engl. Nigel Cutland).

63

3. Algoritmi i izraunljivost

maina kae se da je Tjuring potpun (engl. Turing complete). Za sistem izraunavanja koji izraunava identinu klasu funkcija kao Tjuringova maina kaemo
da je Tjuring ekvivalentan (engl. Turing equivalent).
Ako se neka funkcija moe izraunati u nekom od navednih formalizama,
onda kaemo da je ona izraunljiva u tom formalizmu.

Iako su navedni for-

malizmi meusobno veoma razliiti, moe se dokazati da su klase izraunljivih


funkcija identine za sve njih, tj. svi oni formalizuju isti pojam algoritma i

(2
01
5)

izraunljivosti. Drugim reina, svi navedeni formalizmi su Tjuring ekvivalentni.


Zbog toga se, umesto pojmova poput, na primer, Tjuring-izraunljiva ili

urm-

izraunljiva funkcija (i slinih) moe koristiti samo termin izraunljiva funkcija.

Svi navedeni formalizmi za izraunavanje, podrazumevaju u nekom smislu,


pojednostavljeno reeno, beskonau raspoloivu memoriju.

Zbog toga savre-

meni raunari (koji raspolau konanom memorijom) opremljeni savremenim


programskim jezicima nisu Tjuring potpuni, u strogom smislu. S druge starne,

je

svako izraunavanje koje se moe opisati na nekom modernom programskom

3.2 er-Tjuringova teza

vivalentan formalizam.

an

jeziku, moe se opisati i kao program za Tjuringovu mainu ili neki drugi ek-

iz

Veoma vano pitanje je koliko formalne definicije algoritama uspevaju da


pokriju na intuitivni pojam algoritma, tj. da li je zaista mogue efektivno

sk
o

izvriti sva izraunavanja definisana nekom od formalizacija izraunljivosti i,


obratno, da li sva izraunavanja koja intuitivno umemo da izvrimo zaista
mogu da budu opisana korienjem bilo kog od precizno definisanih formalizama izraunavanja. Intuitivno je jasno da je odgovor na prvo pitanje potvr-

ro
n

dan (jer ovek moe da simulira rad jednostavnih maina za izraunavanje),

9 tvrdi da je

ali oko drugog pitanja postoji doza rezerve. er-Tjuringova teza


odgovor na oba navedena pitanja potvrdan.

kt

er-Tjuringova teza:

Klasa intuitivno izraunljivih funkcija identina

le

je sa klasom formalno izraunljivih funkcija.

Ovo tvrenje je hipoteza, a ne teorema i ne moe biti formalno dokazana.

Naime, ono govori o intuitivnom pojmu algoritma, ija svojstva ne mogu biti
formalno, matematiki ispitana. Ipak, u korist ove teze govori injenica da je
dokazano da su sve navedene formalne definicije algoritama meusobno ekvivalentne, kao i da do sada nije pronaen nijedan primer intuitivno, efektivno
izvodivog postupka koji nije mogue formalizovati u okviru nabrojanih formalnih sistema izraunavanja.

9 Ovu

tezu, svaki za svoj formalizam, formulisali su nezavisno er i Tjuring.

64

3. Algoritmi i izraunljivost

3.3 ur maine

ur
urm). Iako su po skupu izraunljivih funkcija nabrojani formalizacije
pojma algoritma jednake, oni se meusobno razlikuju po svom duhu, a ur
maina je verovatno najblia savremenom stilu programiranja: ur maina ima
U daljem tekstu, pojam izraunljivosti bie uveden i izuavan na bazi

maina (

ogranien (mali) skup instrukcija, programe i memoriju.

ur maine su apstrakcije sine koje

(2
01
5)

Kao i drugi formalizmi izraunavanja,

formalizuju pojam algoritma, predstavljajui matematiku idealizaciju raunara.

ur

maine su dizajnirane tako da koriste samo mali broj operacija.

Oigledno je da nije neophodno da formalizam za izraunavanje kao osnovnu

operaciju ima, na primer, stepenovanje prirodnih brojeva, jer se ono moe


svesti na mnoenje.

Slino, nije neophodno da formalizam za izraunavanje

kao primitivnu operaciju ima mnoenje prirodnih brojeva, jer se ono moe

ak ni sabiranje nije neophodno, jer se moe svesti na

je

svesti na sabiranje.

operaciju pronalaenja sledbenika (uveavanja za vrednost

1).

Zaista, defini-

10 i

an

cija prirodnih brojeva podrazumeva postojanje nule i operacije sledbenika

sve operacije nad prirodnim brojevima se svode na te dve elementarne. Pored


njih,

ur maine koriste jo samo dve instrukcije.

Sva ta etiri tipa instrukcija

brojeve itaju i upisuju ih na polja ili registre beskonane trake koja slui kao
su sa

iz

prostor za uvanje podataka, tj. kao memorija maine. Registri trake oznaeni

1 , 2 , 3 , . . ..

Svaki od njih u svakom trenutku sadri neki prirodan

broj. Stanje registara u nekom trenutku zovemo konfiguracija. Sadraj

slici:

2
2

3
3

-tog

kao to je to ilustrovano na sledeoj

...
...

ro
n

1
1

oznaava se sa

sk
o

registra (registra

Spisak i kratak opis

urm instrukcija (naredbi) dati su u tabeli 3.1.11

0 oznaava da se vrednost 0 upisuje u registar ,


a na primer := + 1 oznaava da se sadraj registra (vrednost )
uveava za jedan i upisuje u registar .
urm program je konaan numerisan niz urm instrukcija. Instrukcije se

le

kt

tabeli, na primer,

izravaju redom (poevi od prve), osim u sluaju instrukcije skoka. Izvravanje

programa se zaustavlja onda kada ne postoji instrukcija koju treba izvriti


(kada se doe do kraja programa ili kada se naie na skok na instrukciju koja
ne postoji u numerisanom nizu instrukcija).

1 , 2 , . . . koji su upisani
(1 , 2 , . . . , ),
1 , 2 , . . . , redom smetene u prvih

Poetnu konfiguraciju ini niz prirodnih brojeva


u registre

1 , 2 , . . ..

Ako je funkcija koju treba izraunati

onda se podrazumeva da su vrednosti

10 Skup

prirodnih brojeva se definie induktivno, kao najmanji skup koji sadri nulu i

zatvoren je u odnosu na operaciju pronalaenja sledbenika.

11 Oznake

urm

instrukcija potiu od naziva ovih instrukcija na engleskom jeziku (zero

instruction, succesor instruction, transfer instruction i jump instruction).

65

3. Algoritmi i izraunljivost

oznaka

naziv

efekat

()
()
(, )
(, , )

nulainstrukcija

0 (tj. := 0)
+ 1 (tj. := + 1)
(tj. := )
ako je = , idi na -tu;

instrukcija sledbenik
instrukcija prenosa
instrukcija skoka

inae idi na sledeu instrukciju

urm instrukcija

(2
01
5)

Tabela 3.1: Tabela

12 Podrazumeva se i da, na kraju rada programa, rezultat treba da

registara.

bude smeten u prvi registar.

urm

za poetnu konfiguraciju 1 , 2 , . . . , ne staje sa


(1 , 2 , . . . , ) . Inae, ako program staje sa radom i u
prvom registru je, kao rezultat, vrednost , onda piemo (1 , 2 , . . . , ) .

Kaemo da urm program izraunava funkciju : N N ako za svaku


-torku argumenata 1 , 2 , . . . , za koju je funkcija definisana i vai (1 ,
2 , . . ., ) = istovremeno vai i (1 , 2 , . . . , ) . Funkcija je urmAko

program

Neka je funkcija

Vrednost funkcije

Primer 3.1.

urm program koji je izraunava.

definisana na sledei nain:

iz

izraunljiva ako postoji

an

je

radom, onda piemo

doda vrednost

1,

sk
o

mainom. Ideja algoritma za izraunavanje vrednosti

(, ) = + .
i ur

moe se izraunati za sve vrednosti argumenata

je da se vrednosti

puta, jer vai:

ro
n

+ = + 1 + 1 + ... + 1

Odgovarajui

urm program podrazumeva sledeu poetnu konfiguraciju:

3 . . .
... ...

kt

le

i sledeu konfiguraciju u toku rada programa:

gde je

1
+

...
...

{0, 1, . . . , }.

Algoritam se moe zapisati u vidu dijagrama toka i u vidu


kao u nastavku:

12 Neki opisi

urm programa

ur maina podrazumevaju da iza vrednosti 1 ,2 , . . . , sledi niz nula, tj. da

su svi registri (sem poetnih koji sadre argumente programa) inicijalizovani na nulu. U ovom

tekstu se to nee podrazumevati, delom i zbog toga to promenljive u jeziku C nemaju nulu
kao podrazumevanu vrednost.

66

3. Algoritmi i izraunljivost

:= 0

(2
01
5)

:= + 1
:= + 1

2.
3.
4.

13 .

an

5.

je

(3)
(3, 2, 100)
(1)
(3)
(1, 1, 2)

1.

Prekid rada programa je realizovan skokom na nepostojeu instrukciju 100


Bezuslovni skok je realizovan naredbom oblika

(1, 1, . . .) poreenje registra

Neka je funkcija

definisana na sledei nain:

iz

Primer 3.2.

sa samim sobom uvek garantuje jednakost te se skok vri uvek.

sk
o

(, ) =

0
1

, ako

, inae

urm program koji je rauna koristi sledeu konfiguraciju u toku rada:


gde

...
...

dobija redom vrednosti 0, 1, 2 . . . sve dok ne dostigne vrednost ili vrednost


Prva dostignuta vrednost je broj ne vei od onog drugog. U skladu sa tim

kt

ro
n

zakljukom i definicijom funkcije

izraunata vrednost je

ili

1.

100 je odabran proizvoljno kao broj sigurno vei od broja instrukcija u programu.

le

13 Broj

I u programima koji slede, uniformnosti radi, za prekid programa e se takoe koristiti skok

na instrukciju 100.

67

3. Algoritmi i izraunljivost

:= 0

0 1

>
1 1

:= + 1

(2
01
5)

5.
6.
7.
8.
9.

Primer 3.3.

Napisati

=0
= ?
= ?
:= + 1
0 1
kraj

an

3.
4.

(3)
(1, 3, 6)
(2, 3, 8)
(3)
(1, 1, 2)
(1)
(1, 1, 100)
(1)
(1)

2.

1 1

iz

1.

je

urm program koji izraunava funkciju

sk
o

() = [ ]

Predloeni algoritam se zasniva na sledeoj osobini:

ro
n

= [ ] 2 < ( + 1)2

urm program podrazumeva sledeu poetnu konfiguraciju:

kt

Odgovarajui

2 . . .
... ...

le

i sledeu konfiguraciju u toku svog rada:

3
1 = 2

4
2 = ( + 1)2

...
...

za 1 i odgovarajuih vrednosti
1 i 2 postave
1 se postepeno
uveava za 1 i proverava se da li je jednak broju . Ukoliko se ne naie na ,
a 1 dostigne vrednost 2 , onda se uveava za 1 i tada oba broja 1 i 2
2
imaju vrednost (naravno, za uveano ). Tada je potrebno 2 postaviti na
2
2
2
vrednost ( + 1) , tj. potrebno je uveati 2 za ( + 1) = 2 + 1. Ovo
se postie tako to se 2 najpre uvea za 1, a zatim puta uvea za 2. Nakon
Osnovna ideja algoritma je uveavanje broja

2 ,

sve dok se broj

ne nae izmeu njih. Nakon to se


2
2
na vrednosti kvadrata dva uzastopna broja i ( + 1) , broj

toga se ceo postupak ponavlja.

68

3. Algoritmi i izraunljivost

:= 0

2 := 1

= 1

1 := 1 + 1

je

1 = 2

an

:= + 1
2 := 2 + 1

iz

:= 0

sk
o

2 := 2 + 2
:= + 1

(2)
(3)
(4)
(4)

ro
n

1.

3.

kt

4.

le

5.
6.

7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.

2.

(2
01
5)

1 := 0

:= 0
1 := 0

2 := 1

(1, 3, 17)
(3)
(3, 4, 9)
(1, 1, 5)

= 1 ?
1 := 1 + 1
1 = 2 ?

(2)
(4)
(5)
(4)
(4)
(5)
(5, 2, 5)
(1, 1, 12)
(2, 1)

:= + 1
2 := 2 + 1
:= 0
2 := 2 + 1
2 := 2 + 1
:= + 1
= ?
1

69

3. Algoritmi i izraunljivost

Primer 3.4.

Neka je funkcija

{
() =

definisana na sledei nain:

, ako je

=0

, inae

Nedefinisanost funkcije se postie time to se napravi program koji se ne


zaustavlja, izuzev ako je vrednost prvog argumenta jednaka
2.

(1, 2, 100)
(1, 1, 1)

3.4 Enumeracija urm programa


Kardinalnost.

0:

(2
01
5)

1.

Za dva skupa kae se da imaju istu kardinalnost ako i samo

ako je izmeu njih mogue uspostaviti bijektivno preslikavanje.

Za skupove

koji imaju istu kardinalnost kao skup prirodnih brojeva kae se da su prebro-

je

jivi . Dakle, neki skup je prebrojiv ako i samo ako je njegove elemente mogue

an

poreati u niz (niz odgovara bijekciji sa skupom prirodnih brojeva). Za skupove


koji su ili konani ili prebrojivi, kae se da su najvie prebrojivi. Georg Kantor

14 je prvi pokazao da skup realnih brojeva ima veu kardinalnost od skupa

Skupovi parnih i neparnih brojeva imaju istu kardinalnost jer je

iz

Primer 3.5.

prirodnih brojeva, tj. da skup realnih brojeva nije prebrojiv.

izmeu njih mogue uspostaviti bijektivno preslikavanje

() = + 1.

Ono to

sk
o

je na prvi pogled iznenaujue je da su oba ova skupa prebrojiva, odnosno imaju


istu kardinalnost kao i skup prirodnih brojeva, iako su njegovi pravi podskupovi
(npr.

() = 2

uspostavlja bijekciju izmeu skupa prirodnih i skupa parnih

ro
n

brojeva).

Lema 3.1.

Ureenih parova prirodnih brojeva ima prebrojivo mnogo.

kt

Dokaz: Razmotrimo beskonanu tabelu elemenata koja odgovara svim ureenim parovima prirodnih brojeva. Mogue je izvriti cik-cak obilazak

le

ove tabele, polazei od gornjeg levog ugla kao to je to pokazano na slici

3.1.

Prilikom obilaska, svakom elementu je mogue dodeliti jedinstven redni


broj, ime je uspostavljena traena bijekcija sa skupom prirodnih brojeva.


Korienjem slinih ideja, mogu se dokazati i sledea tvrenja.

Lema 3.2.

Dekartov proizvod konano mnogo prebrojivih skupova je prebrojiv.

Lema 3.3.

Najvie prebrojiva unija prebrojivih skupova je prebrojiv skup.

14 Georg

Cantor, 18451918, nemaki matematiar.

70

3. Algoritmi i izraunljivost

1
1 1

2
2

3
6

2 3

3 4

4
7

7
...

6
7
.
.
.

Slika 3.1: Cik-cak nabrajanje

je

Enumeracija urm programa.

Vano pitanje je koliko ima urm programa i


urm programa (tj. onih koji izraunavaju razliite funkcije).

an

koliko ima razliitih

(2
01
5)

Oigledno je da ih ima beskonano, a naredna tvrenja govore da ih ima pre-

Postoji prebrojivo mnogo razliitih

iz

Lema 3.4.

brojivo mnogo.

trivijalno, ima prebrojivo mnogo ( instrukcije

sk
o

Dokaz: Instrukcija tipa

urm instrukcija.

se mogu poreati u niz na sledei nain:


sa instrukcijama tipa

(1), (2), . . .).

Slino je i

instrukcije bijektivno odgovaraju parovima

ro
n

prirodnih brojeva, pa ih (na osnovu leme 3.2) ima prebrojivo mnogo.


Slino,

instrukcije odgovaraju bijektivno trojkama prirodnih brojeva,

pa ih (na osnovu leme 3.2) ima prebrojivo mnogo. Skup svih instrukcija
je unija ova etiri prebrojiva skupa, pa je na osnovu leme 3.3 i ovaj skup

le

kt

prebrojiv.

Teorema 3.1.

Razliitih

Dokaz: Skup svih

urm programa ima prebrojivo mnogo

urm programa se moe predstaviti kao unija skupa pro-

grama koji imaju jednu instrukciju, skupa programa koji imaju dve instrukcije i tako dalje. Svaki od ovih skupova je prebrojiv (na osnovu leme
3.2) kao konaan Dekartov stepen prebrojivog skupa instrukcija. Dakle,
skup svih

urm programa je prebrojiv (na osnovu leme 3.3) kao prebrojiva

unija prebrojivih skupova.

Na osnovu teoreme 3.1, mogue je uspostaviti bijekciju izmeu skupa svih

urm programa i skupa prirodnih brojeva.

Drugim reima, moe se definisati

71

3. Algoritmi i izraunljivost

pravilo koje svakom

urm programu dodeljuje jedinstven prirodan broj i koje


urm program. Zbog toga, za

svakom prirodnom broju dodeljuje jedinstven

fiksirano dodeljivanje brojeva programima, moemo da govorimo o prvom, drugom, treem, . . . , stotom

urm programu itd.

Razmotrimo narednih nekoliko problema.

(2
01
5)

3.5 Neizraunljivost i neodluivost


1. Neka su data dva konana skupa rei. Pitanje je da li je mogue nadovezati
nekoliko rei prvog skupa i, nezavisno, nekoliko rei drugog skupa tako

{, , } i {, , },
= . Za skupove {, } i

da se dobije ista re. Na primer, za skupove


jedno reenje je

{, }

reenje ne postoji, jer se nadovezivanjem rei prvog skupa uvek

je

dobija re ija su poslednja dva slova razliita, dok se nadovezivanjem rei


drugog skupa uvek dobija re ija su poslednja dva slova ista. Zadatak je

an

utvrditi da li postoji opti algoritam koji za proizvoljna dva zadata skupa


rei odreuje da li traena nadovezivanja postoje.

(1 , . . . , ) = 0,

gde je

polinom

Zadatak je utvrditi da li postoji opti

iz

sa celobrojnim koeficijentima.

2. Neka su date Diofantske jednaine

15

algoritam kojim se odreuje da li proizvoljna zadata diofantska jednaina

16

sk
o

ima racionalnih reenja.

3. Zadatak je utvrditi da li postoji opti algoritam koji proverava da li se


proizvoljni zadati program

17

zaustavlja za date ulazne parametre.

ro
n

4. Zadatak je utvrditi da li postoji opti algoritam koji za proizvoljni zadati skup aksioma i zadato tvrenje proverava da li je tvrnje posledica

18

aksioma.

kt

Za sva etiri navedena problema pokazano je da su algoritamski nereivi ili

neodluivi (tj. ne postoji izraunljiva funkcija koja ih reava). Ovo ne znai

19 , ve samo da ne postoji

le

da nije mogue reiti pojedine instance problema

jedinstven, opti postupak koji bi mogao da rei proizvoljnu instancu problema.

Pored nabrojanih, ima jo mnogo vanih neodluivih problema

15 Ovaj

problem se naziva Posts correspondence problem, jer ga je postavio i reio Emil

Post 1946. godine.

16 Ovaj

problem je 10. Hilbertov problem izloen 1900. godine kao deo skupa problema

koje matematiari XIX veka ostavljaju u amanet matematiarima XX veka.

Problem je

reio Matijaevi 1970-ih godina.

17 Ovaj problem reio je Alan Tjuring 1936. godine.


18 Ovaj, ve pomenut, problem, formulisao je David

Hilbert 1928. godine, a neto kasnije

reenje je proisteklo iz rezultata era, Tjuringa i Gedela.

19 Instanca

ili primerak problema je jedan konkretan zadatak koji ima isti oblik kao i

opti problem. Na primer, za prvi u navedenom spisku problema, jedna instanca je zadatak
ispitivanja da li je mogue nadovezati nekoliko rei skupa
skupa

{, }

tako da se dobije ista re.

{, }

i, nezavisno, nekoliko rei

72

3. Algoritmi i izraunljivost

U nastavku e precizno, korienjem formalizma

ur

maina, biti opisan

trei od navedenih problema, tj. halting problem, izuzetno vaan za teorijsko


raunarstvo.

Problem ispitivanja zaustavljanja programa (halting problem).

Pi-

tanje zaustavljanja raunarskih programa je jedno od najznaajnijih pitanja

(2
01
5)

raunarstva i programiranja. esto je veoma vano da li se neki program zaustavlja za neku ulaznu vrednost, da li se zaustavlja za ijednu ulaznu vrednost
i slino.

Za mnoge konkretne programe i za mnoge konkretne ulazne vred-

nosti, na ovo pitanje moe se odgovoriti. No, nije oigledno da li postoji opti
postupak kojim se za proizvoljni dati program i proizvoljne vrednosti ulaznih
argumenata moe proveriti da li se program zaustavlja ako se pokrene sa tim
argumentima.

Iako se problem ispitivanja zaustavljanja moe razmatrati i za programe


u savremenim programskim jezicima, u nastavku emo razmotriti formulaciju

je

urm programe:
Da li postoji urm program koji na ulazu dobija drugi urm program i neki

broj

i ispituje da li se program

an

halting problema za

zaustavlja za ulazni parametar

urm program mora


urm program, to je naizgled

Problem prethodne formulacije je injenica da traeni


na ulazu da prihvati kao svoj argument drugi

urm programi kao argumente mogu da imaju

iz

nemogue, s obzirom na to da

samo prirodne brojeve. Ipak, ovo se jednostavno razreava zahvaljujui tome

urm programu

mogue dodeliti jedinstveni prirodan broj

sk
o

to je svakom

koji ga identifikuje, i obratno, svakom broju

moe se dodeliti program

(kao to je opisano u poglavlju 3.4). Imajui ovo u vidu, dolazi se do teoreme

urm.

ro
n

o halting problemu za

Teorema 3.2

(Neodluivost halting problema)

Neka je funkcija

definisana

kt

na sledei nain:

le

(, ) =

1,
0,

ako se program

Ne postoji program koji izraunava funkciju

zadate vrednosti
argument

zaustavlja za ulaz

inae.

tj. ne postoji program koji za

moe da proveri da li se program

zaustavlja za ulazni

Dokaz: Pretpostavimo da postoji program

koji izraunava funkciju

se jednostavno moe konstruisati i program


koji vraa rezultat

Onda

sa jednim argumentom

(tj. upisuje ga u prvi registar) ako se program

, a rezultat 0 ako se program ne zaustavlja za ulaz


(dobijen kombinovanjem programa i
programa iz primera 3.4) koji za argument vraa rezultat 0 ako se
ne zaustavlja za (tj. ako je (, ) = 0), a izvrava beskonanu petlju
ako se zaustavlja za (tj. ako je (, ) = 1). Za program vai:
zaustavlja za ulaz

Dalje, postoji i program

73

3. Algoritmi i izraunljivost

() 0
()
Ako postoji takav program

ako je

()

onda se i on nalazi u nizu svih programa

koji ga jedinstveno identifikuje, pa vai:

() 0
()

()

ako je
ako je

()

(2
01
5)

tj. postoji redni broj

()

ako je

jednako upravo , pokazuje se da je definicija ponaanja


(tj. programa ) kontradiktorna: program (tj. program
) za ulaznu vrednost vraa 0 ako se ne zaustavlja za , a izvrava
beskonanu petlju ako se zaustavlja za :
No, ako je

()

()

ako je

an

() 0

je

programa

ako je

()

nije izraunljiva. Poto funkcija

iz

Dakle, polazna pretpostavka je bila pogrena i ne postoji program


tj. funkcija

karakteristina funkcija

sk
o

halting problema, nije izraunljiva, halting problem nije odluiv.

Funkcija koja odgovara halting problemu je jedna od najznaajnih funkcija


iz skupa prirodnih brojeva u skup prirodnih brojeva koje ne mogu biti izraunate, ali takvih, neizraunljivih funkcija, ima jo mnogo. Moe se dokazati da

ro
n

funkcija jedne promenljive koje za ulazni prirodni broj vraaju iskljuivo 0 ili
1 (tj. funkcija iz

{0, 1})

ima neprebrojivo mnogo, dok programa ima samo

prebrojivo mnogo. Iz toga direktno sledi da ima neprebrojivo mnogo funkcija

kt

koje nisu izraunljive.

le

3.6 Vremenska i prostorna sloenost izraunavanja

Prvo pitanje koje se postavlja kada je potrebno izraunati neku funkciju

(tj. napisati neki program) je da li je ta funkcija izraunljiva (tj. da li uopte postoji neki program koji je izraunava). Ukoliko takav program postoji, sledee
pitanje je koliko izvravanje tog program zahteva vremena i prostora (memorije). U kontekstu

urm programa, pitanje je koliko za neki urm program treba

izvriti pojedinanih instrukcija (ukljuujui ponavljanja) i koliko registara se


koristi. U

urm programu navedenom u primeru 3.1 postoje ukupno etiri in-

strukcije, ali se one mogu ponavljati (za neke ulazne vrednosti). Jednostavno

+ 1 puta, a preostale
puta. Dakle, ukupan broj izvrenih instrukcija za ulazne vrednosti i
je jednak 4 + 1. Ako se razmatra samo takozvani red algoritma, onda se zane-

se moe izraunati da se prva instrukcija u nizu izvrava


tri po

maruju konstante kojima se mnoe i sabiraju vrednosti ulaznih argumenata, pa

74

3. Algoritmi i izraunljivost

je vremenska sloenost u ovom primeru linearna po drugom argumentu, argumentu

(i to se zapisuje

()).

Bez obzira na vrednosti ulaznih argumenata,

program koristi tri registra, pa je njegova prostorna sloenost konstantna (i to

(1)).

se zapisuje

Najee se sloenost algoritma odreuje tako da ukazuje na

to koliko on moe utroiti vremena i prostora u najgorem sluaju. Ponekad je


mogue izraunati i prosenu sloenost algoritma prosenu za sve mogue
vrednosti argumenata. O prostornoj i vremenoskoj sloenosti algoritama bie

(2
01
5)

vie rei u drugom tomu ove knjige.

Pitanja i zadaci za vebu


Pitanje 3.1.

Po kome je termin algoritam dobio ime?

Pitanje 3.2.

ta je to algoritam (formalno i neformalno)? Navesti nekoliko

formalizma za opisivanje algoritama. Kakva je veza izmeu formalnog i nefor-

je

malnog pojma algoritma. ta tvrdi er-Tjuringova teza? Da li se ona moe

Pitanje 3.3.

an

dokazati?

Da li postoji algoritam koji opisuje neku funkciju iz skupa prirod-

nih brojeva u skup prirodnih brojeva i koji moe da se isprogramira u programmaini?

iz

skom jeziku C i izvri na savremenom raunaru, a ne moe na Tjuringovoj

urm izraunljiva funkcija intuitivno izraunljiva?


urm izraunljiva?
Pitanje 3.5. U emu je kljuna razlika izmeu urm maine i bilo kog stvarnog

Pitanje 3.4.

Da li je svaka

sk
o

Da li je svaka intuitivno izraunljiva funkcija

ro
n

raunara?

urm naredbe (, , ).
Da li se nekim urm programom moe izraunati hiljadita cifra

Pitanje 3.6.

Opisati efekat

Pitanje 3.7.
21000

kt

broja

Pitanje 3.8.

Da li postoji

urm program koji izraunava broj

le

urm program koji izraunava -tu decimalnu cifru broja

2,

2?

Da li postoji

gde je

zadati

prirodan broj?

Pitanje 3.9.

Da li se nekim

malna cifra broja

Pitanje 3.10.

urm programom moe izraunati hiljadita deci-

Koliko ima racionalnih brojeva? Koliko ima kompleksnih bro-

jeva? Koliko ima razliitih programa za Tjuringovu mainu? Koliko ima razliitih programa u programskom jeziku C?

Pitanje 3.11.

Koliko elemenata ima unija konano mnogo konanih skupova?

Koliko elemenata ima unija prebrojivo mnogo konanih skupova? Koliko elemenata ima unija konano mnogo prebrojivih skupova? Koliko elemenata ima
unija prebrojivo mnogo prebrojivih skupova?

75

3. Algoritmi i izraunljivost

Koliko ima razliitih urm programa? Kakva je kardinalnost


urm programa u odnosu na kardinalnost skupa prirodnih brojeva? Kakva
je kardinalnost skupa urm programa u odnosu na kardinalnost skupa realnih
brojeva? Kakva je kardinalnost skupa urm programa u odnosu na kardinalnost

Pitanje 3.12.

skupa

skupa programa na jeziku C?

Pitanje 3.13.

Da li se svakom

urm programu moe pridruiti jedinstven priro-

dan broj (razliit za svaki program)? Da li se svakom prirodnom broju moe

(2
01
5)

urm program (razliit za svaki broj)?


Pitanje 3.14. Da li se svakom urm programu moe pridruiti jedinstven realan
pridruiti jedinstven

broj (razliit za svaki program)? Da li se svakom realnom broju moe pridruiti


jedinstven

urm program (razliit za svaki broj)?

Pitanje 3.15.

Kako se naziva problem ispitivanja zaustavljanja programa?

je

Kako glasi halting problem? Da li je on odluiv ili nije? Ko je to dokazao?

Pitanje 3.16.

an

1. Da li postoji algoritam koji za drugi zadati

utvruje da li se zaustavlja ili ne?

2. Da li postoji algoritam koji za drugi zadati


tavlja posle 100 koraka?

urm utvruje da li se zaus-

urm program koji za drugi zadati urm program

iz

3. Da li je mogue napisati

urm program

proverava da li radi beskonano?

urm program koji za drugi zadati urm program

sk
o

4. Da li je mogue napisati

proverava da li vraa vrednost 1?

ro
n

5. Da li je mogue napisati

urm program kojim se ispituje da li data izraunurm program) zadovoljava da je

ljiva funkcija (ona za koju postoji

(0) = 0?

kt

6. Da li je mogue napisati

urm program koji za drugi zadati urm program

ispituje da li izraunava vrednost

le

Pitanje 3.17.

2012

i zato?

Na primeru korena uporedite URM sa savremenim asemberl-

skim jezicima. Da li URM ima neke prednosti?

Zadatak
3.1.

Napisati

Zadatak 3.2.

Napisati

Zadatak 3.3.

Napisati

Zadatak 3.4.

Napisati

urm program koji izraunava funkciju (, ) = .


urm program koji izraunava funkciju () = 2 .
urm program koji izraunava funkciju (, ) = .
urm program koji izraunava funkciju:
{
(, ) =

1
0

, ako

, inae

76

3. Algoritmi i izraunljivost

Zadatak 3.5.

Napisati

urm program koji izraunava funkciju


{

(, ) =

, ako

, inae

Napisati

urm program koji izraunava funkciju:


{

() =

/3

, ako

(2
01
5)

Zadatak 3.6.

3|

, inae

urm program koji izraunava funkciju () = !.


[ ]
Zadatak 3.8. Napisati urm program koji izraunava funkciju () = 2
3 .
Zadatak 3.9. Napisati urm program koji broj 1331 smeta u prvi registar.
Zadatak 3.10. Napisati urm program koji izraunava funkciju () = 1000.
Zadatak 3.11. Napisati urm program koji izraunava funkciju (, ) = 2 +
Napisati

an

je

Zadatak 3.7.

(, ),

urm

Napisati

odnosno:

program koji izraunava funkciju

iz

Zadatak 3.12.

2(+)

urm

Napisati

Napisati

le

Zadatak 3.15.

Zadatak 3.16.

Napisati

1
0

, ako

, ako

= 0

, inae

urm program koji izraunavaju sledeu funkciju:

(, ) =
Napisati

(, ) =

, inae

{ [ ]
(, ) =
Napisati

, inae

urm program koji izraunava funkciju

Zadatak 3.17.

, ako

urm program koji izraunava funkciju

(, ) =

kt

Zadatak 3.14.

program koji izraunava funkciju

ro
n

Zadatak 3.13.

sk
o

(, ) =

(, ) =

, <
,

urm program koji izraunava funkciju:


{
(, ) =

/3
2

, 3|
,

77

3. Algoritmi i izraunljivost

Napisati

urm program koji izracunava funkciju (, , ) =

Napisati

urm program koji izracunava funkciju (, , ) =

++

Zadatak 3.19.
(, , ).

Zadatak 3.20.

Napisati

urm program koji izraunava funkciju


{ [ ]
3

(, , ) =

Zadatak 3.21.

Napisati

+1

, ako

2|

, inae

(2
01
5)

Zadatak 3.18.

urm program koji izraunava funkciju


{

1,
2,

ako je

+ >

inae

le

kt

ro
n

sk
o

iz

an

je

(, , ) =

(2
01
5)

Glava 4

je

Vii programski jezici

Razvoj programskih jezika, u bliskoj je vezi sa razvojem raunara tj. sa

an

razvojem hardvera. Programiranje u dananjem smislu nastalo je sa pojavom


raunara fon Nojmanovog tipa iji se rad kontrolie programima koji su smeteni

u memoriji, zajedno sa podacima nad kojim operiu.

Na prvim raunarima

iz

tog tipa moglo je da se programira samo na mainski zavisnim programskim


jezicima, a od polovine 1950-ih nastali su jezici vieg nivoa koji su drastino
olakali programiranje.

sk
o

Prvi programski jezici zahtevali su od programera da bude upoznat sa najfinijim detaljima raunara koji se programira. Problemi ovakvog naina programiranja su viestruki. Naime, ukoliko je eleo da programira na novom rau-

ro
n

naru, programer je morao da izui sve detalje njegove arhitekture (na primer,
skup instrukcija procesora, broj registara, organizaciju memorije).

Programi

napisani za jedan raunar mogli su da se izvravaju iskljuivo na istim takvim


raunarima i prenosivost programa nije bila mogua.

kt

Vii programski jezici namenjeni su ljudima a ne mainama i sakrivaju detalje konkretnih raunara od programera. Specijalizovani programi (tzv. jeziki

le

procesori, programski prevodioci, kompilatori ili interpretatori ) na osnovu specifikacije zadate na viem (apstraktnijem) nivou mogu automatski da proizvedu

mainski kd za specifian raunar na kojem se programi izvravaju. Ovim se


omoguava prenosivost programa (pri emu, da bi se program mogao izvravati
na nekom konkretnom raunaru, potrebno je da postoji procesor vieg programskog jezika ba za taj raunar). Takoe, znatno se poveava nivo apstrakcije
prilikom procesa programiranja to u mnogome olakava ovaj proces.
Razvojni ciklus programa u veini savremenih viih programskih jezika tee
na sledei nain.

Danas je, nakon faze planiranja, prva faza u razvoju pro-

grama njegovo pisanje tj. unoenje programa na viem programskom jeziku


(tzv. izvorni program ili izvorni kd engl. source code), to se radi pomou
nekog editora teksta. Naredna faza je njegovo prevoenje, kada se na osnovu
izvornog programa na viem programskom jeziku dobija prevedeni kd na asem-

78

79

4. Vii programski jezici

blerskom odnosno mainskom jeziku (tzv. objektni kd engl. object code), to


se radi pomou nekog programskog prevodioca.

U fazi povezivanja vie ob-

jektnih programa povezuje se sa objektnim kdom iz standardne biblioteke u


jedinstvenu celinu (tzv. izvrni program engl. executable program). Povezivanje vri specijalizovan program poveziva, tj. linker (engl. linker) ili ureiva

veza . Nakon povezivanja, kreiran je program u izvrnom obliku i on moe da


se izvrava .

Nabrojane faze se obino ponavljaju, vri se dopuna programa,

(2
01
5)

ispravljanje greaka, itd.

4.1 Kratki pregled istorije programskih jezika

Prvim viim programskim jezikom najee se smatra jezik FORTRAN,

nastao u periodu 1953-1957 godine. Njegov glavni autor je Don Bakus , koji

je implementirao i prvi interpretator i prvi kompilator za ovaj jezik. Ime FOR-

je

TRAN dolazi od The IBM Mathematical FORmula TRANslating System, to


ukazuje na to da je osnovna motivacija bila da se u okviru nauno-tehnikih pri-

an

mena omogui unoenje matematikih formula, dok je sistem taj koji bi unete
matematike formule prevodio u niz instrukcija koje raunar moe da izvrava.

2 je dizajnirao programski

Neposredno nakon pojave Fortrana, Don Mekarti

-raunu.

jezik LISP (LISt Processing ), zasnovan na

LISP je uveo funkcionalno

iz

programiranje i dugo bio najpopularniji jezik u oblasti vetake inteligencije.


Krajem 1950-ih godina, nastao je i jezik COBOL (COmmon Business-Oriented

sk
o

Language ), ije su osnovne primene u oblasti poslovanja. Zanimljivo je da puno


starih COBOL programa i danas uspeno radi u velikim poslovnim sistemima
kod nas i u svetu.

Rani programski jezici, nastali pod uticajem asemblerskih jezika, intenzivno

ro
n

koriste skokove u programima (tzv. GOTO naredbu) to dovodi do programa


koje je teko razumeti i odravati.

Kao odgovor na softversku krizu 1970-

ih godina (period kada zbog loe prakse programiranja softver nije mogao da

kt

dostigne mogunosti hardvera), nastala je praksa strukturnog programiranja


u kojoj se insistira na disciplinovanom pristupu programiranju, bez nekontrolisanih skokova i uz korienje samo malog broja naredbi za kontrolu toka

le

programa.

Krajem 1950-ih godina zapoet je razvoj programskog jezika ALGOL 60

koji je uneo mnoge koncepte prisutne skoro u svim dananjim programskim


jezicima.

Tokom 1970-ih pojavio se jezik C koji i dalje predstavlja osnovni

jezik sistemskog programiranja. Tokom 1970-ih pojavio se i jezik Pascal koji je


vrlo elegantan jezik iji je cilj bio da ohrabri strukturno programiranje i koji se
zbog ovoga (u svojim unapreenim oblicima) i danas ponegde koristi u nastavi
programiranja.

1 John

Backus (19242007), ameriki naunik iz oblasti raunarstva, dobitnik Tjuringove

nagrade.

2 John

McCarthy (19272011),

ameriki naunik iz oblasti raunarstva.

Tjuringove nagrade za svoj rad na polju vetake inteligencije.

Dobitnik

80

4. Vii programski jezici

Kao odgovor na jo jednu softversku krizu prelazi se na korienje tzv. objektno-orijentisanih jezika koji olakavaju izradu velikih programa i podelu posla
u velikim programerskim timovima. Tokom 1980-ih se pojavljuje jezik C++
koji nadograuje jezik C objektno-orijentisanim konceptima, a tokom 1990-ih,
pod uticajem interneta, i jezik Java, ija je jedna od osnovnih ideja prenosivost
izvrnog kda izmeu heterogenih raunarskih sistema. Microsoft, je krajem
1990-ih zapoeo razvoj jezika C# koji se danas esto koristi za programiranje

(2
01
5)

Windows aplikacija.

Pojavom veba postaju znaajni skript jezici, kao to su PHP, JavaScript,

Python, Ruby itd.

4.2 Klasifikacije programskih jezika

Po nainu programiranja, programski jezici se klasifikuju u programske

je

paradigme.

Najkorieniji programski jezici danas spadaju u grupu imperativnih pro-

an

gramskih jezika. Kako u ovu grupu spada i programski jezik C (ali i programski jezik Pascal, Fortran, Basic itd.), u nastavku e biti najvie rei upravo o
ovakvim jezicima.

U ovim jezicima stanje programa karakteriu promenljive

kojima se predstavljaju podaci i naredbe kojima se vre odreene transfor-

iz

macije promenljivih. Pored imperativne, znaajne programske paradigme su i

objektno-orijentisana (u nju spadaju C++, Java, C# itd.), funkcionalna (u nju

sk
o

spadaju Lisp, Haskell, ML, itd.), logika (u nju spada, na primer, Prolog). U
savremenim jezicima meaju se karakteristike razliitih programskih paradigmi
tako da je podela sve manje striktna.
Veina programskih jezika danas je proceduralna to znai da je zadatak

ro
n

programera da opie nain (proceduru) kojim se dolazi do reenja problema.


Nasuprot njima, deklarativni programski jezici (na primer Prolog) od programera zahtevaju da precizno opie problem, dok se mehanizam programskog

kt

jezika onda bavi pronalaenjem reenja problema. Iako uspeni u ogranienim


domenima, deklarativni jezici jo nisu dovoljno efikasni da bi bili dominantno

le

korieni.

4.3 Leksika, sintaksa, semantika programskih jezika


Da bi bilo mogue pisanje i prevoenje programa u odgovarajue programe

na mainskom jeziku nekog konkretnog raunara, neophodno je precizno definisati ta su ispravni programi nekog programskog jezika, kao i precizno definisati koja izraunavanja odgovaraju naredbama programskog jezika. Pitanjima
ispravnosti programa bavi se sintaksa programskih jezika (i njena podoblast

leksika programskih jezika ).

Leksika se bavi opisivanjem osnovnih gradivnih

elemenata jezika, a sintaksa nainima za kombinovanje tih osnovnih elemenata


u ispravne jezike konstrukcije. Pitanjem znaenja programa bavi se seman-

tika programskih jezika . Leksika, sintaksa i semantika se izuavaju ne samo za


programske jezike, ve i za druge vetake jezike, ali i za prirodne jezike.

81

4. Vii programski jezici

Leksika.

Osnovni leksiki elementi prirodnih jezika su rei, pri emu se raz-

likuje nekoliko razliitih vrsta rei (imenice, glagoli, pridevi, . . . ) i rei imaju
razliite oblike (padei, vremena, . . . ).

Zadatak leksike analize prirodnog

jezika je da identifikuje rei u reenici i svrsta ih u odgovarajue kategorije.


Slino vai i za programske jezike.

Programi se raunaru zadaju predstavl-

jeni nizom karaktera. Pojedinani karakteri se grupiu u nedeljive celine koje


predstavljaju osnovne leksike elemente, koji bi bili analogni reima govornog

ur maina razlikuje rezervisane rei ( , , ,

(2
01
5)

jezika. Na primer, leksika jezika

i brojevne konstante. Razmotrimo naredni fragment kda u jeziku C:

if (a < 3)
x1 = 3+4*a;

U ovom kdu, razlikuju se sledee lekseme (rei) i njima pridrueni tokeni


kljuna re

an

zagrada
identifikator
operator

celobrojni literal

iz

zagrada
identifikator
operator
operator

sk
o

celobrojni literal
celobrojni literal
operator

ro
n

if
(
a
<
3
)
x1
=
3
+
4
*
a
;

je

(kategorije).

celobrojni literal
interpunkcija

Leksikom programa obino se bavi deo programskog prevodioca koji se

kt

naziva leksiki analizator .

le

Sintaksa.

Sintaksa prirodnih jezika definie naine na koji pojedinane rei

mogu da kreiraju ispravne reenice jezika. Slino je i sa programskim jezicima,

gde se umesto ispravnih reenica razmatraju ispravni programi.


sintaksa jezika
oblika:

ur

Na primer,

maina definie ispravne programe kao nizove instrukcija

(broj), (broj), (broj, broj, broj)

(broj, broj).

Sintaksa definie

formalne relacije izmeu elemenata jezika, time pruajui strukturne opise ispravnih niski jezika.

Sintaksa se bavi samo formom i strukturom jezika bez

bilo kakvih razmatranja u vezi sa njihovim znaenjem. Sintaksika struktura


reenica ili programa se moe predstaviti u obliku stabla. Prikazani fragment
kda je u jeziku C sintaksiki ispravan i njegova sintaksika struktura se moe
predstaviti na sledei nain:

82

4. Vii programski jezici

<

+
*

(2
01
5)

3
4

Dakle, taj fragment kda predstavlja

if-then naredbu (iskaz) kojoj je uslov


a i konstante 3, a telo predstavlja

dat izrazom poreenja vrednosti promenljive


naredba dodele promenljivoj

i proizvoda konstante

vrednosti izraza koji predstavlja zbir konstante

i vrednosti promenljive

a.

Sintaksom programa obino se bavi deo programskog prevodioca koji se

Semantika pridruuje znaenje sintaksiki ispravnim niskama

Za prirodne jezike, semantika pridruuje ispravnim reenicama neke

specifine objekte, misli i oseanja.

Za programske jezike, semantika za dati

jezika.

an

Semantika.

je

naziva sintaksiki analizator.

Tako se, na primer, naredbi

iz

program opisuje koje je izraunavanje opisano tim programom.

if (a < 3) x1 = 3+4*a;

jezika C moe pri-

druiti sledee znaenje: Ako je tekua vrednost promenljive

x1

manja od 3,

treba da dobije vrednost zbira broja 3 i etvorostruke

sk
o

tada promenljiva

tekue vrednosti promenljive

a.

Postoje sintaksiki ispravne reenice prirodnog jezika kojima nije mogue

ro
n

dodeliti ispravno znaenje, tj. za njih nije definisana semantika, na primer:


Bezbojne zelene ideje besno spavaju ili Pera je oenjeni neenja. Slino je
i sa programskim jezicima. Neki aspekti semantike korektnosti programa se
mogu proveriti tokom prevoenja programa (na primer, da su sve promenljive

kt

koje se koriste u izrazima definisane i da su odgovarajueg tipa), dok se neki


aspekti mogu proveriti tek u fazi izvravanja programa (na primer, da ne dolazi

le

do deljenja nulom). Na osnovu toga, razlikuje se statika i dinamika semantika.


Naredni C kd nema jasno definisano dinamiko znaenje, pa u fazi izvravanja

dolazi do greke (iako se prevoenje na mainski jezik uspeno izvrava).

int x = 0;
int y = 1/x;
Dok veina savremenih jezika ima precizno i formalno definisanu leksiku
i sintaksu, formalna definicija semantike postoji samo za neke programske

jezike .

U ostalim sluajevima, semantika programskog jezika se opisuje ne-

formalno, opisima zadatim korienjem prirodnog jezika. est je sluaj da neki

3 Leksika

se obino opisuje regularnim izrazima, sintaksa kontekstno slobodnim gra-

matikama, dok se semantika formalno zadaje ili aksiomatski (npr. u obliku Horove logike) ili

u vidu denotacione semantike ili u vidu operacione semantike.

83

4. Vii programski jezici

aspekti semantike ostaju nedefinisani standardom jezika i preputa se implementacijama kompilatora da samostalno odrede potpunu semantiku. Tako, na
primer, programski jezik C ne definie kojim se redom vri izraunavanje vrednosti izraza, to u nekim sluajevima moe da dovede do razliitih rezultata
istog programa prilikom prevoenja i izvravanja na razliitim sistemima (na
primer, nije definisano da li se za izraunavanje vrednosti izraza

ili funkcija

g).

f() + g()

(2
01
5)

najpre poziva funkcija

4.4 Pragmatika programskih jezika

Pragmatika jezika govori o izraajnosti jezika i o odnosu razliitih naina za


iskazivanje istih stvari. Pragmatika prirodnih jezika se odnosi na psiholoke i

socioloke aspekte kao to su korisnost, opseg primena i efekti na korisnike. Isti

prirodni jezik se koristi drugaije, na primer, u pisanju tehnikih uputstava, a

je

drugaije u pisanju pesama. Pragmatika programskih jezika ukljuuje pitanja


kao to su lakoa programiranja, efikasnost u primenama i metodologija pro-

an

gramiranja. Pragmatika je kljuni predmet interesovanja onih koji dizajniraju


i implementiraju programske jezike, ali i svih koji ih koriste. U pitanja pragmatike moe da spada i izbor naina na koji napisati neki program, u zavisnosti

od toga da li je, u konkretnom sluaju, vano da je program kratak ili da je

iz

jednostavan za razumevanje ili da je efikasan.

Pragmatika jezika se, izmeu ostalog, bavi i sledeim pitanjima dizajna

sk
o

programskih jezika.

Promenljive i tipovi podataka.

U fon Nojmanovom modelu, podaci se

smetaju u memoriju raunara (najee predstavljeni nizom bitova). Meu-

ro
n

tim, programski jezici uobiajeno, kroz koncept promenljivih, nude programerima apstraktniji pogled na podatke. Promenljive omoguavaju programeru da
imenuje podatke i da im pristupa na osnovu imena, a ne na osnovu memorijskih

kt

adresa (kao to je to sluaj kod asemblerskih jezika). Svakoj promenljivoj dodeljen je odreen broj bajtova u memoriji (ili, eventualno, u registrima procesora)
kojima se predstavljaju odgovarajui podaci. Pravila ivotnog veka (engl. life-

le

time) odreuju u kom delu faze izvravanja programa je promenljivoj dodeljen


Nekada je

memorijski prostor (promenljivu je mogue koristiti samo tada).

mogue na razliitim mestima u programu koristiti razliite promenljive istog


imena i pravila dosega indentifikatora (engl. scope) odreuju deo programa u
kome se uvedeno ime moe koristiti za imenovanje odreenog objekta (najee
promenljive).
Organizovanje podataka u tipove omoguava da programer ne mora da
razmilja o podacima na nivou njihove interne (binarne) reprezentacije, ve
da o podacima moe razmiljati znatno apstraktnije, dok se detalji interne
reprezentacije preputaju jezikom procesoru.

Najei tipovi podataka di-

rektno podrani programskim jezicima su celi brojevi (0, 1, 2, -1, -2, . . . ),


brojevi u pokretnom zarezu (1.0, 3.14, . . . ), karakteri (a,

b, 0, ,, !,

. . . ), niske

84

4. Vii programski jezici

("zdravo"), . . . Pored ovoga, programski jezici obino nude i mogunost korienja sloenih tipova (na primer, nizovi, strukture tj. slogovi koji mogu da
objedinjavaju nekoliko promenjivih istog ili razliitog tipa).
Svaki tip podataka karakterie:
vrsta podataka koje opisuje (na primer, celi brojevi),

skup operacija koje se mogu primeniti nad podacima tog tipa (na primer,

(2
01
5)

sabiranje, oduzimanje, mnoenje, . . . ),

nain reprezentacije i detalji implementacije (na primer, zapis u obliku binarnog potpunog komplementa irine 8 bita, odakle sledi opseg vrednosti
od -128 do 127).

x, y i z celobrojnog
int), a da z nakon izvravanja ovog fragmenta ima vrednost jednaku
promenljivih x i y.

Naredni fragment C kda obezbeuje da su promenljive


zbiru

je

tipa (tipa

iz

an

int x, y;
...
int z = x + y;

Prilikom prevoenja i kreiranja mainskog kda, prevodilac, voen tipom promenljivih

x, y i z, dodeljuje odreeni broj bitova u memoriji ovim promenljivim

sk
o

(tj. rezervie odreene memorijske lokacije iskljuivo za smetanje vrednosti


ovih promenljivih) i generie kd (procesorske instrukcije) kojim se tokom
izvravanja programa sabiraju vrednosti smetene na dodeljenim memorijskim

ro
n

lokacijama. Pri tom se vodi rauna o nainu reprezentacije koji se koristi za


zapis. S obzirom da je naglaeno da su promenljive

x , y i z,

celobrojnog tipa,

prevodilac e najverovatnije podrazumevati zapis u potpunom komplementu i


operacija

e se prevesti u mainsku instrukciju kojom se sabiraju brojevi za-

kt

pisani u potpunom komplementu (koja je obino direktno podrana u svakom


procesoru). U zavisnosti od tipa operanada, ista operacija se ponekad prevodi

float,

najverovatnije bi

se podrazumevao zapis u obliku pokretnog zareza i operacija

bi se prevela u

le

na razliite naine. Tako, da su promenljive bile tipa

mainsku instrukciju kojom se sabiraju brojevi zapisani u pokretnom zarezu.


Time, tipovi podataka iz jezika vieg nivoa u odgovarajuem mainskom kdu
postoje samo implicitno, najee samo kroz mainske instrukcije nastale nakon
prevoenja.
Tokom prevoenja programa se razreavaju i pitanja konverzija tipova . Na
primer, u C kdu

int x = 3.1;

promenljiva

je deklarisana kao celobrojna,

pa se za nju odvaja odreeni broj bitova u memoriji i ta memorija se inicijalizuje


binarnim zapisom broja

3.

Naime, realnu vrednost

3.1

nije mogue zapisati

kao celobrojnu promenljivu, pa se vri konverzija tipa i zaokruivanje vrednosti.

Statiki tipizirani jezici (ukljuujui C), zahtevaju da programer definie


tip svake promenljive koja se koristi u programu i da se taj tip ne menja tokom

85

4. Vii programski jezici

izvravanja programa. Meutim, neki statiki tipizirani programski jezici (na


primer Haskell ili ML) ne zahtevaju od programera definisanje tipova, ve se
tipovi automatski odreuju iz teksta programa. S druge strane, u dinamiki

tipiziranim jezicima ista promenljiva moe da sadri podatke razliitog tipa


tokom raznih faza izvravanja programa. U nekim sluajevima doputeno je
vriti operacije nad promenljivima razliitog tipa, pri emu se tip implicitno
Na primer, jezik JavaScript ne zahteva definisanje tipa promen-

jlivih i doputa kd poput

a = 1; b = "2"; a = a + b;.

Kontrola toka izvravanja.

(2
01
5)

konvertuje.

Osnovi gradivni element imperativnih pro-

grama su naredbe . Osnovna naredba je naredba dodele kojom se vrednost neke


promenljive postavlja na vrednost nekog izraza definisanog nad konstantama i
definisanim promenljivim. Na primer,

x1 = 3 + 4*a;.

Naredbe se u programu esto niu i izvravaju sekvencijalno, jedna nakon

Meutim, da bi se postigla vea izraajnost, programski jezici uvode

je

druge.

specijalne vrste naredbi kojima se vri kontrola toka izvravanja programa


Ovim se postie da se u zavisnosti od tekuih

an

(tzv. kontrolne strukture).

vrednosti promenljivih neke naredbe uopte ne izvravaju, neke izvravaju vie


Najee koriene kontrolne strukture su granajue naredbe

(if-then-else), petlje (for,

while, do-while, repeat-until) i naredbe skoka

puta i slino.

iz

(goto). Za naredbu skoka (goto) je pokazano da nije neophodna, tj. svaki program se moe zameniti programom koji daje iste rezultate a pri tome koristi
samo sekvencijalno nizanje naredbi, naredbu izbora (if-then-else) i jednu

do-while).4

sk
o

vrstu petlje (na primer,

Ovaj vaan teorijski rezultat ima svoju

punu praktinu primenu i u dananjem, strukturnom, programiranju naredba


programa.

ro
n

skoka se gotovo uopte ne koristi jer dovodi do nerazumljivih (tzv. pageti)

Potprogrami.

Veina programskih jezika prua mogunost definisanja neke

kt

vrste potprograma, ali nazivi potprograma se razlikuju (najee se koriste termini funkcije, procedure, sabrutine ili metode ). Potprogrami izoluju odreena

le

izraunavanja koja se kasnije mogu pozivati tj. koristiti na vie razliitih mesta
u razliitim kontekstima.

Tako je, na primer, u jeziku C mogue definisati

funkciju kojom se izraunava najvei zajedniki delilac (NZD) dva broja, a


kasnije tu funkciju iskoristiti na nekoliko mesta da bi se izraunao NZD razliitih parova brojeva.

int nzd(int a, int b) { ... }


...
x = nzd(1234, 5678);
y = nzd(8765, 4321);
4 Ovo

tvrenje je poznato kao teorema o strukturnom programiranju, Korado Bema

(nem. Corrado Bhm) i uzepea Jakopinija (it. Giuseppe Jacopini) iz 1966.

86

4. Vii programski jezici

Primetimo da su potprogrami obino parametrizovani tj. mogu da primaju


ulazne parametre (kae se i argumente ). Postoje razliiti naini prenosa parametara u potprograme.

Na primer, u nekim sluajevima (tzv. prenos po vred-

nosti ) funkcija dobija svoju kopiju parametra navedenog u pozivu i sve vreme
barata kopijom, ostavljajui originalni parametar nepromenjen. U nekim sluajevima (tzv. prenos po adresi ), parametar se ne kopira ve se u funkciju prenosi
samo memorijska adresa na kojoj se parametar nalazi i funkcija sve vreme

(2
01
5)

barata originalnim parametrom.

Potprogrami imaju i mogunost vraanja vrednosti izraunavanja pozi-

vaocu. Neki jezici (npr. Pascal) sutinski razlikuju funkcije koje izraunavaju
(i kae se vraaju ) neku vrednost i procedure iji je zadatak samo da proizvedu

odreeni sporedni efekat (npr. da ispiu neto na ekran ili da promene vrednost
promenljive).

Modularnost podrazumeva razbijanje veeg programa na neza-

je

Modularnost.

visne celine. Celine, koje sadre definicije srodnih podataka i funkcija, obino

an

se nazivaju biblioteke (engl. library) i smetaju se u posebne datoteke. Ovim


se postie lake odravanje kompleksnih sistema, kao i mogunost viestruke

upotrebe pojedinih modula u okviru razliitih programa. Celine se obino zasebno prevode i kasnije povezuju u jedinstven program.

iz

Programski jezici obino imaju svoje standardne biblioteke (engl. standard


library) koje sadre funkcije esto potrebne programeru (npr. funkciju za izrau-

sk
o

navanje duine niske karaktera). esto se kd funkcija standardne biblioteke


statiki povezuju sa programom (tj. ukljuuje se u izvrni kd programa).
Osim standardne biblioteke, programske jezike esto karakterie i rantajm

biblioteka (engl. runtime library)

koja predstavlja sponu izmeu kompila-

ro
n

tora (tj. izvrnih programa koje on generie) i operativnog sistema. Funkcije


rantajm biblioteke se ne ukljuuju u izvrni kd programa ve se dinamiki
pozivaju tokom izvravanja programa (i zato, da bi program mogao da se izvri

kt

na nekom operativnom sistemu, neophodno je da na njemu bude instalirana


rantajm biblioteka za taj programski jezik).

le

Upravljanje memorijom.

Neki programski jezici (na primer C, C++) za-

htevaju od programera da eksplicitno rukuje memorijom tj. da od sistema zahteva memoriju u trenutku kada je ona potrebna i da tu memoriju eksplicitno
oslobaa, tj. vraa sistemu kada ona programu vie nije potrebna. Drugi programski jezici (na primer, Java, C#, Haskell, ML) oslobaaju programera ove
dunosti time to koriste tzv. sakupljae otpada (engl. garbage collector) iji je
zadatak da detektuju memoriju koju program ne koristi i da je oslobaaju. Iako
je programiranje u jezicima sa sakljupljaima otpada jednostavnije, programi
su obino sporiji (jer odreeno vreme odlazi na rad sakupljaa otpada).
U cilju obezbeivanja pogodnog naina da se hardverom upravlja, neki
programski jezici doputaju programeru da pristupi proizvoljnoj memorijskoj
adresi (npr. u jeziku C, to se moe raditi korienjem pokazivaa), ime se dobija

87

4. Vii programski jezici

vea sloboda, ali i mnogo vea mogunost pravljenja greaka. Sa druge strane,
neki programski jezici imaju za cilj skrivanje svojstava hardvera od programera, tite memoriju od direktnog pristupa programera i doputaju korienje
podataka samo u okviru memorije zauzete promenljivim programa.

Jeziki procesori

(2
01
5)

4.4.1

Jeziki procesori (ili programski prevodioci) su programi ija je uloga da


analiziraju leksiku, sintaksiku i (donekle) semantiku ispravnost programa
vieg programskog jezika

i da na osnovu ispravnog ulaznog programa vieg

programskog jezika generiu kd na mainskom jeziku (koji odgovara polaznom

programu, tj. vri izraunavanje koje je opisano na viem programskom jeziku).


Da bi konstrukcija jezikih procesora uopte bila mogua, potrebno je imati pre-

cizan opis leksike i sintakse, ali i to precizniji opis semantike vieg programskog

je

jezika.

U zavisnosti od toga da li se ceo program analizira i transformie u main-

an

ski kd pre nego to moe da se izvri, ili se analiza i izvravanje programa


obavljaju naizmenino deo po deo programa (na primer, naredba po naredba),

Kompilatori (ili kompajleri) su programski prevodioci kod ko-

iz

Kompilatori.

jeziki procesori se dele u dve grupe: kompilatore i interpretatore.

jih su faza prevoenja i faza izvravanja programa potpuno razdvojene.


Nakon analize izvornog kda programa vieg programskog jezika, kompi-

sk
o

latori generiu izvrni (mainski) kd i dodatno ga optimizuju, a zatim


uvaju u vidu izvrnih (binarnih) datoteka . Jednom sauvani mainski
kd mogue je izvravati neogranien broj puta, bez potrebe za ponovnim
Krajnjim korisnicima nije neophodno dostavljati izvorni

ro
n

prevoenjem.

kd programa na viem programskom jeziku, ve je dovoljno distribuirati

izvrni mainski kd .

Jedan od problema u radu sa kompilatorima je

da se prevoenjem gubi svaka veza izmeu izvrnog i izvornog kda pro-

kt

grama. Svaka (i najmanja) izmena u izvornom kdu programa zahteva


ponovno prevoenje programa ili njegovih delova. S druge strane, kom-

le

pilirani programi su obino veoma efikasni.

Interpretatori.

Interpretatori su programski prevodioci kod kojih su faza

prevoenja i faza izvravanja programa isprepletane. Interpretatori analiziraju deo po deo (najee naredbu po naredbu) izvornog kda programa
i odmah nakon analize vre i njegovo izvravanje. Rezultat prevoenja
se ne smeta u izvrne datoteke, ve je prilikom svakog izvravanja neophodno iznova vriti analizu izvornog kda. Zbog ovoga, programi koji
se interpretiraju se obino izvravaju znatno sporije nego u sluaju kompilacije. S druge strane, razvojni ciklus programa je eto krai ukoliko

5 Ipak,

ne samo u akademskom okruenju, smatra se da je veoma poeljno da se uz

izvrni distribuira i izvorni kd programa (tzv. softver otvorenog kda, engl. open source) da
bi korisnici mogli da vre modifikacije i prilagoavanja programa za svoje potrebe.

88

4. Vii programski jezici

se koriste interpretatori.

Naime, prilikom malih izmena programa nije

potrebno iznova vriti analizu celokupnog kda.


Za neke programske jezike postoje i interpretatori i kompilatori. Intepretator se tada koristi u fazi razvoja programa da bi omoguio interakciju korisnika
sa programom, dok se u fazi eksploatacije kompletno razvijenog i istestiranog
programa koristi kompilator koji proizvodi program sa efikasnim izvravanjem.

(2
01
5)

Danas se esto primenjuje i tehnika kombinovanja kompilatora i interpreta-

tora. Naime, kd sa vieg programskog jezika se prvo kompilira u neki precizno

definisan meujezik niskog nivoa (ovo je obino jezik neke apstraktne virtuelne
maine), a zatim se vri interpretacija ovog meujezika i njegovo izvravanje

na konkretnom raunaru. Ovaj pristup primenjen je kod programskog jezika


Java, kod .Net jezika (C#, VB), itd.

Ukoliko je raspoloiv kd nekog programa na nekom viem pro-

an

Pitanje 4.1.

je

Pitanja i zadaci za vebu

gramskom jeziku (na primer, na jeziku C), da li je mogue jednoznano konstruisati odgovarajui mainski kd? Ukoliko je raspoloiv mainski kd nekog

programa, da li je mogue jednoznano konstruisati odgovarajui kd na jeziku

Pitanje 4.2.

iz

C?

Za koji programski jezik su izgraeni prvi interpretator i kompi-

sk
o

lator i ko je bio njihov autor? Koji su najkorieniji programski jezici 1960-ih,


koji 1970-ih, koji 1980-ih i 1990-ih, a koji danas? ta je to strukturno, a ta
objektno-orijentisano programiranje?
Koje su najznaajnije programske paradigme? U koju paradigmu

ro
n

Pitanje 4.3.

spada programski jezik C? ta su to proceduralni, a ta su to deklarativni jezici?

Pitanje 4.4.

ta je rezultat leksike analize programa? ta leksiki analizator

kt

dobija kao svoj ulaz, a ta vraa kao rezultat svog rada? ta je zadatak sintaksike analize programa? ta sintaksiki analizator dobija kao svoj ulaz, a ta

le

vraa kao rezultat svog rada?

Pitanje 4.5.

Navesti primer leksiki ispravnog, ali sintaksiki neispravnog dela

programa. Navesti primer sintaksiki ispravnog, ali semantiki neispravnog dela


programa.

Pitanje 4.6.

ta karakterie svaki tip podataka? Da li su tipovi prisutni i u

prevedenom, mainskom kdu?

ta je to konverzija tipova?

ta znai da je

programski jezik statiki, a ta znai da je dinamiki tipiziran?

Pitanje 4.7.

Koje su osnovne naredbe u programskim jezicima?

GOTO naredba i po emu je ona specifina?

ta je to

89

4. Vii programski jezici

Pitanje 4.8.

emu slue potprogrami? Koji su najee vrste potprograma?

emu slue parametri potprograma, a emu slui povratna vrednost? Koji su


najei naini prenosa parametara?

Pitanje 4.9.

ta podrazumeva modularnost programa? emu slue biblioteke?

ta je standardna, a ta rantajm biblioteka?


ta su prednosti, a ta mane mogunosti pristupa proizvoljnoj

memoriji iz programa? ta su sakupljai otpada?

Pitanje 4.11.

(2
01
5)

Pitanje 4.10.

ta je kompilator, a ta interpretator? Koje su osnovne pred-

nosti, a koje su mane korienja kompilatora u odnosu na korienje interpretatora?

Pitanje 4.12.

Ako se koristi kompilator, da li je za izvravanje programa ko-

risniku neophodno dostaviti izvorni kd programa? Ako se koristi interpretator,

je

da li je za izvravanje programa korisniku neophodno dostaviti izvorni kd pro-

le

kt

ro
n

sk
o

iz

an

grama?

le

E
ro
n

kt
sk
o
d

iz
an

Jezik C

90

je

(2
01
5)

Deo II

(2
01
5)

Glava 5

je

Osnovno o programskom jeziku C


Programski jezik C je programski jezik opte namene koji je 1972. godine

1 u Belovim telefonskim laboratorijama (engl. Bell Telephone

an

razvio Denis Rii

Laboratories) u SAD. Ime C dolazi od injenice da je jezik nastao kao naslednik

jezika B (a koji je bio pojednostavljena verzija jezika BCPL). C je jezik koji


je bio namenjen prevashodno pisanju sistemskog softvera i to u okviru opera-

iz

tivnog sistema Unix. Meutim, vremenom je poeo da se koristi i za pisanje


aplikativnog softvera na velikom broju drugih platformi. C je danas prisutan

sk
o

na irokom spektru platformi od mikrokontrolera do superraunara. Jezik


C je uticao i na razvoj drugih programskih jezika (najznaajniji od njih je jezik
C++ koji se moe smatrati proirenjem jezika C).
Jezik C spada u grupu imperativnih, proceduralnih programskih jezika.

ro
n

Kako je izvorno bio namenjen za sistemsko programiranje, programerima nudi


prilino direktan pristup memoriji i konstrukcije jezika su tako osmiljene da
se jednostavno prevode na mainski jezik. Zahvaljuju tome, u C-u se relativno

kt

jednostavno kreiraju programi koji su ranije uglavnom pisani na asemblerskom


jeziku.

Jezik je kreiran u minimalistikom duhu ima mali broj kljunih

rei, a dodatna funkcionalnost programerima se nudi uglavnom kroz korienje

le

(standardizovanih) bibliotekih funkcija (na primer, ne postoje naredbe jezika

kojima bi se uitavali podaci sa tastature raunara ili ispisivali na ekran, ve


se ovi zadaci izvravaju pozivanjem funkcija iz standardne biblioteke).
U razvoju jezika C se od samog poetka insistiralo na standardizaciji i

prenosivosti kda (tzv. portabilnosti), zahvaljujui emu se isti programi na


C-u mogu koristiti (tj. prevoditi) na razliitim platformama.

5.1 Standardizacija jezika


Postoji nekoliko znaajnih neformalnih i formalnih standarda jezika C:

1 Dennis

Ritchie

(19412011),

ameriki

informatiar,

1983. godine.

91

dobitnik

Tjuringove

nagrade

92

5. Osnovno o programskom jeziku C

K&R C.

Brajan Kerningen

2 i Denis Rii objavili su 1978. godine prvo izdanje

knjige Programski jezik C (The C Programming Language). Ova knjiga,


meu programerima obino poznata kao K&R ili kao white book, godinama je sluila kao neformalna specifikacija jezika.

ak i posle pojave

novih standarda, K&R je dugo vremena sluio kao najmanji zajedniki


imenilac koji je korien kada je bilo potrebno postii visok stepen prenosivosti, jer su konstrukte opisane u prvoj verziji K&R knjige uglavnom

ANSI C i ISO C.

(2
01
5)

podravali svi C prevodioci.

Tokom 1980-ih godina, C se proirio na veliki broj het-

erogenih platformi i time se javila potreba za zvaninom standardizacijom jezika. Godine 1989. ameriki nacionalni institut za standardizaciju

(ANSI) objavio je standard pod zvaninim nazivom ANSI X3.159-1989

Programming Language C . Ova verzija jezika C se obino jednostavnije

je

naziva ANSI C ili C89. Godine 1990. Meunarodna organizacija za standardizaciju (ISO) usvojila je ovaj dokument (uz sitnije izmene) pod oz-

an

nakom ISO/IEC 9899:1990 ime je briga o standardizaciji jezika C prela


od amerikog pod meunarodno okrilje.

Ova verzija jezika se ponekad

naziva i C90, pa C89 i C90 predstavljaju isti jezik. Ovaj jezik predstavlja

nadskup K&R jezika C i ukljuuje mnoge konstrukte do tada nezvanino

C99.

iz

podrane od strane velikog broja prevodilaca.


Godine 1999. usvojen je novi standard jezika C ISO/IEC 9899:1999,

sk
o

poznat pod kraim imenom C99.

Ovaj standard uveo je sitne izmene

u odnosu na prethodni i uglavnom proirio jezik novim konstruktima, u


velikoj meri inspirisanim modernim programskim jezicima kakav je C++.
Godine 2007. zapoet je rad na novom standardu jezika

ro
n

C11 (nekada C1X).

C koji je zavren 2011. godine i objavljen kao ISO/IEC 9899:2011. Ovaj,


sada tekui standard, ozvaniio je neka svojstva ve podrana od strane
popularnih kompilatora i precizno opisao memorijski model radi jasnije i

kt

bolje podrke tzv. vienitnim izraunavanjima (kada se nekoliko izrau-

le

navanja u programu odvija paralelno).

U nastavku teksta uglavnom e biti razmatran ANSI C, pri emu e biti

uvedeni i neki konstrukti jezika C99 i C11 (uz jasnu naznaku da se radi o
dopunama).

Pitanja za vebu
Pitanje 5.1.1.

Kada je nastao programski jezik C? Ko je njegov autor? Za

koji operativni sistem se vezuje nastanak programskog jezika C?

Pitanje 5.1.2.
2 Brian

U koju grupu jezika spada C? Za ta se najvie koristi?

Kerninghan (1942), kanadsko-ameriki informatiar.

93

5. Osnovno o programskom jeziku C

Pitanje 5.1.3.

Koja je najpoznatija knjiga o jeziku C? Nabrojati sve zvanine

standarde jezika C.

5.2 Prvi programi


Jezik C deli mnoga svojstva sa drugim programskim jezicima, ali ima i svoje

(2
01
5)

specifinosti. U nastavku teksta jezik C bie prezentovan postupno, koncept


po koncept, esto iz opte perspektive programiranja i programskih jezika. Na

poetku, bie navedeno i prodiskutovano nekoliko jednostavnijih programa koji


ilustruju osnovne pojmove programskog jezika C.

Program Zdravo!

Prikaz jezika C bie zapoet programom koji na standardni izlaz ispisuje

Zdravo!.

Neki delovi programa e biti objanjeni samo povrno, a u

kasnijem tekstu e biti dat njihov detaljni opis.

an

Program 5.1.

je

poruku

#include <stdio.h>

sk
o

iz

int main() {
printf("Zdravo!\n"); /* ispisuje tekst */
return 0;
}
Navedeni program sastoji se iz definicije jedne funkcije i ona se zove

main

ro
n

(od engleskog main glavna, glavno). Program moe da sadri vie funkcija,
ali obavezno mora da sadri funkciju koja se zove

main

i izvravanje programa

uvek poinje od te funkcije. Prazne zagrade iza njenog imena ukazuju na to da

kt

se eventualni argumenti ove funkcije ne koriste. Re

int pre imena funkcije oz-

naava da ova funkcija, kao rezultat, vraa celobrojnu vrednost (engl. integer),
tj. vrednost tipa

int.
main

le

Naredbe funkcije

su grupisane izmeu simbola

{i}

(koji oznaavaju

poetak i kraj tela funkcije). Obe naredbe funkcije zavravaju se simbolom

;.

Kao to je ranije pomenuto, programi obino imaju vie funkcija i funkcija

main poziva te druge funkcije za obavljanje raznovrsnih podzadataka.

Funkcije

koje se pozivaju mogu da budu korisniki definisane (tj. napisane od strane istog programera koji pie program) ili biblioteke (tj. napisane od strane nekog
drugog tima programera). Odreene funkcije ine takozvanu standardnu bib-

lioteku programskog jezika C i njihov kd se obino isporuuje uz sam kompi-

main je poziv standardne biblioteke


printf koja ispisuje tekst na takozvani standardni izlaz (obino ekran).
Tekst koji treba ispisati se zadaje izmeu para znakova ", koji se ne ispisuju.
U ovom sluaju, tekst koji se ispisuje je Zdravo!. Ni znakovi \n se ne ispisuju,
lator. Prva naredba u navedenoj funkciji

funkcije

nego obezbeuju prelazak u novi red.

Da bi C prevodilac umeo da generie

94

5. Osnovno o programskom jeziku C

kd poziva funkcije

printf,

potrebno je da zna tip njene povratne vrednosti i

tipove njenih argumenata. Ovi podaci o funkciji

printf, njen svojevrsni opis,


stdio.h (ova datoteka

takozvana deklaracija, nalaze se u datoteci zaglavlja

ini deo standardne biblioteke zaduen za ulazno-izlaznu komunikaciju i deo je


instalacije prevodioca za C). Prva linija programa, kojom se prevodiocu saoptava da je neophodno da ukljui sadraj datoteke

stdio.h

je pretprocesorska

direktiva. To nije naredba C jezika, ve instrukcija C pretprocesoru koji pred-

stdio.h.
return 0; prekida izvravanje funkcije main i, kao njen rezultat,
vrednost 0. Vrednost funkcije vraa se u okruenje iz kojeg je ona poz-

umesto prve linije upisuje celokupan sadraj datoteke


Naredba
vraa

(2
01
5)

stavlja nultu fazu kompilacije i koji pre kompilacije program priprema tako to

vana, u ovom sluaju u okruenje iz kojeg je pozvan sm program. Uobiajena


konvencija je da se iz funkcije

main

vraa vrednost

da ukae na to da je

izvravanje proteklo bez problema, a ne-nula vrednost da ukae na problem ili


Tekst naveden izmeu simbola

/*

i simbola

je

greku koja se javila tokom izvravanja programa.

*/

predstavlja komentare. Oni

an

su korisni samo programerima, doprinose itljivosti i razumljivosti samog programa. Njih C prevodilac ignorie i oni ne utiu na izvrnu verziju programa.
Primetimo da je svaka naredba u prikazanom programu pisana u zaseb-

nom redu, pri emu su neki redovi uvueni u odnosu na druge. Naglasimo da

iz

sa stanovita C prevodioca ovo nije neophodno (u ekstremnom sluaju, doputeno bi bilo da je ceo kd osim prve linije naveden u istoj liniji). Ipak, smatra
se da je nazubljivanje (engl. indentation) kda u skladu sa njegovom sintak-

sk
o

sikom strukturom nezaobilazna praksa. Naglasimo i da postoje razliiti stilovi


nazubljivanja (na primer, da li otvorena vitiasta zagrada poinje u istom ili
sledeem redu).

Meutim, obino se smatra da nije bitno koji se stil koristi

ro
n

dok god se koristi na uniforman nain.


Ukoliko se, na primer, koristi GCC prevodilac (to je est sluaj pod operativnim sistemom Linux), izvorni program , poput navedenog programa (unet u
nekom editoru teksta i sauvan u datoteci), moe se prevesti u izvrni program

kt

tako to se u komandoj liniji navodi:

gcc -o ime_izvrsnog_koda ime_izvornog_koda


zdravo.c, a eljeno ime
izvrnog programa je zdravo, potrebno je uneti tekst:
gcc -o zdravo zdravo.c
U tom sluaju, izvrni program pokree se sa ./zdravo. Ako se ime izvrnog
3
programa izostavi, podrazumeva se ime a.out .

le

Na primer, ako je izvorni kd sauvan u datoteci

Nakon pokretanja programa dobija se sledei izlaz.

Zdravo!
Tokom prevoenja, prevodilac moe da detektuje greke (engl. error) u
izvornom programu. Tada prevodilac ne generie izvrni program nego izve-

3 Razlog za ovo je istorijski a.out je skraeno za assembler output jer je izvrni program
obino bio izlaz nakon faze asembliranja.

95

5. Osnovno o programskom jeziku C

tava programera o vrsti tih greaka i brojevima linija u kojima se nalaze. Programer, na osnovu tog izvetaja, treba da ispravi greke u svom programu i
ponovi proces prevoenja.

Pored greaka, prevodilac moe da prijavi i up-

ozorenja (engl. warning) za mesta u programu koja ukazuju na potencijalne


propuste u programu.

Ako u prevoenju ne postoje greke ve samo upo-

zorenja, generie se izvrni program, ali on se moda nee ponaati na eljeni


nain, te treba biti oprezan sa njegovim korienjem. Vie rei o grekama i

(2
01
5)

upozorenjima bie u poglavlju 9.2.5.

Program koji ispisuje kvadrat unetog celog broja

Prethodni program nije uzimao u obzir nikakve podatke koje bi uneo korisnik, ve je prilikom svakog pokretanja davao isti izlaz.

Naredni program

oekuje od korisnika da unese jedan ceo broj i onda ispisuje kvadrat tog broja.

je

Program 5.2.

an

#include <stdio.h>

sk
o

iz

int main() {
int a;
printf("Unesite ceo broj: ");
scanf("%i", &a);
printf("Kvadrat unetog broja je: %i", a*a);
return 0;
}
main je takozvana deklaracija promenljive. Ovom deklaa celobrojnog tipa tipa int. Naredna naredba
(poziv funkcije printf) na standardni izlaz ispisuje tekst Unesite ceo broj:,
a naredba nakon nje (poziv funkcije scanf) omoguava uitavanje vrednosti

ro
n

Prva linija funkcije

kt

racijom se uvodi promenljiva

neke promenljive sa standardnog ulaza (obino tastature).


funkcije

scanf

le

sluaju treba proitati podatak tipa

%i.

U okviru poziva

zadaje se format u kojem e podatak biti proitan u ovom

int i format se u tom sluaju zapisuje kao

Nakon formata, zapisuje se ime promenljive u koju treba upisati proi-

& govori da e promenljiva a biti promenjena u funkciji


scanf, tj. da e proitani broj biti smeten na adresu promenljive a. Korienjem funkcije printf, pored fiksnog teksta, moe se ispisati i vrednost neke

tanu vrednost. Simbol

promenljive ili izraza. U formatu ispisa, na mestu u tekstu gde treba ispisati
vrednost izraza zapisuje se format tog ispisa u ovom sluaju

%i4 ,

jer e biti

ispisana celobrojna vrednost. Nakon niske koja opisuje format, navodi se izraz
koji treba ispisati u ovom sluaju vrednost

4 Umesto %i,
podatak tipa

a*a,

potpuno ravnopravno mogue je koristiti i

int,

%d

jer je u dekadnom brojevnom sistemu.

tj. kvadrat broja koji je

%d. %i

dolazi od toga to je

96

5. Osnovno o programskom jeziku C

korisnik uneo. Nakon prevoenja i pokretanja programa, korisnik unosi broj,


a zatim se ispisuje njegov kvadrat. Na primer,

(2
01
5)

Unesite ceo broj: 5


Kvadrat unetog broja je: 25

Program koji izraunava rastojanje izmeu taaka

Sledei primer prikazuje program koji rauna rastojanje izmeu dve take

u dekartovskoj ravni. Osnovna razlika u odnosu na prethodne programe je to

se koriste razlomljeni brojevi, tj. brojevi u pokretnom zarezu. Dakle, u ovom

int

programu, umesto promenljivih tipa

koriste se promenljive tipa

double,
%lf

dok se prilikom uitavanja i ispisa ovakvih vrednost za format koristi niska

sqrt

%i.

Dodatno, za raunanje kvadratnog korena koristi se funkcija

deklarisana u zaglavlju

math.h.

an

Program 5.3.

je

umesto niske

iz

#include <stdio.h>
#include <math.h>

kt

ro
n

sk
o

int main() {
double x1, y1, x2, y2;
printf("Unesi koordinate prve tacke: ");
scanf("%lf%lf", &x1, &y1);
printf("Unesi koordinate druge tacke: ");
scanf("%lf%lf", &x2, &y2);
printf("Rastojanje je: %lf\n",
sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)));
return 0;
}

le

Nakon unosa podataka, traeno rastojanje se rauna primenom Pitagorine

teoreme

(2 1 )2 + (2 1 )2 .

Poto u jeziku C ne postoji operator ste-

penovanja, kvadriranje se sprovodi mnoenjem.


Za prevoenje programa koji koriste matematike funkcije, prilikom ko-

rienja GCC prevodioca potrebno je navesti argument

-lm

(kao poslednji ar-

gument). Na primer,

gcc -o rastojanje rastojanje.c -lm


Nakon uspenog prevoenja i pokretanja programa korisnik unosi podatke

i ispisuje se rezultat. Na primer,

Unesi koordinate prve tacke: 0.0 0.0


Unesi koordinate druge tacke: 1.0 1.0
Rastojanje je: 1.414214

97

5. Osnovno o programskom jeziku C

Program koji ispituje da li je uneti broj paran


Naredni program ispituje da li je uneti broj paran.

Program 5.4.
#include <stdio.h>

an

je

(2
01
5)

int main() {
int a;
printf("Unesi broj: ");
scanf("%d", &a);
if (a % 2 == 0)
printf("Broj %d je paran\n", a);
else
printf("Broj %d je neparan\n", a);
return 0;
}

Ceo broj je paran ako i samo ako je ostatak pri deljenju sa dva jednak nuli.

==.

%,

dok se poreenje jednakosti

Operator ispitanja jednakosti (==) i operator dodele (=) se

sutinski razlikuju. Naredba

if

iz

vri operatorom

Ostatak pri deljenju se izraunava operatorom

je naredba grananja kojom se u zavisnosti od

toga da li je navedeni uslov (u ovom sluaju

a % 2 == 0) ispunjen usmerava
() iza kojih ne sledi simbol

;.

sk
o

tok programa. Uslov se uvek navodi u zagradama

U sluaju da je uslov ispunjen, izvrava se prva naredba navedena nakon

uslova (takozvana

then grana), dok se u sluaju da uslov nije ispunjen izvrava,


else (takozvana else grana). I

ukoliko postoji, naredba navedena nakon rei

ro
n

then i else grana mogu da sadre samo jednu naredbu ili vie naredbi.

Ukoliko

sadre vie naredbi, onda te naredbe ine blok iji se poetak i kraj moraju

{ i }.

Grana

else

ne mora da postoji.

kt

oznaiti zagradama

le

Program koji ispisuje tablicu kvadrata i korena


Naredni program ispisuje kvadrate i korene svih celih brojeva od 1 do 100.

Program 5.5.
#include <stdio.h>
#include <math.h>
#define N 100
int main() {
int i;
for (i = 1; i <= N; i++)
printf("%3d %5d %7.4f\n", i, i*i, sqrt(i));

98

5. Osnovno o programskom jeziku C

return 0;

Novina u ovom programu, u odnosu na prethodne, je petlja

for

koja slui

da se odreene naredbe ponove vie puta (obino uz razliite vrednosti promenljivih). Petlja se izvrava tako to se prvo izvri inicijalizacija promenljive
na vrednost 1 (zahvaljujui kdu

promenljive

i=1),

u svakom koraku petlje se vrednost

uveava za 1 (zahvaljujui kdu

vrednost promenljive

i++)

i sve to se ponavlja dok

i <= N). Pre preN menja se brojem 100 i to zahvaljujui tzv. pret#define N 100 koja se esto koristi za definisanje konne postane

(zahvaljujui uslovu

voenja programa vrednost


procesorskoj direktivi

(2
01
5)

stantnih parametara u programima (efekat je isti kao da je u petlji stajalo

for (i = 1; i <= 100; i++),

meutim, gornja granica je jasno izdvojena

na poetku programa i lake se moe uoiti i promeniti.

O petljama e biti

vie rei u glavi 7, a o pretprocesoru e biti vie rei u poglavlju 9.2.1.

printf.

izmeu 1 i 100 izvrava se telo petlje

je

Za svaku vrednost promenljive


naredba

U okviru format niske se, umesto

%d,

koristi

%3d,

ime se

%7.4f,

an

postie da se broj uvek ispisuje u polju irine 3 karaktera. Slino se, korienjem
postie da se vrednost korena ispisuje na 4 decimale u polju ukupne

iz

irine 7 karaktera.

Program koji ispituje zbir prvih prirodnih brojeva.

sk
o

Naredni program ispisuje prvi prirodni broj za koji je zbir svih prirodnih
brojeva do tog broja vei od 100.

Program 5.6.

ro
n

#include <stdio.h>

kt

#define N 100

le

int main() {
int i = 1;
int s = 1;
while(s <= N) {
i++;
s = s+i;
}
printf("%d\n", i);
return 0;
}

while koja se
int i = 1; je deklaracija
sa inicijalizacijom njom se promenljvoj i dodeljuje inicijalna vrednost 1. Kao
Novina u ovom programu, u odnosu na prethodne, je petlja

izvrava sve dok je ispunjen zadati uslov. Deklaracija

99

5. Osnovno o programskom jeziku C

100 u
N uvedeno pretprocesorskom direktivom.

i u prethodnom programu, fleksibilnosti radi, umesto fiksne vrednost


uslovu petlje koristi se simboliko ime

Program koji prevodi mala u velika slova.


Naredni program na standardni izlaz prepisuje reenicu koja se unosi na

(2
01
5)

standardni ulaz, zamenjujui pri tom sva mala slova velikim.

Program 5.7.

sk
o

iz

an

je

#include <stdio.h>
#include <ctype.h>
int main() {
int c;
printf("Otkucaj recenicu (zavrsi je znakom .): ");
do {
c = getchar();
putchar(toupper(c));
} while (c != .);
putchar(\n);
return 0;
}
Kada se pokrene program, dobija se ovakav rezultat.

ro
n

Otkucaj recenicu (zavrsi je znakom .): Ovo je C program.


OVO JE C PROGRAM.
getchar koja uitava karakter sa standardc), funkcija toupper koja prevodi mala
u velika slova (a ne menja argument ako nije malo slovo) i funkcija putchar
koja ispisuje karakter na standardni izlaz. Da bi se koristile funkcije getchar i
putchar potrebno je ukljuiti zaglavlje <stdio.h>, a da bi se koristila funkcija
toupper potrebno je ukljuiti zaglavlje <ctype.h>. U programu je koriena
petlja do-while ije se telo uvek izvrava bar jednom i u kojoj se provera uslova
petlje vri na kraju (za razliku od petlje while u kojoj se uslov proverava na
U programu se koristi funkcija

le

kt

nog ulaza (i smeta ga promenljivu

poetku petlje i telo petlja ne mora da se izvri ni jednom).


izvrava sve dok je uitani i prepisani karakter

Telo petlje se

razliit od take. Pri tome,

unetni tekst (sa velikim slovima umesto malim) se ispisuje uvek kada se pritisne
taster za unos (enter ). Kada se unese i prepie taka, tada se petlja zavrava.

Pitanja i zadaci za vebu


Pitanje 5.2.1.

Funkciju kojeg imena mora da sadri svaki C program?

100

5. Osnovno o programskom jeziku C

Pitanje 5.2.2.

ta su to pretprocesorske direktive? Da li je

#include<stdio.h>

pretprocesorska direktiva, naredba C-a ili poziv funkcije iz standardne biblioteke?


ta su to datoteke zaglavlja?

Pitanje 5.2.4.

ta je standardna biblioteka programskog jezika?

Pitanje 5.2.5.

Kojom naredbom se vraa rezultat funkcije u okruenje iz kojeg

je ona pozvana?

Zadatak 5.2.1.

Napisati program koji za uneti poluprenik

i povrinu kruga (za broj

Zadatak 5.2.2.

koristiti konstantu

M_PI

i veliine dva preostala ugla

sin()

i . Napomena: koristiti
cos() iz zaglavlja math.h
.

Zadatak 5.2.4.

iz

Napisati program koji za unetu brzinu u

varajuu brzinu u .

Zadatak 5.2.5.

ispisuje odgo

0 , ubrzanje
tela koje se kree

sk
o

Napisati program koji za unetu poetnu brzinu

izraunava trenutnu brzinu

i preeni put

ravnomerno ubrzano.

ro
n

Napisati program koji za unetih 9 brojeva

2
5
8

1 , 2 , . . . , 9

izrau-

3
6
9

le

kt

nava determinantu:

Napisati program koji ispisuje maksimum tri uneta broja.

Zadatak 5.2.8.

Napisati program koji uitava cele brojeve

Zadatak 5.2.7.

je zadat u stepenima) izraunava

an

( > 0

sinusnu i/ili kosinusnu teoremu i funkcije

Zadatak 5.2.6.

je

i ugla izmeu njih

duinu tree stranice

math.h).

Napisati program koji za unete dve duine stranica trougla

( > 0, > 0)

i vreme

izraunava obim

Napisati program koji za unete koordinate temena trougla

Zadatak 5.2.3.

iz zaglavlja

izraunava njegov obim i povrinu.

(2
01
5)

Pitanje 5.2.3.

sve kubove brojeva izmeu njih.

i i zatim ispisuje

(2
01
5)

Glava 6

an

je

Predstavljanje podataka i
operacije nad njima
u programu.

Tipovi promenljivih,

koje su osnovni oblici podataka kojima se operie

iz

Promenljive i konstante,

U ovoj glavi bie opisani naredni pojmovi:

koji odreuju vrstu podataka koje promenljive mogu

sk
o

da sadre, nain reprezentacije i skup vrednosti koje mogu imati, kao i


skup operacija koje se sa njima mogu primeniti.
koje uvode spisak promenljivih koje e se koristiti, odreuju kog

ro
n

Deklaracije,

su tipa i, eventualno, koje su im poetne vrednosti.

Operatori,

odgovaraju operacijama koje su definisane nad podacima odreene

kt

vrste.

Izrazi,

koji kombinuju promenljive i konstante (korienjem operatora), dajui

le

nove vrednosti.

6.1 Promenljive i deklaracije


Promenljive su osnovni objekti koji se koriste u programima. Svaka promen-

ljiva mora biti deklarisane pre korienja.

6.1.1

Promenljive i imena promenljivih

Promenljiva je objekat kojem je pridruen neki prostor u memoriji i u


svakom trenutku svog postojanja ima vrednost kojoj se moe pristupiti
koja se moe proitati i koristiti, ali i koja se (ukoliko nije traeno drugacije)
moe menjati.

101

102

6. Predstavljanje podataka i operacije nad njima

Imena promenljivih (ali i funkcija, struktura, itd.) odreena su identifika-

a,
i, x1, x2 itd. Generalno, identifikator moe da sadri slova i cifre, kao i simbol
_ (koji je pogodan za duga imena), ali identifikator ne moe poinjati cifrom.
Dodatno, kljune rei jezika C (na primer, if, for, while) ne mogu se koristiti
torima . U prethodnim programima koriene su promenljive ija su imena

kao identifikatori.
U identifikatorima, velika i mala slova se razlikuju. Na primer, promenljive

se tretiraju kao dve razliite promenljive.

esta praksa je

(2
01
5)

sa imenima

da malim slovima poinju imena promenljivih i funkcija, a velikim imena simbolikih konstanti (vidi poglavlja o nabrojivim tipovima 6.7.4 i pretprocesoru
9.2.1), vrednosti koje se ne menjaju u toku programa.

Imena promenljivih i funkcija, u principu, treba da oslikavaju njihovo zna-

enje i ulogu u programu, ali za promenljive kao to su indeksi u petljama


se obino koriste kratka, jednoslovna imena (na primer

i).

Ako ime promen-

je

ljive sadri vie rei, onda se, radi bolje itljivosti, te rei razdvajaju sim-

_ (na primer, broj_studenata) ili poetnim velikim slovima (na primer,


brojStudenata) ovo drugo je takozvana kamilja notacija (CamelCase). Pos-

an

bolom

toje razliite konvencije za imenovanje promenljivih. U nekim konvencijama,


kao to je maarska notacija, poetna slova imena promenljivih predstavljaju

kratku oznaka tipa te promenljive (na primer,

iBrojStudenata).1

_,

iz

Iako je dozvoljeno, ne preporuuje se korienje identifikatora koji poinju


simbolom

jer se oni obino koriste za sistemske funkcije i promenljive.

ANSI C standard (C89) garantuje da se barem 31 poetnih znakova imena

sk
o

promenljive smatra znaajnom, dok standard C99 poveava taj broj na 63.
Ukoliko dve promenljive imaju vie od 63 poetna znaka ista, onda se ne garan-

6.1.2

ro
n

tuje da e te dve promenljive biti razlikovane.

Deklaracije

3 sadri

kt

Sve promenljive moraju biti deklarisane pre korienja. Deklaracija

tip i listu od jedne ili vie promenljivih tog tipa, razdvojenih zarezima.

/* deklaracija celog broja


*/
/* deklaracija vise celih brojeva */

le

int broj;
int a, b;

U optem sluaju nije propisano koju vrednost ima promenljiva neposredno

nakon to je deklarisana . Prilikom deklaracije moe se izvriti poetna inicijalizacija. Mogue je kombinovati deklaracije sa i bez inicijalizacije.

1 Postoje

argumenti protiv korienja takve notacije u jezicima u kojima kompilatori vre

proveru korektnosti tipova.

2 Za takozvane spoljanje promenljive ove vrednosti su 6 (C89) odnosno 31


3 Deklaracije promenljivih najee su ujedno i definicije. Odnos izmeu

(C99).
deklaracija i

definicija promenljivih u jeziku C veoma je suptilan i bie razmotren u glavi 9.

4 Samo

u nekim specijalnim sluajevima (koji e biti diskutovani u daljem tekstu), po-

drazumevana vrednost je 0.

103

6. Predstavljanje podataka i operacije nad njima

int vrednost = 5;
/* deklaracija sa inicijalizacijom */
int a = 3, b, c = 5; /* deklaracije sa inicijalizacijom */
Izraz kojim se promenljiva inicijalizuje zvaemo inicijalizator.

const

Kvalifikator

(dostupan u novijim standardima jezika C) moe biti

dodeljen deklaraciji promenljive da bi naznaio i obezbedio da se njena vrednost

/* ovu promenljivu nije moguce menjati */


const double GRAVITY = 9.81;
const

Kvalifikator

(2
01
5)

nee menjati, na primer:

mogue je navesti i nakon imena tipa.

double const GRAVITY = 9.81;

je

Izmeu ova dva naina navoenja kvalifikatora razlike postoje samo kod
glavama.

an

sloenijih tipova (pre svega pokazivaa) i o tome e biti vie rei u narednim

const T moe biti dodeljena promenljivoj tipa T, ali proconst T ne moe biti dodeljena vrednost (osim prilikom inici-

Vrednost tipa
menljivoj tipa

iz

jalizacije) pokuaj menjanja vrednosti konstantne promenljive (kao i svakog


drugog konstantog sadraja) dovodi do greke prilikom prevoenja programa.
Deklaracije promenljivih mogu se navoditi na razliitim mestima u pro-

sk
o

gramu. Najee se navode na poetku funkcije (u dosada navedenim primerima to je bila funkcija

main).

Ukoliko je promenljiva deklarisana u nekoj

funkciji, onda kaemo da je ona lokalna za tu funkciju i druge funkcije ne


Razliite funkcije mogu imati lokalne promenljive istog

ro
n

mogu da je koriste.

imena. Promenljive deklarisane van svih funkcija su globalne i mogu se koristiti u vie funkcija. Vidljivost tj. oblast vaenja identifikatora (i njima uvedenih
promenljivih) odreena je pravilima dosega identifikatora o emu e vie rei

kt

biti u poglavlju 9.2.2.

le

Pitanja i zadaci za vebu


Koji su osnovni oblici podataka kojima se operie u programu?

Pitanje 6.1.2.

Da li se promenljivoj moe menjati tip u toku izvravanja pro-

Pitanje 6.1.1.
grama?

Pitanje 6.1.3.

Da li ime promenljive moe poinjati simbolom

_?

Da li se

ovaj simbol moe koristiti u okviru imena?

Pitanje 6.1.4.

Da li ime promenljive moe poinjati cifrom? Da li se cifre

mogu koristiti u okviru imena?

Pitanje 6.1.5.

Koliko poetnih karaktera u imenu promenljive u jeziku C se

garantovano smatra bitnim?

104

6. Predstavljanje podataka i operacije nad njima

Pitanje 6.1.6.

ta je to inicijalizacija promenljive? U optem sluaju, ukoliko

celobrojna promenljiva nije inicijalizovana, koja je njena poetna vrednost?

Pitanje 6.1.7.

ta je uloga kvalifikatora

const?

6.2 Osnovni tipovi podataka

(2
01
5)

Kao i u veini drugih programskih jezika, u jeziku C podaci su organizovani


u tipove. To omoguava da se u programima ne radi samo nad pojedinanim
bitovima i bajtovima (tj. nad nulama i jedinicama), ve i nad skupovima bitova
koji su, pogodnosti radi, organizovani u sloenije podatke (na primer, cele

brojeve ili brojeve u pokretnom zarezu). Jedan tip karakterie: vrsta podataka

koje opisuje, nain reprezentacije, skup operacija koje se mogu primeniti nad
podacima tog tipa, kao i broj bitova koji se koriste za reprezentaciju (odakle

Tip

int

U jeziku C, cele brojeve opisuje tip

an

6.2.1

je

sledi opseg moguih vrednosti).

int

(od engleskog integer, ceo broj ).

Podrazumeva se da su vrednosti ovog tipa oznaene i reprezentuju se najee


metike operacije (na primer,

iz

koristei potpuni komplement. Nad podacima ovog tipa mogu se koristiti arit-

+, -, *, /, %),

<, >=) i druge.


int, ali je proVeliina tipa int

relacije (na primer,

Standardom nije propisano koliko bitova koriste podaci tipa

sk
o

pisano da se koristi najmanje esnaest bita (tj. dva bajta).

je obino prilagoena konkretnoj maini, tj. njenom procesoru. Na dananjim

int obino zauzimaju 32 ili 64 bita , tj. 4 ili 8 bajtova5 .


int mogu biti pridrueni kvalifikatori short, long i (od standarda
C99) long long.
Ovi kvalifikatori uvode cele brojeve potencijalno razliitih
duina u odnosu na int. Nije propisano koliko tipovi short int, long int i
long long int zauzimaju bitova, ali propisano je da short zauzima barem dva
bajta, da int zauzima barem onoliko bajtova koliko i short int, da long int
zauzima barem onoliko bajtova koliko int i da zauzima barem etiri bajta, a
da long long int zauzima barem onoliko koliko zauzima long int. Ime tipa
short int moe se krae zapisati short, ime tipa long int moe se krae
zapisati long, a ime tipa long long int moe se krae zapisati sa long long.
Bilo kojem od tipova short, int, long i long long mogu biti pridrueni
kvalifikatori signed ili unsigned. Kvalifikator unsigned oznaava da se broj

tretira kao neoznaen i da se sva izraunavanja izvravaju po modulu 2 , gde


je broj bitova koji tip koristi. Kvalifikator signed oznaava da se broj tretira

le

kt

Tipu

ro
n

raunarima, podaci tipa

kao oznaen i za njegovu reprezentaciju se najee koristi zapis u potpunom


komplementu. Ukoliko uz tip
kvalifikator

signed

short, int, long ili long long nije naveden ni


unsigned, podrazumeva se da je vrednost

ni kvalifikator

oznaen broj.

5 Kaemo

da veliina podataka zavisi od sistema, pri emu se pod sistemom podrazumeva

i hardver raunara i operativni sistem na kojem e se program izvravati.

105

6. Predstavljanje podataka i operacije nad njima

Podaci o opsegu ovih (i drugih tipova) za konkretan raunar i C prevodilac sadrani su u standardnoj datoteci zaglavlja

<limits.h>.

Pregled danas

najeih vrednosti (u tridesetdvobitnom okruenju) dat je u tabeli 6.1.


oznaeni (signed)

neoznaeni (unsigned)

karakteri

1B = 8b

1B = 8b

(char)

[-2 ,

27 -1]

[0,

28 -1]

[0, 255]

kratki

2B = 16b

2B = 16b

(short int)

[-32K, 32K-1] =

15

[-2

215 -1]

(2
01
5)

[-128, 127]

[0, 64K-1] =

[0,

216 -1]

[-32768, 32767]

[0, 65535]

dugi

4B = 32b

4B = 32b

(long int)

[-2G, 2G-1] =
,

231 -1]

[0, 4G-1] =

[0,

232 -1]

je

31

[-2

[0, 4294967295]

veoma dugi

8B = 64b

8B = 64b

(long long int)

[-2

263 -1] =
18
18
[-9.210 , 9.210 ]
,

[0,
[0,

264 -1] =
19
1.8410 ]

iz

od C99

63

an

[-2147483648,2147483647]

Slika 6.1: Najei opseg tipova (vai i na x86 + gcc platformi).

sk
o

Prilikom tampanja i uitavanja vrednosti celobrojnih tipova, u pozivu

printf ili scanf, potrebno je navesti i razliite formate


unsigned, %l za long), o emu e vie rei biti u glavi 12.

funkcije

(npr.

%u

za

ro
n

Konaan opseg tipova treba uvek imati u vidu jer iz ovog razloga neke
matematike operacije nee dati oekivane vrednosti (kaemo da dolazi do

prekoraenja .

Na primer, na tridesetdvobitnom sistemu, naredni program

kt

tampa negativan rezultat.

Program 6.1.

le

#include <stdio.h>

int main() {
int a = 2000000000, b = 2000000000;
printf("Zbir brojeva %d i %d je: %d\n", a + b);
return 0;
}
Zbir brojeva 2000000000 i 2000000000 je: -294967296
Da su promenljive bile deklarisane kao promenljive tipa

tampane korienjem formata

%u,

unsigned int

rezultat bi bio 4000000000 i bio bi ispravan

106

6. Predstavljanje podataka i operacije nad njima

i u klasinom matematikom smislu (u smislu sabiranja neogranienih celih


brojeva).

Program 6.2.
#include <stdio.h>

(2
01
5)

int main() {
unsigned int a = 2000000000, b = 2000000000;
printf("Zbir brojeva %u i %u je: %u\n", a, b, a + b);
return 0;
}

char
char

Male cele brojeve opisuje tip

simbol, znak).

an

Tip

(od engleskog character karakter,

I nad podacima ovog tipa mogu se primenjivati aritmetike


Podatak tipa

char zauzima tano jedan


char smatra oznaenim

iz

operacije i relacije.

6.2.2

je

Zbir brojeva 2000000000 i 2000000000 je: 4000000000

ne propisuje da li se podatak tipa

bajt.

Standard

ili neoznaenim

brojem (na nekom sistemu se moe smatrati oznaenim, a na nekom drugom

char mogu se
unsigned obezbeuje

unsigned i signed.

sk
o

se moe smatrati neoznaenim). Na tip


Kvalifikator

primeniti kvalifikatori
da se vrednost tretira

kao neoznaen broj, skup njegovih moguih vrednosti je interval od


sva izraunavanja nad podacima ovog tipa se izvravaju po modulu

signed

ro
n

Kvalifikator

0 do 255 i
28 = 256.

obezbeuje da se vrednost tretira kao oznaen broj i za

njegovu reprezentaciju se najee koristi zapis u potpunom komplementu, a


skup njegovih moguih vrednosti je interval od

char

128

do

127.

opti brojevni tip podataka i moe da se koristi za predstavl-

kt

Iako je

janje vrednosti malih celih brojeva, u jeziku C se ovaj tip obino koristi za

le

brojeve koji predstavljaju kdove karaktera (otuda i ime

char).

Standard ne

propisuje koje kodiranje se koristi, ali na savremenim PC raunarima i C im-

plementacijama, najee se koristi ASCII kodiranje karaktera. U tom sluaju,


karakteri su u potpunosti identifikovani svojim ASCII kdovima i obratno. Bez
obzira da li je u pitanju oznaeni ili neoznaeni karakter, opseg dozvoljava da
se sauva svaki ASCII kd (podsetimo e, ASCII kodovi su sedmobitni i imaju
vrednosti izmeu 0 i 127).

c),

c tipa char moe se ispisati sa printf("%d",


printf("%c", c). Formati koji se koriste za ispisivanje i

Brojevna vrednost promenljive


a znakovna sa

uitavanje vrednosti ovog i drugih tipova navedeni su u glavi 12.


Standardna biblioteka sadri mnoge funkcije (i makroe) za rad sa karakter-

<ctype.h>. Najkorienije
isalpha, isdigit i sline kojima se proverava da li je karakter slovo abecede

skim tipom i one su deklarisane u datoteci zaglavlja


su

107

6. Predstavljanje podataka i operacije nad njima

ili je cifra, kao i

toupper, tolower

kojima se malo slovo prevodi u veliko i

obratno. Vie detalja o standardnoj biblioteci moe se nai u glavi 11.

6.2.3

Tipovi

float, double i long double

Realne brojeve ili, preciznije, brojeve u pokretnom zarezu opisuju tipovi

(2
01
5)

float, double i (od standarda C99) long double . Tip float opisuje brojeve
u pokretnom zarezu osnovne tanosti, tip double opisuje brojeve u pokretnom zarezu dvostruke tanosti, a tip long double brojeve u pokretnom zarezu
proirene tanosti. Nije propisano koliko ovi tipovi zauzimaju bitova, ali propisano je da

long double

double

zauzima barem onoliko bajtova koliko i

zauzima barem onoliko bajtova koliko

double.

float,

a da

Podaci o opsegu

i detaljima ovih (i drugih tipova) za konkretan raunar i C prevodilac sadrani


su u standardnoj datoteci zaglavlja

<float.h>.

je

I nad podacima ovih tipova mogu se koristiti uobiajene aritmetike operacije (osim operacije raunanja ostatka pri deljenju

%)

i relacije.

an

Brojevi u pokretnom zarezu u savremenim raunarima se najee zapisuju


u skladu sa IEEE754 standardom. Ovaj standard ukljuuje i mogunost zapisa

specijalnih vrednosti (na primer, +, , ). Na primer, vrednost izraza


1.0/0.0 je +, za razliku od celobrojnog izraza 1/0 ije izraunavanje dovodi do

iz

greke prilikom izvravanja programa (engl. division by zero error). Standard


ne definie ponaanje u sluaju celobrojnog deljenja nulom a obino se za takvo
deljenje u kdu prijavljuje samo upozorenje (ukoliko se do tog deljenja doe
Vrednost izraza

sk
o

u fazi izvravanja, prijavljuje se greka i prekida se izvravanje programa).

0.0/0.0

je

tj. not-a-number i ta specijalna vrednost se

koristi da oznai matematiki nedefinisane vrednosti (npr.

ili koren

ro
n

ili logaritam negativnog broja). Specijalne vrednosti dalje mogu da uestvuju


u izrazima. Npr. ako se na izraz ija je vrednost
vrednost, dobija se opet vrednost
vrednost
kao

doda neka konstantna

1.0/ + jednaka je
ponovo imaju
printf, vrednost se tampa

ali vrednost izraza

S druge strane, svi izrazi u kojima uestvuje vrednost

. Ako se koristi
kao nan.

kt

0.0.

+,

inf,

GCC i funkcija

le

Najvei broj funkcija iz C standardne biblioteke (pre svega matematike

<math.h>) koriste tip podataka double. Tip


float se u programima koristi uglavnom zbog utede memorije ili vremena na

funkcije definisane u zaglavlju

raunarima na kojima je izvoenje operacija u dvostrukoj tanosti veoma skupo


(u dananje vreme, meutim, veina raunara podrava efikasnu manipulaciju
brojevima zapisanim u dvostrukoj tanosti).
I prilikom tampanja i uitavanja vrednosti ovih tipova, u pozivu funkcije

printf ili scanf, potrebno je navesti razliite


double6 ), o emu e vie rei biti u glavi 12.
6 to
formata

se tie uitavanja podataka tipa

%lf.

double

formate (npr.

%f

za

float

od standarda C99 doputeno je i navoenje

108

6. Predstavljanje podataka i operacije nad njima

6.2.4

Logiki tip podataka

Iako mnogi programski jezici imaju poseban tip za predstavljanje (logikih)


istinitosnih vrednosti, programski jezik C sve do standarda C99 nije imao
ovakav tip podataka ve je koriena konvencija da se logiki tip predstavlja
preko brojevnih (najee celobrojnih) vrednosti tako to se smatra da vrednost
0 ima istinitosnu vrednost netano, a sve vrednosti razliite od 0 imaju istini-

true

koja oznaava tano i

false

ta sve karakterie jedan tip podataka?

Pitanje 6.2.2.

Navesti barem jedan tipa u jeziku C za koji je standardom

je

definisano koliko bajtova zauzima.

Koliko bajtova zauzima podatak tipa

char?

an

Pitanje 6.2.3.

i konstante

koja oznaava netano.

Pitanja i zadaci za vebu


Pitanje 6.2.1.

bool

(2
01
5)

tosnu vrednost tano. Ipak, C99 standardizuje tip podataka

Ukoliko nije nave-

deno, da li se podrazumeva da je podatak ovog tipa oznaen ili neoznaen?

Pitanje 6.2.4.

signed char?

Koja je

unsigned char?

Koja je

Koliko bajtova zauzima podatak tipa

Pitanje 6.2.5.

iz

najmanja a koja najvea vrednost koju moe da ima?


Koliko bajtova zauzima podatak tipa

sk
o

najmanja a koja najvea vrednost koju moe da ima?

Pitanje 6.2.6.

Koja ogranienja vai za duine u bajtovima tipova

Pitanje 6.2.7.

Ako je opseg tipa

ro
n

int, long int?

Pitanje 6.2.8.

short int,

int oko etiri milijarde, koliko je sizeof(int)?

Ukoliko je tip promenljive

int,

da li se podrazumeva da je

kt

njena vrednost oznaena ili neoznaena ili to standard ne propisuje?

Pitanje 6.2.9.

U kojoj datoteci zaglavlja se nalaze podaci o opsezima celobro-

le

jevnih tipova za konkretnu implementaciju?

Pitanje 6.2.10.
(a)

char

a 32-bitnom sistemu, koliko bajtova zauzima podatak tipa:

(b)

int

(c)

short int

(d)

unsigned long

Pitanje 6.2.11.

Koja ogranienja vai za duine u bajtovima tipova

Pitanje 6.2.12.

U kojoj datoteci zaglavlja se nalaze podaci o opsezima tipova

double?

broja u pokretnom zarezu za konkretnu implementaciju?

float

109

6. Predstavljanje podataka i operacije nad njima

6.3 Konstante i konstantni izrazi


Svaki izraz koji se pojavljuje u programu je ili promenljiva ili konstanta ili
poziv funkcije ili sloen izraz. Konstante su fiksne vrednosti kao, na primer,

0, 2, 2007, 3.5, 1.4e2

ili

a.

Ista vrednost se ponekad moe predstaviti

razliitim konstantama. Za sve konstante i za sve izraze, pravilima jezika jednoznano su odreeni njihovi tipovi.

Poznavanje tipova konstanti i izraza je

(2
01
5)

vano jer od tih tipova moe zavisiti vrednost sloenog izraza u kojem figurie

konstanta ili neki podizraz. Od tipova konstanti i izraza zavisi i koje operacije
je mogue primeniti nad njima. Tipovi konstanti i izraza su neophodni i da bi

se znalo koliko memorijskog prostora treba rezervisati za neke meurezultate


u fazi izvravanja.

6.3.1

Celobrojne konstante

je

123 ili 45678


int. Velike celobrojne konstante koje ne mogu biti reprezentovane
tipom int, a mogu u tip long su tipa long. Ako ne mogu da budu reprezentovane ni tipom long, a mogu tipom unsigned long, onda su tipa unsigned long.
Celobrojne konstante navedene u tekstu programa kao to su

an

su tipa

Dakle, taan tip dekadne celobrojne konstante ne moe da se odredi ako se ne

iz

znaju detalji sistema. Na primer, na veini sistema poziv

sk
o

printf("%d %d", 2147483647, 2147483648);


ispisuje

jer se

ro
n

2147483647 -2147483648
2147483647

kao konstanta tipa

tumai kao konstanta tipa

unsigned long,

int,

dok se

2147483648
%d.

tumai

to ne odgovara formatu

Ukoliko se eli da se neka celobrojna konstanta tretira kao da ima tip

kt

unsigned,

onda se na njenom kraju zapisuje slovo

unsigned long, ako


unsigned int inae. Ukoliko

ili

U.

Tip takve kon-

ona moe da bude reprezentovana tim tipom,

se eli eksplicitno naglasiti da se neka celobro-

le

stante bi

jna konstanta tretira kao da je tipa

l ili L. Na primer, 12345l


unsigned long.
slovo

long, onda se na
long, 12345 je

je tipa

njenom kraju zapisuje


tipa

int,

12345ul

je

Osim u dekadnom, celobrojne konstante mogu biti zapisane i u oktalnom i


u heksadekadnom sistemu. Zapis konstante u oktalnom sistemu poinje cifrom

0,

a zapis konstante u heksadekadnom sistemu poinje simbolima

primer, broj
zapis),

31

se moe u programu zapisati na sledee naine:

0x ili 0X. Na
31 (dekadni

037 (oktalni zapis), 0x1f (heksadekadni zapis). I oktalne i heksadekadne


U ili u tj. l i L na kraju svog zapisa.

konstante mogu da budu oznaene slovima

Negativne konstante ne postoje, ali se efekat moe postii izrazima gde se


ispred konstante navodi unarni operator

-123

- (kada se u tekstu programa naie na

vrednost predstavljena ovim izrazom jeste minus stodvadesettri, ali izraz

110

6. Predstavljanje podataka i operacije nad njima

nije konstanta ve je sainjen od unarnog operatora primenjenog na konstantu).


Slino, moe se navesti i operator plus, ali to nema efekta (npr.
kao i

123).

6.3.2

+123

je isto

Konstante u pokretnom zarezu

Konstante realnih brojeva ili, preciznije, konstantni brojevi u pokretnom


jedno i drugo.

123.4)

ili eksponent (1e-2) ili i

(2
01
5)

zarezu sadre decimalnu taku (na primer,

Vrednosti ispred i iza decimalne take mogu biti izostavljene

.4 ili 5. (ali ne i .).


- ili znakom + (koji
ne proizvodi nikakav efekat). Tip svih ovih konstanti je double, osim ako na
kraju zapisa imaju slovo f ili F kada je njihov tip float (npr. 1.23f). Slova L
i l na kraju zapisa oznaavaju da je tip vrednosti long double.

(ali ne istovremeno). Na primer, ispravne konstante su i

Karakterske konstante

Iako se tip

char

an

6.3.3

je

Brojevi su oznaeni i konstante mogu poinjati znakom

koristi i za predstavljanje malih celih brojeva, on se pre-

vashodno koristi za predstavljanje kdova karaktera (najee ASCII kdova).

Direktno specifikovanje karaktera korienjem numerikih kdova nije prepo-

iz

ruljivo. Umesto toga, preporuuje se korienje karakterskih konstanti. Karakterske konstante u programskom jeziku C se navode izmeu

navodnika.

Vrednost date konstante je numerika vrednost datog karaktera u korienoj

0 predstavlja vrednost 48 (koja nema veze sa numerikom


A je karakterska konstanta ija je vrednost u ASCII kdu 65,

terska konstanta
vrednou 0),

sk
o

karakterskoj tabeli (na primer, ASCII). Na primer, u ASCII kodiranju, karak-

ro
n

je karakterska konstanta ija je vrednost u ASCII kdu 97, to je ilus-

trovano sledeim primerom.

le

kt

char c = a;
char c = 97; /* ekvivalentno prethodnom (na ASCII masinama),
ali se ne preporucuje zbog toga sto smanjuje
citljivost i prenosivost programa */

Karakterske konstante su tipa

tipa

char

int, ali se najee dodeljuju promenljivama

i tada se njihova vrednost konvertuje (vie o konverzijama tipova

prilikom dodele bie reeno u poglavlju 6.5).


vie karaktera izmeu navodnika (npr.

ab),

Standard doputa i navoenje


ali vrednost ovakve konstante

nije precizno definisana standardom (stoga emo takve konstante izbegavati u


programima).
Specijalni karakteri se mogu navesti korienjem specijalnih sekvenci karaktera koje poinju karakterom
sledee specijalne sekvence:

(engl. escape sequences).

Jezik C razlikuje

111

6. Predstavljanje podataka i operacije nad njima

alert (bell) character


backspace
formfeed
newline
carriage return
horizontal tab
vertical tab
backslash

(2
01
5)

\a
\b
\f
\n
\r
\t
\v
\\
\?
\
\"
\ooo
\xhh

question mark
single quote
(npr.
(npr.

\012)
\x12)

double quote
octal number
hexadecimal number

Karakterska konstanta

\0 predstavlja karakter ija je vrednost nula.

Ovaj

je

karakter ima specijalnu ulogu u programskom jeziku C jer se koristi za oznaavanje kraja niske karaktera (o emu e vie biti rei u nastavku).

Iako je

an

numerika vrednost ovog karaktera ba 0, esto se u programima pie

\0

umesto 0 da bi se istakla karakterska priroda ovog izraza.


Poto se karakterske konstante identifikuju sa njihovim numerikim vred-

int i mogu ravnopravno da uestvuju

nostima, one predstavljaju podatke tipa

iz

u aritmetikim izrazima (o izrazima e vie biti reeno u nastavku ove glave).

0 <= c && c <= 9 proverava da li


c sadri ASCII kd neke cifre, dok se izrazom c - 0
vrednost cifre iji je ASCII kd sadran u promenljivoj c.

Na primer, na ASCII sistemima, izraz


dobija numerika

Konstantni izrazi

ro
n

6.3.4

sk
o

karakterska promenljiva

Konstantni izraz je izraz koji sadri samo konstante (na primer,

4 + 3*5).

Takvi izrazi mogu se izraunati u fazi prevoenja i mogu se koristiti na svakom


mestu na kojem se moe pojaviti konstanta. Tip konstantnog izraza zavisi od

kt

tipova operanada (vie o tome bie reeno u poglavlju 6.5.3)./

le

Pitanja i zadaci za vebu

Pitanje 6.3.1.

Deklarisati oznaenu karaktersku promenljivu pod imenom

inicijalizovati je tako da sadri kd karaktera

Pitanje 6.3.2.

Deklarisati neoznaenu karaktersku promenljivu

inicijalnu vrednost jednaku kdu karaktera

Pitanje 6.3.3.

Y.

;.

x, tako da ima

Deklarisati promenljivu koja je tipa neoznaeni dugi ceo broj i

inicijalizovati tako da sadri heksadekadnu vrednost

Pitanje 6.3.4.

FFFFFFFF.

Da li C omoguava direktan zapis binarnih konstanti? Koji je

najkrai nain da se celobrojna promenljiva inicijalizuje na binarni broj

101110101101010011100110?

112

6. Predstavljanje podataka i operacije nad njima

Pitanje 6.3.5.

Koja je razlika izmeu konstanti

3.4 i 3.4f?

Pitanje 6.3.6.
Pitanje 6.3.7.

0123,

a koja izmeu

Kojeg su tipa i koje brojeve predstavljaju sledee konstante?

1234 (b) .
3u (i) 0

(a)
(h)

123

(c)

6423ul

(d)

12.3e-2

(e)

3.74e+2f

Kolika je vrednost konstantnog izraza

0x47

(g)

0543

0x20 + 020 + 2 - 0

Pitanje 6.3.8.

(f )

(2
01
5)

konstanti

Ako se na sistemu koristi ASCII tabela karaktera, ta ispisuje

sledei C kd:

char c1 = a; char c2 = 97;


printf("%c %d %d %c", c1, c1, c2, c2);

je

6.4 Operatori i izrazi

an

Izrazi se u programskom jeziku C grade od konstanti i promenjivih primenom irokog spektra operatora. Osim od konstanti i promenljivih, elemen-

tarni izrazi se mogu dobiti i kao rezultat poziva funkcija, operacija pristupa
elementima nizova, struktura i slino.

iz

Operatorima su predstavljene osnovne operacije i relacije koje se mogu vriti


nad podacima osnovnih tipova u jeziku C. Za celobrojne tipove, te operacije
Podrane su i operacije

sk
o

ukljuuju aritmetike, relacijske i logike operacije.

koje se primenjuju nad pojedinanim bitovima celobrojnih vrednosti.


Operatori se dele na osnovu svoje arnosti tj. broja operanada na koje se primenjuju. Unarni operatori deluju samo na jedan operand i mogu biti prefiksni

ro
n

kada se navode pre operanda i postfiksni kada se navode nakon svog operanda.

Binarni operatori imaju dva operanda i obino su infiksni tj. navode se izmeu
svojih operanda. U jeziku C postoji jedan ternarni operator koji se primenjuje

kt

na tri operanda.

Vrednost izraza odreena je vrednou elementarnih podizraza (konstanti,


promenljivih) i pravilima pridruenim operatorima. Neka pravila izraunavanja

le

vrednosti izraza nisu propisana standardom i ostavljena je sloboda implementa-

torima prevodilaca da u potpunosti preciziraju semantiku na nain koji dovodi


do efikasnije implementacije. Tako, na primer, standardi ne definiu kojim se

+ pre njihovog sabiranja, pa nije prof i g e biti prva pozvana prilikom izraunavanja izraza

redom izraunavaju operandi operatora

pisano koja od funkcija

f() + g().
6.4.1

Prioritet i asoscijativnost operatora

Izrazi mogu da obuhvataju vie operatora i zagrade

se koriste da bi

odredile kojim redosledom ih treba primenjivati. Ipak, slino kao i u matematici, postoje konvencije koje omoguavaju izostavljanje zagrada. Jedna od osnovnih takvih konvencija je prioritet operatora koji definie kojim redosledom

113

6. Predstavljanje podataka i operacije nad njima

e se dva razliita operatora primenjivati kada se nau u istom, nezagraenom


izrazu. Na primer, kako je i oekivano, vrednost konstantnog izraza

23,

bie

jer operator

ima prioritet u odnosu na operator

+.

3 + 4 * 5

Semantika jezika

C uglavnom potuje prioritet koji vai u matematici, ali, s obzirom na mnogo


vei broj operatora uvodi i dodatna pravila. Prioritet operatora dat je u tabeli
navedenoj u dodatku A. Navedimo neke osnovne principe u definisanju prior-

(2
01
5)

iteta:
1. Unarni operatori imaju vei prioritet u odnosu na binarne.

2. Postfiksni unarni operatori imaju vei prioritet u odnosu na prefiksne


unarne operatore.

3. Aritmetiki operatori imaju prioritet u odnosu na relacijske koji imaju


prioritet u odnosu na logike operatore.

je

4. Operatori dodele imaju veoma nizak prioritet.

Druga vana konvencija je asocijativnost operatora koja definie kojim re-

an

dosledom e se izraunavati dva ista operatora ili operatora istog prioriteta


kada se nau uzastopno u istom, nezagraenom izrazu.

Obino se razlikuju

leva asocijativnost, kada se izraz izraunava sleva na desno i desna asocijativnost, kada se izraz izraunava zdesna na levo. Neki jezici razlikuju i neaso-

iz

cijativnost, kada je zabranjeno da se isti operator dva puta uzastopno ponovi


u istom izrazu. Matematiki, neki operatori su asocijativni, to znai da vred-

sk
o

nost izraza ne zavisi od redosleda primene uzastopno ponovljenog operatora.


Na primer, u matematici uvek vai

+ ( + ) = ( + ) + .

Zbog naina

+) nisu uvek
(INT_MIN + INT_MAX) + 1 ima vrednost 0 bez
izraz INT_MIN + (INT_MAX + 1) ima vrednost 0,

reprezentacije podataka u raunaru mnogi operatori (ukljuujui i


asocijativni. Na primer, izraz

ro
n

nastanka prekoraenja, dok

ali dolazi do prekoraenja . Ovakvo ponaanje je posledica injenice da je u

- ima
1 - 2 - 3 je -4 (a ne 2, to bi
ega je jasno da - nije asocijativan

jeziku C sabiranje celih brojeva zapravo sabiranje po modulu. Operator

kt

levu asocijativnost. Na primer, vrednost izraza


bio sluaj da ima desnu asocijativnost, iz

le

operator). Veina operatora ima levu asocijativnost (najznaajniji izuzeci su


prefiksni unarni operatori i operatori dodele). Asocijativnost operatora data je

u tabeli u dodatku A.

6.4.2

Operator dodele

Operatorom dodele se neka vrednost pridruuje datoj promenljivoj. Operator dodele se zapisuje

7 INT_MIN

=.

INT_MAX su simbolika imena ije su vrednosti uvedene direktivom #define u


limits.h. Njima odgovaraju vrednosti najmanje i najvee vrednosti tipa

datoteci zaglavlja

int

Na primer,

na konkretnom sistemu.

114

6. Predstavljanje podataka i operacije nad njima

broj_studenata = 80;
broj_grupa
= 2;
U dodeljivanju vrednosti, sa leve strane operatora dodele moe da se nalazi
promenljiva, a bie diskutovano kasnije, i element niza ili memorijska lokacija.
Ti objekti, objekti kojima moe biti dodeljena vrednost nazivaju se l-vrednosti

(2
01
5)

(od engleskog l-value ili left-value).


Operator dodele se moe koristiti za bilo koji tip l-vrednosti, ali samo ako je
desna strana odgovarajueg tipa (istog ili takvog da se njegova vrednost moe
konvertovati u tip l-vrednosti o emu e vie rei biti u poglavlju 6.5).

Tip izraza dodele je tip leve strane, a vrednost izraza dodele je vrednost koja

e biti dodeljena levoj strani (to nije uvek vrednost koju ima desna strana).
Promena vrednosti objekta na levoj strani je propratni (boni, sporedni) efekat
(engl. side effect) do kojeg dolazi prilikom izraunavanja vrednosti izraza. Na

broj_studenata = 80; svodi se na izraunavanje


broj_studenata = 80. Tip promenljive broj_studenata je istovremeno i tip ovog izraza, vrednost je jednaka 80, a prilikom ovog izraunavanja
menja se vrednost promenljive broj_studenata. Ovakvo ponaanje moe se

je

primer, izvravanje naredbe

an

izraza

iskoristiti i za viestruko dodeljivanje. Na primer, nakon sledee naredbe, sve


imae vrednost

sk
o

x = y = z = 0;

6.4.3

0:

x, y i z

iz

tri promenljive

Aritmetiki operatori

ro
n

Nad operandima brojevnih tipova mogu se primeniti sledei aritmetiki


operatori:

binarni operator sabiranja;

binarni operator oduzimanja;

binarni operator mnoenja;

le

kt

binarni operator (celobrojnog) deljenja;


binarni operator ostatka pri deljenju;

unarni operator promene znaka;

unarni operator.

Operator

% mogue je primeniti iskljuivo nad operandima celobrojnog tipa.

Operator deljenja oznaava razliite operacije u zavisnosti od tipa svojih

8 Kada se operator deljenja primenjuje na dve celobrojne vrednosti

operanada.

8 Na

hardveru su operacije nad celim brojevima i brojevima u pokretnom zarezu imple-

mentirane nezavisno i u izvrnom programu koristi se jedna od njih, izabrana u fazi prevoenja u zavisnosti od tipova operanada. Informacije o tipovima iz izvornog programa su

115

6. Predstavljanje podataka i operacije nad njima

primenjuje se celobrojno deljenje (tj. rezultat je celi deo kolinika). Na primer,


izraz

9/5 ima vrednost 1.

U ostalim sluajevima primenjuje se deljenje realnih

brojeva (preciznije, deljenje brojeva u pokretnom zarezu).

Na primer, izraz

9.0/5.0 ima vrednost 1.8 (jer se koristi deljenje brojeva u pokretnom zarezu).
U sluaju da je jedan od operanada ceo broj, a drugi broj u pokretnom zarezu,
vri se implicitna konverzija celobrojnog operanda u broj u pokretnom zarezu
bie u poglavlju 6.5).
Prefiksni unarni operatori
od svih binarnih operatora.
prioriteta binarnih operatora

imaju desnu asocijativnost i vii prioritet

Operatori

+ i -.

(2
01
5)

i primenjuje se deljenje brojeva u pokretnom zarezu (vie rei o konverzijama

*, /

imaju isti prioritet, vii od

Svi navedeni binarni operatori imaju levu

asocijativnost.

Inkrementiranje i dekrementiranje.

Inkrementiranje generalno znai po-

je

stepeno uveavanje ili uveavanje za neku konkretnu vrednost.

U programi-

ranju se pod inkrementiranjem obino podrazumeva uveavanje za 1, a pod

++,

(uveavanja za 1) zapisuje se sa

--:

a operator dekrementiranja (umanjivanja

za 1) zapisuje se sa

U jeziku C, operator inkrementiranja

an

dekrementiranjem umanjivanje za 1.

(prefiksno i postfiksno) inkrementiranje;

--

(prefiksno i postfiksno) dekrementiranje.

sk
o

iz

++

Oba operatora mogu se primeniti nad celim brojevima i brojevima u pokretnom


zarezu. Inkrementiranje i dekrementiranje se mogu primenjivati samo nad lvrednostima (najee su to promenljive ili elementi nizova). Tako, na primer,

5++

nije ispravan. Oba operatora su unarna (imaju po jedan operand) i

ro
n

izraz

++n) ili postfiksnom obliku (na


n++). Razlika izmeu ova dva oblika je u tome to ++n uveava vrednost
promenljive n pre nego to je ona upotrebljena u irem izrazu, a n++ je uveava
nakon to je upotrebljena. Preciznije, vrednost izraza n++ je stara vrednost
promenljive n, a vrednost izraza ++n je nova vrednost promenljive n, pri emu
mogu se upotrebiti u prefiksnom (na primer,

le

kt

primer,

se u oba sluaja, prilikom izraunavanja vrednosti izraza, kao propratni efekat,

uveava vrednost promenljive

5,

n.

Na primer, ako promenljiva

ima vrednost

onda

x = n++;

dodeljuje promenljivoj

vrednost

5,

x = ++n;
na ovaj, ali i na druge sline naine, upotrebljene tokom prevoenja i one se ne uvaju u
izvrnom programu.

116

6. Predstavljanje podataka i operacije nad njima

dodeljuje promenljivoj

6.

nost

vrednost

6.

Promenljiva

u oba sluaja dobija vred-

Slino, kd

int a = 3, b = 3, x = a++, y = ++b;


printf("a = %d, b = %d, x = %d, y = %d\n);
ispisuje

(2
01
5)

a = 4, b = 4, x = 3, y = 4

Ukoliko ne postoji iri kontekst, tj. ako inkrementiranje ini itavu naredbu,
vrednost izraza se i ne koristi i onda nema razlike izmeu naredbe

an

int a = 3, b = 3;
a++; ++b;
printf("a = %d, b = %d\n", a, b);

n++; i ++n;.

je

Na primer,

prethodni kd ispisuje

iz

a = 4, b = 4

Sm trenutak u kojem se vri izvravanje propratnog efekta precizno je


definisan standardom i odreen tzv. sekvencionim takama (engl. sequence

sk
o

point) jezika u kojima se garantuje da je efekat izvren. Tako je, na primer,


izmeu svake dve susedne promenljive koje se deklariu (mesto oznaenom sim-

,)

bolom

;),

sekvenciona taka, kao i kraj naredbe i deklaracije (mesto oznaeno

dok operator

+ to

esto nije . Efekat moe biti izvren i pre sekvencione

ro
n

sa

take, ali za to ne postoji garancija, tako neto zavisi od konkretne implementacije (od kompilatora) i na to se ne treba oslanjati. Na primer, naredni
kd

le

kt

int a = 3, x = a++, y = a++;


int b = 3, z = b++ + b++;
printf("a = %d, x = %d, y = %d,\n", a, x, y);
printf("b = %d, z = %d\n", b, z);

ispisuje

a = 5, x = 3, y = 4,
b = 5, z = 6
Zaista,

prima originalnu vrednost promenljive

nakon inicijalizacije promenljive


prvo uveanje promenljive

9 Precizan

(vrednost

3).

Poto je zarez

oznaava mesto gde je sekvenciona taka,

vri se na tom mestu tako da

prima uveanu

spisak svih sekvencionih taaka moe se nai u standardu jezika.

117

6. Predstavljanje podataka i operacije nad njima

a (vrednost 4). Drugo uveanje promenljive a (na vred5 vri se na kraju deklaracije sa inicijalizacijama, tj. na mestu oznaenom

vrednost promenljive
nost
sa

;).

U drugom sluaju u nekoj implementaciji se moe desiti da promenljiva

sabira dva puta originalnu vrednost promenljive

(vrednost

3),

jer

ne oz-

naava sekvencionu taku i na tom mestu promenljiva jo ne mora biti uveana,


a promenljiva

b se uveava i to dva puta na kraju deklaracije sa inicijalizacijama


;, jer na tom mestu postoji sekvenciona taka).

(na mestu obeleenom sa

(2
01
5)

Primetimo da semantika operatora inkrementiranja moe biti veoma komp-

likovana i stoga se ne savetuje korienje sloenijih izraza sa ovim operatorima,


koji se oslanjaju na fine detalje semantike.

6.4.4

Relacijski i logiki operatori

Relacijski operatori.

Nad celim brojevima i brojevima u pokretnom zarezu

jednako;

!=

razliito.

>

an

==

je

mogu se koristiti sledei binarni relacijski operatori:

<

vee ili jednako;

iz

>=

vee;

manje;
manje ili jednako;

sk
o

<=

<, <=, > i >= imaju isti prioritet i to vii od op!= i svi imaju levu asocijativnost. Rezultat
relacionog operatora primenjenog nad dva broja je vrednost 0 (koja odgovara
istinitosnoj vrednosti netano) ili vrednost 1 (koja odgovara istinitosnoj vrednosti netano). Na primer, izraz 3 > 5 ima vrednost 0, a izraz 7 < 5 != 1
je isto to i (7 < 5) != 1 i ima vrednost 1 jer izraz 7 < 5 ima vrednost 0,
to je razliito od 1. Ako promenljiva x ima vrednost 2, izraz 3 < x < 5 ima
vrednost 1 (tano) to je razliito od moda oekivane vrednosti 0 (netano) jer
2 nije izmeu 3 i 5. Naime, izraz se izraunava sleva na desno, podizraz 3 < x
ima vrednost 0, a zatim izraz 0 < 5 ima vrednost 1. Kako u ovakvim sluaRelacijski operatori poretka

==

i razliitosti

le

kt

ro
n

eratora jednakosti

jevima kompilator ne prijavljuje greku, a u fazi izvravanja se dobija rezultat


neoekivan za poetnike, ovo je opasna greka programera koji su navikli na uobiajenu matematiku notaciju. Dakle, proveru da li je neka vrednost izmeu
dve zadate neophodno je vriti uz primenu logikog operatora

&&.

Binarni relacijski operatori imaju nii prioritet od binarnih aritmetikih


operatora.
Operator
dodele

==

koji ispituje da li su neke dve vrednosti jednake i operator

razliiti su operatori i imaju potpuno drugaiju semantiku. Njihovo

nehotino meanje est je uzrok greaka u C programima.

118

6. Predstavljanje podataka i operacije nad njima

Logiki operatori.

Logiki operatori primenjuju se nad brojevnim vrednos-

tima i imaju tip rezultata

int.

Brojevnim vrednostima pridruene su logike ili

0, onda je njegova
0 (netano), a inae je njegova logika vrednost 1 (tano). Iako
su sve vrednosti operanada koje su razliite od 0 doputene i tumae se kao
tano, rezultat izraunavanja tano nije proizvoljna vrednost razliita od 0, ve
iskljuivo vrednost 1.

istinitosne vrednosti na sledei nain: ukoliko je broj jednak


logika vrednost

(2
01
5)

Postoje sledei logiki operatori:


logika negacija ne;

&&

logika konjunkcija i;

||

logika disjunkcija ili.

Operator

&&

ima vii prioritet u odnosu na operator

||,

a oba su levo

relacijske i logike operatore. Operator

je

asocijativna. Binarni logiki operatori imaju nii prioritet u odnosu na binarne

!, kao unarni operator, ima vii prioritet

an

u odnosu na bilo koji binarni operator i desno je asocijativan. Na primer,

vrednost izraza

5 && 4.3

vrednost izraza

10.2 || 0

vrednost izraza

0 && 5

vrednost izraza

!1

vrednost izraza

!9.2

vrednost izraza

!0

vrednost izraza

!(2>3)

irazom

d
1;

iz

jednaka je

sk
o

jednaka je

jednaka je

0;

1;

jednaka je

3 < x && x < 5


3 i 5;

0;

0;

1;

proverava se da li je vrednost promenljive

a > b || b > c && b > d

kt

izraz

1;

jednaka je

jednaka je

ro
n

izmeu

jednaka je

ekvivalentan je izrazu

le

(a>b) || ((b>c) && (b>d));

izrazom

g % 4 == 0 && g % 100 != 0 || g % 400 == 0


g prestupna.

proverava se

da li je godina

Lenjo izraunavanje.

U izraunavanju vrednosti logikih izraza koristi se

strategija lenjog izraunavanja (engl. lazy evaluation).

Osnovna karakteris-

tika ove strategije je izraunavanje samo onog to je neophodno. Na primer,


prilikom izraunavanja vrednosti izraza

2<1 && a++


(2<1) jednaka 0, pa je i vrednost
0. Zato nema potrebe izraunavati vrednost podizraza a++, te e vrednost promenljive a ostati nepromenjena
bie izraunato da je vrednost podizraza

celog izraza (zbog svojstva logikog i) jednaka

119

6. Predstavljanje podataka i operacije nad njima

nakon izraunavanja vrednosti navedenog izraza. S druge strane, nakon izraunavanja vrednosti izraza

a++ && 2<1


vrednost promenljive

e biti promenjena (uveana za 1). U izrazima u ko-

jima se javlja logiko i, ukoliko je vrednost prvog operanda jednaka 1, onda se

(2
01
5)

izraunava i vrednost drugog operanda.

U izrazu u kojem se javlja logiko ili, ukoliko je vrednost prvog operanda


jednaka 1, onda se ne izraunava vrednost drugog operanda. Ukoliko je vred-

nost prvog operanda jednaka 0, onda se izraunava i vrednost drugog operanda.


Na primer, nakon

1<2 || a++_
a,

a nakon

an

2<1 || a++

iz

Bitovski operatori

a.

se menja (uveava za 1) vrednost promenljive

6.4.5

je

se ne menja vrednost promenljive

C podrava naredne operatore za rad nad pojedinanim bitovima, koji se

sk
o

mogu primenjivati samo na celobrojne argumente:


bitovska negacija;

&

bitovska konjunkcija;

bitovska disjunkcija;

bitovska eksluzivna disjunkcija;

pomeranje (iftovanje) bitova ulevo;

kt

pomeranje (iftovanje) bitova udesno.

le

ro
n

Kao unarni operator, operator

tivan.

ima najvei prioritet i desno je asocija-

Prioritet operatora pomeranja je najvei od svih binarnih bitovskih

operatora nalazi se izmeu prioriteta aritmetikih i relacijskih operatora.


Ostali bitovski operatori imaju prioritet izmeu relacijskih i logikih operatora
i to

&

ima vei prioritet od

koji ima vei prioritet od

|.

Ovi operatori imaju

levu asocijativnost.

& bitovsko

i primenom ovog operatora vri se konjunkcija pojedinanih

bitova dva argumenta (-ti bit rezultata predstavlja konjunkciju

-tih

bitova argumenata).

tipa

Na primer, ukoliko su promenljive

x1

x2

unsigned char i ukoliko je vrednost promenljive x1 jednaka 74, a promenljive x2 jednaka 87, vrednost izraza x1 & x2 jednaka je 66. Naime,

120

6. Predstavljanje podataka i operacije nad njima

broj

74

01001010,

se binarno zapisuje kao

junkcija njihovih pojedinanih bitova daje


pis broja

66.

broj 87 kao 01010111, i kon01000010, to predstavlja za-

S obzirom na to da se prevoenje u binarni sistem efikasnije

sprovodi iz heksadekadnog sistema nego iz dekadnog, prilikom korienja


bitovskih operatora konstante se obino zapisuju heksadekadno. Tako bi,
u prethodnom primeru, broj

x1 imao vrednost zapisanu kao 0x4A, a broj


0x57.

bi imao vrednost zapisanu kao

| bitovsko

(2
01
5)

x2

ili primenom ovog operatora vri se (obina) disjunkcija po-

jedinanih bitova dva navedena argumenta. Za brojeve iz tekueg primera,


vrednost izraza

bitovsko

x1 | x2

je

01011111,

0x5F.

tj. 95, tj.

ekskluzivno ili primenom ovog operatora vri se ekskluzivna

disjunkcija pojedinanih bitova dva argumenta.

jedinini komplement

x1 ^ x2

je

00011101,

Za brojeve iz tekueg

tj. 29, tj.

0x1D.

je

primera, vrednost izraza

primenom ovog operatora vri se komplemen-

u tekuem primeru je

10110101,

levo pomeranje (iftovanje)

tj.

B5,

tj.

181.

primenom ovog operatora bitovi prvog

~x1

an

tiranje (invertovanje) svakog bita argumenta. Na primer, vrednost izraza

iz

argumenta se pomeraju u levo za broj pozicija naveden kao drugi argument. Poetni bitovi prvog argumenta se zanemaruju, dok se na zavrna
mesta rezultata upisuju nule.

Levo pomeranje broja za jednu poziciju

x ima tip
unsigned char i vrednost 0x95, tj. 10010101, vrednost izraza x << 1 je
00101010, tj. 0x2A.
Na primer, ukoliko promenljiva

sk
o

odgovara mnoenju sa dva.

ro
n

desno pomeranje (iftovanje)

primenom ovog operatora bitovi pr-

vog argumenta se pomeraju u desno za broj pozicija naveden kao drugi


argument. Krajnji (desni) bitovi prvog argumenta se zanemaruju, a to

kt

se tie poetnih (levih) bitova rezultata, postoji mogunost da se oni


popunjavaju uvek nulama (tzv. logiko pomeranje ) ili da se oni popune

le

vodeim bitom (koji predstavlja znak) prvog argumenta (tzv. aritmetiko

pomeranje ).

Osnovna motivacija aritmetikog pomeranja je da desno

pomeranje broja za jednu poziciju odgovara celobrojnom deljenju sa dva.


Koje pomeranje e se vriti zavisi od tipa prvog argumenta. Ukoliko je
argument neoznaen, poetni bitovi rezultata e biti postavljeni na nulu,
bez obzira na vrednost vodeeg bita prvog argumenta.

Ukoliko je ar-

gument oznaen, poetni bitovi rezultata e biti postavljeni na vrednost

vodeeg bita prvog argumenta. Na primer, ukoliko promenljiva x ima tip


signed char i vrednost 0x95, tj. 10010101, vrednost izraza x >> 1 je
11001010, tj. 0xCA. Ukoliko je tip promenljive x unsigned char, tada je
vrednost izraza x >> 1 broj 01001010, tj. 0x4A.
Definisani su i operatori sloenih bitovskih dodela (&=,
Na primer,

a &= 1

ima isto znaenje kao

a = a & 1.

|=, ^=, <<=, >>=).

121

6. Predstavljanje podataka i operacije nad njima

Bitovske operatore ne treba meati sa logikim operatorima.

1 && 2 je 1 (tano i tano je tano), dok


0 (000...001 & 000..010 = 000...000).

vrednost izraza

1 & 2

jednaka

Na primer,

je vrednost izraza

Vie rei o upotrebi bitovskih operatora kao i primeri programa bie dati u
drugom tomu ove knjige.

Sloeni operatori dodele

(2
01
5)

6.4.6

i = i + 2; moe se zapisati
x = x * (y+1); ima isto dejstvo kao i

Dodela koja ukljuuje aritmetiki operator


krae i kao

x *= y+1;.

i += 2;.

Slino, naredba

Za veinu binarnih operatora postoje odgovarajui sloeni opera-

tori dodele:

+=, -=, *=, /=, %=, &=, |=, =, =

je

Operatori dodele imaju nii prioritet od svih ostalih operatora i desnu aso-

an

cijativnost.
Izraunavanje vrednosti izraza

izraz1 op= izraz2

iz

obino ima isto dejstvo kao i izraunavanje vrednosti izraza

gde je

op

sk
o

izraz1 = izraz1 op izraz2

jedan od nabrojanih operatora.

Meutim, postoje sluajevi kada

10 , te treba biti obazriv sa ko-

navedena dva izraza imaju razliite vrednosti

ro
n

rienjem sloenih operatora dodele.


Krai zapis uz korienje sloenih operatora dodele obino daje i neto
efikasniji kd (mada savremeni kompilatori obino umeju i sami da prepoznaju situacije u kojima se izraz moe prevesti isto kao da je zapisan u kraem

kt

obliku).

Naredni primer ilustruje primenu sloenog operatora dodele (obratiti panju

le

na rezultat operacija koji zavisi od tipa operanda).

Program 6.3.
#include <stdio.h>
int main() {
unsigned char c = 254;
10 Na

i-ti element niza


a[i++] = a[i++] + 1
promenljiva inkrementira dva puta. Slino, prilikom izraunavanja izraza a[f()] += 1,
funkcija f() se poziva samo jednom, dok se u sluaju a[f()] = a[f()] + 1 funkcija f()
poziva dva puta, to moe da proizvede razliiti efekat ukoliko funkcija f() u dva razliita
a),

primer, prilikom izraunavanja izraza

promenljiva

a[i++] += 1 (a[i]

oznaava

inkrementira se samo jednom, dok se u sluaju

poziva vraa razliite vrednosti. Funkcije i nizovi su detaljnije opisani u narednim glavama.

122

6. Predstavljanje podataka i operacije nad njima

c += 1; printf("c = %d\n", c);


c += 1; printf("c = %d\n", c);
return 0;

Izlaz programa:

6.4.7

(2
01
5)

c = 255
c = 0

Operator uslova

Ternarni operator uslova

?:

se koristi u sledeem optem obliku:

je

izraz1 ? izraz2 : izraz3;

Prioritet ovog operatora je nii u odnosu na sve binarne operatore osim


Izraz

izraz1

,.

an

dodela i operatora

se izraunava prvi. Ako on ima ne-nula vrednost (tj. ako ima

istinitosnu vrednost tano), onda se izraunava vrednost izraza


vrednost itavog uslovnog izraza. Inae se izraunava vrednost

izraz2
izraz3

i to je
i to je

iz

vrednost itavog uslovnog izraza. Na primer, izraunavanjem izraza

sk
o

m = (a > b) ? a : b
vrednost promenljive

b,

postavlja se na maksimum vrednosti promenljivih

dok se izraunavanjem izraza

ro
n

m = (a < 0) ? -a : a
vrednost promenljive

postavlja na apsolutnu vrednost promenljive

a.

kt

Opisana semantika ternarnog operatora takoe je lenja. Na primer, nakon


izvravanja kda

le

n = 0;
x = (2 > 3) ? n++ : 9;

promenljiva

imae vrednost

9,

a promenljiva

e zadrati vrednost

jer se

drugi izraz nee izraunavati.

6.4.8

Operator zarez

Binarni operator zarez (,) je operator kao i svaki drugi (najnieg je prioriteta od svih operatora u C-u) i prilikom izraunavanja vrednosti izraza
izgraenog njegovom primenom, izraunavaju se oba operanda, pri emu se
vrednost celokupnog izraza definie kao vrednost desnog operanda (ta vred-

123

6. Predstavljanje podataka i operacije nad njima

nost se esto zanemaruje). Ovaj operator se esto koristi samo da spoji dva
izraza u jedinstveni (da bi se takav sloeni izraz mogao upotrebiti na mestima
gde sintaksa zahteva navoenje jednog izraza). To je najee u inicijalizaciji i
koraku

for petlje (o emu e vie rei biti u poglavlju 7.4).

Jo jedna od estih

upotreba je i u kdu oblika

Treba razlikovati operator

(2
01
5)

x = 3, y = 5; /* ekivalentno bi bilo i x = 3; y = 5; */
, od zareza koji razdvajaju promenljive prilikom

deklaracije i poziva funkcije (koji nisu operatori).

esta greka u korienju

ovog operatora je pri pokuaju pristupa viedimenzionom nizu (vie o nizovima


reeno je u poglavlju 6.6.4).

A[1, 2] potpuno je ekvivalentno sa


A dvodimenzioni. Ispravan nain pristupa
A[1][2].
Na primer

elementu na poziciji

6.4.9

(1, 2)

je

je

to je pogreno ako je niz

Operator sizeof

an

A[2],

Veliinu u bajtovima koju zauzima neki tip ili neka promenljiva mogue
je odrediti korienjem operatora

int

sizeof.

Tako,

sizeof(int)

predstavlja

i na tridesetidvobitnim sistemima vrednost ovog izraza je

veliinu tipa

iz

najee 4.

Vrednost koju vraa operator

sizeof

ima tip

size_t.

Ovo je neoznaen

celobrojni tip, koji obino slui za reprezentovanje veliine objekata u memoriji.

size_t

ne mora nuno da bude jednak tipu

sk
o

Tip

unsigned int

(standard C99

zahteva samo da vrednosti ovog tipa imaju barem dva bajta).

ro
n

Pitanja i zadaci za vebu

Kako se grade izrazi?

Pitanje 6.4.2.

Nabrojati aritmetike, relacijske operatore, logike i bitovske

kt

Pitanje 6.4.1.
operatore.

ta je to asocijativnost, a ta prioritet operatora?

Pitanje 6.4.4.

Navesti neki operator jezika C koji ima levu i neki operator

le

Pitanje 6.4.3.

koji ima desnu asocijativnost.

Pitanje 6.4.5.

Kakav je odnos prioriteta unarnih i binarnih operatora?

Pitanje 6.4.6.

Kakav je odnos prioriteta logikih, aritmetikih i relacijskih

operatora?

Pitanje 6.4.7.

Kakav je odnos prioriteta operatora dodele i ternarnog opera-

tora?

Pitanje 6.4.8.
eratora?

Da li dodele spadaju u grupu nisko ili visoko prioritetnih op-

124

6. Predstavljanje podataka i operacije nad njima

Pitanje 6.4.9.

Koji operator jezika C ima najnii prioritet?

Pitanje 6.4.10.

Imajui u vidu asocijativnost C operatora, ta je rezultat

izvravanja kda:

double a = 2.0, b = 4.0, c = -2.0;


printf("%f\n", (-b + sqrt(b*b - 4*a*c)) / 2.0 * a);

Pitanje 6.4.11.

(2
01
5)

Kako popraviti kd tako da ispravno izraunava reenje kvadratne jednaine?

Postaviti zagrade u naredne izraze u skladu sa podrazumevanim

prioritetom i u skladu sa podrazumevanom asocijativnou operatora (na primer,

je

3+4*5+7 (3+(4*5))+7).
(a) a = b = 4 (b) a = 3 == 5 (c) c = 3 == 5 + 7 <= 4
(d) 3 - 4 / 2 < 3 && 4 + 5 * 6 <= 3 % 7 * 2
(e) a = b < c ? 3 * 5 : 4 < 7, 2 (f ) a = b + c && d != e

Pitanje 6.4.12.

Koja je vrednost narednih izraza:

an

/ 4 (b) 3.0 / 4 (c) 14 % 3 (d) 3 >= 7


&& 7 (f ) 3 || 0 (g) a = 4 (h) (3 < 4) ? 1 : 2
< 5 < 5 (i) 3 < 7 < 5 (j) 6%3 || (6/3 + 5)
< 5 ? 6 + 2 : 8 + 3

iz

3
(e) 3
(k) 3
(j) 3
(a)

Pitanje 6.4.13.

Da li su definisana deljenja

Pitanje 6.4.14.

Da li su ispravni sledei izrazi i ako jesu ta je njihova vred-

(a)

2++ (b) a++ (c) 2** (d) a** (e) 2>>2 (f ) a>>2 (g) a &&= 0 (e) a ||= -7

naredbi:

Koje vrednosti imaju relevantne promenljive nakon navedenih

ro
n

Pitanje 6.4.15.

a=b++;, ako pre ove naredbe promenljiva a ima vrednost 1,


b vrednost 3;

a promenljiva

a+=b;, ako pre


b vrednost 3?

a promenljiva

kt

1.

ove naredbe promenljiva

ima vrednost

1,

le

2.

sk
o

nost:

1/0 i 1.0/0.0?

3.

4.

int a=5; b = (a++ - 3) + (a++ - 3);?


int a = 1, b = 1, x, y;
x = a++; y = ++b;

5.

int a=3; b = (a++ - 3) && (a++ - 3);?

6.

int a, b=2, c; c = b++; a = c>b && c++;

7.

unsigned char a, b=255; a = ++b && b++;

Pitanje 6.4.16.
Navesti primere.

ta znai to da se operatori

&&, ||

?:

izraunavaju lenjo?

125

6. Predstavljanje podataka i operacije nad njima

Pitanje 6.4.17.

ta ispisuje naredni kd?

int a = 3, b = 0, c, d;
c = a % 2 || b++;
d = a % 3 || b++;
printf("%d %d %d %d", a, b, c, d);

1. Napisati izraz koji je taan ako je godina

(2
01
5)

Pitanje 6.4.18.
prestupna.

2. Napisati izraz ija je vrednost jednaka manjem od brojeva

a i b.

3. Napisati izraz ija je vrednost jednaka apsolutnoj vrednosti broja


4. Napisati izraz koji je, na ASCII sistemu, taan ako je karakter
slovo.

samoglasnik.

je

5. Napisati izraz koji je taan ako je karakter

a.
c malo

p q.
c malo slovo ima vrednost odgovarajueg velikog
vrednost c.

6. Napisati izraz ija je vrednost jednaka vrednosti implikacije


slova, a inae ima

Napisati program koji za zadati sat, minut i sekund izraunava

Zadatak 6.4.1.

an

7. Napisati izraz koji ako je

koliko je vremena (sati, minuta i sekundi) ostalo do ponoi. Program treba i

iz

da izvri proveru da li su uneti podaci korektni.

Napisati program koji za uneta tri pozitivna broja u pokretnom

sk
o

Zadatak 6.4.2.

zarezu ispituje da li postoji trougao ije su duine stranica upravo ti brojevi

uslov provere napisati u okviru jednog izraza.

Zadatak 6.4.3.

Napisati program koji izraunava zbir cifara unetog etvoro-

ro
n

cifrenog broja.

Zadatak 6.4.4.

Napisati program koji razmenjuje poslednje dve cifre unetog

kt

prirodnog broja. Na primer, za uneti broj

1234

program treba da ispie

1243.

Napisati program koji ciklino u levo rotira poslednje tri cifre unetog prirodnog

le

broja. Na primer, za uneti broj

Zadatak 6.4.5.

12345

program treba da ispie

12453.

Napisati program koji za uneti par prirodnih brojeva izrau-

nava koji je po redu taj par u cik-cak nabrajanju datom na slici 3.1. Napisati i
program koji za dati redni broj u cik-cak nabrajanju odreuje odgovarajui par

prirodnih brojeva.

Zadatak 6.4.6.

Napisati program koji za unete koeficijente

reenje jednaine

+ = 0.

Zadatak 6.4.7.
2

izraunava

reenja ili ima vie od jednog reenja.

Program treba da prijavi ukoliko jednaina nema

1 , 1 , 1 , 2 , 2
1 + 1 = 1 , 2 + 2 = 2 .

Napisati program koji za unete koeficijente

izraunava reenje sistema jednaina

Program treba da prijavi ukoliko sistem nema reenja ili ima vie od jednog
reenja.

126

6. Predstavljanje podataka i operacije nad njima

Zadatak 6.4.8.

Napisati program koji za unete koeficijente

( =

0)

izraunava (do na mainsku tanost) i ispisuje realna reenja kvadratne

2
jednaine + + = 0.
Napisati program koji ispisuje sve delioce unetog neoznaenog

celog broja (na primer, za unos

24).

Zadatak 6.4.10.

24

treeni delioci su

1, 2, 3, 4, 6, 8, 12i

(2
01
5)

Zadatak 6.4.9.

Napisati program koji uitava karaktere sa standardnog ulaza

sve dok se ne unese taka (karakter

.), zarez (karakter ,) ili kraj datoteke (EOF)

i prepisuje ih na standardni izlaz menjajui svako malo slovo velikim. (Napomena:

getchar,

za uitavanje karaktera koristiti funkciju

putchar)

je

6.5 Konverzije tipova

a za ispis funkciju

Konverzija tipova predstavlja pretvaranje vrednosti jednog tipa u vredJezik C je veoma fleksibilan po pitanju konverzije tipova

an

nost drugog tipa.

i u mnogim situacijama doputa korienje vrednosti jednog tipa tamo gde se

oekuje vrednost drugog tipa (ponekad se kae da je C slabo tipiziran jezik ).


Iako su konverzije esto neophodne da bi se osiguralo korektno funkcionisanje

iz

programa i omoguilo meanje podataka razliitih tipova u okviru istog programa, konverzije mogu dovesti i do gubitka podataka ili njihove loe inter-

sk
o

pretacije. Jezik C je statiki tipiziran, pa, iako se prilikom konverzija konvertuju vrednosti izraza, promenljive sve vreme ostaju da budu onog tipa koji im

6.5.1

ro
n

je pridruen deklaracijom.

Vrste konverzija

Postoje eksplicitne konverzije (koje se izvravaju na zahtev programera)

kt

i implicitne konverzije (koje se izvravaju automatski kada je to potrebno).


Neke konverzije je mogue izvesti bez gubitka informacija, dok se u nekim

le

sluajevima prilikom konverzije vri izmena same vrednosti podatka.


Jedan oblik konverzije predstavlja konverzija vrednosti nieg tipa u vred-

nost vieg tipa (na primer,

short u long, int u float ili float u double) u

kom sluaju najee ne dolazi do gubitka informacije. Konverzija tog oblika

11

se ponekad naziva promocija (ili napredovanje ).

float a=4;

/* 4 je int i implicitno se konvertuje u float */

Naglasimo da do gubitka informacija ipak moe da doe. Na primer, kd

11 C

standard definie tzv. konverzioni rang svakog tipa i napredovanje i nazadovanje se

odnose na konverzioni rang.

127

6. Predstavljanje podataka i operacije nad njima

float f = 16777217;
printf("%f\n", f);
obino (tj. na velikom broju konkretnih sistema) ispisuje

16777216.00000
16777217.0 ne moe da se zapie u okviru tipa float ako on koristi
float za zapis mantise koristi

etiri bajta i IEEE 754 zapis. Naime, tada tip

(2
01
5)

jer vrednost

tri bajta, tj. dvadeset etiri binarne cifre i moe da reprezentuje sve pozitivne
celobrojne vrednosti do
je

24

+1

224

i binarno se zapisuje kao

konverzije u

float

224 . Broj 16777217 jednak


1000000000000000000000001, pa prilikom

ali samo neke vee od

(duine etiri bajta) dolazi do gubitka informacija.

Drugi oblik konverzije predstavlja konverzija vrednosti vieg tipa u vrednost

long

short, double

int).

Ovaj oblik konverzije

je

nieg tipa (na primer,

ponekad se naziva democija (ili nazadovanje ). Prilikom ovog oblika konverzije,

an

mogue je da doe do gubitka informacije (u sluaju da se polazna vrednost


ne moe predstaviti u okviru novog tipa). U takvim sluajevima, kompilator

obino izdaje upozorenje, ali ipak vri konverziju.

sk
o

iz

int b = 7.0f; /* 7.0f je float pa se vrsi konverzija u 7 */


int c = 7.7f; /* 7.7f je float i vrsi se konverzija u 7,
pri cemu se gubi informacija */
unsigned char d = 256; /* d dobija vrednost 0 */
Prilikom konverzije iz brojeva u pokretnom zarezu u celobrojne tipove po-

ro
n

dataka i obratno potrebno je potpuno izmeniti interni zapis podataka (na


primer, iz IEEE754 zapisa brojeva u pokretnom zarezu u zapis u obliku potpunog komplementa).

Ovo se najee vri uz odsecanje decimala, a ne

zaokruivanjem na najblii ceo broj (tako je

7.7f

konvertovano u

7,

a ne u

Prilikom konverzija celobrojnih tipova istog internog zapisa razliite irine

kt

8).

(razliitog broja bajtova), vri se odsecanje vodeih bitova zapisa (u sluaju

le

konverzija u ui tip) ili proirivanje zapisa dodavanjem vodeih bitova (u sluaju


konverzija u iri tip). U sluaju da je polazni tip neoznaen, konverzija u iri tip

se vri dodavanjem vodeih nula (engl. zero extension ). U sluaju da je polazni

tip oznaen, konverzija u iri tip se vri proirivanjem vodeeg bita (engl. sign

extension ) i na taj nain se zadrava vrednost i pozitivnih i negativnih brojeva


zapisanih u potpunom komplementu.

int c = 7.7f; ilustruje i zato vrednost izraza dodele nije


7.7f), nego vrednosti koja je dodeljena
objektu na levoj strani operatora dodele (u ovom sluaju 7).
esto se deava da se vrednost tipa char dodeljuje promenljivoj tipa int i
Navedeni primer

jednaka desnoj strani (u ovom sluaju

tom prilikom takoe dolazi do implicitne konverzije. S obzirom na to da standard ne definie da li je tip

char

oznaen ili neoznaen, rezultat konverzije se

razlikuje od implementacije do implementacije (ukoliko je karakter neoznaen,

128

6. Predstavljanje podataka i operacije nad njima

prilikom proirivanja dopisuju mu se vodee nule, a ukoliko je oznaen, dopisuje


se vrednost njegovog vodeeg bita), to moe dovesti do problema prilikom
prenoenja programa sa jedne na drugu platformu. Ipak, standard garantuje
da e svi karakteri koji mogu da se tampaju (engl. printable characters) uvek
imati pozitivne kdove (i vodei bit 0), tako da oni ne predstavljaju problem
prilikom konverzija (proirivanje se tada uvek vri nulama). Ukoliko se tip

char

koristi za smetanje neeg drugog osim karaktera koji mogu da se tampaju,

signed ili unsigned da bi se

programi izvravali identino na svim raunarima.

(2
01
5)

preporuuje se eksplicitno navoenje kvalifikatora

Sve brojevne vrednosti (i cele i u pokretnom zarezu) prevode se u istinitosne


vrednosti tako to se 0 prevodi u 0, a sve ne-nula vrednosti se prevode u 1.

6.5.2

Eksplicitne konverzije

je

Operator eksplicitne konverzije tipa ili operator kastovanja (engl. type cast
operator) se navodi tako to se ime rezultujueg tipa navodi u malim zagradama

an

ispred izraza koji se konvertuje:

(tip)izraz

iz

Operator kastovanja je prefiksni, unaran operator i ima vii prioritet od svih


binarnih operatora. U sluaju primene operatora kastovanja na promenljivu,
vrednost izraza je vrednost promenljive konvertovana u traeni tip, a vrednost

sk
o

same promenljive se ne menja (i, naravno, ne menja se njen tip).


Eksplicitna konverzija moe biti neophodna u razliitim situacijama.

Na

primer, ukoliko se na celobrojne operande eli primena deljenja brojeva u

ro
n

pokretnom zarezu:

3.250000

le

kt

int a = 13, b = 4;
printf("%d\t", a/b);
printf("%f\n", (double)a/(double)b);

Prilikom prvog poziva funkcije

to je izraz

a/b

printf

upotrebljen je format

celobrojnog tipa navoenje

%f

umesto

%d,

%d,

zbog toga

naravno, ne utie

na njegov tip i rezultat i ne bi imalo smisla.


U nastavku e biti prikazano da je, u navedenom primeru, bilo dovoljno
konvertovati i samo jedan od operanada u tip

double

i u tom sluaju bi se

drugi operand implicitno konvertovao.

6.5.3

Implicitne konverzije

Prilikom primene nekih operatora vre se konverzije vrednosti operanada


implicitno, bez zahteva progremera.

129

6. Predstavljanje podataka i operacije nad njima

Ve je reeno da se prilikom primene operatora dodele vri (ukoliko je


potrebno) implicitna konverzija vrednosti desne strane dodele u tip leve strane
dodele, pri emu se je tip izraza dodele tip leve strane. Na primer,

int a;
double b = (a = 3.5);
a, vri se konverzija
int, a zatim se, prilikom dodele prou double vrednost 3.0.

konstante 3.5 u vrednost 3 tipa

menljivoj

b,

vri konverzija te vrednosti

(2
01
5)

U navedenom primeru, prilikom dodele promenljivoj

double

Prilikom primene nekih aritmetikih operatora vre se implicitne konverzije


(najee promocije) koje obezbeuju da operandi postanu istog tipa pogodnog
za primenu operacija. Ove konverzije se nazivaju uobiajene aritmetike kon-

verzije (engl. usual arithmetic conversions ).

primenjuju prilikom primene aritmetikih (+,

>, <=, >=, ==, !=),

-, *, /)

i relacijskih binarnih

prilikom primene uslovnog operatora

je

operatora (<,

Ove konverziju se, na primer,

?:.

char

short

an

Aritmetiki operatori se ne primenjuju na male tipove tj. na podatke tipa


(zbog toga to je u tim sluajevima verovatno da e doi do

prekoraenja tj. da rezultat nee moi da se zapie u okviru malog tipa), ve

se pre primene operatora mali tipovi promoviu u tip

12 .

int.

Ovo se naziva

iz

celobrojna promocija (engl. integer promotion)

ro
n

sk
o

unsigned char cresult, c1, c2, c3;


c1 = 100;
c2 = 3;
c3 = 4;
cresult = c1 * c2 / c3;

le

kt

U navedenom primeru, vri se celobrojna promocija promenljivih c1, c2 i


c3 u int pre izvoenja operacija, a zatim se vri konverzija rezultata u tip
char prilikom upisa u promenljivu cresult. Kada se celobrojna promocija ne
bi vrila, mnoenje c1 * c2 bi dovelo do prekoraenja jer se vrednost 300 ne
moe predstaviti u okviru tipa char i rezultat ne bi bio korektan (tj. ne bi bila
dobijena vrednost (100 3)/4).

Generalno, prilikom primene aritmetikih operacija primenjuju se sledea

pravila konverzije:
1. Ako je bar jedan od operanada tipa
tuje u

long double;

long double,

2. inae, ako je jedan od operanada tipa


u

double;

12 Celobrojna

double,

onda se drugi konver-

onda se drugi konvertuje

promocija ima jednostavno opravdanje ako se razmotri prevedeni mainski

program. Naime, tip

int

odgovara irini registara u procesoru tako da se konverzija malih

vrednosti vri jednostavnim upisivanjem u registre. Procesori obino nemaju mainske instrukcije za rad sa kraim tipovima podataka i operacije nad kraim tipovima podataka
(sluaj u kojem se ne bi vrila celobrojna promocija) zapravo bi bilo tee ostvariti.

130

6. Predstavljanje podataka i operacije nad njima

float,

3. inae, ako je jedan od operanada tipa

float;

4. inae, svi operandi tipa

char i short

5. ako je jedan od operanada tipa

long long;

onda se drugi konvertuje u

promoviu se u

int.

long long,

onda se drugi konvertuje u

long,

onda se drugi konvertuje u

6. inae, ako je jedan od operanada tipa

(2
01
5)

long.

U sluaju korienja neoznaenih operanada (tj. meanja oznaenih i neoznaenih operanada), pravila konverzije su neto komplikovanija:

13 od oznaenog, oznaeni operand se kon-

1. Ako je neoznaeni operand iri


vertuje u neoznaeni iri tip;

je

2. inae, ako je tip oznaenog operanda takav da moe da predstavi sve vrednosti neoznaenog tipa, tada se neoznaeni tip prevodi u iri, oznaeni.

an

3. inae, oba operanda se konvertuju u neoznaeni tip koji odgovara ozna-

enom tipu.

Problemi najee nastaju prilikom poreenja vrednosti razliitih tipova.

int

zauzima 16 bitova, a

iz

Na primer, ako

long 32 bita, tada je -1l < 1u.


signed long i unsigned int.
vrednosti tipa unsigned int, vri

Zaista, u ovom primeru porede se vrednosti tipa


Poto

signed long

moe da predstavi sve

sk
o

signed long i vri se poreenje. S druge strane,


-1l > 1ul. U ovom sluaju porede se vrednosti tipa signed long
i unsigned long. Poto tip signed long ne moe da predstavi sve vrednosti
tipa unsigned long, oba operanda se konvertuju u unsigned long. Tada se
-1l konvertuje u ULONG_MAX (najvei neoznaen broj koji se moe zapisati u
32 bita), dok 1ul ostaje neizmenjen i vri se poreenje.

se konverzija oba operanda u

ro
n

vai da je

kt

Ukoliko se eli postii uobiajeni poredak brojeva, bez obzira na irinu


tipova na prenosiv nain, poreenje je poeljno izvriti na sledei nain:

le

signed
si = /* neka vrednost */;
unsigned ui = /* neka vrednost */;
/* if (si < ui) - ne daje uvek korektan rezultat */
if (si < 0 || (unsigned)si < ui) {
...
}

13 Preciznije,

standard uvodi pojam konverzionog ranga (koji raste od

i u ovoj situaciji se razmatra konverzioni rang.

char ka long long)

131

6. Predstavljanje podataka i operacije nad njima

Pitanja i zadaci za vebu


Pitanje 6.5.1.

ta su to implicitne, a ta eksplicitne konverzije?

nain se vrednost karakterske promenljive

Na koji

se moe eksplicitno konvertovati u

celobrojnu vrednost?

Pitanje 6.5.2.

ta su to promocije, a ta democije? Koje od narednih kon-

(2
01
5)

verzija su promocije, a koje democije: (a) int u short, (b) char u float, (c)
double u long, (d) long u int?

Pitanje 6.5.3.

Navesti pravila koja se primenjuju prilikom primene aritmetikih

operatora.

Pitanje 6.5.4.

Pitanje 6.5.5.

konvertuju

Ako aritmetiki operator ima dva argumenta, a nijedan od njih

long double, ni tipa double, ni tipa float, u koji tip se implicitno


argumenti tipa char i short int?

iz

nije ni tipa

an

je

Koje vrednosti imaju promenljive e i f nakon kda


unsigned char c = 255, d = 1, e = c + d; int f = c + d;?
Koje vrednosti imaju promenljive e, g i f nakon kda
unsigned char c = 255, d = 1; signed char e = c;
char f = c + d; int g = c + d;?

Pitanje 6.5.6.

sk
o

1. Koju vrednost ima promenljiva

tipa

float

nakon naredbe

x = (x = 3/2);?
2. Ako promenljiva

ima tip

ro
n

c = 1.5 * c;?

char,

koji tip e ona imati nakon dodele

x tipa float
x = 3/2 + (double)3/2 + 3.0/2;?

kt

3. Koju vrednost ima promenljiva

4. Ako je promenljiva

nakon naredbe:

le

ima

float, a promenljiva a tipa int,


f = (a = 1/2 < 0.5)/2;?

tipa

Koje vrednosti imaju promenljive

iic

koju vrednost

nakon naredbi

Pitanje 6.5.7.

nakon naredbe

char c, c1 = 130, c2 = 2; int i; i = (c1*c2)/4; c = (c1*c2)/4;

Pitanje 6.5.8.

tip c1, c2, c = (c1*c2)/c2; promenljiva


c1 ako je

Da li nakon naredbe

nuno ima vrednost promenljive

tip

tip

char,

tip

tip

int,

tip

tip

float?

132

6. Predstavljanje podataka i operacije nad njima

6.6 Nizovi i niske


esto je u programima potrebno korienje velikog broja srodnih promenljivih. Umesto velikog broja pojedinano deklarisanih promenljivih, mogue je
koristiti nizove .

Obrada elemenata nizova se onda obino vri na uniforman

6.6.1

(2
01
5)

nain, korienjem petlji.

Primer korienja nizova

Razmotrimo, kao ilustraciju, program koji uitava 10 brojeva sa standard-

nog ulaza, a zatim ih ispisuje u obratnom poretku. Bez nizova, neophodno je

koristiti deset promenljivih. Da se u zadatku trailo ispisivanje unatrag 1000


brojeva, program bi bio izrazito mukotrpan za pisanje i nepregledan.

je

Program 6.4.

an

#include <stdio.h>

sk
o

iz

int main() {
int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9;
scanf("%d%d%d%d%d%d%d%d%d%d",
&b0, &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &b9);
printf("%d %d %d %d %d %d %d %d %d %d",
b9, b8, b7, b6, b5, b4, b3, b2, b1, b0);
}

ro
n

1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1

Umesto 10 razliitih srodnih promenljivih, mogue je upotrebiti niz i time

kt

znatno uprostiti prethodni program.

Program 6.5.

le

#include <stdio.h>
int main() {
int b[10], i;
for (i = 0; i < 10; i++)
scanf("%d", &b[i]);
for (i = 9; i >= 0; i--)
printf("%d ", b[i]);
return 0;
}

133

6. Predstavljanje podataka i operacije nad njima

6.6.2

Deklaracija niza

Nizovi u programskom jeziku C mogu se deklarisati na sledei nain:

tip ime_niza[dimenzija];
Dimenzija predstavlja broj elemenata niza. Na primer, deklaracija

uvodi niz

a od 10 celih brojeva.

(2
01
5)

int a[10];

Prvi element niza ima indeks 0, pa su elementi

niza:

a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]

Indeksi niza su obino nenegativni celi brojevi (mada je u nekim prilikama kada

je

se nizovi koriste u kombinaciji sa pokazivaima doputeno koristiti i negativne

an

indekse, o emu e vie biti rei u poglavlju 10.3).

Prilikom deklaracije moe se izvriti i inicijalizacija:

int a[5] = { 1, 2, 3, 4, 5 };

jednak je:

iz

Nakon ove deklaracije, sadraj niza

sk
o

Veliina memorijskog prostora potrebnog za niz odreuje se u fazi prevoenja programa, pa broj elemenata niza (koji se navodi u deklaraciji) mora

ro
n

biti konstantan izraz. U narednom primeru, deklaracija niza


su deklaracije nizova

bic

neispravne

14 :

a je ispravna, dok

le

kt

int x;
char a[100+10];
int b[];
float c[x];

Ako se koristi inicijalizacija, mogue je navesti veu dimenziju od broja

navedenih elemenata (kada se inicijalizuju samo poetni elementi deklarisanog


niza). Neispravno je navoenje manje dimenzije od broja elemenata inicijalizatora.
Dimenziju niza je mogue izostaviti samo ako je prilikom deklaracije izvrena
i inicijalizacija niza i tada se dimenzija odreuje na osnovu broja elemenata u
inicijalizatoru. Na primer, nakon deklaracije

14 Standardi

nakon C99 uvode pojam niza promenljive duine (engl. variable length array,

VLA). U tom svetlu, deklaracija niza


razmatrani.

bila bi ispravna. Ipak, u ovoj knjizi, VLA nee biti

134

6. Predstavljanje podataka i operacije nad njima

int b[] = { 1, 2, 3 };
sadraj niza

jednak je:

sizeof

primeni na ime niza, rezultat je veliina niza u

(2
01
5)

Kada se operator
bajtovima.

Ukoliko dimenzija niza nije zadata eksplicitno ve je implicitno

odreena inicijalizacijom, broj elemenata moe se izraunati na sledei nain:

sizeof(ime niza)/sizeof(tip elementa niza)

Kada se pristupa elementu niza, indeks moe da bude proizvoljan izraz


celobrojne vrednosti, na primer:

an

je

a[2*2+1]
a[i+2]

U fazi prevoenja (pa ni u fazi izvravanja

15 ) ne vri se nikakva provera da

li je indeks pristupa nizu u njegovim granicama i mogue je bez ikakve prijave

iz

greke ili upozorenja od strane prevodioca pristupati i lokaciji koji se nalazi


van opsega deklarisanog niza (na primer, mogue je koristiti element
ak element

a[-1]

a[13], pa

u prethodnom primeru). Ovo najee dovodi do fatalnih

sk
o

greaka prilikom izvravanja programa. S druge strane, ovakva (jednostavna)


politika upravljanja nizovima omoguava veu efikasnost programa.
Pojedinani elementi nizova su l-vrednosti (tj. mogue im je dodeljivati

ro
n

vrednosti). Meutim, nizovi nisu l-vrednosti i nije im mogue dodeljivati vrednosti niti ih menjati. To ilustruje sledei primer:

le

kt

int a[3] = {5, 3, 7};


int b[3];
b = a;
/* Neispravno - nizovi se ne mogu dodeljivati. */
a++;
/* Neispravno - nizovi se ne mogu menjati. */

6.6.3

Niske

Posebno mesto u programskom jeziku C zauzimaju nizovi koji sadre karaktere niske karaktera ili krae niske (engl. strings ). Konstantne niske navode
se izmeu dvostrukih navodnika (na primer,

"ja sam niska").

U okviru niski,

specijalni karakteri navode se korienjem specijalnih sekvenci (na primer,

15 U

fazi izvravanja, operativni sistem obino proverava da li se pokuava upis van memo-

rije koja je dodeljena programu i ako je to sluaj, obino nasilno prekida izvravanje programa
(npr. uz poruku

segmentation fault).

O ovakvim grekama bie vie rei u poglavlju 9.3.5.

135

6. Predstavljanje podataka i operacije nad njima

"prvi red\ndrugi red").

Niske su interno reprezentovane kao nizovi karak-

tera na iji desni kraj se dopisuje karakter


(engl. null terminator ).

nulom (engl.

\0,

tzv. zavrna, terminalna nula

Zbog toga, niske u C-u se nazivaju niske zavrene

null terminated strings )

16 .

Posledica ovoga je da ne postoji

ogranienje za duinu niske, ali je neophodno proi kroz celu nisku da bi se


odredila njena duina.

(2
01
5)

Niske mogu da se koriste i prilikom inicijalizacije nizova karaktera.

char s1[] = {Z, d, r, a, v, o};


char s2[] = {Z, d, r, a, v, o, \0};
char s3[] = "Zdravo";
Nakon navedenih deklaracija, sadraj niza
2

a sadraj nizova
0

r a v
s2 i s3 jednak je:

je

jednak je:

an

s1

Z d r a v o \0
Niz s1 sadri 6 karaktera (i zauzima 6 bajtova).

Deklaracije za

s2

s3

iz

su ekvivalentne i ovi nizovi sadre po 7 karaktera (i zauzimaju po 7 bajtova).


Prvi niz karaktera nije terminisan nulom i ne moe se smatrati ispravnom

x)
"x" koja sadri

niskom. Potrebno je jasno razlikovati karakterske konstante (na primer,


dva karaktera,

sk
o

koje predstavljaju pojedinane karaktere i niske (na primer,

x i \0).

Ukoliko se u programu niske nalaze neposredno jedna uz drugu, one se

ro
n

automatski spajaju. Na primer:

printf("Zdravo, " "svima");

kt

je ekvivaletno sa

le

printf("Zdravo, svima");

Standardna biblioteka definie veliki broj funkcija za rad sa niskama. Pro-

totipovi ovih funkcija se nalaze u zaglavlju

strlen

slui za izraunavanje duine niske.

rauna se zavrna nula.

string.h.

Na primer, funkcija

Pri raunanju duine niske, ne

Ilustracije radi, jedan od naina da se neposredno,

bez pozivanja neke funkcije (naravno, uvek je preporuljivo pozvati biblioteku


funkciju ukoliko je dostupna), izrauna duina niske
nakon ijeg izvravanja promenljiva

16 Neki

dat je sledeim kdom,

sadri traenu duinu:

programski jezici koriste drugaije konvencije za interni zapis niski.

Na primer,

u Pascal-u se pre samog sadraja niske zapisuju broj koji predstavlja njenu duinu (tzv. Pniske).

136

6. Predstavljanje podataka i operacije nad njima

int i = 0;
while (s[i] != \0)
i++;
Kd koji obrauju niske obino ih obrauje karakter po karakter i obino
sadri petlju oblika:

(2
01
5)

while (s[i] != \0)


...
ili oblika:

for (i = 0; s[i] != \0; i++)


...

je

Kako zavrna nula ima numeriku vrednost 0 (to predstavlja istinitosnu

an

vrednost netano), poreenje u prethodnoj petlji moe da se izostavi:

for (i = 0; s[i]; i++)


...

iz

Izuzetno neefikasan kd dobija se pozivanjem funkcije

strlen

za izrauna-

vanje duine niske u svakom koraku iteracije:

sk
o

for (i = 0; i < strlen(s); i++)


...

Jo jedna funkcija standardne biblioteke za rad sa niskama je funkcija

u nisku

koja, kada se pozove sa strcpy(dest, src), vri kopiranje niske src


dest, pretpostavljajui da je niska kojoj se dodeljuje vrednost dovoljno

ro
n

strcpy

velika da primi nisku koja se dodeljuje. Ako to nije ispunjeno, vri se promena

kt

sadraja memorijskih lokacija koje su van dimenzija niza to moe dovesti do


fatalnih greaka prilikom izvravanja programa. Ilustracije radi, navedimo kako

le

se kopiranje niski moe izvesti neposredno. U nisku

po karakter niske

src

dest se prebacuje karakter

sve dok dodeljeni karakter ne bude zavrna nula:

int i = 0;
while ((dest[i] = src[i]) != \0)
i++;

Poreenje razliitosti sa terminalnom nulom se moe izostaviti, a petlja se,


moe preformulisati kao

for

petlja:

int i;
for (i = 0; dest[i] = src[i]; i++)
;
/* prazno telo petlje */

137

6. Predstavljanje podataka i operacije nad njima

6.6.4

Viedimenzioni nizovi

Pored jednodimenzionih mogu se koristiti i viedimenzioni nizovi, koji se


deklariu na sledei opti nain:

tip ime_niza[dimenzija_1]...[dimenzija_2];

(2
01
5)

Dvodimenzioni nizovi (matrice) tumae se kao jednodimenzioni nizovi iji


su elementi nizovi. Zato se elementima dvodimenzionog niza pristupa sa:

ime_niza[vrsta][kolona]
a ne sa

ime_niza[vrsta, kolona]

(greke do kojih moe doi zbog pokuaja

ovakvog pristupa ve su napomenute u kontekstu operatora zarez (,), u poglavlju


6.4).

je

Elementi se u memoriji smetaju po vrstama pa se, kada se elementima

pristupa u redosledu po kojem su smeteni u memoriji, najbre menja poslednji

an

indeks. Niz se moe inicijalizovati navoenjem liste inicijalizatora u vitiastim


zagradama; poto su elementi opet nizovi, svaki od njih se opet navodi u okviru
vitiastih zagrada (mada je unutranje vitiaste zagrade mogue i izostaviti).

iz

sk
o

char a[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

Razmotrimo, kao primer, jedan dvodimenzioni niz:

Kao i u sluaju jednodimenzionih nizova, ako je naveden inicijalizator, vred-

ro
n

nost prvog indeksa mogue je i izostaviti (jer se on u fazi kompilacije moe


odrediti na osnovu broja inicijalizatora):

le

kt

char a[][3] = {
{1, 2, 3},
{4, 5, 6}
};

U memoriji su elementi poreani na sledei nain: a[0][0], a[0][1],


a[0][2], a[1][0], a[1][1], a[1][2], tj. vrednosti elemenata niza poreane
su na sledei nain: 1, 2, 3, 4, 5, 6. U ovom primeru, element a[v][k] je -ti
po redu, pri emu je jednako 3*v+k. Pozicija elementa viedimenzionog niza
moe se slino izraunati i sluaju nizova sa tri i vie dimenzija.

17

Razmotrimo, kao dodatni primer, dvodimenzioni niz koji sadri broj dana
za svaki mesec, pri emu su u prvoj vrsti vrednosti za obine, a u drugoj vrsti
za prestupne godine:

17 Nekada

programeri ovu tehniku izraunavanja pozicija eksplicitno koriste da matricu

smeste u jednodimenzioni niz, ali, poto jezik doputa korienje viedimenzionih nizova, za
ovim nema potrebe.

138

6. Predstavljanje podataka i operacije nad njima

char broj_dana[][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
Za skladitenje malih prirodnih brojeva koristi se tip

char, a u nultu kolonu


m (tj. da bi

nalazili upravo u koloni

(2
01
5)

su upisane nule da bi se podaci za mesec

se mesecima pristupalo korienjem indeksa 1-12, umesto sa indeksa 0-11). Niz

broj_dana je mogue koristiti da bi se, na primer, promenljiva bd postavila na


mesec i godinu godina:

broj dana za mesec

je

int prestupna = (godina % 4 == 0 && godina % 100 != 0) ||


godina % 400 == 0;
char bd = broj_dana[prestupna][mesec];

Vrednost logikog izraza je uvek nula (netano) ili jedan (tano), pa se

prestupna

moe koristiti kao indeks pri pristupanju nizu.

an

vrednost

Napisati deklaraciju sa inicijalizacijom niza

iz

Pitanje 6.6.1.

Pitanja i zadaci za vebu

tipa

int

koji za

elemente ima neparne brojeve manje od 10.

bude

zdravo

Navesti primer inicijalizacije niza tipa

i to:

sk
o

Pitanje 6.6.2.

char tako da mu sadraj

(i) navoenjem pojedinanih karaktera izmeu vitiastih

zagrada i (ii) konstantom niskom.

izraza

Ukoliko je niz

ro
n

Pitanje 6.6.3.

sizeof(a)?

Pitanje 6.6.4.

Ako je niz

a deklarisan kao float a[10];, koja je vrednost


tipa

float

inicijalizovan u okviru deklaracije i

kt

njegova dimenzija nije navedena, kako se ona moe izraunati?

le

Pitanje 6.6.5.

Kada je u deklaraciji niza dozvoljeno izostaviti njegovu dimen-

ziju?

Pitanje 6.6.6.

Precrtati sve neispravne linije narednog kda.

int a[];
int b[] = {1, 2, 3};
int c[5] = {1, 2, 3};
int d[2] = {1, 2, 3};
c = b;
b++;

139

6. Predstavljanje podataka i operacije nad njima

Pitanje 6.6.7.

Deklarisati i inicijalizovati dvodimenzioni niz koji sadri ma-

tricu

Pitanje 6.6.8.

1
4

2
5

1
3
5

Zadatak 6.6.1.

2
4 .
6

(2
01
5)

Deklarisati i inicijalizovati dvodimenzioni niz koji sadri ma-

tricu

zatim i

3
6

Napisati program koji unosi prirodan broj

elemenata niza celih brojeva, nakon ega:

1. ispisuje unete brojeve unatrag;

an

3. ispisuje zbir elemenata unetog niza.

.).

Zadatak 6.6.2.

Sa standardnog ulaza se uitava tekst sve dok se ne unese taka


Napisati program koji u unetom tekstu prebrojava pojavljivanje

iz

(tj. karakter

je

2. ispisuje najvei element unetog niza;

( < 1000),

svake od cifara (broj pojavljivanja smestiti u niz od 10 elemenata).

Zadatak 6.6.3.

sk
o

Napisati program koji za uneti datum u obliku (dan, mesec,

godina) odreuje koji je to po redu dan u godini. Proveriti i koretknost unetog


datuma. U obzir uzeti i prestupne godine. Koristiti niz koji sadri broj dana

ro
n

za svaki mesec i uporediti sa reenjem zadatka bez korienja nizova.

Zadatak 6.6.4.

Paskalov trougao sadri binomne koeficijente

program koji ispisuje prvih

redova trougla (

< 100).

()

. Napisati
Na primer, za = 6

1
2
3
4
5

le

1
1
1
1
1
1

kt

ispisuje se:

1
3 1
6 4 1
10 10 5 1

0 = = 1, kao da se svaki
unutranji lan trougla moe dobiti kao zbir odgovarajua dva lana prethodne
() (1) (1)

vrste, tj. da vai da je = 1 +


).

(primetite da su ivice trougla 1 tj. da vai

Zadatak 6.6.5.
ziju matrice (

()

( )

Napisati program koji sa standardnog ulaza unosi prvo dimen-

< 10)

pa zatim elemente matrice. Na primer,

140

4
1
5
9
4

6. Predstavljanje podataka i operacije nad njima

2
6
1
5

3
7
2
6

4
8
3
7

Program izraunava i ispisuje sumu elemenata glavne dijagonale i sumu elematrice navedene u primeru je
je

1 + 6 + 2 + 7 = 16,

(2
01
5)

menata iznad sporedne dijagonale matrice. Suma elemenata glavne dijagonale


a iznad sporedne dijagonale

1 + 2 + 3 + 5 + 6 + 9 = 26

Zadatak 6.6.6.
ziju matrice (

Napisati program koji sa standardnog ulaza unosi prvo dimen-

< 100)

pa zatim elemente matrice i zatim proverava da li je

matrica donje-trougaona. Matrica je donje-trougaona ako se u gornjem trouglu

0
6
1
5

0
0
2
6

0
0

0
7

1
5

9
4

an

je

(iznad glavne dijagonale, ne ukljuujui je) nalaze sve nule. Na primer:

iz

sk
o

6.7 Korisniki definisani tipovi

Programski jezik C ima svega nekoliko ugraenih osnovnih tipova. Ve nizovi i niske predstavljaju sloene tipove podataka.

Osim nizova, postoji jo

ro
n

nekoliko naina izgradnje sloenih tipova podataka. Promenljive se mogu organizovati u strukture (tj. slogove ), pogodne za specifine potrebe.

Na taj

nain se povezane vrednosti (ne nuno istog tipa) tretiraju kao jedna celina

kt

i za razliku od nizova gde se pristup pojedinanim vrednostima vri na osnovu brojevnog indeksa, pristup pojedinanim vrednostima vri se na osnovu
imena polja strukture. Pored struktura, mogu se koristiti unije, koje su sline

le

strukturama, ali kod kojih se jedan isti memorijski prostor koristi za vie pro-

menljivih. Mogu se koristiti i nabrojivi tipovi, sa konanim skupom vrednosti.


Pored definisanja novih tipova, ve definisanim tipovima se moe pridruiti i
novo ime.

6.7.1

Strukture

Osnovni tipovi jezika C esto nisu dovoljni za pogodno opisivanje svih podataka u programu. Ukoliko je neki podatak sloene prirode tj. sastoji se od
vie delova, ti njegovi pojedinani delovi mogu se uvati nezavisno (u zasebnim
promenljivama), ali to esto vodi programima koji su nejasni i teki za odravanje. Umesto toga, pogodnije je koristiti strukture. Za razliku od nizova koji
objedinjuju jednu ili vie promenljivh istog tipa, struktura objedinjuje jednu ili

141

6. Predstavljanje podataka i operacije nad njima

vie promenljivih, ne nuno istih tipova. Definisanjem strukture uvodi se novi


tip podataka i nakon toga mogu da se koriste promenljive tog novog tipa, na
isti nain kao i za druge tipove.
Korienje struktura bie ilustrovano na primeru razlomaka. U jeziku C ne
postoji tip koji opisuje razlomke, ali moe se definisati struktura koja opisuje
razlomke. Razlomak moe da bude opisan parom koji ine brojilac i imenilac,

brojilac, a
razlomak moe se

na primer, celobrojnog tipa. Brojilac (svakog) razlomka zvae se

imenilac.

Struktura

(2
01
5)

imenilac (svakog) razlomka zvae se


definisati na sledei nain:

struct razlomak {
int brojilac;
int imenilac;
};
struct zapoinje definiciju strukture.

Nakon nje, navodi se ime

je

Kljuna re

an

strukture, a zatim, izmeu vitiastih zagrada, opis njenih lanova (ili polja).
Imena lanova strukture se ne mogu koristiti kao samostalne promenljive, one
postoje samo kao deo sloenijeg objekta.

Prethodnom definicijom strukture

struct razlomak,

uveden je samo novi tip pod imenom

ali ne i promenljive

iz

tog tipa.

Strukture mogu sadrati promenljive proizvoljnog tipa. Na primer, mogue


je definisati strukturu koja sadri i niz.

ro
n

sk
o

struct student {
char ime[50];
float prosek;
};

Strukture mogu biti ugnjedene, tj. lanovi struktura mogu biti druge struk-

kt

ture. Na primer:

le

struct dvojni_razlomak {
struct razlomak gore;
struct razlomak dole;
};
Definicija strukture uvodi novi tip i nakon nje se ovaj tip moe koristiti

kao i bilo koji drugi. Definicija strukture se obino navodi van svih funkcija.
Ukoliko je navedena u okviru funkcije, onda se moe koristiti samo u okviru
te funkcije. Prilikom deklarisanja promenljivih ovog tipa, kao deo imena tipa,
neophodno je korienje kljune rei

struct razlomak a, b, c;

struct,

na primer:

142

6. Predstavljanje podataka i operacije nad njima

Definicijom strukture je opisano da se razlomci sastoje od brojioca i imenioca, dok se navedenom deklaracijom uvode tri konkretna razlomka koja se
nazivaju

a, b i c.

Mogua je i deklaracija sa inicijalizacijom, pri emu se inicijalne vrednosti


za lanove strukture navode izmeu vitiastih zagrada:

(2
01
5)

struct razlomak a = { 1, 2 };
Redosled navoenja inicijalizatora odgovara redosledu navoenja lanova
strukture. Dakle, navedenom deklaracijom je uveden razlomak

1,

a imenilac

2.

a iji je brojilac

Definisanje strukture i deklarisanje i inicijalizacija promenljivih moe se


uraditi istovremeno (otuda i neuobiajeni simbol

nakon zatvorene vitiaste

zagrade prilikom definisanja strukture):

an

je

struct razlomak {
int brojilac;
int imenilac;
} a = {1, 2}, b, c;

lanu strukture se pristupa preko imena promenljive (iji je tip struktura)

iz

iza kojeg se navodi taka a onda ime lana, na primer:

sk
o

a.imenilac

Na primer, vrednost promenljive


na sledei nain:

a tipa struct razlomak moe biti ispisan

ro
n

printf("%d/%d", a.brojilac, a.imenilac);


Naglasimo da je operator

.,

iako binaran, operator najvieg prioriteta (istog

kt

nivoa kao male zagrade i unarni postfiksni operatori).


Ne postoji konflikt izmeu imena polja strukture i istoimenih promenljivih,

le

pa je naredni kd korektan.

int brojilac = 5, imenilac = 3;


a.brojilac = brojilac; a.imenilac = imenilac;

Od ranije prikazanih operacija, nad promenljivama tipa strukture dozvoljene su operacije dodele a nisu dozvoljeni aritmetiki i relacijski operatori.
Operator

sizeof

se moe primeniti i na ime strukturnog tipa i na promen-

ljive tog tipa i u oba sluaja dobija se broj bajtova koje struktura zauzima u
memoriji. Napomenimo da taj broj moe nekada biti i vei od zbira veliina
pojedinanih polja, jer se zbog uslova poravnanja (engl. alignment), o kojem e
vie biti rei u glavi 10, ponekad izmeu dva uzastopna polja strukture ostavlja
prazan prostor.

143

6. Predstavljanje podataka i operacije nad njima

Nizovi struktura
esto postoji povezana skupina sloenih podataka. Umesto da se oni uvaju
u nezavisnim nizovima (to bi vodilo programima tekim za odravanje) bolje je
koristiti nizove struktura. Na primer, ako je potrebno imati podatke o imenima
i broju dana meseci u godini, mogue je te podatke uvati u nizu sa brojevima
dana i u (nezavisnom) nizu imena meseci. Bolje je, meutim, opisati strukturu

(2
01
5)

mesec koja sadri broj dana i ime:

struct opis_meseca {
char ime[10];
int broj_dana;
};
i koristiti niz ovakvih struktura:

13

an

(deklarisan je niz duine

je

struct opis_meseca meseci[13];

da bi se meseci mogli referisati po svojim rednim

brojevima, pri emu se poetni element niza ne koristi).

iz

18 :

Mogua je i deklaracija sa inicijalizacijom (u kojoj nije neophodno navoenje


broja elemenata niza)

kt

ro
n

sk
o

struct opis_meseca meseci[] = {


{ "",0 },
{ "januar",31 },
{ "februar",28 },
{ "mart",31 },
...
{ "decembar",31 }
};

U navednoj inicijalizaciji unutranje vitiaste zagrade je mogue izostaviti:

le

struct opis_meseca meseci[] = {


"",0,
"januar",31,
"februar",28,
"mart",31,
...
"decembar",31
};

Nakon navedene deklaracije, ime prvog meseca u godini se moe dobiti sa

meseci[1].ime,
18 U

njegov broj dana sa

meseci[1].broj_dana

itd.

ovom primeru se zanemaruje injenica da februar moe imati i 29 dana.

144

6. Predstavljanje podataka i operacije nad njima

Kao i obino, broj elemenata ovako inicijalizovanog niza moe se izraunati


na sledei nain:

sizeof(meseci)/sizeof(struct opis_meseca)

Unije

(2
01
5)

6.7.2

Unije su donekle sline strukturama. One objedinjuju nekoliko promenljivih


koje ne moraju imati isti tip. No, za razliku od struktura kod kojih se sva polja

u strukturi istovremeno popunjavaju i sva se mogu istovremeno koristiti, kod


unije se u jednom trenutku moe koristiti samo jedno polje. Veliina strukture

odgovara zbiru veliina njenih polja, dok veliina unije odgovara veliini njenog
najveeg polja. Osnovna svrha unija je uteda memorije.

Skoro sva sintaksika pravila koja se odnose na strukutre se prenose i na

struct

je

unije (jedina razlika je da se umesto kljune rei

koristi kljuna re

an

union).

Naredna unija omoguava korisniku da izabere da li e vreme da pamti kao


ceo broj sekundi ili kao razlomljen broj (koji obuhvata i manje delove sekunde).

iz

sk
o

union vreme {
int obicno;
float precizno;
};

Oba polja unije nee se moi koristiti istovremeno.

ro
n

Nakon definisanja tipa unije, mogue je definisati i promenljive ovog tipa,


na primer:

kt

union vreme a;
a.obicno = 17;

Unije se esto koriste i kao lanovi struktura. Neka se, na primer, u pro-

le

gramu uvaju i obrauju informacije o studetima i zaposlenima na nekom fakultetu. Za svakoga se uva ime, prezime i matini broj, za zaposlene se jo uva

i koeficijent za platu, dok se za studente uva broj indeksa:

struct akademac {
char ime_i_prezime[50];
char jmbg[14];
char vrsta;
union {
double plata;
char indeks[7];
} dodatno;
};

145

6. Predstavljanje podataka i operacije nad njima

U ovom sluaju poslednji lan strukture (dodatno) je unijskog tipa (sm


tip unije nije imenovan).

vrsta

lan strukture

tipa

char sadri informaciju


z) ili o studentu (na

o tome da li se radi o zaposlenom (na primer, vrednost


primer, vrednost

s).

Promenljive

plata

indeks

dele zajedniki memorijski

prostor i podrazumeva se da se u jednom trenutku koristi samo jedan podatak


u uniji. Na primer:

(2
01
5)

int main() {
struct akademac pera = {"Pera Peric", "0101970810001", z};
pera.dodatno.plata = 56789.5;
printf("%f\n", pera.dodatno.plata);
struct akademac ana = {"Ana Anic", "1212992750501", s};
strcpy(ana.dodatno.indeks, "12/123");
printf("%s\n", ana.dodatno.indeks);

je

pera.dodatno.indeks bi naruio podatak o koeficiana.dodatno.koeficijent naruio

an

Pokuaj promene polja

jentu plate, dok bi pokuaj promene polja

podatak o broju indeksa.

iz

Navedimo, kao ilustraciju, kako se korienjem unije moe otkriti binarni


zapis broja u pokretnom zarezu:

6.7.3

ro
n

sk
o

union { float x; unsigned char s[4]; } u;


u.x = 1.234f;
printf("%x%x%x%x", u.s[0], u.s[1], u.s[2], u.s[3]);

Polja bitova

kt

Jo jedan od naina utede memorije u C programima su polja bitova


(engl. bit fields).

Naime, najmanji celobrojni tip podataka je

char

koji za-

le

uzima jedan bajt, a za predstavljanje neke vrste podataka dovoljan je manji


broj bitova. Na primer, zamislimo da elimo da predstavimo grafike karak-

teristike pravougaonika u nekom programu za crtanje. Ako je doputeno samo


osnovnih 8 boja (crvena, plava, zelena, cijan, magenta, uta, bela i crna) za
predstavljanje boje dovoljno je 3 bita. Vrsta okvira (pun, isprekidan, takast)
moe da se predstavi sa 2 bita.

Na kraju, da li pravougaonik treba ili ne

treba popunjavati moe se kodirati jednim bitom. Ovo moe da se iskoristiti


za definisanje sledeeg polja bitova.

struct osobine_pravougaonika {
unsigned char popunjen
unsigned char boja

: 1;
: 3;

146

6. Predstavljanje podataka i operacije nad njima

};

unsigned char vrsta_okvira

: 2;

Iza svake promenljive, naveden je broj bitova koji je potrebno odvojiti


za tu promenljivu.

Veliina ovako definisanog polja bitova (vrednost izraza

sizeof(struct osobine_pravougaonika))

je samo 1 bajt (iako je potrebno

samo 6 bitova, svaki podatak mora da zauzima ceo broj bajtova, tako da je

(2
01
5)

odvojen 1 bit vie nego sto je potrebno). Da je u pitanju bila obina struktura,
zauzimala bi 3 bajta.

Polje bitova se nadalje koristi kao obina struktura. Na primer:

...
#define ZELENA
...
#define PUN 00

02

6.7.4

iz

an

je

struct osobine_pravougaonika op;


op.popunjen = 0;
op.boja = ZELENA;
op.vrsta_okvira = PUN;

Nabrojivi tipovi (enum)

sk
o

U nekim sluajevima korisno je definisati tip podataka koji ima mali skup
doputenih vrednosti. Ovakvi tipovi se nazivaju nabrojivi tipovi . U jeziku C
nabrojivi tipove se definiu korienjem kljune rei

enum.

Na primer:

le

kt

ro
n

enum znak_karte {
KARO,
PIK,
HERC,
TREF
};

Nakon navedene definicije, u programu se mogu koristiti imena KARO, PIK,


HERC, TREF, umesto nekih konkretnih konstantnih brojeva, to popravlja itljivost
programa. Pri tome, obino nije vano koje su konkretne vrednosti pridruene
imenima

KARO, PIK, HERC, TREF,

usobno razliite i celobrojne.

PIK

vrednost 1,

HERC

ve je dovoljno znati da su one sigurno me-

U navedenom primeru,

vrednost 2 i

TREF

vrednost 3.

navoenje celobrojnih vrednosti. Na primer:

enum znak_karte {
KARO = 1,
PIK = 2,
HERC = 4,

KARO

ima vrednost 0,

Mogue je i eksplicitno

147

6. Predstavljanje podataka i operacije nad njima

};

TREF = 8

Vrednosti nabrojivih tipova nisu promenljive i njima se ne moe menjati


vrednost.

S druge strane, promenljiva moe imati tip koji je nabrojiv tip i

koristiti se na uobiajene naine.


Slian efekat (uvoenja imena sa pridruenim celobrojnim vrednostima) se

#define

(videti poglavlje 9.2.1),

enum).

(2
01
5)

moe postii i pretprocesorskom direktivom

ali u tom sluaju ta imena ne ine jedan tip (kao u sluaju da se koristi

Grupisanje u tip je pogodno zbog provera koje se vre u fazi prevoenja.

Slino kao i kod struktura i unija, uz definiciju tipa mogue je odmah deklarisati i promenljive.

Promenljive se mogu i naknadno definisati (uz obavezno

ponovno korienje kljune rei

enum).

Na primer,

je

enum znak_karte znak;

iz

struct karta {
unsigned char broj;
enum znak_karte znak;
} mala_dvojka = {2, TREF};

an

Nabrojivi tipovi mogu uestvovati u izgradnji drugih sloenih tipova.

Nabrojivi tipovi se esto koriste da zamene konkretne brojeve u programu,

sk
o

na primer, povratne vrednosti funkcija.

Mnogo je bolje, u smislu itljivosti

programa, ukoliko funkcije vraaju (razliite) vrednosti koje su opisane nabrojivim tipom (i imenima koja odgovaraju pojedinim povratnim vrednostim) nego

ro
n

konkretne brojeve. Tako, na primer, tip povratne vrednosti neke funkcije moe
da bude nabrojiv tip definisan na sledei nain:

le

kt

enum return_type {
OK,
FileError,
MemoryError,
TimeOut
};

6.7.5

Typedef

U jeziku C mogue je kreirati nova imena postojeih tipova koristei kljunu


re

typedef.

Na primer, deklaracija

typedef int Length;

148

6. Predstavljanje podataka i operacije nad njima

Length

uvodi ime

kao sinonim za tip

int.

Ime tipa

Length

se onda moe

koristiti u deklaracijama, eksplicitnim konverzijama i slino, na isti nain kao

int:

to se koristi ime

Length len, maxlen;


Novo ime tipa se navodi kao poslednje, na poziciji na kojoj se u deklaraci-

typedef.

(2
01
5)

jama obino navodi ime promenljive, a ne neposredno nakon kljune rei

Obino se novouvedena imena tipova piu velikim poetnim slovima da bi se


istakla.
Deklaracijom

typedef

se ne kreira novi tip ve se samo uvodi novo ime za

potojei tip. Staro ime za taj tip se moe koristiti i dalje.


Veoma esto korienje

typedef

deklaracija je u kombinaciji sa struktu-

rama da bi se izbeglo pisanje kljune rei

struct

pri svakom korienju imenu

an
d

struct point {
int x, y;
};
typedef struct point Point;

je

strukturnog tipa. Na primer:

iz

Point a, b;

sk
o

Definicija strukture i pridruivanje novog imena se mogu uraditi istovremeno. Na primer:

ro
n

typedef struct point {


int x, y;
} Point;

kt

Point a, b;
Deklaracija

typedef

je slina pretprocesorskoj direktivi

#define

(videti

le

poglavlje 9.2.1), s tim to nju obrauje kompilator (a ne pretprocesor) i moe


da da rezultat i u sluajevima u kojima jednostavne pretprocesorske tekstualne

zamene to ne mogu. Na primer:

typedef int (*PFI)(char *, char *);


PFI, za tip pokaziva na funkciju koja prima dva char * argumenta
int (vie rei o pokazivaima na funkcije e biti u glavi 10) i koje se

uvodi ime
i vraa

moe koristiti na primer kao:

PFI strcmp, numcmp;

149

6. Predstavljanje podataka i operacije nad njima

Osim estetskih razloga, postoje dve osnovne svrhe za korienje kljune rei

typedef

i imenovanje tipova. Prvi je parametrizovanje tipova u programu da

bi se dobilo na njegovoj prenosivosti. Ukoliko se

typedef

koristi za uvoenje

novih imena za tipove koji su mainski zavisni, u sluaju da se program prenosi


na drugu mainu, potrebno je promeniti samo

short, int

long

typedef

typedef

deklaracije. Jedan od

za imenovanje celobrojnog tipa, i zatim odabir

u zavisnosti od maine.

Point

razumeti nego dugo ime strukture.

Pitanja i zadaci za vebu


Pitanje 6.7.1.

Definisati strukturu

Pitanje 6.7.2.

Definisati strukturu

typedef

Druga svrha upotrebe

je poboljanje itljivosti programa tip sa imenom

complex

se jednostavnije

(2
01
5)

primera je korienje

koja ima dva lana tipa

student

double.

kojom se predstavljaju podaci o

je

studentu (ime, prezime, JMBG, prosena ocena).

Pitanje 6.7.3.

an

Da li je nad vrednostima koje su istog tipa strukture dozvoljeno

koristiti operator dodele i koje je njegovo dejstvo?

Pitanje 6.7.4.

Navesti primer inicijalizacije niza struktura tipa

iz

struct datum { unsigned dan, mesec, godina; } na dananji i sutranji

datum.

Pitanje 6.7.5.

sk
o

Data je struktura:

ro
n

struct tacka {
int a, b;
char naziv[5];
}

(a,b) u ravni kojoj je dodelstruct tacka, napisati naredbe koje

Ova struktura opisuje taku sa koordinatama

naziv.

kt

jeno ime

Za dve promenljive tipa

le

kopiraju sadraj prve promenljive u drugu promenljivu.


Kakva je veza izmeu nabrojivog (enum) i celobrojnog tipa u

Pitanje 6.7.7.

Na koji nain se postojeem tipu

Pitanje 6.7.6.

C-u?

NoviTip?

Pitanje 6.7.8.

Uvesti novo ime

Pitanje 6.7.9.
jedan lan tipa

Definisati novi tip

int

Zadatak 6.7.1.

real

i jedan lan tipa

za tip

novitip
float.

moe dodeliti novo ime

double.
koji odgovara strukturi koji ima

Napisati program koji uitava 10 kompleksnih brojeva i meu

njima odreuje broj najveeg modula. Definisati i koristiti strukturu

complex
.

150

6. Predstavljanje podataka i operacije nad njima

Zadatak 6.7.2.

Napraviti program koji uitava redni broj dana u nedelji (broji

se od ponedeljka) i ispisuje da li je radni dan ili vikend (definisati i koristiti

le

kt

ro
n

sk
o

iz

an

je

(2
01
5)

nabrojivi tip podataka).

(2
01
5)

Glava 7

je

Naredbe i kontrola toka

Osnovni elementi kojima se opisuju izraunavanja u programima su naredbe.


u zavisnosti od vrednosti promenljivih.

an

Naredbe za kontrolu toka omoguavaju razliite naine izvravanja programa,


Naredbe za kontrolu toka ukljuuju

naredbe grananja i petlje. Iako u jeziku C postoji i naredba skoka (goto), ona

nee biti opisivana, jer esto dovodi do loe strukturiranih programa, neitljivih
se napisati i bez nje.

iz

i tekih za odravanje a, dodatno, svaki program koji koristi naredbu

goto moe

Na osnovu teoreme o strukturnom programiranju, od

if) i jedna
while), ali se u programima esto koriste i druge

naredbi za kontrolu toka dovoljna je naredba grananja (tj. naredba

sk
o

vrsta petlje (na primer, petlja

naredbe za kontrolu toka radi bolje itljivosti kda. Iako mogu da postoje opte
preporuke za pisanje kda jednostavnog za razumevanje i odravanje, izbor

ro
n

naredbi za kontrolu toka u konkretnim situacijama je najee stvar afiniteta


programera.

kt

7.1 Naredba izraza

Osnovni oblik naredbe koji se javlja u C programima je takozvana naredba

le

izraza (ova vrsta naredbi obuhvata i naredbu dodele i naredbu poziva funkcije).
Naime, svaki izraz zavren karakterom

; je naredba.

Naredba izraza se izvrava

tako to se izrauna vrednost izraza i izraunata vrednost se potom zanemaruje.


Ovo ima smisla ukoliko se u okviru izraza koriste operatori koji imaju bone
efekte (na primer,

=, ++, +=

itd.) ili ukoliko se pozivaju funkcije. Naredba do-

dele, kao i naredbe koje odgovaraju pozivima funkcija sintaksiki su obuhvaene


naredbom izraza. Naredni primer ilustruje nekoliko vrsta naredbi:

3 + 4*5;
n = 3;
c++;
f();

151

152

7. Naredbe i kontrola toka

Iako su sve etiri navedene naredbe ispravne i sve predstavljaju naredbe izraza,
prva naredba ne proizvodi nikakav efekat i nema semantiko opravdanje pa se
retko sree u stvarnim programima. etvrta naredba predstavlja poziv funkcije

(pri emu se, ako je ima, povratna vrednost funkcije zanemaruje).


Zanimljiva je i prazna naredba koja se obeleava samo znakom

telo

for

; (na primer,

petlje moe sadrati samo praznu naredbu).

(2
01
5)

7.2 Sloene naredbe (blokovi)

U nekim sluajevima potrebno je vie razliitih naredbi tretirati kao jednu


jedinstvenu naredbu. Vitiaste zagrade

{i}

se koriste da grupiu naredbe u

sloene naredbe tj. blokove i takvi blokovi se mogu koristiti na svim mestima

gde se mogu koristiti i pojedinane naredbe. Iza zatvorene vitiaste zagrade


ne pie se znak

;.

Vitiaste zagrade koje okruuju vie naredbi neke petlje su

je

jedan primer njihove upotrebe, ali one se, za grupisanje naredbi, koriste i u
drugim kontekstima. Doputeno je i da blok sadri samo jednu naredbu, ali

an

tada nema potrebe koristiti blok (izuzetak je definicija funkcije koja ne moe da
bude pojedinana naredba ve mora biti blok i telo naredbe

do-while koje uvek

mora biti navedeno izmeu vitiastih zagrada). Svaki blok, na poetku moe
da sadri (mogue praznu) listu deklaracija promeljivih (koje se mogu koristiti

iz

samo u tom bloku). Vidljivost tj. oblast vaenja imena promenljivih odreena je
pravilima dosega (o emu e vie rei biti u poglavlju 9.2.2). Nakon deklaracija,

sk
o

navode se naredbe (elementarne ili sloene, tj. novi blokovi). Postoje razliite
konvencije za nazubljivanje vitiastih zagrada prilikom unosa izvornog kda.

ro
n

7.3 Naredbe grananja

Naredbe grananja (ili naredbe uslova), na osnovu vrednosti nekog izraza,

kt

odreuju naredbu (ili grupu naredbi) koja e biti izvrena.

Naredba

if-else

le

7.3.1

Naredba uslova

if

ima sledei opti oblik:

if (izraz)
naredba1
else
naredba2

naredba1 i naredba2 su ili pojedinane naredbe (kada se za;) ili blokovi naredbi zapisani izmeu vitiastih zagrada
(iza kojih se ne pie simbol ;).
Deo naredbe else je opcioni, tj. moe da postoji samo if grana. Izraz izraz
Naredba

vravaju simbolom

predstavlja logiki uslov i najee je u pitanju celobrojni izraz (ali moe biti i
izraz ija je vrednost broj u pokretnom zarezu) za koji se smatra, kao i uvek, da

153

7. Naredbe i kontrola toka

je taan (tj. da je uslov ispunjen) ako ima ne-nula vrednost, a inae se smatra
da je netaan. Na primer, nakon naredbe

promenljiva

e imati vrednost

2,

e imati vrednost

1.

a nakon naredbe

promenljiva

je

if (7)
a = 1;
else
a = 2;

(2
01
5)

if (5 > 7)
a = 1;
else
a = 2;

Kako se ispituje istinitosna vrednost izraza koji je naveden kao uslov, ponekad

if (n != 0) je ekvivalentno sa

an

je mogue taj uslov zapisati krae. Na primer,

if (n).

Dodela je operator, pa je naredni C kd je sintaksiki ispravan, ali verovatno

iz

je semantiki pogrean (tj. ne opisuje ono to je bila namera programera):

ro
n

sk
o

a = 3;
if (a = 0)
printf("a je nula\n");
else
printf("a nije nula\n");

a na nulu
a jednako 0), a zatim ispisuje tekst a nije nula, jer
je vrednost izraza a = 0 nula, to se smatra netanim. Zamena operatora ==
operatorom = u naredbi if je esta greka.
Naime, efekat ovog kda je da postavlja vrednost promenljive

kt

(a ne da ispita da li je

le

if-else vieznanost.

Naredbe koje se izvravaju uslovno mogu da sadre

if naredbi. Ukoliko vielse se odnosi na poslednji

nove naredbe uslova, tj. moe biti vie ugnjedenih


tiastim zagradama nije obezbeeno drugaije,
prethodei neuparen

if.

Ukoliko se eli drugaije ponaanje, neophodno je

navesti vitiaste zagrade. U narednom primeru,


na prvo

if

else

(iako nazubljivanje sugerie drugaije):

if (izraz1)
if (izraz2)
naredba1
else
naredba2

se odnosi na drugo a ne

154

7. Naredbe i kontrola toka

U narednom primeru,

else

se odnosi na prvo a ne na drugo

if

7.3.2

Konstrukcija

(2
01
5)

if (izraz1) {
if (izraz2)
naredba1
} else
naredba2

else-if

Za viestruke odluke esto se koristi konstrukcija sledeeg oblika:

iz

an

je

if (izraz1)
naredba1
else if (izraz2)
naredba2
else if (izraz3)
naredba3
else
naredba4

U ovako konstruisanoj naredbi, uslovi se ispituju jedan za drugim. Kada

sk
o

je jedan uslov ispunjen, onda se izvrava naredba koja mu je pridruena i


time se zavrava izvravanje itave naredbe. Naredba

naredba4 u gore navedeizraz1, izraz2,

nom primeru se izvrava ako nije ispunjen nijedan od uslova

Naredni primer ilustruje ovaj tip uslovnog grananja.

ro
n

izraz3.

le

kt

if (a > 0)
printf("A je veci od nule\n");
else if (a < 0)
printf("A je manji od nule\n");
else /* if (a == 0) */
printf("A je nula\n");

7.3.3

Naredba

if-else

Naredna naredba

if (a > b)
x = a;
else
x = b;

i operator uslova

155

7. Naredbe i kontrola toka

odreuje i smeta u promenljivu

veu od vrednosti

a i b.

Naredba ovakvog

oblika se moe zapisati krae korienjem ternarnog operatora uslova

?:

(koji

je opisan u poglavlju 6.4.7), na sledei nain:

x = (a > b) ? a : b;

Naredba

switch

(2
01
5)

Naredba

switch se koristi za viestruko odluivanje i ima sledei opti oblik:

an

switch (izraz) {
case konstantan_izraz1: naredbe1
case konstantan_izraz2: naredbe2
...
default:
naredbe_n
}

je

7.3.4

Naredbe koje treba izvriti oznaene su sluajevima (engl. case) za razliite

izraz.

Svakom sluaju pridruen

je konstantni celobrojni izraz. Ukoliko zadati izraz

ima vrednost kon-

mogue pojedinane vrednosti zadatog izraza

izraz

iz

stantnog izraza navedenog u nekom sluaju, onda se izvravanje nastavlja od


prve naredbe pridruene tom sluaju, pa se nastavlja i sa izvravanjem naredbi

sk
o

koje odgovaraju sledeim sluajevima iako izraz nije imao njihovu vrednost,
sve dok se ne naie na kraj ili naredbu
ako vrednost izraza

izraz

break.

Na sluaj

default se prelazi
default je

nije navedena ni uz jedan sluaj. Sluaj

opcioni i ukoliko nije naveden, a nijedan postojei sluaj nije ispunjen, onda se

ro
n

ne izvrava nijedna naredba u okviru bloka

switch. Sluajevi mogu biti navedefault), ali razliiti poretci

deni u proizvoljnom poretku (ukljuujui i sluaj

mogu da daju razliito ponaanje programa. Iako to standard ne zahteva, sluaj

default

default
izraz nije navedena ni uz jedan

kt

se gotovo uvek navodi kao poslednji sluaj. I ukoliko sluaj

nije naveden kao poslednji, ako vrednost izraza

drugi sluaj, prelazi se na izvravanje naredbi od naredbe pridruene sluaju

le

default.

switch esto se koristi naredba break. Kada se naie


break, naputa se naredba switch. Najee se naredbe priduene
svakom sluaju zavravaju naredbom break (ak i nakon poslednje navedenog
sluaja, to je najee default). Time se ne menja ponaanje programa, ali se

U okviru naredbe

na naredbu

obezbeuje da poredak sluajeva ne utie na izvravanje programa, te je takav


kd jednostavniji za odravanje.
Izostavljanje naredbe
naredbi

break,

break,

tj. previanje injenice da se, ukoliko nema

nastavlja sa izvravanjem naredbi narednih sluajeva, esto

dovodi do greaka u programu.

S druge strane, izostavljanje naredbe

break

moe biti pogodno (i opravdano) za pokrivanje vie razliitih sluajeva jednom


naredbom (ili blokom naredbi).

156

7. Naredbe i kontrola toka

U narednom primeru proverava se da li je uneti broj deljiv sa tri, kori

switch.

cenjem naredbe

Program 7.1.
#include <stdio.h>

(2
01
5)

int main() {
int n;
scanf("%i",&n);

an

je

switch (n % 3) {
case 1:
case 2:
printf("Uneti broj nije deljiv sa 3");
break;
default: printf("Uneti broj je deljiv sa 3");
}
return 0;

n % 3 jednaka 1 ili 2,
Uneti broj nije deljiv sa 3, a inae e biti ispisan tekst
Uneti broj je deljiv sa 3. Da u nije navedena naredba break, onda bi u
sluaju da je vrednost izraza n % 3 jednaka 1 (ili 2), nakon teksta Uneti broj
nije deljiv sa 3, bio ispisan i tekst Uneti broj je deljiv sa 3 (jer bi

iz

U navedenom primeru, bilo da je vrednost izraza

sk
o

bie ispisan tekst

ro
n

bilo nastavljeno izvravanje svih naredbi za sve naredne sluajeve).

7.4 Petlje

kt

Petlje (ciklusi ili repetitivne naredbe) uzrokuju da se odreena naredba (ili

le

grupa naredbi) izvrava vie puta (sve dok je neki logiki uslov ispunjen).

7.4.1

Petlja

Petlja

while

while

ima sledei opti oblik:

while(izraz)
naredba
U petlji

while

ispituje se vrednost izraza

izraz

i ako ona ima istinitosnu

naredba
izraz iznova

vrednost tano (tj. ako je vrednost izraza razliita od nule), izvrava se


(to je ili pojedinana naredba ili blok naredbi). Zatim se uslov

proverava i sve se ponavlja dok mu istinosna vrednost ne postane netano


(tj. dok vrednost ne postane jednaka nuli). Tada se izlazi iz petlje i nastavlja
sa izvravanjem prve sledee naredbe u programu.

157

7. Naredbe i kontrola toka

Ukoliko iza

while

sledi samo jedna naredba, onda, kao i oblino, nema

potrebe za vitiastim zagradama. Na primer:

while (i < j)
i++;
while

petlja se izvrava beskonano:

(2
01
5)

Sledea

while (1)
i++;

Petlja

Petlja

for

for

ima sledei opti oblik:

je

7.4.2

izraz1, izraz2 i izraz3 su izrazi. Obino su izraz1 i izraz3


izraz2 je relacijski izraz. Izraz izraz1 se

izrazi dodele ili inkrementiranja, a

Komponente

an

for (izraz1; izraz2; izraz3)


naredba

izraz2

iz

obino naziva inicijalizacija i koristi se za postavljanje poetnih vrednosti promenljivih, izraz

je uslov izlaska iz petlje, a

izraz3 je korak i njime se


naredba naziva se telo

petlje.

sk
o

menjaju vrednosti relevantnih promenljivih. Naredba


Inicijalizacija (izraz
avanja petlje.

izraz1)

izraunava se samo jednom, na poetku izvr-

Petlja se izvrava sve dok uslov (izraz

izraz2)

ima ne-nula

ro
n

vrednost (tj. sve dok mu je istinitosna vrednost tano), a korak (izraz

izraz3)

izraunava se na kraju svakog prolaska kroz petlju. Redosled izvravanja je,


dakle, oblika: inicijalizacija, uslov, telo, korak, uslov, telo, korak, . . . , uslov,

telo, korak, uslov, pri emu je uslov ispunjen svaki, osim poslednji put. Dakle,

kt

gore navedena opta forma petlje


petlju

while:

for

ekvivalentna je konstrukciji koja koristi

le

izraz1;
while (izraz2) {
naredba
izraz3;
}
Petlja

for

se obino koristi kada je potrebno izvriti jednostavno poetno

dodeljivanje vrednosti promenljivama i jednostavno ih menjati sve dok je ispunjen zadati uslov (pri emu su i poetno dodeljivanje i uslov i izmene lako
vidljivi u definiciji petlje). To ilustruje sledea tipina forma

for

petlje:

158

7. Naredbe i kontrola toka

for(i = 0; i < n; i++)


...
Bilo koji od izraza izraz1, izraz2, izraz3 moe biti izostavljen, ali simboli
; i tada moraju biti navedeni. Ukoliko je izostavljen izraz izraz2, smatra se da
je njegova istinitosna vrednost tano. Na primer, sledea for petlja se izvrava
koja prekida izvravanje, na primer,

break

ili

return):

for (;;)
...
Ako je potrebno da neki od izraza
izraza, moe se koristiti operator

,.

izraz1, izraz2, izraz3

an

i=2, j=8

i=3, j=7

i=1, j=9

iz

i=0, j=10

objedini vie

je

for (i = 0, j = 10; i < j; i++, j--)


printf("i=%d, j=%d\t", i, j);
Prethodni kd ispisuje

(2
01
5)

beskonano (ako u bloku naredbi koji ovde nije naveden nema neke naredbe

i=4, j=6

Sledei program, koji ispusuje tablicu mnoenja, ilustruje dvostruku

Program 7.2.

sk
o

petlje:

ro
n

#include<stdio.h>

le

kt

int main() {
int i, j, n=3;
for(i = 1; i <= n; i++) {
for(j = 1; j <= n; j++)
printf("%i * %i = %i\t", i, j, i*j);
printf("\n");
}
return 0;
}
1 * 1 = 1
2 * 1 = 2
3 * 1 = 3

1 * 2 = 2
2 * 2 = 4
3 * 2 = 6

1 * 3 = 3
2 * 3 = 6
3 * 3 = 9

for

159

7. Naredbe i kontrola toka

7.4.3

Petlja

Petlja

do-while

do-while

ima sledei opti oblik:

do {
naredbe
} while(izraz)
naredbe) naveden izmeu vitiastih zagrada se izvrava
izraz). Ako je on taan, telo se izvrava
nastavlja sve dok izraz izraz nema vrednost nula (tj. sve dok

(2
01
5)

Telo (blok naredbi

i onda se izraunava uslov (izraz


ponovo i to se

njegova istinitosna vrednost ne postane netano).


Za razliku od petlje

while,

naredbe u bloku ove petlje se uvek izvravaju

barem jednom.

Naredni program ispisuje cifre koje se koriste u zapisu unetog neoznaenog

je

broja, zdesna na levo.

ro
n

sk
o

iz

#include <stdio.h>
int main() {
unsigned n;
printf("Unesi broj: ");
scanf("%u", &n);
do {
printf("%u ", n % 10);
n /= 10;
} while (n > 0);
return 0;
}

an

Program 7.3.

le

kt

Unesi broj: 1234


4 3 2 1

Primetimo da, u sluaju da je koriena

broj

7.4.4

while,

a ne

do-while

petlja, za

ne bi bila ispisana ni jedna cifra.

Naredbe

break i continue

U nekim situacijama pogodno je napustiti petlju ne zbog toga to nije ispunjen uslov petlje, ve iz nekog drugog razloga. To je mogue postii naredbom

break

kojom se izlazi iz tekue petlje (ili naredbe

1 Naredbom break

switch)1

ne izlazi se iz bloka naredbe grananja.

Na primer:

160

7. Naredbe i kontrola toka

for(i = 1; i < n; i++) {


if(i > 10)
break;
...
}
break

se naruava strukturiranost kda i to moe da

(2
01
5)

Korienjem naredbe

otea njegovu analizu (na primer, analizu ispravnosti ili analizu sloenosti).
U nekim situacijama, korienje naredbe
ali kd koji koristi naredbu

break

break

moe da pobolja itljivost,

uvek se moe napisati i bez nje. U datom

primeru, odgovarajui alternativni kd je, na primer:

Naredbom

continue

je

for(i = 1; i<n && i<=10; i++)


...

se prelazi na sledeu iteraciju u petlji. Na primer,

iz

an

for(i = 0; i < n; i++) {


if (i % 10 == 0)
continue; /* preskoci brojeve deljive sa 10 */
...
}
break,

korienjem naredbe

sk
o

Slino kao za naredbu

continue

se naruava

strukturiranost kda, ali moe da se pobolja itljivost. Kd koji koristi naredbu

continue

uvek se moe napisati i bez nje. U datom primeru, odgovarajui al-

ro
n

ternativni kd je, na primer:

kt

for(i = 0; i < n; i++)


if (i % 10 != 0) /* samo brojevi koji nisu deljivi sa 10 */
...
U sluaju ugnjedenih petlji, naredbe

break i continue imaju dejstvo samo

le

na unutranju petlju. Tako, na primer, fragment

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


for (j = 0; j < 3; j++) {
if (i + j > 2) break;
printf("%d %d
", i, j);
}

ispisuje

0 0

0 1 0 2

1 0

1 1

2 0

161

7. Naredbe i kontrola toka

Pitanja i zadaci za vebu


Pitanje 7.1.

Koju vrednost ima promenljiva

nakon izvravanja kda

if (!x)
x += 2;
x *= 2;

Pitanje 7.2.

0,

a koju ako je imala vrednost

Koju vrednost ima promenljiva

nakon izvravanja kda

int x = 0;
if (x > 3);
x++;
Navesti primer naredbe u kojoj se javlja

Pitanje 7.4.

Kako se, u okviru naredbe

i i j tipa int odrediti njihovu vrednost nakon

ro
n

sk
o

iz

naredbi:

i=2; j=5;
switch(j/i)
{
case 1: i++;
break;
case 2: i += ++j;
default: j += ++i;
}

oznaava sluaj koji pokriva

an

Ako su promenljive

switch,

vieznanost.

Pitanje 7.5.

if-else

je

Pitanje 7.3.

sve sluajeve koji nisu ve pokriveni?

5?

(2
01
5)

ako je pre navedenog kda imala vrednost

Ako su promenljive

kt

Pitanje 7.6.

i i j tipa int odrediti njihovu vrednost nakon

naredbi:

le

int i=2, j=4;


switch (j%3) {
case 0: i=j++;
case 1: j++;++i;
case 2: j=i++;
default:
}

Pitanje 7.7.

ta se ispisuje prilikom izvravanja narednog kda?

int i = 2; int j = 2;
while(i + 2*j <= 15) {
i++;

162

7. Naredbe i kontrola toka

Pitanje 7.8.

(2
01
5)

if (i % 3 == 0)
j--;
else {
i+=2; j++;
}
printf("%d %d\n", i, j);
ta se ispisuje prilikom izvravanja narednog kda?

Pitanje 7.9.

je

for (i = 0; i < 5; i++)


for (j = 0; j < 5; j++) {
if ((i + j) % 3 == 0) break;
printf("%d %d\n", i, j);
}

ta se ispisuje prilikom izvravanja narednog kda?

ta se ispisuje prilikom izvravanja narednog kda?

sk
o

Pitanje 7.10.

iz

an

for (i = 0; i < 5; i++)


for (j = 0; j < 5; j++) {
if ((i + j) % 3 == 0) continue;
printf("%d %d\n", i, j);
}

ro
n

for (i = 1, j = 10; i < j; i++, j--)


for (k = i; k <= j; k++)
printf("%d ", k);

Pitanje 7.11.

Ukoliko se u naredbi

for (e1; e2; e3) ...

izostavi izraz

e2,

koja e biti njegova podrazumevana vrednost?

kt

Pitanje 7.12.

Da li je u naredbi

for(e1; e2; e3) ...,

mogue da su izrazi

sainjeni od vie nezavisnih podizraza i ako jeste, kojim operatorom su

le

e1 i e3

povezani ti podizrazi?

Pitanje 7.13.

Izraziti sledei kd (i) petljom

while

i (ii) petljom

for

while

i (ii) petljom

do-while

do {
naredbe
} while(izraz)

Pitanje 7.14.

Izraziti sledei kd (i) petljom

for (izraz1; izraz2; izraz3)


naredba

Pitanje 7.15.

Izraziti sledei kd (i) petljom

for

i (ii) petljom

do-while

163

7. Naredbe i kontrola toka

while (izraz)
naredba

Pitanje 7.16.

Transformisati naredni kd tako da ne sadri

Pitanje 7.17.

(2
01
5)

while(A) {
if(B) break;
C;
}

Transformisati naredni kd tako da ne sadri

continue:

je

for(;A;) {
if(B) continue;
C;
}

Transformisati naredni kd i zapisati ga u obliku

tako da ne sadri

break:

while

petlje

an

Pitanje 7.18.

break:

for(i = 1;;i++) if (i++ == 3) break; else printf("%d", i);

2.

for(i = 1;;) if (++i == 3) break; else printf("%d", i);

3.

for(i = 10;;) if (--i == 3) break; else printf("%d", i);

4.

for(i = 1; i<5;) if (++i == 5) break; else printf("%d", i);

Pitanje 7.19.

sk
o

iz

1.

Transformisati naredni kd i zapisati ga u obliku

sva tri izraza neprazna i bez korienja naredbe

break.

for

petlje sa

for(i = 10;;) if (--i == 3) break; else printf("%d", i);

2.

for(i = 1;;) if (i++ == 3) break; else printf("%d", i);

ro
n

1.

Pitanje 7.20.

Da li se naredne petlje zaustavljaju:

le

kt

unsigned char c; for(c=10; c<9; c++) { ... }


signed char c; for(c=10; c<9; c++) { ... }
signed char c; for(c=0; c<128; c++) { ... }
unsigned char c; for(c=0; c<128; c++) { ... }
char c; for(c=0; c<128; c++) { ... }

Zadatak 7.1.

Napisati program koji ispisuje sve neparne brojeve manje od

unetog neoznaenog celog broja

Zadatak 7.2.
sin()
broj

Napisati program koji izraunava i ispisuje vrednost funkcije

u 100 taaka intervala

Zadatak 7.3.
dimenzija

[0, 2]

na jednakim rastojanjima.

Napisati program koji uitava realan broj


.

i izraunava

Zadatak 7.4.

n.

i neoznaeni ceo

Napisati programe koji ispisuje naredne dijagrame, pri emu se


unosi. Svi primeri su za = 4:

164

7. Naredbe i kontrola toka

a) **** b) ****
****
***
****
**
****
*

c) *
**
***
****

d) ****
***
**
*

e)

*
**
***
****

f) * * * * g)
* * *
* *
*

*
* *
* * *
* * * *

Zadatak 7.5.

Napisati program koji odreuje sumu svih delilaca broja (koristiti

Zadatak 7.6.

(2
01
5)

injenicu da se delioci javljaju u paru).

Napisati program koji odreuje da li je uneti neoznaeni ceo broj

prost.

Zadatak 7.7.

Napisati program koji ispisuje sve proste inioce unetog neoz-

Zadatak 7.8.

Napisati program koji uitava cele brojeve sve dok se ne unese

a onda ispisuje:

an

0,

24 traeni prosti inioci su 2, 2, 2,


3).

je

naenog celog broja (na primer, za unos

1. broj unetih brojeva;

4. minimum unetih brojeva;

iz

3. proizvod unetih brojeva;

2. zbir unetih brojeva;

sk
o

5. maksimum unetih brojeva;

6. aritmetiku sredinu unetih brojeva (

1 +...+
);

ro
n

7. geometrijsku sredinu unetih brojeva (


8. harmonijsku sredinu unetih brojeva (

1
1

1 . . . );

);
+...+ 1

kt

Zadatak 7.9.

Napisati program koji uitava cele brojeve sve dok se ne unese

i izraunava duinu najdue serije uzastopnih jednakih brojeva.

le

Zadatak 7.10.

Napisati program koji za uneti neoznaeni ceo broj

nava ceo deo njegovo korena

Zadatak 7.11.

izrau-

(koristiti algoritam opisan u primeru 3.3).

Korienjem injenice da niz definisan sa

0 = 1,

+1 =

2
2

, napisati program koji (bez korienja funkcije sqrt) procenjuje

vrednost
. Iterativni postupak zaustaviti kada je |+1 | < 0.0001.

tei ka

165

7. Naredbe i kontrola toka

Zadatak 7.12.

Fibonaijev niz brojeva

1, 1, 2, 3, 5, 8, 13, 21, . . .

je definisan

uslovima

0 = 1,

1 = 1,

Napisati program koji ispisuje prvih

+2 = +1 + .
lanova ovog niza (koristiti ideju da se

u svakom trenutku pamte, u dve promenljive, vrednosti dva prethodna elementa

Zadatak 7.13.
celog broja

n,

Napisati program koji ispisuje sve cifre unetog neoznaenog

poevi od cifre jedinica.

Napisati i program koji izraunava

sumu cifara unetog neoznaenog celog broja

Zadatak 7.14.

(2
01
5)

niza).

n.

Napisati program koji nadovezuje dva uneta neoznaena cela

broja (na primer, za unos

123 i 456 program ispisuje 123456).

Ako je jedan od

brojeva 0, rezultat treba da bude jednak drugom broju. Pretpostaviti da rezultat

Napisati program koji izraunava broj dobijen obrtanjem cifara

unetog celog broja (na primer, za unos

program ispisuje broj

etog neoznaenog celog broja (na primer, za uneti broj

iz

246).

Zadatak 7.17.

4321).

Napisati program koji izbacuje sve neparne cifre iz zapisa un-

Zadatak 7.16.

1234

an

Zadatak 7.15.

unsigned.

je

staje u opseg tipa

123456

Napisati program koji umee datu cifru

neoznaenog celog broja

= 5, = 2, = 1234,

program ispisuje

na datu poziciju

sk
o

(pozicije se broje od 0 sa desna). Na primer, za unos

12534.

ro
n

Zadatak 7.18.

program ispisuje

1. Napisati program koji razmenjuje prvu i poslednju cifru unetog neoznaenog celog broja (na primer, za unos

1234

program ispisuje

4231).

kt

2. Napisati program koji ciklino pomera cifre unetog neoznaenog celog

le

broja u levo (na primer, za unos

1234

program ispisuje

2341).

3. Napisati program koji ciklino pomera cifre unetog neoznaenog celog


broja u desno (na primer, za unos

Zadatak 7.19.

1234

program ispisuje

4123).

Napisati program koji za zadati dan, mesec i godinu ispituje da

li je uneti datum korektan (uzeti u obzir i prestupne godine). Koristiti


naredbu.

Zadatak 7.20.

switch

Definisati nabrojivi tip za predstavljanje kolskog uspeha. Na

osnovu prosene ocene i broja jedinica uenika odrediti kolski uspeh. Nakon
toga, upotrebom naredbe

switch

ispisati odgovarajuu poruku.

166

7. Naredbe i kontrola toka

Zadatak 7.21.

Napisati program koji uitava neoznaene cele brojeve sve dok

se ne unese 0, a na standardni prepisuje sve one brojeve koji su:


1. manji od minimuma prethodno unetih brojeva (prvi broj se uvek ispisuje);
2. vei od aritmetike sredine prethodno unetih brojeva.

Zadatak 7.22.

(najvie 100000) ele0, a zatim prethodni niz ponovi

0112122312232334...

Napisati program koji ispisuje prvih

menata niza koji se dobija tako to se kree od


pri emu se svaki broj uvea za

Zadatak 7.23.

1,

tj.

(2
01
5)

Sa standardnog ulaza se unose dva niza brojeva (svaki sadri

najvie 100 elemenata). Napisati program koji odreuje njihov presek, uniju i
razliku (redosled prikaza elemenata nije bitan, i u ulaznim nizovima se elementi

Napisati program koji proverava da li je data niska palindrom

(ita se isto sleva i zdesna, na primer,

an

Zadatak 7.24.

je

ne ponavljaju).

anavolimilovana).

Prilagoditi program

tako da se razmaci zanemaruju i ne pravi se razlika izmeu malih i velikih slova

Ana voli Milovana

je palindrom).

(na primer,

Napisati program koji obre i ispisuje datu nisku.

Zadatak 7.26.

Napisati program koji sa standardnog ulaza unosi prvo dimenz-

sk
o

iju matrice (

iz

Zadatak 7.25.

< 100)

pa zatim elemente matrice i zatim ispisuje sve dijagonale

matrice paralelne sa sporednom dijagonalom. Na primer, unos:

3 1 2 3 4 5 6 7 8 9

kt

ro
n

opisuje matricu

1
4
7

2
5
8

3
6
9

le

za koju program ispisuje

1
2 4
3 5 7
6 8
9

Zadatak 7.27.

Napisati program koji sa standardnog ulaza uitava prvo di-

menzije matrice (

< 100 i < 100) a zatim redom i elemente matrice. Nakon


) onih elemenata matrice koji su jednaki zbiru svih

toga ispisuje indekse ( i

svojih susednih elemenata (pod susednim elementima podrazumevamo okolnih

polja matrice ako postoje). Na primer, za matricu:

167

1
0
1
0

7. Naredbe i kontrola toka

1
8
1
3

2
1
1
0

1
9
0
2

3
0
0
2
[1][1], [3][1], i [3][4]

zadovoljavaju traeni uslov.

le

kt

ro
n

sk
o

iz

an

je

(2
01
5)

polja na pozicijama

(2
01
5)

Glava 8

je

Funkcije
Svaki C program sainjen je od funkcija.

Funkcija

main

mora da postoji

main (ali i
printf),

biblioteke (poput funkcije

drugih) pozivaju se druge funkcije, bilo


bilo korisniki definisane (kakve e biti

ove funkcije . Iz funkcije

an

i, pojednostavljeno reeno, izvravanje programa uvek poinje izvravanjem

opisane u nastavku) . Druge funkcije koriste se da bi kd bio krai, itljiviji,


U funkciju se obino izdvaja neko izrau-

iz

modularniji, ire upotrebljiv itd.

navanje, neka obrada koja predstavlja celinu za sebe i koristi se vie puta u

sk
o

programu. Tako se dobija ne samo krai i jednostavniji kd, ve i kvalitetniji


u smislu da je neko izraunavanje skriveno u funkciji i ona moe da se koristi
ak i ako se ne zna kako tano je ona implementirana, ve je dovoljno znati ta

ro
n

radi, tj. kakav je rezultat njenog rada za zadate argumente.

8.1 Primeri definisanja i pozivanja funkcije


Poj-

kt

Naredni programi ilustruju jednostavne primere korienja funkcija.

movi koji su u okviru ovog primera samo ukratko objanjeni bie detaljnije

le

objanjeni u nastavku teksta.

Program 8.1.
#include <stdio.h>
int kvadrat(int n);
int main() {
printf("Kvadrat broja %i je %i\n", 5, kvadrat(5));
1U

glavi 9 bie objanjeno da se odreeni delovi izvrnog programa, obino sistemski

pozivi i odreene inicijalizacije, izvravaju i pre poziva funkcije


delovi programa izvravaju i nakon njenog zavretka.

2 Iz

funkcija programa moe se pozivati i funkcija

i generalno se ne preporuuje.

168

main,

main,

kao i da se odreeni

ali to obino nema mnogo smisla

169

8. Funkcije

printf("Kvadrat broja %i je %i\n", 9, kvadrat(9));


return 0;

int kvadrat(int n) {
return n*n;
}

(2
01
5)

int kvadrat(int n); deklarie funkciju kvadrat koja e biti defin3


kvadrat ima jedan
parametar tipa int i vraa rezultat tipa int. U funkciji main, u okviru poziva
funkcije printf poziva se funkcija kvadrat za vrednosti 5 i 9 (tipa int) i
ispisuje se rezultat, tipa int, koji ona vraa. Svaki poziv funkcije je izraz (koji
Linija

isana kasnije u kdu . Iz deklaracije se vidi da funkcija

moe ravnopravno dalje uestvovati u irim izrazima) iji je tip povratni tip
funkcije, a vrednost povratna vrednost funkcije. Na mestu poziva, tok izvra-

je

vanja programa prelazi na poetak funkcije koja je pozvana, a kada se zavri


izvravanje funkcije tok izvravanja programa vraa se na mesto poziva. Defini-

return

kvadrat

je jednostavna: ona kao rezultat, korienjem naredbe

an

cija funkcije

vraa kvadrat celobrojne vrednosti

ija se vrednost postavlja na os-

novu vrednosti koja je prosleena prilikom poziva.

stepen izraunava celobrojni stepen realne

iz

U narednom programu, funkcija


promenljive.

sk
o

Program 8.2.
#include <stdio.h>

ro
n

int max = 10;

float stepen(float x, unsigned n);

le

kt

int main() {
unsigned i;
for(i = 0; i < max; i++)
printf("%d %f %f\n", i, stepen(2.0f,i), stepen(3.0f,i));
return 0;
}
float stepen(float x, unsigned n) {
unsigned i;
float s = 1.0f;
for(i = 1; i<=n; i++)
s *= x;
3 Za

razliku od funkcija gde se deklaracije i definicije prilino jednostavno razlikuju, kod

promenljivih je ovu razliku mnogo tee napraviti.


promenljivih u jeziku C bie diskutovan u glavi 9.

Odnos izmeu deklaracija i definicija

170

8. Funkcije

return s;

}
i

i deklarisana u funkciji main, druga promenljiva


stepen, a promenljiva max deklarisana je van svih

Primetimo da je promenljiva
deklarisana je u funkciji

funkcija. Promenljive deklarisana u funkcijama nazivamo obino lokalne pro-

menljive i njih je mogue koristiti samo u okviru funkcije u kojoj su definisane,


menljive i one su zajednike za vie funkcija.

(2
01
5)

dok promenljive deklarisana van svih funkcija nazivamo obino globalne proO ovoj temi bie vie rei u

poglavlju 9.2.2.

8.2 Deklaracija i definicija funkcije

Deklaracija (ili prototip ) funkcije ima sledei opti oblik:

an

a definicija funkcije ima sledei opti oblik:

je

tip ime_funkcije(niz_deklaracija_parametara);

iz

tip ime_funkcije(niz_deklaracija_parametara) {
deklaracije
naredbe
}

sk
o

Imena funkcija su identifikatori i za njih vae potpuno ista pravila kao i za


imena promenljivih. Radi itljivosti kda, poeljno je da ime funkcije oslikava
ono ta ona radi.

ro
n

U navedenim primerima, prvo je navedena deklaracija funkcije, a tek kasnije


njena definicija. U prvom primeru, deklaracija je

kt

int kvadrat(int n);


a definicija

le

int kvadrat(int n) {
return n*n;
}
Definicija funkcija mora da bude u skladu sa navedenim prototipom, tj. mo-

raju da se podudaraju tipovi povratne vrednosti i tipovi parametara. Deklaracija ukazuje prevodiocu da e u programu biti koriena funkcija sa odreenim
tipom povratne vrednosti i parametrima odreenog tipa. Zahvaljujui tome,
kada prevodilac (na primer, u okviru funkcije

kvadrat,

main),

naie na poziv funkcije

moe da proveri da li je njen poziv ispravan (ak iako je definicija

funkcije nepoznata u trenutku te provere). Poto prototip slui samo za proveravanje tipova u pozivima, nije neophodno navoditi imena parametara, ve je

171

8. Funkcije

dovoljno navesti njihove tipove. U navedenom primeru, dakle, prototip je mogao da bude i

int kvadrat(int);
Nije neophodno za svaku funkciju navoditi najpre njen prototip, pa onda
definiciju.

Ukoliko je navedena definicija funkcije, onda se ona moe koris-

cije funkcije moe da utvrdi sve relevantne tipove).

(2
01
5)

titi u nastavku programa i bez navoenja prototipa (jer prevodilac iz definiMeutim, kada postoji

vie funkcija u programu i kada postoje njihove meuzavisnosti, moe biti

veoma teko (i to nepotrebno teko) poreati njihove definicije na nain koji


omoguava prevoenje (sa proverom tipova argumenata). Zato je uobiajena

praksa da se na poetku programa navode prototipovi funkcija, ime poredak


njihovih definicija postaje irelevantan.

je

Ukoliko se ni definicija ni deklaracije funkcije ne navedu pre prvog poziva


te funkcije, prevodilac pretpostavlja da funkcija vraa vrednost tipa

int

i ne

an

vri nikakvu provera ispravnosti argumenata u pozivima funkcije. Ovakvo ponaanje je predvieno jedino zbog kompatibilnosti sa starim verzijama jezika C,
te je opta preporuka da se svakako pre prvog poziva funkcije navede njena

deklaracija ili definicija.

iz

Definicije funkcija mogu se navesti u proizvoljnom poretku i mogu se nalaziti u jednoj ili u vie datoteka.

U drugom sluaju, potrebno je instruirati

prevodilac da obradi vie izvornih datoteka i da napravi jednu izvrnu verziju

sk
o

(videti poglavlje 9.2.6).

Postojanje dve deklaracije iste funkcije u okviru jednog programa je dozvoljeno, ali postojanje dve deklaracije funkcije istog imena, a razliitih lista paramPostojanje dve definicije funkcije

ro
n

etara dovodi do greke tokom prevoenja.

istog imena u jednom programu dovodi do greke tokom prevoenja ili povezivanja (ak i ako su liste parametara razliite).
Prototipovi funkcija iz standardne biblioteke dati su u datotekama zaglavlja

kt

i da bi se one mogle bezbedno koristiti dovoljno je samo ukljuiti odgovarajue


zaglavlje.

Meutim, neki prevodioci (ukljuujui GCC) poznaju prototipove

le

funkcija standardne biblioteke, ak i kada zaglavlje nije ukljueno. Tako, ako se


u GCC-u ne ukljui potrebno zaglavlje, dobija se upozorenje, ali ne i greka jer

su prototipovi standardnih funkcija unapred poznati. Ipak, ovakav kd treba


izbegavati i zaglavlja bi uvek trebalo eksplicitno ukljuiti (tj. pre svakog poziva
funkcije trebalo bi osigurati da kompilator poznaje njen prototip).

8.3 Parametri funkcije


Funkcija moe imati parametre koje obrauje i oni se navode u okviru
definicije, iza imena funkcije i izmeu zagrada. Termini parametar funkcije i

argument funkcije se ponekad koriste kao sinonimi. Ipak, pravilno je termin


parametar funkcije koristiti za promenljivu koja ini deklaraciju funkcije, a
termin argument funkcije za izraz naveden u pozivu funkcije na mestu parame-

172

8. Funkcije

Ponekad se argumenti funkcija nazivaju i stvarni argumenti, a

tra funkcije.

parametri funkcija formalni argumenti. U primeru iz poglavlja 8.1,

int kvadrat(int n);,


kvadrat(5) i kvadrat(9).

etar funkcije

n je param-

su njeni argumenti u pozivima

Parametri funkcije mogu se u telu funkcije koristiti kao lokalne promenljive


te funkcije a koje imaju poetnu vrednost odreenu vrednostima argumenata
u pozivu funkcije.

(2
01
5)

Kao i imena promenljivih, imena parametara treba da oslikavaju njihovo

znaenje i ulogu u programu. Pre imena svakog parametra neophodno je navesti


njegov tip.

Ukoliko funkcija nema parametara, onda se izmeu zagrada ne

navodi nita ili se navodi kljuna re

void.

Ukoliko se, umesto kljune rei

void,

izmeu zagrada ne navede nita, prevodilac u pozivima funkcije ne proverava


da li je ona zaista pozvana bez argumenata.

Promenljive koje su deklarisane kao parametri funkcije lokalne su za tu

tavie, bilo koja druga

je

funkciju i njih ne mogu da koriste druge funkcije.

funkcija moe da koristi isto ime za neki svoj parametar ili za neku svoju
Kvalifikatorom

const

an

lokalnu promenljivu.

mogu, kao i sve promenljive, biti oznaeni parametri

funkcije ime se obezbeuje da neki parametar ili sadraj na koji ukazuje neki

parametar nee biti menjan u funkciji. Ovo se najee koristi u kombinaciji


Funkcija

main

iz

sa prenosom nizova (videti poglavlje 8.7) i pokazivaa (videti glavu 10).


moe biti bez parametara ili moe imati dva parametra un-

apred odreenog tipa (videti poglavlje 12.4).

sk
o

Prilikom poziva funkcije, vri se prenos argumenata, to e biti opisano u


narednom poglavlju.

ro
n

8.4 Prenos argumenata

Na mestu u programu gde se poziva neka funkcija kao njen argument se

kt

moe navesti promenljiva, ali i bilo koji izraz istog tipa (ili izraz ija vrednost
moe da se konvertuje u taj tip). Na primer, funkcija
poglavlja 8.1 moe biti pozvana sa

kvadrat(5),

ali i sa

kvadrat iz primera
kvadrat(2+3).

iz

le

Argumenti funkcija se uvek prenose po vrednosti. To znai da se vrednost

koja se koristi kao argument funkcije kopira kada pone izvravanje funkcije i
onda funkcija radi samo sa tom kopijom, ne menjajui original.

Na primer,

kvadrat deklarisana sa int kvadrat(int n) i ako je pozvana


sa kvadrat(a), gde je a neka promenljiva, ta promenljiva e nakon izvrenja
funkcije kvadrat ostati nepromenjena, ma kako da je funkcija kvadrat definisana. Naime, kada pone izvravanje funkcije kvadrat, vrednost promenljive
a bie iskopirana u lokalnu promenljivu n koja je navedena kao parametar
ako je funkcija

funkcije i funkcija e koristiti samo tu kopiju u svom radu. Prenos argumenata


ilustruje i funkcija

Program 8.3.

swap

definisana na sledei nain:

173

8. Funkcije

#include <stdio.h>

(2
01
5)

void swap(int a, int b) {


int temp = a;
a = b;
b = temp;
}
int main() {
int x = 3, y = 5;
swap(x, y);
printf("x = %d, y = %d\n", x, y);
}
swap

argumenti

ostati nepromenjene nakon ovog poziva.

an

xiy

b zamenjuju vrednosti, ali ako je funkcija


swap(x, y), onda e vrednosti promenljivih

je

U funkciji

pozvana iz neke druge funkcije sa

x = 3, y = 5

iz

Mogue je i da se ime parametra funkcije poklapa sa imenom promenljive

Program 8.4.

sk
o

koja je prosleena kao stvarni argument. Na primer:

#include <stdio.h>

kt

ro
n

void f(int a) {
a = 3;
printf("f: a = %d\n", a);
}

le

int main() {
int a = 5;
f(a);
printf("main: a = %d\n", a);
}

I u ovom sluaju radi se o dve razliite promenljive (promenljiva u pozvanoj


funkciji je kopija promenljive iz funkcije u kojoj se poziv nalazi).

f: a = 3
main: a = 5
Ukoliko je potrebno promeniti neku promenljivu unutar funkcije, onda se
kao argument ne alje vrednost te promenljive nego njena adresa (i ta adresa

174

8. Funkcije

se onda prenosi po vrednosti). O tome e biti rei u glavi 10. Alternativno,


mogue je da funkcija samo izrauna vrednost i vrati je kao rezultat, a da se
izmena promenljive izvri u funkciji pozivaocu, naredbom dodele.
Prenos nizova vri se na specifian nain, o emu e biti rei u poglavlju
8.7.

(2
01
5)

8.5 Konverzije tipova argumenata funkcije

Prilikom poziva funkcije, ukoliko je poznata njena deklaracija, vri se implic-

itna konverzija tipova argumenata u tipove parametara (ako se oni razlikuju).


Slino, prilikom vraanja vrednosti funkcije (putem

return

naredbe) vri se

konverzija vrednosti koja se vraa u tip povratne vrednosti funkcije.


U sledeem primeru, prilikom poziva funkcije

f vri
3:

vrednosti u celobrojnu vrednost i program ispisuje

je

Program 8.5.

an

#include <stdio.h>

sk
o

iz

void f(int a) {
printf("%d\n", a);
}
int main() {
f(3.5);
}

double

se konverzija

ro
n

Ukoliko ni deklaracija ni definicija funkcije nisu navedene pre njenog poziva,


u fazi prevoenja ne vri se nikakva provera ispravnosti tipova argumenata i
povratne vrednosti a u situacijama gde se poziva funkcija vre se podrazumevane
promocije argumenata:

kt

short

se promoviu u

one obuhvataju celobrojne promocije (tipovi

int),

i promociju tipa

float

u tip

double.

char

U ovom

sluaju (da deklaracija ni definicija nisu navedene pre poziva funkcije), uko-

le

liko je definicija funkcije ipak navedena negde u programu, zbog kompilacije

koja je sprovedena na opisani nain, izvrni program moe da bude generisan, ali njegovo ponaanje moe da bude neoekivano. Ako je u navedenom
primeru definicija funkcije

prevoenja funkcije

nee biti poznat tip funkcije

main

navedena nakon definicije funkcije

okviru poziva bie preneta vrednost


funkcije

3.5

main,

prilikom

i kao parametar u

zapisana u pokretnom zarezu (kao

f (koja je kompilirana nakon


main) prima parametar tipa int i dobijenu vrednost 3.5 tumaie kao

vrednost tipa

double).

S druge strane, funkcija

ceo broj zapisan u potpunom komplementu. Zato bi tako modifikovani program


ispisao vrednost

(a ne

3.5,

kao u prvom sluaju).

175

8. Funkcije

8.6 Povratna vrednost funkcije


Funkcija moe da vraa rezultat i
kao rezultat.

tip

oznaava tip vrednosti koja se vraa

Funkcija rezultat vraa naredbom

return r;

samo da vraa vrednost


vanje.

r izraz
return r; ne

gde je

zadatog tipa ili tipa koji se moe konvertovati u taj tip. Naredba

r kao rezultat rada funkcije, nego i prekida njeno izvrareturn naredbu,

Ako funkcija koja treba da vrati vrednost ne sadri

(2
01
5)

kompilator moe da prijavi upozorenje, a u fazi izvravanja rezultat poziva e


biti nedefinisana vrednost (to je obino pogreno). Ako funkcija ne treba da
vraa rezultat, onda se kao tip povratne vrednosti navodi specijalan tip
i tada naredba

return

nema argumenata (tj. navodi se

tom sluaju nije ni neophodno navoditi naredbu

return;).

void

tavie, u

return iza poslednje naredbe

u funkciji.

Funkcija koja je pozvala neku drugu funkciju moe da ignorie, tj. da ne


Kvalifikator

const

je

koristi vrednost koju je ova vratila.

moe se primeniti i na tip povratne vrednosti funkcije.

an

To nema mnogo smisla, osim u kombinaciji sa pokazivaima (videti glavu 10)


i retko se koristi.

sk
o

8.7 Nizovi i funkcije

iz

Iako je sintaksiki ispravno i drugaije, funkcija main uvek treba da ima


int kao tip povratne vrednosti (jer okruenje iz kojeg je program pozvan uvek
kao povratnu vrednost oekuje tip int).

Niz se ne moe preneti kao argument funkcije.

Umesto toga, mogue je

kao argument navesti ime niza. Tokom kompilacije, imenu niza pridruena je
niza.

ro
n

informacija o adresi poetka niza, o tipu elemenata niza i o broju elemenata


Kada se ime niza navede kao argument funkcije, onda do te funkcije

(iji je tip odgovarajueg parametra pokazivaki tip, o emu e biti vie rei u
glavi 10) stie informacija o adresi poetka niza i o tipu elemenata (ali ne i o

kt

imenu niza niti o broju elemenata niza). Poto funkcija koja je pozvana dobija
informaciju o adresi poetka originalnog niza, ona moe da neposredno menja

le

njegove elemente (i takve izmene e biti sauvane nakon izvrenja funkcije), to


je drugaije u odnosu na sve ostale tipove podataka.

Prenos adrese poetka

niza vri se kao i uvek po vrednosti. U pozvanoj funkciji, adresa poetka


niza navedenog u pozivu se kopira i moe se menjati (tj. ona je l-vrednost), pri
emu te izmene ne utiu na njenu originalnu vrednost (adresu poetka niza).
S druge strane, kao to je ranije reeno, originalna adresa poetka niza nije
l-vrednost i ne moe se menjati.
Funkcija koja prima niz moe biti deklarisana na neki od narednih naina:

tip ime_funkcije(tip ime_niza[dimenzija]);


tip ime_funkcije(tip ime_niza[]);

176

8. Funkcije

S obzirom na to da se u funkciju prenosi samo adresa poetka niza, a ne i


dimenzija niza, prvi oblik deklaracije nema puno smisla tako se znatno ree
koristi.
Ukoliko se ime dvodimenzionalnog niza koristi kao argument u pozivu funkcije,
deklaracija parametra u funkciji mora da ukljui broj kolona; broj vrsta je nebitan, jer se i u ovom sluaju prenosi samo adresa (tj. pokaziva na niz vrsta, pri
emu je svaka vrsta niz). U sluaju niza sa vie od dve dimenzije, samo se prva

tip ime_funkcije(tip ime_niza[bv][bk]);


tip ime_funkcije(tip ime_niza[][bk]);

(2
01
5)

dimenzija moe izostaviti (dok je sve naredne dimenzije neophodno navesti).

Naredni primer ilustruje injenicu da se u funkciju ne prenosi ceo niz. Uko-

int i adresni tip reprezentomain, broj 20 (5 elemenata


4
tipa int ija je veliina 4 bajta) i, u okviru funkcije f, broj 4 (veliina adrese
koja je preneta u funkciju). Dakle, funkcija f nema informaciju o broju elemenata niza a.
liko se program pokrene na maini na kojoj su tip

an

je

vani sa 4 bajta) program ispisuje, u okviru funkcije

iz

#include <stdio.h>

Program 8.6.

sk
o

void f(int a[]) {


printf("f: %d\n", sizeof(a));
}

le

kt

ro
n

int main() {
int a[] = {1, 2, 3, 4, 5};
printf("main: %d\n", sizeof(a));
f(a);
return 0;
}
main: 20
f: 4

Prilikom prenosa niza (tj. adrese njegovog poetka) u funkciju, pored imena
niza, korisnik obino treba da eksplicitno prosledi i broj elemenata niza kao
dodatni argument (da bi pozvana funkcija imala tu informaciju).
Povratni tip funkcije ne moe da bude niz. Funkcija ne moe da kreira niz
koji bi bio vraen kao rezultat, a rezultat moe da vrati popunjavanjem niza
koji joj je prosleen kao argument.

4 sizeof

je operator, a ne funkcija, te prilikom poziva

sizeof(a) nema
a.

nata u kojem bi bila izgubljena informacija o broju elemenata niza

prenosa argume-

177

8. Funkcije

ucitaj_broj ne uspeva da uita i promeni


ucitaj_niz ispravno unosi i menja elemente
adresa poetka niza y).

U narednom programu, funkcija


vrednost broja

niza

x,

dok funkcija

(jer joj je poznata

Program 8.7.
#include <stdio.h>

je

an

void ucitaj_niz(int a[], int n) {


int i;
printf("Ucitaj niz: ");
for (i = 0; i < n; i++)
scanf("%d", &a[i]);
}

(2
01
5)

void ucitaj_broj(int a) {
printf("Ucitaj broj: ");
scanf("%d", &a);
}

ro
n

sk
o

iz

int main() {
int x = 0;
int y[3] = {0, 0, 0};
ucitaj_broj(x);
ucitaj_niz(y, 3);
printf("x = %d\n", x);
printf("y = %d %d %d\n", y[0], y[1], y[2]);
}

le

kt

Unesi broj: 5
Unesi niz: 1 2 3
x = 0
y = 1, 2, 3

Prenos niski u funkciju se vri kao i prenos bilo kog drugog niza. Jedina

razlika je to nije neophodno funkciji prosleivati duinu niske, jer se ona moe

5 Na primer,

odrediti i u samoj funkciji zahvaljujui postojanju terminalne nule.


funkcija

strchr

karakter.

stanadardne biblioteke proverava da li data niska sadri dati

U nastavku je navedena jedna njena mogua implementacija, zas-

novana na takozvanoj linearnoj pretrazi niza.


prvu poziciju karaktera

Ova implementacija pronalazi

c u niski s a vraa -1 ukoliko s ne sadrzi c, to je neto

drugaije ponaenja u odnosu na implementaciju iz standardne biblioteke.

5 Naravno,

duina niske ne odreuje duinu niza karaktera u koji je smetena, ve samo

broj karaktera do zavrne nule.

178

8. Funkcije

int strchr(const char s[], char c) {


int i;
for (i = 0; s[i] != \0; i++)
if (s[i] == c)
return i;

(2
01
5)

return -1;

U nekim sluajevima elimo da spreimo da funkcija izmeni niz (ili nisku)


koji joj je prosleen i tada je uz niz potrebno navesti da je konstantan (kljunom
reju

const),

to je i uraeno i u sluaju funkcije

mogla bi se navesti i uz parametar

c,

strchr.

Kljuna re

const

ali to bi (kako se karakter prenosi po

vrednosti) znailo samo da ovaj parametar ne moe da se menja unutar tela

je

funkcije.

an

8.8 Korisniki definisani tipovi i funkcije

Parametri funkcija mogu biti i strukture i drugi korisniki definisani tipovi.


Pored toga, funkcije kao tip povratne vrednosti mogu imati tip strukture.

iz

Prenos argumenta se i u ovom sluaju vri po vrednosti.


od dva cela broja kreira i vraa objekat tipa

sk
o

Funkcija kreiraj_razlomak
struct razlomak:

kt

ro
n

struct razlomak kreiraj_razlomak(int brojilac, int imenilac) {


struct razlomak rezultat;
rezultat.brojilac = brojilac;
rezultat.imenilac = imenilac;
return rezultat;
}
Navedni primer pokazuje i da ne postoji konflikt izmeu imena parametara

le

i istoimenih lanova strukture. Naime, imena lanova strukture su uvek vezana


za ime promenljive (u ovom primeru

rezultat).

Sledei primer ilustruje funkcije sa parametrima i povratnim vrednostima

koji su tipa strukture:

struct razlomak saberi_razlomke(struct razlomak a,


struct razlomak b) {
struct razlomak c;
c.brojilac = a.brojilac*b.imenilac + a.imenilac*b.brojilac;
c.imenilac = a.imenilac*b.imenilac;
return c;
}

179

8. Funkcije

Na slian nain mogu se implementirati i druge operacije nad razlomcima,


kao mnoenje razlomaka, skraivanje razlomka, poreenje razlomaka, itd.
Kao i drugi tipovi argumenata, strukture se u funkcije prenose po vrednosti.
Tako, naredna funkcija ne moe da promeni razlomak koji je upotrebljen kao
argument.

(2
01
5)

void skrati(struct razlomak r) {


int n = nzd(r.brojilac, r.imenilac);
r.brojilac /= n; r.imenilac /= n;
}
Naime, nakon poziva

ostaje jednak

2/4

(u funkciji se menja kopija originalne strukture

nastala prilikom prenosa po vrednosti).

8.9 Rekurzija

an

razlomak

je

struct razlomak r = {2, 4};


skrati(r);

iz

Funkcije mogu da pozivaju druge funkcije. Funkcija moe da pozove i sama


sebe (u tom sluaju argumenti u pozivima su obino razliiti).

Na primer,

sk
o

funkcija

kt

ro
n

double stepen(double x, unsigned n) {


if (n == 0)
return 1;
else
return x*stepen(x, n-1);
}
. Na primer, stepen(2.0, 3) = 2.0*stepen(2.0, 2)
= 4.0*stepen(2.0, 1) = 8.0*stepen(2.0, 0) = 8.0*1 = 8.0.

le

izraunava vrednost

Rekurzivna reenja esto su vremenski i memorijski zahtevna (jer esto za-

uzimaju mnogo prostora na steku poziva), ali zato esto daju krai i razumljiviji
izvorni kd. Rekurzija je veoma vana programerska tehnika i o njenoj upotrebi
e vie rei biti u drugom delu ove knjige.

8.10 Funkcije sa promenljivim brojem argumenata


Ponekad je korisno definisati funkcije koje u pozivu mogu da imaju promenljiv
broj argumenata.

Primetimo da su takve funkcije

mogu biti i korisniki definisane funkcije.

printf

promenljivim brojem argumenata data je kroz zaglavlje


dataka

va_list

scanf

a takve

Podrka za definisanje funkcija sa

<stdarg.h>

i tip po-

kojim se predstavlja lista argumenata prosleenih funkciji,

180

8. Funkcije

va_start kojim se zapoinje obrada takve liste argumenata, makro


va_arg koji uzima naredni argument iz liste i konvertuje ga u podatak eljenog
tipa i makro va_end kojim se zavrava obrada liste argumenata. U deklaraciji

makro

funkcije sa promenljivim brojem argumenata navode se samo tri take.


Na primer, funkcija u narednom kodu izraunava i vraa zbir prosleenih
argumenata (osim prvog). Njen prvi parametar je broj argumenata koje treba

(2
01
5)

sabrati (prvi argument ne uestvuje u zbiru).

iz

an

int sumof(int n_args, ...) {


int i;
int sum;
va_list args;
va_start(args, n_args);
sum = 0;
for (i = 1; i <= n_args; i++)
sum += va_arg(args, int);
va_end(args);
return sum;
}

je

#include <stdio.h>
#include <stdarg.h>

ro
n

sk
o

int main() {
printf("%d\n", sumof(5, 1, 2, 3, 4, 5));
return 0;
}

kt

Pitanja i zadaci za vebu


Pitanje 8.1.

ta je to deklaracija funkcije, a ta je to definicija funkcije? U

Pitanje 8.2.

ta je to parametar, a ta argument funkcije?

Pitanje 8.3.

Koliko najmanje parametara moe da ima funkcija? Kako izgleda

le

kojim sluajevima se koriste deklaracije?

deklaracija funkcije koja nema parametara? Koja je razlika izmeu deklaracija

void f(void); i void f();?

Pitanje 8.4.
vraa rezultat?

ta se navodi kao tip povratne vrednosti za funkciju koja ne


Da li takva funkcija mora da sadri naredbu

takva funkcija moe da sadri naredbu

return

return?

return?

Da li

ta se navodi kao argument

naredbe?

Pitanje 8.5.

Kako se prenose argumenti funkcija u C-u?

situaciji prenos argumenata ne vri po vrednosti?

Da li se u nekoj

181

8. Funkcije

Pitanje 8.6.

ta ispisuje sledei program?

int f(int x) {
x = x+2;
return x+4;
}

Pitanje 8.7.

ta ispisuje sledei program?

an
d
iz

sk
o

int main() {
int n = 4, k = 5;
f(n, k);
printf("%d %d\n", n, k);
}

je

void f(int n,int k) {


n = 3 * k++;
}

Pitanje 8.8.

(2
01
5)

int main() {
int x = 1, y = 2;
x = f(x+y);
printf("%d\n", x);
}

ta ispisuje sledei program?

le

kt

ro
n

void f(int x) {
x += (++x) + (x++);
}
int main() {
int x = 2;
f(x); f(x);
printf("%d\n", x);
}

Pitanje 8.9.
1. Koje su informacije od navedenih, tokom kompilacije, pridruene imenu
niza: (i) adresa poetka niza; (ii) tip elemenata niza; (iii) broj elemenata
niza; (iv) adresa kraja niza?
2. Koje se od ovih informacija uvaju u memoriji tokom izvravanja programa?
3. ta se sve od navedenog prenosi kada se ime niza navede kao argument
funkcije: (i) adresa poetka niza; (ii) elementi niza; (iii) podatak o broju
elemenata niza; (iv) adresa kraja niza.

182

8. Funkcije

Pitanje 8.10.

ta ispisuje naredni program:

Pitanje 8.11.

je

int main() {
int i;
int a[] = {1, 2, 3, 4};
f(a);
for(i = 0; i < sizeof(a)/sizeof(int); i++)
printf("%d ", a[i]);
}

(2
01
5)

void f(int a[]) {


int i;
for(i = 0; i < sizeof(a)/sizeof(int); i++)
a[i] = a[i] + 1;
}

Koja funkcija standardne biblioteke se koristi za izraunavanje

an

duine niske i u kojoj datoteci zaglavlja je ona deklarisana?

Pitanje 8.12.

emu je jednako

Pitanje 8.13.

Navesti neku implementaciju funkcije

Pitanje 8.14.

Navesti liniju kda koja obezbeuje da se prilikom poziva

iz

a emu

celobrojni argument 2 implicitno prevede u

sk
o

funkcije

sizeof("abc"),

strlen.
double

void

vrednost.

ro
n

int main() {
f(2);
return 0;
}

strlen("abc")?

Kako se vri prenos unija u funkciju?

kt

Pitanje 8.15.
Zadatak 8.1.

Napisati funkciju koja proverava da li je uneti pozitivan ceo broj

prost i program koji je testira. Uporediti sa reenjem koje sadri samo funkciju

le

main.

Zadatak 8.2.

Napisati program koji za tri take Dekartove ravni zadate paro-

vima svojih koordinata (tipa

double)

izraunava povrinu trougla koji obrazuju

(koristiti
Heronov obrazac, na osnovu kojeg je povrina trougla jednaka vrednosti

( )( )( ),

gde su

, i

duine stranica, a

njegov poluo-

bim; napisati i koristiti funkciju koja rauna rastojanje izmeu dve take Dekar-

tove ravni).

Zadatak 8.3.

Za prirodan broj se kae da je savren ako je jednak zbiru svih

svojih pravih delioca (koji ukljuuju broj


savrene brojeve manje od 10000.

1,

ali ne i sam taj broj). Ispisati sve

183

8. Funkcije

Zadatak 8.4.

Napisati funkciju koja poredi dva razlomka i vraa 1 ako je prvi

vei, 0 ako su jednaki i -1 ako je prvi manji.

Zadatak 8.5.

Napisati funkciju (i program koji je testira) koja:

1. proverava da li dati niz sadri dati broj;


2. pronalazi indeks prve pozicije na kojoj se u nizu nalazi dati broj (-1 ako

(2
01
5)

niz ne sadri broj).

3. pronalazi indeks poslednje pozicije na kojoj se u nizu nalazi dati broj (-1
ako niz ne sadri broj).

4. izraunava zbir svih elemenata datog niza brojeva;

5. izraunava prosek (aritmetiku sredinu) svih elemenata datog niza brojeva;

je

6. izraunava najmanji element datog elemenata niza brojeva;

7. odreuje poziciju najveeg elementa u nizu brojeva (u sluaju vie pojavlji-

an

vanja najveeg elementa, vratiti najmanju poziciju);

iz

Zadatak 8.6.

8. proverava da li je dati niz brojeva ureen neopadajue.

Napisati funkciju (i program koji je testira) koja:

sk
o

1. izbacuje poslednji element niza;


2. izbacuje prvi element niza (napisati varijantu u kojoj je bitno ouvanje
redosleda elemenata i varijantu u kojoj nije bitno ouvanje redosleda);

ro
n

3. izbacuje element sa date pozicije

k;

4. ubacuje element na kraj niza;


5. ubacuje element na poetak niza;

kt

6. ubacuje dati element

na datu poziciju

k;
x

iz niza.

le

7. izbacuje sva pojavljivanja datog elementa

Napomena: funkcija kao argument prima niz i broj njegovih trenutno popun-

jenih elemenata, a vraa broj popunjenih elemenata nakon izvoenja zahtevane

operacije.

Zadatak 8.7.

Napisati funkciju (i program koji je testira) koja:

1. odreuje duinu najdue serije jednakih uzastopnih elemenata u datom


nizu brojeva;
2. odreuje duinu najveeg neopadajueg podniza datog niza celih brojeva;
3. odreuje da li se jedan niz javlja kao podniz uzastopnih elemenata drugog;
4. odreuje da li se jedan niza javlja kao podniz elemenata drugog (elementi
ne moraju da budu uzastopni, ali se redosled pojavljivanja potuje);

184

8. Funkcije

5. obre dati niz brojeva;


6. rotira sve elemente datog niza brojeva za
7. rotira sve elemente datog niza brojeva za

k
k

pozicija ulevo;
pozicija udesno;

8. izbacuje viestruka pojavljivanja elemenata iz datog niza brojeva (napisati


varijantu u kojoj se zadrava prvo pojavljivanje i varijantu u kojoj se

(2
01
5)

zadrava poslednje pojavljivanje).


9. spaja dva niza brojeva koji su sortirani neopadajui u trei niz brojeva
koji je sortiran neopadajui.

Zadatak 8.8.

Napisati funkciju koja poredi dve niske leksikografski (kao u

reniku, u skladu sa kdnim rasporedom sistema).

Funkcija vraa negativan

rezultat ukoliko prva niska leksikografski prethodi drugoj, nulu u sluaju da su

je

niske jednake i pozitivan rezultat ukoliko druga niska leksikografski prethodi

Zadatak 8.9.

an

prvoj.

Napisati funkciju koja za dve niske proverava da li je:

1. prva podniz druge (karakteri prve niske se ne moraju nalaziti na susednim

iz

pozicijama u drugoj).

2. prva podniska druge (karakteri prve niske se moraju nalaziti na susednim


pozicijama u drugomq). Ako jeste funkcija treba da vrati poziciju prve

sk
o

1.

niske u drugoj, a ako nije, onda

Napisati funkciju koja proverava da

ro
n

li jedna zadata niska sadri drugu zadatu nisku.

Zadatak 8.10.

Napisati funkciju koja za dve niske proverava da li je jedan

permutacija druge (niska je permutacija druge ako se od nje dobija samo pre-

kt

metanjem njegovih karaktera - bez ikakvog brisanja ili dodavanja karaktera).


Na primer, funkcija odredi da niske

"abc"

"cba"

jesu, a da niske

nisu permutacija.

le

"ab"

Zadatak 8.11.

"aab"i

Za datu kvadratnu matricu kaemo da je magini kvadrat ako

je suma elemenata u svakoj koloni i svakoj vrsti jednaka.


koji sa standardnog ulaza uitava prirodni broj

( < 10)

Napisati program
i zatim elemente

kvadratne matrice, proverava da li je ona magini kvadrat i ispisuje odgovarajuu poruku na standardni izlaz. Koristiti pomone funkcije za izraunavanje
zbira elemenata vrsta, kolona i dijagonala matrice.
Primer, matrica:

7 12
2 13

16 3
9
6
je magini kvadrat.

1 14
8 11

10 5
15 4

185

8. Funkcije

Zadatak 8.12.
zija najvie

Definisati strukturu kojom se moe predstaviti matrica dimen-

100100 (struktura sadri dvodimenzionalni niz brojeva tipa float

i dimenzije).
1. Napisati funkciju koja uitava matricu sa standardnog ulaza.
2. Napisati funkciju koja ispisuje matricu na standardni izlaz.

(2
01
5)

3. Napisati funkciju koja sabira dve matrice istih dimenzija.

4. Napisati funkciju koja mnoi dve matrice odgovarajuih dimenzija.

Zadatak 8.13.

Napisati funkcije koji vre unos, ispis, sabiranje i mnoenje

velikih prirodnih brojeva (za koje nije dovoljna veliina tipa

unsigned long).
1000

je

Cifre velikog broja smetati u niz i pretpostaviti da brojevi nemaju vie od

le

kt

ro
n

sk
o

iz

an

cifara.

(2
01
5)

Glava 9

an

je

Organizacija izvornog i izvrnog


programa

U prethodnim glavama ve je naglaeno da se izvorni program pie najee

na viim programskim jezicima i predstavlja sredstvo komunikacije izmeu programera i raunara, ali i izmeu programera smih. Specijalizovani programi,

iz

prevodioci (kompilatori), prevode izvorni u izvrni program , napisan na mainskom jeziku raunara, tj. na jeziku neposredno podranom arhitekturom pro-

sk
o

cesora.
Postoji mnotvo pisanih pravila (tj. pravila koja proistiu iz standarda
jezika koji se koristi) i nepisanih pravila (razne konvencije i obiaji) za organizovanje kda izvornog programa.

Ta pravila olakavaju programiranje i

ro
n

omoguuju programeru kreiranje razumljivih programa koji se efikasno mogu


prevoditi i izvravati. Svi programi u prethodnim poglavljima bili su jednostavni, imali su svega nekoliko funkcija i nije bilo potrebno previe obraati

kt

panju na pomenuta pravila.

Meutim, sa uslonjavanjem programa, poto-

vanje kodeksa postaje kljuno jer u protivnom pisanje i odravanje kda postaje

veoma komplikovano . Takoe, postoje pravila za organizovanje kda izvrnog

le

programa koja omoguavaju njegovo efikasno izvravanje na odreenom rau-

naru, u sklopu odreenog operativnog sistema, to podrazumeva i nesmetano


izvravanje istovremeno sa drugim programima. Zato pravila organizacije kda
izvrnog programa zavise i od vieg programskog jezika koji se koristi, ali i od
hardvera, mainskog jezika, kao i operativnog sistema raunara na kome e se
program izvravati.
I u fazi prevoenja i u fazi izvravanja mogu se javiti greke i one moraju
biti ispravljene da bi program funkcionisao ispravno. Greke tokom izvravanja
mogu biti takve da program ne moe dalje da nastavi sa izvravanjem (npr. ako
program pokua da pristupi delu memorije koji mu nije dodeljen, operativni

1 Postoji

izreka da dobre od loih programera vie razlikuje disciplina pri programiranju

nego pamet.

186

187

9. Organizacija izvornog i izvrnog programa

sistem nasilno prekida njegovo izvravanje), ali mogu da budu takve da se program nesmetano izvrava, ali da su rezultati koje prikazuje pogreni. Dakle, to
to ne postoje greke u fazi prevoenja i to to se program nesmetano izvrava,
jo uvek ne znai da je program ispravan, tj. da zadovoljava svoju specifikaciju
i daje tane rezultate za sve vrednosti ulaznih parametara.

Ispravnost pro-

grama u tom, dubljem smislu zahteva formalnu analizu i ispitivanje te vrste


ispravnosti najee je van moi automatskih alata.

Ipak, sredstva za pri-

(2
01
5)

javljivanje greaka tokom prevoenja i izvravanja programa znatno olakavaju

proces programiranja i esto ukazuju i na sutinske propuste koji naruavaju


ispravnost programa.

9.1 Od izvornog do izvrnog programa

Iako proces prevoenja jednostavnih programa poetnicima izgleda kao

je

jedan, nedeljiv proces, on se sastoji od vie faza i podfaza (a od kojih se svaka


i sama sastoji od vie koraka). U sluaju jezika C, ti koraci su obino pretpro-

an

cesiranje (engl. preprocessing), kompilacija (engl. compilation) i povezivanje


(engl. linking). Tokom svih faza prevoenja, moe biti otkrivena i prijavljena
greka u programu. U izvetajima o grekama obino se ne navodi eksplicitno

Faza pretprocesiranja je pripremna faza kompilacije. Ona

sk
o

Pretprocesiranje.

iz

na osnovu vrste greke).

u kojoj fazi je greka detektovana (mada se ta informacija moe rekonstruisati

omoguava da se izvre neke jednostavne transformacije izvornog teksta programa pre nego to on bude prosleen kompilatoru kompilator, dakle, ne
obrauje tekst programa koji je programer napisao, ve samo tekst koji je nas-

ro
n

tao njegovim pretprocesiranjem. Jedan od najvanijih zadataka pretprocesora


je da omogui da se izvorni kd pogodno organizuje u vie ulaznih datoteka.
Pretprocesor izvorni kd iz razliitih datoteka objedinjava u tzv. jedinice pre-

kt

voenja i prosleuje ih kompilatoru.

Na primer, u

.c

datoteke koje sadre

izvorni kd ukljuuju se datoteke zaglavlja (engl. header files)

.h

koje sadre

deklaracije promenljivih, funkcija i tipova podataka tako da svaka jedinica pre-

le

voenja sadri zajedniki tekst nekoliko

standardne biblioteke) i jedne

.c

.h (na primer, ve pomenuta zaglavlja

datoteke.

Program koji vri pretprocesiranje naziva se pretprocesor (engl. preproces-

sor). Rezultat rada pretprocesora, moe se dobiti korienje GCC prevodioca


navoenjem opcije

-E

(na primer,

gcc -E program.c).

Vie rei o fazi pretprocesiranja bie u poglavlju 9.2.1.

Kompilacija.

Kompilator kompilira (tj. prevodi) svaku jedinicu prevoenja

zasebno, sprovoenjem sledeih faza (videti poglavlje 4.3):

leksika analiza izdvajanje leksema , osnovnih jezikih elemenata;

sintaksika analiza kreiranje sintaksnog stabla;

188

9. Organizacija izvornog i izvrnog programa

semantika analiza provera semantike i transformacija kreiranog stabla;

generisanje meukda generisanje kda na jeziku interne reprezentacije;

optimizacija meukda optimizovanje generisanog kda;

generisanje kda na mainskom jeziku prevoenje optimizovanog kda

(2
01
5)

u objektne module.

Kompilacijom se od svake jedinice prevoenja gradi zasebni objektni modul

(engl. object module) . Objektni moduli sadre programe (mainski kd funkcija)


i podatke (memorijski prostor rezervisan za promenljive). Iako su u mainskom
obliku, objektni moduli se ne mogu izvravati.

Na primer, rezultat rada GCC kompilatora moe se dobiti navoenjem op-

-c

(na primer,

gcc -c program.c).

Ovim se dobija datoteka

program.o

je

cije

objektni modul koji je na Linux sistemu u ELF formatu (engl. Executable

an

and Linkable Format), formatu u kome je i izvrna datoteka, pri emu objektni modul nije izvran (kae se da je relokatibilan jer je u njemu tek potrebno
razreiti memorijske adrese) i mora se povezati da bi se dobila izvrna datoteka.
vri se najopsenija optimizacija kda to uzrokuje da

iz

gcc -O3,

Mnoge dodatne opcije utiu na rezultat kompilacije. Na primer, ukoliko se


navede opcija

se rezultujui kd (esto znatno) bre izvrava. Ukoliko se navede opcija

-Wall

Povezivanje.

sk
o

navode se sva upozorenja na mogue greke tokom kompilacije.

Povezivanje je proces kreiranja jedinstvene izvrne datoteke

od jednog ili vie objektnih modula koji su nastali ili kompilacijom izvornog

ro
n

kda programa ili su objektni moduli koji sadre mainski kd i podatke stan-

dardne ili neke nestandardne biblioteke . Program koji vri povezivanje zove
se poveziva , linker (engl. linker) ili ureiva veza.
Nakon kompilacije, u objektnim modulima adrese mainskog kda funkcija

kt

i adrese nekih promenljivih nisu razreene (moe se smatrati da su prazne jer su


umesto stvarnih postavljene specijalne, fiktivne adrese esto vrednost 0) i tek

le

tokom povezivanja vri se njihovo korektno razreavanje (zamena ispravnim


vrednostima).

Zato je faza povezivanja neophodna, ak iako jedan objektni

modul sadri sve promenljive i funkcije koje se koriste u programu (to najee
nije sluaj jer se koriste funkcije standardne biblioteke iji se izvrni kd ne
nalazi u objektnim modulima nastalim kompilacijom izvornog kda).
Kao to je ve reeno, pored objektnih modula nastalih kompilacijom izvornog kda koje je programer napisao, izvrnom programu se moe dodati unapred pripremljen mainski kd nekih biblioteka.

2 Objektni

.obj.

moduli na sistemu Linux najee imaju ekstenziju

3 Biblioteke

nekoliko

.o

Taj kd je mogao nastati

na sistemu Linux najee imaju ekstenziju

.a

.o,

a na sistemu Windows

(jer su arhive koje sadre

datoteka), dok na sistemu Windows najee imaju ekstenziju

.lib.

189

9. Organizacija izvornog i izvrnog programa

prevoenjem sa jezika C, ali to ne mora biti sluaj.

Na primer, neke bib-

lioteke su pisane u asembleru, a neke su nastale prevoenjem sa drugih viih


programskih jezika.

Mehanizam povezivanja, dakle, doputa i kombinovanje

kda napisanog na razliitim programskim jezicima. Mehanizam povezivanja


bitno skrauje trajanje kompilacije jer se kompilira samo tanak sloj korisnikog
izvornog kda dok se kompleksan kd biblioteka koristi unapred kompiliran.
Takve biblioteke uvek su praene datotekama zaglavlja koje slue kompilatoru

(2
01
5)

da proveri i ispravno prevede kd u kojem se poziva na funkcionalnost biblioteke.

Najei primer korienja unapred pripremljenog mainskog kda sa prate-

im datotekama zaglavlja je korienje standardne biblioteke (pregled sadraja


standardne biblioteke bie dat u glavi 11). Kd standardne biblioteke je obino
dostavljen uz prevodilac i dat je samo u obliku mainskog, a ne izvornog kda
(na primer, obino nije mogue videti izvorni kd funkcije

printf).

Deo stan-

(na primer, deklaracija funkcije

je

dardne biblioteke su datoteke zaglavlja koje sadre samo potrebne deklaracije

printf moe se pronai u zaglavlju <stdio.h>).

an

Pored statikog povezivanja , koje se vri nakon kompilacije, postoji i di-

namiko povezivanje , koje se vri tokom izvravanja programa (zapravo na njegovom poetku). Naime, statiko povezivanje u izvrnu datoteku umee main-

ski kd svih bibliotekih funkcija. Da bi se smanjila veliina izvrnih datoteka,

iz

mainski kd nekih esto korienih funkcija se ne ukljuuje u izvrnu datoteku


programa ve postoji u tzv. bibliotekama koje se dinamiki povezuju (engl. dy-

namic link library) . Izvrne datoteke sadre nerazreene pozive funkcija koje

sk
o

se dinamiki povezuju i tek prilikom pokretanja programa, dinamike biblioteke


se zajedno sa programom uitavaju u memoriju raunara i adrese poziva bibliotekih funkcija se razreavaju.

Zato, prilikom izvravanja programa bib-

ro
n

lioteke sa dinamikim povezivanjem moraju biti prisutne na sistemu. Na primer,


funkcije standardne biblioteke intenzivno pozivaju funkcije rantajm biblioteke
(o tome je bilo rei na strani 86) i razreavanje takvih poziva vri se dinamiki,
u fazi izvravanja programa. Jo jedna prednost dinamikog povezivanja bib-

kt

liotekih funkcija je da se nove verzije biblioteka (esto sa ispravljenim sitnijim


grekama) mogu koristiti bez potrebe za izmenom programa koji te biblioteke

le

koristi.

Proces povezivanja obino se automatski pokree odmah nakon kompilacije.

Na primer, ako se koristi GCC prevodilac, prevoenje programa od jedne datoteke i povezivanje sa objektnim modulima standardne biblioteke se postie
na sledei nain:

gcc -o program program.c


Ovim se dobija izvrni program

program

(u ELF formatu).

U procesu povezivanja, automatski se ukljuuju potrebni objektni moduli


standardne biblioteke (na operativnom sistemu Linux ovaj modul se obino zove

4 Ekstenzija
Windows

.dll.

ovih datoteka u sistemu Linux je obino

.so (shared object), dok je u sistemu

190

9. Organizacija izvornog i izvrnog programa

libc ili slino).


-l. Na primer,

Dodatne biblioteke mogu se ukljuiti navoenjem parametra

gcc -o program -lm program.c


u proces povezivanja ukljuuje i standardnu biblioteku

libm

koja nije po-

Odvojena kompilacija i povezivanje.

(2
01
5)

drazumevano obuhvaena povezivanjem.

Korak kompilacije i korak povezi-

vanja mogue je razdvojiti tj. mogue je prvo prevesti datoteku sa izvornim


programom i eksplicitno napraviti objektni modul (u ovom sluaju bi se zvao

program.o),

a tek zatim ovako napravljeni objektni modul povezati (ukljuu-

jui i objektni kd standardne biblioteke) i dobiti izvrni program. U sluaju


da se koristi GCC, to se postie sa:

je

gcc -c program.c
gcc -o program program.o

-c govori GCC prevodiocu da ne treba da vri

an

Kao to je ve reeno, parametar

povezivanje ve samo kompilaciju i da rezultat eksplicitno sauva kao objekpoziv vri povezivanje tog objektnog

program.o. Drugi
program.

modula i daje izvrni program

iz

tni modul u datoteci

Program se moe izgraditi i iz vie jedinica prevoenja.


je izvorni kd programa razdvojen u dve datoteke

Na primer, ako

program1.c i program2.c,

sk
o

izvrni program mogue je dobiti komandom:

gcc -o program program1.c program2.c

ro
n

Naravno, svaka datoteka se odvojeno prevodi i tek onda se vri povezivanje.


Dakle, efekat je isti kao da je pozvano

kt

gcc -c program1.c
gcc -c program2.c
gcc -o program program1.o program2.o

le

Razdvajanjem kompilacije i povezivanja u dve faze omogueno je da se mod-

uli koji se ne menjaju ne prevode iznova svaki put kada je potrebno napraviti
novu verziju izvrnog program (kada se promeni neka izvorna datoteka). Na
primer, ako je promena izvrena samo u datoteci
ponovo prevoditi datoteku

Program make.

program2.c.

Program

make

program1.c,

nije potrebno

(prvu verziju napisao je Sjuart Feldman,

1977. godine) olakava generisanje izvrnih programa od izvornih datoteka.


Iako postoje varijante za razne platforme, program

make

najee se koristi na

operativnom sistemu Linux. Alternativa (ili nadogradnja) programa

make

su

savremena integrisana razvojna okruenja (engl. integrated development environment, IDE) u kojima programer na interaktivni nain specifikuje proces
kompilacije.

191

9. Organizacija izvornog i izvrnog programa

Prilikom korienja programa

Makefile

ime

make,

korisnik u datoteci koja obino ima

specifikuje nain dobijanja novih datoteka od starih.

Speci-

fikuju se zavisnosti izmeu datoteka i akcije koje se izvravaju ukoliko su te


zavisnosti naruene (linije koje sadre akcije moraju da ponu tabulatorom, a
ne razmacima). Nakon pokretanja programa

make,

ukoliko se desi da je neka

zavisnost naruena, izvrava se odgovarajua akcija i rekurzivno se nastavlja sa


proverom zavisnosti, sve dok se sve zavisnosti ne ispune. Na primer, datoteka
sledeeg sadraja

(2
01
5)

Makefile

program: program1.o program2.o biblio.o


gcc -o program program1.o program2.o biblio.o

an

program2.o : program2.c biblio.h


gcc -c program2.c

je

program1.o : program1.c biblio.h


gcc -c program1.c

program zavisi od sledeih datoteka: program1.o, program2.o


biblio.o. Ukoliko je zavisnost naruena (to znai, ukoliko je bilo koja od
datoteka program1.o, program2.o ili biblio.o novijeg datuma od datoteke
program), izvrava se povezivanje. Slino, ako je datoteka program1.c ili
biblio.h novijeg datuma o program1.o koji od njih zavisi (verovatno tako
to datoteka program1.c ukljuuje zaglavlje biblio.h), vri se njena kompilacija. Analogno je i za program2.
Program make ima jo mnogo opcija ali one nee ovde biti opisivane.

kae da datoteka

ro
n

sk
o

iz

Izvravanje programa.

Nakon uspenog prevoenja moe da sledi faza

izvravanja programa.

Izvrni programi smeteni su u datotekama na disku i pre pokretanja uita-

kt

vaju se u glavnu memoriju. Za ovo je zaduen program koji se naziva punilac


ili louder (engl. loader) koji je obino integrisan u operativni sistem. Njegov

le

zadatak je da proveri da li korisnik ima pravo da izvri program, da prenese


program u glavnu memoriju, da prekopira argumente komandne linije (o kojima

e vie biti rei u poglavlju 12.4) u odgovarajui deo memorije programa koji
se pokree, da inicijalizuju odreene registre u procesoru i na kraju da pozovu
poetnu funkciju programa.
funkcija

_start

Nasuprot oekivanju, to nije funkcija

koja poziva funkciju

main,

main,

ve

ali pre toga i nakon toga vri do-

datne pripremne i zavrne operacije sa programom, korienjem usluga rantajm


biblioteke tj. operativnog sistema.
Pre konane distribucije korisnicima, program se obino intenzivno testira
tj. izvrava za razliite vrednosti ulaznih parametara.

Ukoliko se otkrije da

postoji greka tokom izvravanja (tzv. bag od engl. bug), vri se pronalaenje
uzroka greke u izvornom programu (tzv. debagovanje ) i njeno ispravljanje. U
pronalaenju greke mogu pomoi programi koji se nazivaju debageri i koji

192

9. Organizacija izvornog i izvrnog programa

omoguavaju izvravanje programa korak po korak (ili pauziranje njegovog


izvravanja u nekim karakteristinim takama), uz prikaz meuvrednosti promenljivih. Da bi program mogao da bude analiziran primenom debagera, on
mora biti preveden na poseban nain, tako da izvrna verzija sadri i informacije
o izvornom kdu. Na primer, za prevodilac GCC potrebno je koristiti opciju

-g.

Takva verzija izvrnog programa zove se razvojna (debag) verzija, a verzija

(2
01
5)

koja se isporuuje krajnjem korisniku zove se objavljena (riliz) (engl. release).

Pitanja i zadaci za vebu


Pitanje 9.1.1.

Navesti i objasniti osnovne faze na putu od izvornog do izvrnog

programa.

U kom obliku se isporuuje standardna C biblioteka?

Pitanje 9.1.3.

Kako se korienjem GCC prevodioca moe izvriti samo faza

pretprocesiranja kda i prikazati rezultat?

Kako se moe izvriti samo faza

an

kompilacije, bez povezivanja objektnih modula?

Pitanje 9.1.4.

je

Pitanje 9.1.2.

ta su jedinice prevoenja? ta su datoteke zaglavlja? U kojoj

iz

Pitanje 9.1.5.

fazi se od vie datoteka grade jedinice prevoenja?

ta su objektni moduli? ta sadre? Da li se mogu izvravati?

Kojim procesom nastaju objektni moduli? Kojim procesom se od objektnih mod-

Pitanje 9.1.6.

sk
o

ula dobija izvrni program?

Da li svi objektni moduli koji se ukljuuju u kreiranje izvrnog

programa moraju nastati kompilacijom sa programskog jezika C? Da li je mogue

ro
n

kombinovati razliite programske jezike u izgradnji izvrnih programa?

Pitanje 9.1.7.

ta znai da u objektnim modulima pre povezivanja adrese nisu

kt

korektno razreene?

Pitanje 9.1.8.

U kom formatu su objektni moduli i izvrne datoteke na Linux

le

sistemima?

Pitanje 9.1.9.

ta je statiko, a ta dinamiko povezivanje? Koje su prednosti

dinamikog u odnosu na statiko povezivanje?

Pitanje 9.1.10.

U kojim fazama prevoenja programa se vri prijavljivanje

greaka?

Pitanje 9.1.11.

Kako se korienjem GCC prevodioca vri odvojena kompi-

lacija i povezivanje programa u datotekama

Pitanje 9.1.12.
Pitanje 9.1.13.

p1.c i p2.c.

ta je i emu slui program

make?

Kako se zove alat koji omoguava da se program izvrava

korak-po-korak i da se prate vrednosti promenljivih?

193

9. Organizacija izvornog i izvrnog programa

9.2 Organizacija izvornog programa


Vii programski jezici namenjeni su prvenstveno oveku (a ne raunaru).
Obino je daleko lake neki algoritam pretoiti u program na viem programskom jeziku nego u program na mainskom jeziku. Isto vai i za razumevanje
programa koje je napisao neko drugi. Ipak, pisanje, razumevanje i odravanje
veoma dugih programa moe da predstavlja veliki izazov za programera, ak
Da bi se olakalo

(2
01
5)

i kada je program napisan na viem programskom jeziku.

pisanje, razumevanje i odravanje programa, za jezik C (kao i za svaki drugi

vii programski jezik), programeru su na raspolaganju mnoga sredstva koja

omoguavaju da program bude krai, pregledniji, da se efikasnije kompilira, da


se bre izvrava itd.

Osnovni koraci u organizovanju sloenijih programa obino su podela sloenih zadataka na jednostavnije poslove i njihovo izdvajanje u zasebne funkcije

je

(tzv. funkcionalna dekompozicija ), definisanje odgovarajuih tipova podataka


i organizovanje podataka definisanjem odgovarajuih promenljivih. Funkcije u

an

programu trebalo bi da budu to nezavisnije i to slabije meusobno uslovljene


(loe je ako je za razumevanje rada neke funkcije potrebno potpuno razumeti
tano kako radi neka druga funkcija).

Veliki programi se organizuju u vie

datoteka tj. modula koji sadre podatke i funkcije koji objedinjavaju odreenu

iz

funkcionalnost (npr. definiciju tipa podataka za predstavljanje kompleksnih


brojeva i funkcije za izvoenje operacija nad tim tipom ima smisla grupisati u
zaseban modul za rad sa kompleksnim brojevima). Mnogi moduli mogu biti

sk
o

korieni u razliitim programima i tada se obino grade kao biblioteke.


Opisani pristup programiranju omoguavaju i olakavaju razliiti mehanizmi jezika C. Na primer, pretprocesor, izmeu ostalog, olakava korienje

ro
n

standardne, ali i korisniki definisanih biblioteka.

Pretprocesor sa linkerom

omoguava da se program podeli na vie datoteka, tako da se te datoteke


mogu spojiti u jedinstven izvrni program. Doseg identifikatora (engl. scope)
odreuje da li se neka imena mogu koristiti u itavim jedinicama prevoenja ili

kt

samo u njihovim manjim delovima (najee funkcijama ili jo uim blokovima).


Postojanje promenljivih ija je upotreba ograniena na samo odreene uske

le

delove izvornog kda olakava razumevanje programa i smanjuje mogunost


greaka i smanjuje meusobnu zavisnost izmeu raznih delova programa. iv-

otni vek promenljivih (engl. lifetime) odreuje da li je neka promenljiva dostupna tokom itavog izvravanja programa ili samo tokom nekog njegovog dela.
Postojanje promenljivih koje traju samo pojedinano izvravanje neke funkcije
znatno tedi memoriju, dok postojanje promenljivih koje traju itavo izvravanje programa omoguava da se preko njih vri komunikacija izmeu razliitih
funkcija modula. Povezanost identifikatora (engl. linkage) u vezi je sa deljenjem podataka izmeu razliitih jedinica prevoenja i daje mogunost korienja
zajednikih promenljivih i funkcija u razliitim jedinicama prevoenja (modulima), ali i mogunost sakrivanja nekih promenljivih tako da im se ne moe
pristupiti iz drugih jedinica prevoenja. Odnos izmeu dosega, ivotnog veka
i povezanosti je veoma suptilan i sva ova tri aspekta objekata odreuju se na

194

9. Organizacija izvornog i izvrnog programa

osnovu mesta i naina deklarisanja tj. definisanja objekata, ali i primenom kvalifikatora

auto, register, static i extern

o emu e biti vie rei u nastavku

ovog poglavlja.
Sva ova sredstva donose potencijalna olakanja u proces programiranja, ali
sva stvaraju i mogunosti raznih greaka ukoliko se ne koriste na ispravan nain.

Pretprocesor

(2
01
5)

9.2.1

Kada se od izvornog programa napisanog na jeziku C proizvodi program


na mainskom jeziku (izvrni program), pre samog prevodioca poziva se C
pretprocesor.

Pretprocesiranje, dakle, predstavlja samo pripremnu fazu, pre

kompilacije. Sutinski, pretprocesor vri samo jednostavne operacije nad tekstualnim sadrajem programa i ne koristi nikakvo znanje o jeziku C. Pretpro-

cesor ne analizira znaenje naredbi napisanih u jeziku C ve samo pretpro-

je

cesorske direktive (engl. preprocessing directive) (one se ne smatraju delom


jezika C) na osnovu kojih vri odreene transformacije teksta izvornog proNeke od operacija pretprocesora su zamena komentara belinama ili

an

grama.

\. Dve najee
#include (za ukljuivanje sadraja neke

spajanje linija razdvojenih u izvornom programu simbolom


koriene pretprocesorske direktive su

#define

koja zamenjuje neki tekst, makro, drugim tekstom.

druge datoteke) i

iz

Pretprocesor omoguava i definisanje makroa sa argumentima, kao i uslovno


prevoenje (odreeni delovi izvornog programa se prevode samo ukoliko su ispunjeni zadati uslovi). Da bi mogao da izvri svoje zadatke, tokom izvravanja

sk
o

pretprocesor izvrava odreenu jednostavniju leksiku analizu (tokenizaciju) na


koju se nadovezuje kasnija faza leksike analize, koja se vri tokom kompilacije.

ro
n

Ukljuivanje datoteka zaglavlja

Veliki programi obino su podeljeni u vie datoteka, radi preglednosti i


lakeg odravanja. esto je potrebno da se iste promenljive, funkcije i koris-

kt

niki definisani tipovi koriste u vie datoteka i neophodno je da kompilator


prilikom prevoenja svake od njih poznaje deklaracije

5 promenljivih, funkcija

le

i tipova podataka koji se u njoj koriste. ak i kada programer pie samo jednu
datoteku, program po pravilu koristi i funkcionalnost koju mu prua stan-

dardna biblioteka i da bi ona mogla da se koristi, neophodno je da kompilator


tokom kompilacije zna deklaracije standardnih funkcija (npr. funkcije

printf),

promenljivih i tipova. Jedno reenje bilo bi da programer u svakoj datoteci,


na poetku navede sve potrebne deklaracije, ali ponavljanje istih deklaracija
na vie mesta u izvornom kdu je mukotrpan posao i otvara prostor za greke.
Bolje reenje (koja se obino i koristi) je da se deklaracije izdvajaju u zasebne

5 Podsetimo,

deklaracije sadre informacije koje su potrebne kompilatoru da prevede

odreenu datoteku i tako generie objektni modul (npr. prototip funkcije je deklaracija),
dok definicije sadre mnogo vie informacija informacije koje su dovoljne da nakon faze
povezivanja nastane izvrni program (npr. ceo kd funkcije predstavlja njenu definiciju).
Kompilator ne mora da poznaje definiciju funkcije da bi generisao njen poziv, ali linker
mora, da bi mogao da taj poziv razrei.

195

9. Organizacija izvornog i izvrnog programa

datoteke koje se onda ukljuuju gde god je potrebno. Takve datoteke zovu se

datoteke zaglavlja (engl. header files). Osnovni primer datoteka zaglavlja su zaglavlja standardne biblioteke. Primer kreiranja korisniki definisanih datoteka
zaglavlja bie naveden u poglavlju 9.2.6. U datoteku koja se prevodi, sadraj
neke druge datoteke ukljuuje se direktivom

#include.

Linija oblika:

i linija oblika

#include <ime_datoteke>
zamenjuju se sadrajem datoteke

ime_datoteke.

(2
01
5)

#include "ime_datoteke"

U prvom sluaju, datoteka

koja se ukljuuje trai se u okviru posebnog skupa direktorijuma include path


(koja se veini kompilatora zadaje korienjem opcije

-I)

i koja obino po-

je

drazumevano sadri direktorijum u kojem se nalazi datoteka u koju se vri


ukljuivanje. Ukoliko je ime, kao u drugom sluaju, navedeno izmeu znakova
datoteka se trai u sistemskom include direktorijumu u kojem se nalaze

an

< i >,

standardne datoteke zaglavlja, ija lokacija zavisi od sistema i od C prevodioca

koji se koristi.

Ukoliko se promeni ukljuena datoteka, sve datoteke koje zavise od nje


direktive

#include.

#include

direktivi, do kompilatora stie program koji

sk
o

Poto, zahvaljujui

iz

moraju biti iznova prevedene. Datoteka koja se ukljuuje i sama moe sadrati

ne postoji fiziki u jednoj datoteci, ve je kombinacija teksta koji se nalazi


u razliitim datotekama, kae se da se program sastoji od razliitih jedinica

prevoenja (a ne od vie datoteka). Jedinice prevoenja imaju mnogo direk-

ro
n

tniju vezu sa objektnim modulima, povezivanjem i izvrnim programom od


pojedinanih fizikih datoteka koje programer kreira.

kt

Makro zamene

Pretprocesorska direktiva

#define omoguava zamenjivanje niza karaktera

le

u datoteci, makroa (engl. macro) drugim nizom karaktera pre samog pre-

voenja. Njen opti oblik je:

#define originalni_tekst novi_tekst


U najjednostavnijem obliku, ova direktiva koristi se za zadavanje vrednosti

nekom simbolikom imenu, na primer:

#define MAX_LEN 80
Ovakva definicija se koristi da bi se izbeglo navoenje iste konstantne vrednosti na puno mesta u programu.

Umesto toga, koristi se simboliko ime

koje se moe lako promeniti izmenom na samo jednom mestu.


denom primeru,

U nave-

MAX_LEN je samo simboliko ime i nikako ga ne treba meati sa

196

9. Organizacija izvornog i izvrnog programa

promenljivom (ak ni sa promenljivom koja je

const).

Naime, za ime

MAX_LEN

u memoriji se ne rezervie prostor tokom izvravanja programa, ve se svako


njeno pojavljivanje, pre samog prevoenja zamenjuju zadatom vrednou (u
navedenom primeru vrednou 80). Tako

MAX_LEN

nije vidljiva ni kompila-

toru, ni linkeru, niti u bilo kom obliku postoji u izvrnom programu.


Makro moe biti bilo koji identifikator, pa ak i kljuna re jezika C. Tekst

zamene (novi_tekst u navedenom optem obliku) je tekst do kraja reda, a


reda koji se nastavlja.

\ na kraju svakog

(2
01
5)

mogue je da se prostire na vie redova ako se navede simbol

Direktive zamene mogu da koriste direktive koje im

prethode.

Zamene se ne vre u konstantnim niskama niti u okviru drugih simbolikih

#define MAX_LEN 80 nee uticati


printf( "MAX_LEN is 80"); niti na simboliko ime MAX_LEN_VAL.

imen a . Na primer, gore navedena direktiva


na naredbu

Mogue je defisati i pravila zamene sa argumentima od kojih zavisi tekst

max(A, B)

((A) > (B) ? (A) : (B))

an

#define

je

zamene. Na primer, sledea definicija

max(A, B) koji zavisi od argumenata. Ukoliko je u nasmax(2, 3), to e, pre prevoenja,


biti zamenjeno sa ((2) > (3) ? (2) : (3)). Slino, tekst max(x+2, 3*y)
bie zamenjen tekstom ((x+2) > (3*y) ? (x+2) : (3*y)). Tekst max(2, 3)
definie tekst zamene za

iz

tavku datoteke, u nekoj naredbi navedeno

i slini ne predstavljaju poziv funkcije i nema nikakvog prenosa argumenata kao

sk
o

kod pozivanja funkcija. Postoje i druge razlike u odnosu na poziv funkcije. Na


primer, ukoliko je negde u programu navedeno

max(a++, b++), na osnovu date

definicije, ovaj tekst bie zamenjen tekstom

ro
n

((a++) > (b++) ? (a++) : (b++)),

to e dovesti do toga da se vea od vrednosti

a i b inkrementira dva puta (to

moda nije planirano).

Vano je voditi rauna i o zagradama u tekstu zamene, da bi bio ouvan

kt

poredak primene operacija. Na primer, ukoliko se definicija

le

#define kvadrat(x) x*x

primeni na

kvadrat(a+2),

tekst zamene e biti

a+2*a+2,

a ne

(a+2)*(a+2),

kao to je verovatno eljeno i zbog toga bi trebalo koristiti:

#define kvadrat(x) (x)*(x)


Navedena definicija, meutim, i dalje ne daje ponaanje koje je verovatno

eljeno.

Naime, kada se makro primeni na izraz

zamenjen izrazom

a/(b*b)).

a/(b)*(b),

a/kvadrat(b), on e biti
(a/b)*b (a ne sa sa

to je ekvivalentno sa

Zbog toga je bolja definicija:

6 Zato je neophodno da pretprocesor tokom svog rada izvri jednostavniju leksiku analizu.

197

9. Organizacija izvornog i izvrnog programa

#define kvadrat(x) ((x)*(x))


Tekst zamene moe da sadri itave blokove sa deklaracijama, kao u sledeem
primeru:

#define swap(t, x, y) { t z; z=x; x=y; y=z; }


a i b se,
swap(int, a, b).
menljivama

#,

Celobrojnim pro-

zahvaljujui ovom makrou, mogu razmeniti vrednosti sa

Ukoliko se u direktivi
navede simbol

t.

(2
01
5)

koji definie zamenjivanje vrednosti dve promenljive tipa

#define,

u novom tekstu, ispred imena parametra

kombinacija e biti zamenjena vrednou parametra nave-

denog izmeu dvostrukih navodnika. Ovo moe da se kombinuje sa nadovezivanjem niski. Na primer, naredni makro moe da poslui za otkrivanje greaka:

printf(#expr " = %g\n", expr)

je

dprint(expr)

an

#define

Tako e tekst:

dprint(x/y);

iz

unutar nekog programa biti zamenjen tekstom:

sk
o

printf("x/y" " = %g\n", x/y);

Poto se niske automatski nadovezuju, efekat ove naredbe je isti kao efekat
naredbe:

ro
n

printf("x/y = %g\n", x/y);

esta je potreba da se prilikom pretprocesiranja dve niske nadoveu da bi

##.

kt

se izgradio sloeni identifikator.

Ovo se postie petprocesorskim operatorom

Na primer,

le

#define dodaj_u_niz(ime, element) \


niz_##ime[brojac_##ime++] = element
Poziv

dodaj_u_niz(a, 3);
se tada zamenjuje naredbom

niz_a[brojac_a++] = 3;
Dejstvo primene direktive zamene je od mesta na kojem se nalazi do kraja
datoteke ili do reda oblika:

198

9. Organizacija izvornog i izvrnog programa

#undef originalni_tekst
Kao to je reeno, makro zamene i funkcije se, iako mogu izgledati slino,
sutinski razlikuju. Kod makro zamena nema provere tipova argumenata niti
implicitnih konverzija to moe da dovodi do greaka u kompilaciji ili do neoekivanog rada programa. Argument makroa u zamenjenoj verziji moe biti nave-

(2
01
5)

den vie puta to moe da utie na izvravanje programa, a izostavljanje zagrada


u tekstu zamene moe da utie na redosled izraunavanja operacija. S druge

strane, kod poziva makroa nema prenosa argumenata te se oni izvravaju bre
nego odgovarajue funkcije. Ipak, moderni kompilatori kratke funkcije obino
umeu (engl. inline) itavo telo funkcije na mesto poziva, starajui se o argu-

mentima i tada nema gubitaka u vremenskoj ili prostornoj efikasnosti u odnosu

na korienje makroa. Sve u svemu, makro zamene sa argumentima mogu imaju


i dobre i loe strane i treba ih koristiti oprezno.

je

Mnoge standardne funkcije za ulaz i izlaz iz standardne C biblioteke mogu


biti, alternativno, implementirane i kao makroi (na primer,

getc, printf

koji koristi funkciju

fprintf,

getchar koji koristi

itd.).

an

funkciju

Uslovno prevoenje

iz

Pretprocesorskim direktivama je mogue iskljuiti delove kda iz procesa


prevoenja, u zavisnosti od vrednosti uslova koji se rauna u fazi pretprocesiranja. Direktiva

#if

izraunava vrednost konstantnog celobrojnog izraza (koji

sk
o

moe, na primer, da sadri konstante i simbolika imena definisana direktivom

#define).

Ukoliko je dobijena vrednost jednaka nuli, onda se ignoriu (ne

#endif ili do direktive #else ili do


#elif koja ima znaenje kao else-if. U okviru argumenta direktive
#if, moe se koristiti izraz defined(ime) koji ima vrednost 1 ako je simboliko
ime ime definisano nekom prethodnom direktivom, a 0 inae. Krai zapis za
#if defined(ime) je #ifdef ime, a krai zapis za #if !defined(ime) je
#ifndef ime. Na primer, sledei program:

kt

direktive

ro
n

prevode) sve linije programa do direktive

le

Program 9.1.

#define SRPSKI
#include <stdio.h>
int main()
{
#ifdef SRPSKI
printf("Zdravo, svete");
#else
printf("Hello, world");
#endif

199

9. Organizacija izvornog i izvrnog programa

return 0;

ispisuje tekst na srpskom jeziku, a izostavljanjem direktive iz prvog reda ispisivao bi tekst na engleskom jeziku.
grananja zasnovanog na C naredbi

if.

Ovo grananje se sutinski razlikuje od


Naime, u navedenom primeru prevodi

se samo jedna od dve verzije programa i dobijeni izvrni program nema nikakvu

(2
01
5)

informaciju o drugoj verziji. Za razliku od toga, kada se koristi grananje koje


koristi C jezik (a ne pretprocesor), program sadri kd za sve mogue grane.

9.2.2

Doseg identifikatora

Jedna od glavnih karakteristika dobrih programa je da se promenljive veinom definiu u funkcijama (ili ak nekim uim blokovima) i upotreba promen-

ljive je uglavnom ograniena na funkciju (ili blok) u kojoj je deklarisana. Ovim

je

se smanjuje zavisnost izmeu funkcija i ponaanje funkcije odreeno je samo


njenim ulaznim parametrima, a ne nekim globalnim stanjem programa. Time

an

se omoguava i da se analiza rada programa zasniva na analizi pojedinanih


funkcija, nezavisnoj od konteksta celog programa. Ipak, u nekim sluajevima
promenljivih.

prihvatljivo je da funkcije meusobno komuniciraju korienjem zajednikih

Doseg, tj. vidljivost identifikatora (engl. scope of identifiers)

iz

odreena je nainom tj. mestom u izvornom kdu na kojem su uvedeni.


Doseg identifikatora odreuje deo teksta programa u kojem je mogue ko-

sk
o

ristiti odreeni identifikator i u kojem taj identifikator identifikuje odreeni objekat (na primer, promenljivu ili funkciju). Svaki identifikator ima neki doseg.
Jezik C spada u grupu jezika sa statikim pravilima dosega to znai da se doseg
svakog identifikatora moe jednoznano utvrditi analizom izvornog kda (bez

ro
n

obzira na mogue tokove izvravanja programa).

U jeziku C postoje sledee

vrste dosega:

doseg nivoa datoteke (engl. file level scope) koji podrazumeva da ime vai

kt

od take uvoenja do kraja datoteke;

doseg nivoa bloka (engl. block level scope) koji podrazumeva da ime vai

le

od take uvoenja do kraja bloka u kojem je uvedeno;

doseg nivoa funkcije (engl. function level scope) koji podrazumeva da ime
vai u celoj funkciji u kojoj je uvedeno; ovaj doseg imaju jedino labele
koje se koriste uz

goto

naredbu;

doseg nivoa prototipa funkcije (engl. function prototype scope) koji podrazumeva da ime vai u okviru prototipa (deklaracije) funkcije; ovaj
doseg imaju samo imena parametara u okviru prototipova funkcije; on
omoguava da se u prototipovima funkcija navode i imena (a ne samo
tipovi) argumenata, to nije obavezno, ali moe da olaka razumevanje i
dokumentovanje kda.

7 Za

lokalizaciju programa bolje je koristiti specijalizovane alate npr. GNU gettext.

200

9. Organizacija izvornog i izvrnog programa

Najznaajni nivoi dosega su doseg nivoa datoteke i doseg nivoa bloka. Identifikatori koji imaju doseg nivoa datoteke najee se nazivaju spoljanji ili glob-

alni , dok se identifikatori koji imaju ostale nivoe dosega (najee doseg nivoa

8 Na osnovu diskusije sa poetka ovog

bloka) nazivaju unutranji ili lokalni .

poglavlja, jasno je da je poeljno koristiti identifikatore promenljivih lokalnog


dosega kada god je to mogue. S druge strane, funkcije su obino globalne. Imajui u vidu podelu na globalne i lokalne objekte, C program se esto definie

(2
01
5)

kao skup globalnih objekata (promenljivih, funkcija, tipova podataka itd.).

U ranim verzijama jezika C nije bilo mogue definisati funkciju u okviru


definicije druge funkcije, tj. funkciju sa dosegom nivoa bloka, pa nije bilo

lokalnih funkcija , dok je od standarda C99 i takva mogunost predviena.

Doseg globalnih funkcija je doseg nivoa datoteke i protee se od mesta deklaracije


pa do kraja datoteke. U nastavku su dati primeri razliitih dosega:

je

int a;
/* a je globalna promenljiva - doseg nivoa datoteke */

sk
o

iz

an

/* f je globalna funkcija - doseg nivoa datoteke */


void f(int c) {
/* c je lokalna promenljiva doseg nivoa bloka (tela funkcije f) */
int d;
/* d je lokalna promenljiva doseg nivoa bloka (tela funkcije f) */

ro
n

void g() { printf("zdravo"); }


/* g je lokalna funkcija doseg nivoa bloka (tela funkcije f) */

le

kt

for (d = 0; d < 3; d++) {


int e;
/* e je lokalna promenljiva doseg nivoa bloka (tela petlje) */
...
}
kraj:
/* labela kraj - doseg nivoa funkcije */

/* h je globalna funkcija - doseg nivoa datoteke */


void h(int b); /* b - doseg nivoa prototipa funkcije */
8 Iako

tekst standarda koristi termine spoljanji i unutranji, u nastavku teksta e u veini

biti korieni termini globalni i lokalni, da bi se izbegla zabuna sa spoljanjom i unutranjom


povezanou objekata.

201

9. Organizacija izvornog i izvrnog programa

Jezik C doputa tzv. konflikt identifikatora tj. mogue je da postoji vie


identifikatora istog imena. Ako su njihovi dosezi jedan u okviru drugog, tada
identifikator u uoj oblasti dosega sakriva identifikator u iroj oblasti dosega.
Na primer, u narednom programu, promenljiva
sakriva promenljivu

inicijalizovanu na vrednost

inicijalizovana na vrednost

3.

(2
01
5)

void f() {
int a = 3, i;
for (i = 0; i < 4; i++) {
int a = 5;
printf("%d ", a);
}
}

je

5 5 5 5

an

Ovim je omogueno da prilikom uvoenja novih imena programer ne mora

da brine da li je takvo ime ve upotrebljeno u irem kontekstu.

ivotni vek objekata i kvalifikatori

iz

9.2.3

static i auto

U odreenoj vezi sa dosegom, ali ipak nezavisno od njega je pitanje trajanja


objekata (pre svega promenljivih). ivotni vek (engl. storage duration, lifetime)

sk
o

promenljive je deo vremena izvravanja programa u kojem se garantuje da je za


tu promenljivu rezervisan deo memorije i da se ta promenljiva moe koristiti.

ro
n

U jeziku C postoje sledee vrste ivotnog veka:

statiki (engl. static) ivotni vek koji znai da je objekat dostupan tokom
celog izvravanja programa;

automatski (engl. automatic) ivotni vek koji najee imaju promenljive

kt

koje se automatski stvaraju i uklanjaju prilikom pozivanja funkcija;

dinamiki (engl. dynamic) ivotni vek koji imaju promenljive koje se

le

alociraju i dealociraju na eksplicitan zahtev programera (videti poglavlje


10.9).

ivotni vek nekog objekta se odreuje na osnovu pozicije u kdu na kojoj je


objekat uveden i na osnovu eksplicitnog korienja nekog od kvalifikatora

(automatski ivotni vek) ili

static

auto

(statiki ivotni vek).

Lokalne automatske promenljive


Najee koriene lokalne promenljive su promenljive deklarisane u okviru
bloka.

Rekli smo da je njihov doseg nivoa bloka, one su dostupne od take

202

9. Organizacija izvornog i izvrnog programa

deklaracije do kraja bloka i nije ih mogue koristiti van bloka u kojem su deklarisane. Ne postoji nikakva veza izmeu promenljivih istog imena deklarisanih u
razliitim blokovima.
Lokalne promenljive podrazumevano su automatskog ivotnog veka (sem
ako je na njih primenjen kvalifikator

static

ili kvalifikator

extern

o emu

e biti rei u narednim poglavljima). Iako je mogue i eksplicitno okarakterisati


ivotni vek korienjem kvalifikatora

auto, to se obino ne radi jer se za ovakve

(2
01
5)

promenljive automatski ivotni vek podrazumeva. Poetna vrednost lokalnih

automatskih promenljivih nije odreena i zavisi od ranijeg sadraja memorijske


lokacije koja je pridruena promenljivoj, pa se smatra nasuminom.

Automatske promenljive postoje samo tokom izvravanja funkcije u kojoj


su deklarisane i prostor za njih je rezervisan u stek okviru te funkcije (videti
poglavlje 9.3.3). Ne postoji veza izmeu promenljive jednog imena u razliitim

aktivnim instancama jedne funkcije (jer svaka instanca funkcije ima svoj stek

je

okvir i u njemu prostor za promenljivu tog imena). Dakle, ukoliko se u jednu


funkciju ue rekurzivno, kreira se prostor za novu promenljivu, potpuno neza-

an

visan od prostora za prethodnu promenljivu istog imena.

Formalni parametri funkcija, tj. promenljive koje prihvataju argumente


funkcije imaju isti status kao i lokalne automatske promenljive.
ime se kompilatoru sugerie da se ove promenljive u-

iz

register

Na lokalne automatske promenljive i parametre funkcija mogue je primeniti


i kvalifikator

vaju u registrima procesora, a ne u memoriji (o organizaciji izvrnog programa


i organizaciji memorije tokom izvravanja programa bie vie rei u poglavlju

sk
o

9.3.3). Meutim, s obzirom na to da dananji kompilatori tokom optimizacije


kda veoma dobro mogu da odrede koje promenljive ima smisla uvati u reg-

ro
n

istrima, ovaj kvalifikator se sve ree koristi.

Globalne statike promenljive i funkcije


Globalne promenljive deklarisane su van svih funkcija i njihov doseg je nivoa

kt

datoteke tj. mogu se koristiti od take uvoenja, u svim funkcijama do kraja


datoteke.

ivotni vek ovih promenljivih uvek je statiki, tj. prostor za ove

le

promenljive rezervisan je tokom celog izvravanja programa: prostor za njih


se rezervie na poetku izvravanja programa i oslobaa onda kada se zavri

izvravanje programa. Prostor za ove promenljive obezbeuje se u segmentu


podataka (videti poglavlje 9.3.3). Ovakve promenljive se podrazumevano inicijalizuju na vrednost 0 (ukoliko se ne izvri eksplicitna inicijalizacija).
S obzirom na to da ovakve promenljive postoje sve vreme izvravanja programa i na to da moe da ih koristi vie funkcija, one mogu da zamene prenos
podataka izmeu funkcija. Meutim, to treba initi samo sa dobrim razlogom
(na primer, ako najvei broj funkcija treba da koristi neku zajedniku promenljivu) jer, inae, program moe postati neitljiv i teak za odravanje.
Globalne promenljive uvek imaju statiki vek. Na njih je mogue primeniti
kvalifikator

static,

meutim, on ne slui da bi se naglasio statiki ivotni vek

203

9. Organizacija izvornog i izvrnog programa

(to se podrazumeva), ve naglaava da one imaju unutranju povezanost (videti


poglavlje 9.2.4).

Lokalne statike promenljive


U nekim sluajevima poeljno je uvati informaciju izmeu razliitih poziva
funkcije (npr. potrebno je brojati koliko puta je pozvana neka funkcija). Jedno

(2
01
5)

reenje bilo bi uvoenje globalne promenljive, statikog ivotnog veka, meu-

tim, zbog globalnog dosega tu promenljivu bilo bi mogue koristiti (i promeniti)


i iz drugih funkcija, to je nepoeljno. Zato je poeljna mogunost definisanja

promenljivih koje bi bile statikog ivotnog veka (da bi uvale vrednost tokom
itavog izvravanja programa), ali lokalnog dosega (da bi se mogle koristiti i
menjati samo u jednoj funkciji).

U deklaraciji lokalne promenljive moe se primeniti kvalifikator

static

je

u tom sluaju ona ima statiki ivotni vek kreira se na poetku izvravanja programa i oslobaa prilikom zavretka rada programa.

Tako modifiko-

an

vana promenljiva ne uva se u stek okviru svoje funkcije, ve u segmentu podataka (videti poglavlje 9.3.3). Ukoliko se vrednost statike lokalne promenljive
promeni tokom izvravanja funkcije, ta vrednost ostaje sauvana i za sledei
Ukoliko inicijalna vrednost statike promenljive nije nave-

0.

Statike promenljive se inicijalizuju samo

iz

dena, podrazumeva se vrednost

poziv te funkcije.

jednom, konstantnim izrazom, na poetku izvravanja programa tj. prilikom

njegovog uitavanja u memoriju .

Doseg ovih promenljivih i dalje je nivoa

sk
o

bloka tj. promenljive su i dalje lokalne, to daje eljene osobine.


Naredni program ilustruje kako se promenljiva
tokom svakog poziva, dok promenljiva

u funkciji

a u funkciji f iznova kreira


g zadrava svoju vrednost

ro
n

tokom raznih poziva.

Program 9.2.

kt

#include <stdio.h>

le

void f() {
int a = 0;
printf("f: %d ", a);
a = a + 1;
}
void g() {
static int a = 0;
printf("g: %d ", a);
a = a + 1;
}
9 Ovakvo

ponaanje je razliito u odnosu na jezik C++ gde se inicijalizacija vri prilikom

prvog ulaska u blok u kojem je ovakva promenljiva definisana.

204

9. Organizacija izvornog i izvrnog programa

int main() {
f(); f();
g(); g();
return 0;
}
f: 0 f: 0 g: 0 g: 1

9.2.4

Povezanost identifikatora i kvalifikatori

(2
01
5)

Kada se prevede i pokrene, prethodni program ispisuje:

static i extern

Pravila dosega daju mogunost progameru da odredi da li eli da je neko ime

vidljivo samo u jednoj ili u vie funkcija definisanih u jednoj jedinici prevoenja.
voljan i potrebna je malo finija kontrola.

je

Meutim, kada se program sastoji od vie jedinica prevoenja, doseg nije doPoeljno je da postoji mogunost

an

definisanja: (i) objekata (promenljivih ili funkcija) koji se mogu koristiti samo
u pojedinanim funkcijama, (ii) objekata koji se mogu koristiti u vie funkcija
neke jedinice prevoenja, ali ne i van te jedinice prevoenja i (iii) objekata koji

se mogu koristiti u svim funkcijama u celom programu, mogue i u razliitim

iz

jedinicama prevoenja.

Identifikator koji je deklarisan u razliitim dosezima ili u istom dosegu vie


puta moe da oznaava isti objekat ili razliite objekte.

ta e biti sluaj,

sk
o

odreuje se na osnovu povezanosti identifikatora (engl. linkage of identifiers).


Povezanost identifikatora tesno je vezana za fazu povezivanja programa i najee se koristi da odredi meusobni odnos objekata u razliitim jedinicama

ro
n

prevoenja. Izmeu ostalog, ona daje odgovor na pitanje da li je i kako mogue


objekte definisane u jednoj jedinici prevoenja koristiti u nekoj drugoj jedinici
prevoenja. Na primer, da li je doputeno da se u dve razliite jedinice prevoenja koristi identifikator

kt

taj identifikator

za neku globalnu celobrojnu promenljivu i da li

oznaava jednu istu ili dve razliite promenljive.

le

Jezik C razlikuje identifikatore:

bez povezanosti (engl. no linkage),

identifikatore sa spoljanjom povezanou (engl. external linkage) i

identifikatore sa unutranjom povezanou (engl. internal linkage).

Ne treba meati spoljanju i unutranju povezanost sa spoljanjim i unutranjim dosegom (otuda i korienje alternativnih termina globalni i lokalni
za doseg) povezanost (i unutranja i spoljanja) se odnosi iskljuivo na globalne objekte (tj. objekte spoljanjeg dosega), dok su lokalni objekti (tj. objekti
unutranjeg dosega) najee bez povezanosti (osim ako im se povezanost ne
promeni kvalifikatorom

extern

o emu e biti rei u nastavku). Unutranja i

spoljanja povezanost identifikatora ima smisla samo kod objekata sa statikim


ivotnim vekom, dok su objekti automatskog ivotnog veka bez povezanosti.

205

9. Organizacija izvornog i izvrnog programa

Da bi se povezanost potpuno razumela, potrebno je skrenuti panju na jo


jedan znaajan aspekt jezika C i razjasniti ta se podrazumeva pod deklaraci-

jom , a ta pod definicijom objekta. Deklaracijom se uvodi novi identifikator


i opisuje se njegov tip (bez obzira da li je u pitanju promenljiva ili funkcija).
Deklaracija je ono to je kompilatoru potrebno da bi se taj identifikator mogao
dalje koristiti u programu (na primer, da bismo mogli da pozivamo funkciju
dovoljno je samo da znamo njenu deklaraciju

void f();).

f,

Deklaraciju moemo

(2
01
5)

shvatiti kao deo koda kojim kompilatoru kaemo negde u programu postoji
objekat tog i tog tipa. Definicijom se taj objekat zaista implementira tj. in-

stancira (definicijom kaemo evo ga objekat taj i taj). Definicija je ono to


je u fazi povezivanja potrebno da bi sva korienja nekog identifikatora u programu mogla da budu razreena. Na primer, definicija funkcije

f implementira

tu funkciju tj. uvodi njen kod i svaki poziv te funkije se onda razreava tako
to se poziva upravo taj kd. Definicija globalne promenljive

int a = 3; kae

je

da u objektnom kodu generisanom na osnovu te jedinice prevoenja treba da


bude rezervisana memorija za jedan podatak tipa

int, da taj podatak treba da


au

an

bude incijalno postavljen na vrednost 3 i da se sva korienja te promenljive

tekstu programa u stvari odnosne na taj podatak. Objekti mogu da imaju vei
broj (istovetnih) deklaracija, ali mogu da imaju samo jednu definiciju. Ako su

iz

e doi do greke u fazi povezivanja.

date samo deklaracije, a ne i definicije, faza kompilacije proi e uspeno, ali


U sluaju funkcija, pitanje ta je deklaracija, a ta je definicija jasno je na
osnovu toga da li prototip prati i telo funkcije. Slino, svaka deklaracija lokalne

sk
o

promenljive koja je do sada prikazana bila je ujedno i njena definicija. Meutim, to je neto drugaije kod globalnih promenljivih. Naime, ako deklaraciju
prati inicijalizacija, ona se uvek ujedno smatra i definicijom. Ali, ako je globalna

int a;),

ro
n

promenljiva uvedena bez inicijalizacije (npr. ako postoji globalna deklaracija


nije jasno da li je u pitanju deklaracija ili definicija.

Takav kod se

smatra naelnom definicijom (engl. tentative definition). Ako postoji stvarna


definicija iste promenljive (na primer, deklaracija sa inicijalizacijom), onda se

kt

naelna definicija smatra samo deklaracijom. Meutim, ako stvarne definicije


nema, onda se naelna definicija smatra definicijom (uz inicijalnu vrednost 0),

le

tj. ponaanje je isto kao da pored naelne definicije postoji stvarna definicija
sa inicijalizatorom 0. Takoe, ako se pri deklaraciji promenljive (bilo lokalne,

bilo globalne) navede kvalifikator

extern

(o kome e biti rei u nastavku) ta

deklaracija obavezno prestaje da bude definicija (i tada nije doputeno navoditi


inicijalnu vrednost).

Identifikatori bez povezanosti


Identifikatori bez povezanosti nisu vidljivi prilikom procesa povezivanja i
mogu se potpuno nezavisno ponavljati u razliitim funkcijama, bilo da su one
navedene u jednoj ili u vie jedinica prevoenja. Svaka deklaracija identifikatora bez povezanosti ujedno je i njegova definicija i ona odreuje jedinstveni
nezavisni objekat. Bez povezanosti su najee lokalne promenljive (bez obzira

206

9. Organizacija izvornog i izvrnog programa

da li su automatskog ili statikog ivotnog veka), parametri funkcija, korisniki


definisani tipovi, labele itd.
i struktura

imena

Na primer, ako su funkcije

f,

funkcije

g1

g2

definisane u razliitim jedinicama prevoenja, sva pojavljivanja

i sva pojavljivanja imena

oznaavaju razliite, potpuno nezavisne

promenljive i tipove.

int g1(int i) {
static int j;
}
int g2() {
static int i, j;
...
}

je

Spoljanja povezanost i kvalifikator extern

struct i { int a; }

(2
01
5)

int f() {
int i;
...
}

an

Spoljanja povezanost identifikatora omoguava da se isti objekat koristi u


vie jedinica prevoenja. Sve deklaracije identifikatora sa spoljanjom poveza-

nou u skupu jedinica prevoenja odreuju jedan isti objekat (tj. sve pojave
ovakvog identifikatora u razliitim jedinicama prevoenja odnose se na jedan

iz

isti objekat), dok u celom programu mora da postoji tano jedna definicija tog
objekta. Tako se jedan identifikator koristi za isti objekat u okviru vie jedinica
Kvalifikator

extern

sk
o

prevoenja.

najee se koristi iskljuivo kod programa koji se sas-

toje od vie jedinica prevoenja i slui da naglasi da neki identifikator ima


spoljanju povezanost.

extern.

Jedino deklaracije mogu biti okvalifikovane kvalifika-

Samim tim, nakon njegovog navoenja nije mogue navoditi

ro
n

torom

inicijalizaciju promenljivih niti telo funkcije (to ima smisla samo prilikom
definisanja). Slino, za niz u
Poto

extern

kt

ziju.

extern

deklaraciji nije potrebno navoditi dimen-

deklaracije nisu definicije, njima se ne rezervie nikakva

memorija u programu ve se samo naglaava da se oekuje da negde (najee

le

u drugim jedinicama prevoenja) postoji definicija objekta koji je se

extern

deklaracijom deklarie (i time uvodi u odgovarajui doseg).

Ipak, postoje sluajevi kada se spoljanja povezanost podrazumeva i nije

neophodno eksplicitno upotrebiti

extern

deklaraciju.

Sve globalne funkcije

jezika C podrazumevano imaju spoljanju povezanost (osim ako na njih nije


primenjen kvalifikator

static kada je povezanost unutranja) i zato se prilikom


extern. Slino kao

njihove deklaracije retko kad eksplicitno navodi kvalifikator

kod funkcija, podrazumevana povezanost globalnih promenljivih je spoljanja


(osim ako na njih nije primenjen kvalifikator

static

kada je povezanost un-

utranja). Ranije je ve reeno da deklaracije globalnih promenljivih (oblika


npr.

int x;),

ako nisu praene inicijalizacijom, predstavljaju samo naelne

definicije, tj. ako negde postoji stvarna definicija objekta sa tim imenom, one
nisu definicije ve samo deklaracije.

U tom svetlu, kvalifikator

extern

nije

207

9. Organizacija izvornog i izvrnog programa

neophodno navesti uz takve deklaracije. Ipak, za razliku od funkcija, njegova


upotreba se savetuje da bi se eksplicitno naglasilo da se eli samo deklaracija (a
ne i definicija) promenljive i kako odgovor na pitanje da li je neto deklaracija
ili definicija ne bi zavisio od ostatka izvornog teksta programa.
Kod lokalnih promenljivih, svaka deklaracija ujedno je i definicija i ovakvi
objekti su po pravilu bez povezanosti (ak i ako je na njih primenjen kvalifikator

static). Zato je kod lokalnih promenljivih neophodno koristiti kvaliextern kada se eli naglasiti da je u pitanju deklaracija (a ne defini-

(2
01
5)

fikator

cija) promenljive i da je ta promenljiva definisana na nekom drugom mestu


(tj. da promenljiva ima spoljanju povezanost). Ovom, donekle neobinom kon-

strukcijom, postie se da globalna promenljiva (sa spoljanjom povezanou)

u nekoj drugoj jedinici prevoenja, u tekuoj jedinici prevoenja ima samo


lokalni doseg.

Razmotrimo naredni primer koji sadri dve jedinice prevoenja.

je

Program 9.3.

#include <stdio.h>
extern int a;
void f();

void f() {
printf("a=%d\n", a);
}

int g() {
extern int b;
printf("b=%d\n", b);
f();
}
int main() {
a = 1;
/* b = 2; */
g();
return 0;
}

le

kt

ro
n

sk
o

iz

an

#include <stdio.h>
int a;
int b = 3;

b=3
a=0

U prvoj jedinici prevoenja postoje globalne promenljive


funkcija

f.

a i b kao i globalna

Sve one podrazumevano imaju statiki ivotni vek i spoljanju

povezanost. Linija

int b = 3;

sadri inicijalizaciju tako da je jasno da je u

pitanju definicija (i to stvarna). U prvom trenutku nije jasno da li je

int a;

deklaracija ili definicija i u pitanju je samo naelna definicija, meutim, poto


ne postoji druga definicija promenljive

a, ova linija se ipak tumai kao definicija,

uz podrazumevanu inicijalnu vrednost 0.


dve deklaracije: deklaraciju promenljive

Druga jedinica prevoenja sadri


i funkcije

f.

U sluaju promenljive

208

9. Organizacija izvornog i izvrnog programa

extern ime je naglaeno da je u pitanju


a iz
kvalifikator extern nije naveden, program

eksplicitno je upotrebljen kvalifikator

promenljiva sa spoljanjom povezanou i da se eli pristup promenljivoj


prve jedinice prevoenja. ak i da

bi radio identino (obe definicije bile bi naelne i tek tokom povezivanja bio
bi napravljen jedinstven objekat statikog ivotnog veka inicijalizovan na nulu

U sluaju funkcije f nije bilo


extern jer je jasno da je u pitanju deklaracija. Identifikator
b je uveden u lokalni doseg funkcije g uz kvalifikator extern ime je naglaeno
da se misli na promenljivu b definisanu u prvoj jedinici prevoenja. U funkciji
main postavlja se vrednost promenljive a na 1. Pokuaj postavljanja vrednosti
promenljive b (pod komentarom) ne bi uspeo jer identifikator b nije u dosegu
funkcije main.
na koji bi se obe ove promenljive odnosile).

(2
01
5)

neophodno navoditi

je

Unutranja povezanost i kvalifikator static

Globalni objekat ima unutranju povezanost ako se kvalifikuje kvalifika-

static.10

Unutranja povezanost povezuje sva pojavljivanja istog iden-

an

torom

tifikatora, na nivou tano jedne jedinice prevoenja.

Ukoliko se u istoj je-

dinici prevoenja, u istom dosegu naie na vie deklaracija identifikatora sa

unutranjom povezanou sve one se odnose na isti objekat i za taj objekat


kvalifikator

static

iz

mora postojati tano jedna definicija u toj jedinici prevoenja. S druge strane,
onemoguava korienje promenljive ili funkcije u drugim

datotekama koje ine program. Povezivanje, naravno, nee uspeti ni ukoliko

sk
o

je za neku promenljivu ili funkciju deklarisanu sa

static u drugoj datoteci


extern. Ukoliko neka

navedena deklaracija na koju je primenjen kvalifikator

druga jedinica prevoenja sadri deklaraciju istog identifikatora neophodno je

ro
n

da postoji definicija odgovarajueg objekta, razliitog od objekta iz prve jedinice prevoenja.

Osnovna uloga unutranje povezanosti obino je u tome da neki deo kda


uini zatvorenim, u smislu da je nemogue menjanje nekih njegovih globalnih

kt

promenljivih ili pozivanje nekih njegovih funkcija iz drugih datoteka. Time se


taj deo kda enkapsulira i iz drugih jedinica prevoenja mu se moe pris-

le

tupiti samo kroz preostale take komunikacije (funkcije i globalne promenljive


sa spoljanjom povezanou). Cilj programera, dakle, nije da onemogui druge

programere da koriste deo njegovog kda, ve da im omogui jasan interfejs


ijim korienjem se onemoguuju nehotine greke.

Ukoliko je u jednoj je-

dinici prevoenja deklarisana globalna promenljiva ili funkcija sa unutranjom


povezanou, i u drugim jedinicama prevoenja se moe deklarisati globalna
promenljiva ili funkcija istog imena, ali e se ona odnositi na drugi, nezavisan
objekat.
Kao primer, razmotrimo naredne dve jedinice prevoenja

Program 9.4.
10 Kvalifikator static

u programskom jeziku C ima potpuno drugu ulogu i dejstvo kada se

primenjuje na lokalne promenljive: u tom sluaju, ovaj kvalifikator oznaava da promenljiva


ima statiki ivotni vek (videti poglavlje 9.2.3).

209

9. Organizacija izvornog i izvrnog programa

#include <stdio.h>
static int a = 3;
int b = 5;

#include <stdio.h>
int g(); /* int f(); */
int a, b;

static int f() {


printf("f: a=%d, b=%d\n",
a, b);
}

(2
01
5)

int main() {
printf("main: a=%d, b=%d\n",
a, b);
g(); /* f() */
return 0;
}

int g() {
f();
}
Program ispisuje

an

je

main: a=0, b=5


f: a=3, b=5

U prvoj jedinici prevoenja promenljiva

i funkcija

i funkcija

imaju unutranju

imaju spoljanju povezanost (o ko-

povezanost (dok promenljiva

a, b

i funkcije

g i main

iz

joj e biti rei u nastavku poglavlja). U drugoj jedinici prevoenja promenljive


imaju spoljanju povezanost. Ime

u dve razliite je-

a, definstatic sakrivena je i nije joj


Slino je i sa funkcijom f (uk-

dinice prevoenja odnosi se na dve razliite promenljive. Promenljiva

sk
o

isana u prvoj jedinici prevoenja, kljunom reju


mogue pristupiti iz ostalih jedinica prevoenja.

lanjanje komentara u drugoj jedinici prevoenja dovelo bi do greke prilikom

ro
n

povezivanja jer je definicija funkcije

skrivena u prvoj jedinici prevoenja).

Sa druge strane, sva pojavljivanja imena


pojavljivanja imena

odnose se na istu promenljivu i sva

odnose se na istu funkciju.

Poto u prvoj jedinici prevoenja postoji definicija promenljive

kt

goj jedinici prevoenja


promenljive

int b;

b,

u dru-

je samo njena deklaracija. Poto je definicija

iz prve jedinice prevoenja skrivena, prilikom povezivanja druge

le

jedinice prevoenja nije dostupna definicija promenljive

a,

onda se

int a;

drugoj jedinici prevoenja smatra njenom definicijom (uz podrazumevanu vred-

nost 0).

9.2.5

Greke u fazi prevoenja i povezivanja

U procesu generisanja izvrnog programa od izvornog programa, greke


(engl. error) mogu biti otkrivene u nekoliko faza. Poruke o otkrivenim grekama
se obino usmeravaju na standardni izlaz za greke,

stderr

(videti poglavlje

12.1). ak i u veoma kratkim programima, za svaku od ovih faza moe da postoji greka koja tada moe biti otkrivena. Razmotrimo jednostavan (vetaki,
bez konkretne svrhe) program naveden u nastavku i greke do kojih moe doi

210

9. Organizacija izvornog i izvrnog programa

malim izmenama:

Program 9.5.

Pretprocesiranje.

(2
01
5)

#include<stdio.h>
int main() {
int a = 9;
if (a == 9)
printf("9");
return 0;
}

Na primer, ukoliko je, umesto pretprocesorske direktive

je

#include, u programu navedeno #Include, bie prijavljena greka (jer ne postoji direktiva #Include):

an

primer.c:1:2: error: invalid preprocessing directive #Include

iz

Kompilacija

Leksika analiza: Na primer, ukoliko u programu pie

int a = 9;,

int a = 09; umesto


09, tj. neis-

bie detektovana neispravna oktalna konstanta

09

i bie prijavljena greka:

sk
o

pravna leksema

ro
n

primer.c:4:9: error: invalid digit "9" in octal constant


Sintaksika analiza:

Na primer, ukoliko, umesto

programu postoji naredba

if a == 9 ...,

if (a == 9) ...,

zbog izostavljenih zagrada

kt

bie prijavljena greka:

le

primer.c:5:6: error: expected ( before a

Semantika analiza:

if (a == 9) ...,

Na primer, ukoliko u programu, umesto naredbe

postoji naredba

if ("a" * 9) ..., tokom provere


* nije mogue primenjivati

tipova bie prijavljena greka (jer operator


nad niskama):

primer.c:5:8: error: invalid operands to binary *


(have char * and int)

211

9. Organizacija izvornog i izvrnog programa

Povezivanje.
naredba
funkcije

Na primer, ukoliko u programu, umesto

print(...);,
print):

printf(...);, postoji

bie prijavljena greka (jer nije raspoloiva definicija

primer.c:(.text+0x20): undefined reference to print


collect2: ld returned 1 exit status

(2
01
5)

Sve greke u izvornom programu koje mogu biti otkrivene u celokupnom

procesu prevoenja bivaju otkrivene u fazi leksike, sintaksike ili semantike

analize, ili u fazi linkovanja. Dakle, tokom generisanja i optimizacije meukda,


kao i tokom generisanja kda ne moe biti prijavljenih greaka (barem kada je

prevodilac ispravan). Dobro je poznavati faze u prevoenju i vrste greaka koje


u tim fazama mogu biti otkrivene, jer se sa tim znanjem prijavljene greke lake
otklanjaju.

Ukoliko prevodilac naie na greku ili greke u izvornom kdu, to prijavljuje

je

(navodi vrstu greke, liniju i kolonu programa u kojoj je greka) i ne generie

an

izvrni program. Izvrni program se, naravno, ne generie ni u sluaju ako je


greka otkrivena u fazi povezivanja. Programer tada treba da otkloni detektovane greke i ponovi proces prevoenja.

Pored prijave greaka, kompilator moe da izda i upozorenja (engl. warn-

iz

ing) koja ukazuju na potencijalne propuste u programu, ali se i pored njih


izvrni program moe generisati. Na primer, ukoliko navedeni program, umesto
naredbe

if (a == 9) ...

sadri naredbu

if (a = 9) ...,

prevodilac moe

sk
o

izdati upozorenje:

ro
n

primer.c:4: warning: suggest parentheses around assignment


used as truth value
Ukoliko navedeni program, umesto naredbe

if (9 == 9) ...,

if (a == 9) ... sadri naredbu

prevodilac moe izdati upozorenje:

kt

primer.c:3: warning: unused variable a

le

Ukoliko navedeni program, umesto naredbe

if (a == 9) ... sadri naredbu

prevodilac moe izdati upozorenje:

if (a / 0) ...,

primer.c:4: warning: division by zero

Ukoliko se u fazi izvravanja naie na celobrojno deljenje nulom (kao to je


to sluaj sa navedenim primerom), na veini sistema e doi do greke u fazi
izvravanja (videti poglavlje 9.3.5). Ipak, standard proglaava ponaanje programa u sluaju deljenja nulom nedefinisanim, pa navedeni kd dovodi u fazi
prevoenja samo do upozorenja, a ne do greke.
Upozorenja, ak i kada je uspeno generisan izvrni kd, ne treba ignorisati
i dobra praksa moe da bude da se izvorni kd modifikuje sve dok ima ijednog
upozorenja.

212

9. Organizacija izvornog i izvrnog programa

Svaki prevodilac predvia vie vrsta upozorenja i te vrste zavise od konkretnog


prevodioca. Na primer, u prevodiocu GCC, sve vrste upozorenja se omoguavaju
opcijom

-Wall.

9.2.6

Primer organizacije programa u vie datoteka

(2
01
5)

Kao primer programa sastavljenog iz vie datoteka i vie jedinica prevoenja, razmotrimo definisanje jednostavne korisnike biblioteke za rad sa
pozitivnim razlomcima.

Biblioteka je projektovana tako da prikae to vie

koncepata opisanih u ovoj glavi (u realnoj situaciji neka reenja moda bi

bila drugaija). Biblioteka prua definiciju tipa za reprezentovanje razlomaka


(RAZLOMAK), funkcije za kreiranje razlomka na osnovu brojioca i imenioca, za
skraivanje razlomka i za sabiranje razlomaka.

Primena ovih funkcija moe

dovesti do dva (u ovom primeru) ishoda: da je operacija izvrena uspeno i

je

da se prilikom primene operacije javlja neispravan razlomak (onaj kojem je


imenilac 0). Ovim ishodima odgovaraju lanovi

OK

IMENILAC_0

nabrojivog

Kako im nisu eksplicitno pridruene vrednosti ovim

an

RAZLOMAK_GRESKA.

tipa

0 i 1. Tekstualni opis moguih


razlomak_poruka. Ishod rada funkcije bie uvan u
globalnoj promenljivoj razlomak_greska.
Datoteka razlomak.h je javni interfejs biblioteke i sadri deklaracije funkcija
imenima e implicitno biti pridruene vrednosti

iz

ishoda uva se u nizu

i promenljivih koje su na raspolaganju njenim korisnicima.

sk
o

#ifndef __RAZLOMAK_H_
#define __RAZLOMAK_H_

kt

ro
n

typedef struct razlomak {


unsigned brojilac;
unsigned imenilac;
} RAZLOMAK;

le

typedef enum {OK, IMENILAC_0} RAZLOMAK_GRESKA;


extern RAZLOMAK_GRESKA razlomak_greska;
extern char* razlomak_poruka[];
RAZLOMAK napravi_razlomak(unsigned br, unsigned im);
RAZLOMAK skrati_razlomak(RAZLOMAK r);
RAZLOMAK saberi_razlomke(RAZLOMAK r1, RAZLOMAK r2);
#endif
Kao to je ve reeno, u deklaracijama funkcija nije bilo neophodno navoditi

kvalifikator

extern (jer funkcije podrazumevano imaju spoljanju povezanost),


razlomak_greska i niza razlomak_poruka

dok je on upotrebljen kod promenljive

da bi se nedvosmisleno naglasilo da su u pitanju deklaracije, a ne definicije.

213

9. Organizacija izvornog i izvrnog programa

Datoteka zaglavlja

razlomak.h

poinje i zavrava se pretprocesorskim di-

rektivama. Generalno, u datoteci zaglavlja, pored prototipova funkcija, mogu


da se nalaze i neke definicije (najee korisniki definisanih tipova, a ponekad
ak i funkcija i promenljivih). U sluaju da se datoteka zaglavlja ukljui vie
puta u neku jedinicu prevoenja (to se esto dogaa preko posrednog ukljuivanja), desilo bi se da neka jedinica prevoenja sadri viestruko ponavljanje
nekih definicija to bi dovelo do greke prilikom kompilacije. Ovaj problem se

(2
01
5)

moe reiti korienjem pretprocesorskih direktiva i uslovnim prevoenjem. Da

bi se spreilo viestruko ukljuivanje, svaka datoteka zaglavlja u tom sluaju


treba da ima sledei opti oblik:

#ifndef IME
#define IME

je

...

gde je tekst

IME

an

#endif

karakteristian za tu datoteku (na primer njeno ime obo-

IME

Prilikom prvog ukljuivajna ove da-

i zbog toga naredna ukljuivanja (iz iste

iz

toteke, definie se simboliko ime

gaeno nekim specijalnim simbolima).

datoteke) ignoriu celokupan njen sadraj. Ovaj mehanizam olakava odravanje datoteka zaglavlja i primenjen je i u navedenom primeru.

sk
o

Implementacija biblioteke sadrana je u datoteci

razlomak.c.

#include "razlomak.h"

kt

ro
n

char* razlomak_poruka[] = {
"Operacija uspesno sprovedena",
"Greska: imenilac je nula!"
};

le

static const RAZLOMAK NULA = {0, 0};


RAZLOMAK_GRESKA razlomak_greska;

static int nzd(unsigned a, unsigned b) {


return (b == 0) ? a : nzd(b, a % b);
}
RAZLOMAK skrati_razlomak(RAZLOMAK r) {
if (r.imenilac == 0) {
razlomak_greska = IMENILAC_0; return NULA;
}
unsigned n = nzd(r.brojilac, r.imenilac);
r.brojilac /= n;
r.imenilac /= n;

214

9. Organizacija izvornog i izvrnog programa

razlomak_greska = OK;
return r;

(2
01
5)

RAZLOMAK napravi_razlomak(unsigned br, unsigned im) {


RAZLOMAK rez;
rez.brojilac = br;
rez.imenilac = im;
if (im == 0) {
razlomak_greska = IMENILAC_0; return NULA;
}
return skrati_razlomak(rez);
}

iz

an

je

RAZLOMAK saberi_razlomke(RAZLOMAK r1, RAZLOMAK r2) {


if (r1.imenilac == 0 || r2.imenilac == 0) {
razlomak_greska = IMENILAC_0; return NULA;
}
return napravi_razlomak(
r1.brojilac*r2.imenilac + r1.imenilac*r2.brojilac,
r1.imenilac*r2.imenilac);
}

sk
o

Prvi korak predstavlja ukljuivanje datoteke zaglavlja

razlomak.h.

Iako

ovaj korak nije uvek neophodan (ukoliko se pre svakog poziva funkcije javlja
njena definicija), svakako se preporuuje pre definicija ukljuiti deklaracije da
bi se tokom kompilacije proverilo da li su deklaracije i definicije uparene.

razlomak_poruka i globalne prorazlomak_poruka inicijalizovani su


kao pokazivai na konstantne niske. Imenima OK i IMENILAC_0 odgovaraju
vrednosti 0 i 1, pa pokaziva razlomak_poruka[OK] ukazuje na konstantnu
nisku "Operacija uspesno sprovedena", a razlomak_poruka[IMENILAC_0]
na konstantnu nisku "Greska: imenilac je nula!". Datoteka sadri konstantu NULA koja se koristi kao specijalna povratna vrednost u sluaju greke,
kao i pomonu funkciju nzd za pronalaenje najveeg zajednikog delioca dva

ro
n

Datoteka sadri definiciju globalnog niza

razlomak_poruka.

Elementi niza

le

kt

menljive

broja.

S obzirom na to da se ne predvia da ih korisnik biblioteke direktno

koristi, one su sakrivene postavljanjem unutranjeg povezivanja korienjem


kvalifikatora

static.

Program koji demonstrira upotrebu biblioteke dat je u zasebnoj datoteci

program.c.

Program 9.6.
#include <stdio.h>
#include "razlomak.h"

215

9. Organizacija izvornog i izvrnog programa

int main() {
unsigned a, b;
RAZLOMAK r1, r2, r;

(2
01
5)

scanf("%u%u", &a, &b);


r1 = napravi_razlomak(a, b);
if (razlomak_greska != OK) {
printf("%s\n", razlomak_poruka[razlomak_greska]);
return 1;
}

an

je

scanf("%u%u", &a, &b);


r2 = napravi_razlomak(a, b);
if (razlomak_greska != OK) {
printf("%s\n", razlomak_poruka[razlomak_greska]);
return 1;
}

iz

r = saberi_razlomke(r1, r2);
if (razlomak_greska != OK)
printf("%s\n", razlomak_poruka[razlomak_greska]);

sk
o

printf("Rezultat je: %u/%u\n", r.brojilac, r.imenilac);


return 0;

Program uitava dva razlomka, sabira ih i ispisuje rezultat, proverava-

razlomak_greska.

U sluaju

da je dolo do greke, opis greke se ispisuje na standardni izlaz.

Datoteka

ro
n

jui u pojedinim koracima vrednost promenljive

razlomak.h

nesmetano je ukljuena u obe jedinice prevoenja.

kt

Odgovarajua

Makefile

datoteka moe da bude:

le

program : program.o razlomak.o


gcc -o program program.o razlomak.o

program.o : program.c razlomak.h


gcc -c -O3 -Wall program.c
razlomak.o : razlomak.c razlomak.h
gcc -c -O3 -Wall razlomak.c

Pitanja i zadaci za vebu


Pitanje 9.2.1.

emu slui direktiva

#include?

216

9. Organizacija izvornog i izvrnog programa

Pitanje 9.2.2.

Gde se trai datoteka filename ako se ukljui pretprocesorskom


#include "filename", a gde ako se ukljui direktivom #include
<filename>? Kada se obino koristi direktiva #include "filename", a kada
direktiva #include <filename> ?
direktivom

Pitanje 9.2.3.

Dokle vai dejstvo pretprocesorske direktive

#define NUM_LINES 1000?

Pitanje 9.2.4.

(2
01
5)

Kako se ponitava njeno dejstvo?

Kako se od neke take u programu ponitava dejstvo pretpro-

cesorske direktive

#define x(y) y*y+y?

Pitanje 9.2.5.

Kako se moe proveriti da li je neko simboliko ime definisano

u trenutnoj jedinici prevoenja?

Objasniti razliku izmeu makroa i funkcija. U kojoj fazi se vri

je

Pitanje 9.2.6.

an

razreavanje poziva makroa, a u kojoj poziva funkcija? Objasniti ta znai da


kod makroa nema prenosa argumenata, a kod funkcija ima.
Kojoj operaciji u tekstualnom editoru je slian efekat direktive

Pitanje 9.2.8.

#include?

iz

a kojoj efekat direktive

Pitanje 9.2.7.

#define,

Kojim parametrom se GCC navodi da izvri samo pretproce-

Pitanje 9.2.9.

sk
o

siranje i prikae rezultat faze pretprocesiranja?


Za svaki od programa koji slede, navesti ta je rezultat pret-

procesiranja programa i ta se ispisuje kada se program prevede i izvri.

#include <stdio.h>
#define x(y) y*y+y
int main() { printf("%d", x(3 + 5)); /* ispis */ }

2.

#include <stdio.h>
#define A(x,y) (x > 2) ? x*y : x-y
int main() { printf("%d %d", A(4,3+2), A(4,3*2); }

le

kt

ro
n

1.

#include <stdio.h>
#define A(x,y) (y>=0) ? x+y : x-y
int main() {
if (b<=0) c = A(a+b,b); else c = A(a-b,b);
printf("%d\n", c);
}

4.

#include <stdio.h>
#define proizvod(x,y) x*y
int main() { printf("%d\n", proizvod(2*3+4, 2+4*5)); }

3.

217

9. Organizacija izvornog i izvrnog programa

5.

#include <stdio.h>
#define A(x,y) (x > 2) ? x*y : x-y
int main() { printf("%d %d\n", A(4,3+2), A(4,3*2)); }

Pitanje 9.2.10.
1. Navesti primer poziva makroa

definiciji

za kvadriranje koji pri definiciji

daje pogrean rezultat dok pri

#define kvadrat(x) ((x)*(x))

2. Navesti primer poziva makroa

dvostruko

(2
01
5)

#define kvadrat(x) x*x

kvadrat

daje ispravan rezultat.

za koji pri definiciji

#define dvostruko(x) (x)+(x) daje pogrean rezultat dok pri definiciji


#define dvostruko(x) ((x)+(x))

Pitanje 9.2.11.

daje ispravan rezultat.

je

Napisati makro za:

1. izraunavanje ostatka pri deljenju prvog argumenta drugim,

an

2. izraunavanje treeg stepena nekog broja,

3. izraunavanje maksimuma dva broja,


4. izraunavanje maksimuma tri broja,

iz

5. izraunavanje apsolutne vrednosti broja,

Koji program pravi od ulaznih datoteka jedinice prevoenja?

Pitanje 9.2.13.

Prilikom generisanja izvrne verzije programa napisanog na

sk
o

Pitanje 9.2.12.

jeziku C, koja faza prethodi kompilaciji, a koja sledi nakon faze kompilacije?
Kako se zove faza prevoenja programa u kojoj se od objektnih

ro
n

Pitanje 9.2.14.

modula kreira izvrni program? Koji program sprovodi tu fazu?

Pitanje 9.2.15.

Kako se korienjem GCC kompilatora moe zasebno prevesti

datoteka

zatim zasebno prevesti datoteka

kt

prva.c,

program?

druga.c

i na kraju povezati

le

sve u program pod imenom

Kako se obino obezbeuje da nema viestrukog ukljuivanja

Pitanje 9.2.17.

Koji sve nivoi dosega identifikatora postoje u jeziku C? Koja

Pitanje 9.2.16.

neke datoteke?

su dva najee koriena?

Kog nivoa je doseg lokalnih, a kog nivoa doseg

globalnih promenljivih?

Pitanje 9.2.18.

Nabrojati tri vrste identifikatora prema vrsti povezivanja.

Pitanje 9.2.19.

Koju povezanost imaju lokalne promenljive?

Pitanje 9.2.20.

Koji kvalifikator se koristi da bi se onemoguilo da se globalna

promenljiva koristi u nekoj drugoj jedinici prevoenja? Koje povezivanje se u


tom sluju primenjuje?

218

9. Organizacija izvornog i izvrnog programa

Pitanje 9.2.21.

Koji kvalifikator se koristi da bi se globalna promenljiva deklar-

isana u drugoj jedinici prevoenja mogla da koristi u drugoj? Koje povezivanje


se u tom sluju primenjuje?

Pitanje 9.2.22.

Ako je za neku spoljanju promenljivu navedeno da je

a za istu tu promenljivu u nekoj drugoj datoteci navedeno da je

extern,

static
u kojoj

Pitanje 9.2.23.

(2
01
5)

fazi e biti prijavljena greka?


Da li je naredna deklaracija ispravna i koliko bajtova je njome

alocirano:
1.

int a[] = {1, 2, 3};

2.

extern int a[];

3.

extern int a[] = {1, 2, 3};

Pitanje 9.2.24.

je

Koje vrste ivotnog veka postoje u jeziku C? Koji ivotni vek

imaju lokalne promenljive (ako na njih nije primenjen kvalifikator

Pitanje 9.2.25.

Ukoliko je za neku lokalnu promenljivu naveden kvalifikator

ta e biti sa njenom vrednou nakon kraja izvravanja funkcije u

static,

static)?

an

Koji ivotni vek imaju globalne promenljive?

f u okviru koje je deklarisana lokalna


b. Koja je podrazupromenljive b?

Navesti primer funkcije

statika promenljiva

i lokalna automatska promenljiva

sk
o

Pitanje 9.2.26.

iz

kojoj je deklarisana?

mevana vrednost promenljive

Pitanje 9.2.27.

a,

a koja

ta ispisuju naredni programi:

le

kt

ro
n

int i = 2;
int f() { static int i; return ++i; }
int g() { return ++i; }
int main() {
int i;
for(i=0; i<3; i++)
printf("%d", f()+g());
}
int i=2;
void f() { static int i; i++; printf("%d",i); }
void g() { i++; printf("%d",i); }
void h() { int i = 0; i++; printf("%d",i); }
int main() {
f(); g(); h(); f(); g(); h();
}

Pitanje 9.2.28.

static,

Ukoliko je na globalnu promenljivu primenjen kvalifikator

kakva joj je povezanost, ta je njen doseg i koliki joj je ivotni vek?

219

9. Organizacija izvornog i izvrnog programa

9.3 Organizacija izvrnog programa


Ukoliko je od izvornog programa uspeno generisana izvrna verzija, ta,
generisana verzija moe biti izvrena. Zahtev za izvravanje se izdaje operativnom sistemu (npr. navoenjem imena programa u komandnoj liniji). Program koji treba da bude izvren najpre se uitava sa spoljne memorije u radnu
memoriju raunara. Operativni sistem mu stavlja odreenu memoriju na raspo-

(2
01
5)

laganje, vri se dinamiko povezivanje poziva rutina niskog nivoa rantajm bibliotekom, vre se potrebne inicijalizacije i onda izvravanje moe da pone. U

fazi izvravanja mogue je da doe do greaka koje nije bilo mogue detektovati
u fazi prevoenja i povezivanja.

Izvrni program generisan za jedan operativni sistem moe se izvravati


samo na tom sistemu. Mogue je da izvrni program koji je generisan za jedan

operativni sistem ne moe da se izvrava na raunaru koji koristi taj operativni

je

sistem, ali ima arhitekturu koja ne odgovara generisanoj aplikaciji (na primer,

9.3.1

an

64-bitna aplikacija ne moe da se izvrava na 32-bitnom sistemu).

Izvrno okruenje operativni sistem i rantajm biblioteka

Kao to je ranije reeno, izvrni program koji je dobijen prevoenjem i

iz

povezivanjem ne moe da se izvrava autonomno. Naime, taj program sadri


pozive rutina niskog nivoa koje nisu ugraene u program (jer bi inae izvrni
program bio mnogo vei). Umesto toga, te rutine su raspoloive u vidu rantajm

sk
o

biblioteke (engl. runtime library). Funkcije rantajm biblioteke obino su realizovane kao niz zahteva operativnom sistemu (najee zahteva koji se odnose
na ulaz/izlaz i na memoriju).

Kada se program uita u memoriju, vri se

ro
n

takozvano dinamiko povezivanje (engl. dynamic linking) i pozivi funkcija i


promenljivih iz izvrnog programa se povezuju sa funkcijama i promenljivama
iz rantajm biblioteke koja je uitana u memoriju u vreme izvravanja.
Svojstva rantajm biblioteke zavise od kompilatora i operativnog sistema

kt

i u najveem delu nisu specifikovana standardom.

tavie, ni granica koja

definie ta je implementirano u vidu funkcija standardne biblioteke a ta u vidu

le

funkcija rantajm biblioteke nije specifikovana niti kruta i zavisi od konkretnog


kompilatora.

Funkcije rantajm biblioteke su raspoloive programima gener-

isanim od strane kompilatora ali obino nisu neposredno raspoloive aplikativnom programeru. Ako se izvrava vie programa kompiliranih istim kompilatorom, svi oni koriste funkcije iste rantajm biblioteke.
Opisani pristup primenjuje se, ne samo na C, ve i na druge programske
jezike. Biblioteka za C ima i svoje specifinosti. U operativnom sistemu Linux,
funkcije C rantajm biblioteke smatraju se i delom operativnog sistema i moraju
da budu podrane. Nasuprot tome, operativni sistem Windows ne sadri nuno
podrku za C bibliteku i ona se isporuuje uz kompilatore. Zbog toga se i delovi
rantajm biblioteke mogu statiki ugraditi u izvrni program (da se ne bi zavisilo
od njenog postojanja na ciljnom sistemu).
Osnovni skup rantajm funkcija koju jezik C koristi je sadran u modulu

220

9. Organizacija izvornog i izvrnog programa

crt0

(od nulta faza za C Run-Time). Zadatak ovog modula je da pripremi

izvravanje programa i obavlja sledee zadatke:

priprema standardnih ulaz-

no/izlaznih tokova, inicijalizacija segmenata memorije, priprema argumenata


funkcije

main,

9.3.2

Vrste i organizacija podataka

main

i slino.

(2
01
5)

poziv funkcije

Pojam tipova u viem programskom jeziku kao to je C namenjen je oveku,

a ne raunaru. Prevonjem se sve konstrukcije jezika vieg nivoa prevode na


jednostavne konstrukcije neposredno podrane od strane procesora.
deava i sa tipovima:

Isto se

svi tipovi koji se pojavljuju u programu bie svedeni

na osnovne tipove neposredno podrane od strane procesora obino samo

na cele brojeve i brojeve u pokretnom zarezu. Dakle, u izvornom programu,

promenljivama je pridruen tip, ali u izvrnom programu nema eksplicitnih

je

informacija o tipovima. Sve informacije o tipovima se razreavaju u fazi prevoenja i u mainskom kdu se koriste instrukcije za konkretne vrste oper-

+ se moe primenjivati nad

an

anada. Na primer, u izvornom programu, operator

raznim tipovima podataka, dok u mainskom jeziku postoje zasebne instrukcije


za sabiranje celih brojeva i za sabiranje brojeva u pokretnom zarezu.

Veliina osnovnih vrsta podataka u bajtovima u izvrnom programu zav-

iz

isi od opcija prevoenja i treba da bude prilagoena sistemu na kojem e se

11 Faktori koje treba uzeti u obzir su hardver, ali i operativni sistem

izvravati.

raunara na kojem e se program izvravati. Centralni hardver je danas obino

sk
o

ili 32-bitni ili 64-bitni tj. obino registri procesora, magistrale i podaci tipa

int

imaju veliinu 32 bita ili 64 bita. I softver (i aplikativni i sistemski) danas je


najee ili 32-bitni ili 64-bitni. Na 64-bitnom hardveru moe da se izvrava

ro
n

i 32-bitni softver, ali ne i obratno. Pod 32-bitnim softverom se najee podrazumeva softver koji koristi 32-bitni adresni prostor tj. moe da adresira

232

bajtova memorijskog prostora (analogno vai i za 64-bitni). Dakle, i operativni

kt

sistemi i aplikacije su danas najee 32-bitni ili 64-bitni. S obzirom na to da se


aplikativni programi izvravaju pod okriljem operativnog sistema, oni moraju
biti prilagoeni operativnom sistemu na kojem e se izvravati. Na 64-bitnom

le

operativnom sistemu mogu da se izvravaju i 32-bitni i 64-bitni programi, a na


32-bitnom operativnom sistemu mogu da se izvravaju 32-bitni ali ne i 64-bitni

programi.

Na veini 32-bitnih sistema konkretni tipovi podataka imaju brojeve bitova

kao to je navedeno u tabeli 6.1 u glavi 6). Prilikom kompilacije za 64-bitne


sisteme, postoji izbor koji tipove podataka e zauzeti 32, a koji 64 bita. Postoji
nekoliko konvencija koje su imenovane tako da se iz imena vidi koji tipovi podataka zauzimaju 64 bita: ILP64 (integer, long, pointer), LP64 (long, pointer),
LLP64 (long long, pointer).

11 Sistem

Savremeni Linux sistemi i GCC obino koriste

na kome se vri prevoenje ne mora biti isti kao onaj na kome e se vriti izvra-

vanje i neki prevodioci doputaju da se u zavisnosti od opcija prevoenja kreiraju aplikacije


koje su namenjene izvravanju na sasvim drugaijoj arhitekturi raunara pod drugim operativnim sistemom.

221

9. Organizacija izvornog i izvrnog programa

LP64 sistem, dok Windows koristi LLP64 sistem.

char
short
int
long
long long
pointer

32

ILP64

LP64

LLP64
8

16

16

16

16

32

64

32

32

32

64

64

32

64

64

64

64

32

64

64

(2
01
5)

tip

64

Za precizno specifikovanje broja bitova mogu se koristiti tipovi iz zaglavlja

<stdint.h>.

Kada se koristi kompilator GCC, podrazumevani broj bitova odgovara sistemu na kojem se vri prevoenje. Ovo se moe promeniti opcijama

-m32 i -m64

je

kojima se moe zadati da se generisani kd aplikacije bude 32-bitni ili 64-bitni

9.3.3

an

(bez obzira da li se prevoenje vri na 32-bitnom ili 64-bitnom sistemu).

Organizacija memorije

Nain organizovanja i korienja memorije u fazi izvravanja programa moe


Tekst u nastavku

iz

se razlikovati od jednog do drugog operativnog sistema.

odnosi se, ako to nije drugaije naglaeno, na irok spektar platformi, pa su,
zbog toga, nainjena i neka pojednostavljivanja.

sk
o

Kada se izvrni program uita u radnu memoriju raunara, biva mu dodeljena odreena memorija i zapoinje njegovo izvravanje. Dodeljena memorija
organizovana je u nekoliko delova koje zovemo segmenti ili zone:

segment kda (engl. code segment ili text segment) ;

segment podataka (engl. data segment) ;

stek segment (engl. stack segment) ;

kt

ro
n

hip segment (engl. heap segment).

le

U nastavku e biti opisana prva tri, dok e o hip segmentu biti vie rei u

poglavlju 10.9, posveenom dinamikoj alokaciji memorije.


Segmentacija je u odreenoj vezi sa ivotnim vekom promenljivih (o kome

je bilo rei u poglavlju 9.2.3): promenljive statikog ivotnog veka se obino


uvaju u segmentu podataka, promenljive automatskog ivotnog veka se obino
uvaju u stek segmentu, dok se promenljive dinamikog ivotnog veka obino
uvaju u hip segmentu.

Segment kda
Fon Nojmanova arhitektura raunara predvia da se u memoriji uvaju podaci i programi. Dok su ostala tri segmenta predviena za uvanje podataka,
u segmentu kda se nalazi sm izvrni kd programa njegov mainski kd

222

9. Organizacija izvornog i izvrnog programa

koji ukljuuje mainski kd svih funkcija programa (ukljuujui kd svih korienih funkcija koje su povezane statiki). Na nekim operativnim sistemima,
ukoliko je pokrenuto vie instanci istog programa, onda sve te instance dele isti
prostor za izvrni kd, tj. u memoriji postoji samo jedan primerak kda.

tom sluaju, za svaku instancu se, naravno, zasebno uva informacija o tome
do koje naredbe je stiglo izraunavanje.

(2
01
5)

Segment podataka

U segmentu podataka uvaju se odreene vrste promenljivih koje su zajednike za ceo program (one koje imaju statiki ivotni vek, najee globalne
promenljive), kao i konstantni podaci (najee konstantne niske).

Ukoliko

se istovremeno izvrava vie instanci istog programa, svaka instanca ima svoj
zaseban segment podataka. Na primer, u programu

an
d
iz

sk
o

#include <stdio.h>
int a;
int main() {
int b;
static double c;
printf("Zdravo\n");
return 0;
}

je

Program 9.7.

u segmentu podataka e se nalaziti promenljive

c,

kao i konstantna niska

(sa zavrnom nulom, a bez navodnika). Promenljiva

ro
n

"Zdravo\n"

automatska i ona e se uvati u segmentu steka.

je lokalna

Ukoliko se ista konstantna

niska javlja na vie mesta u programu, standard ne definie da li e za nju

kt

postojati jedna ili vie kopija u segmentu podataka.

le

Stek segment

U stek segmentu (koji se naziva i stek poziva (engl. call stack) ili programski

stek ) uvaju se svi podaci koji karakteriu izvravanje funkcija. Podaci koji
odgovaraju jednoj funkciji (ili, preciznije, jednoj instance jedne funkcije jer,
na primer, rekurzivna funkcija moe da poziva samu sebe i da tako u jednom
trenutku bude aktivno vie njenih instanci) organizovani su u takozvani stek

okvir (engl. stack frame). Stek okvir jedne instance funkcije obino, izmeu
ostalog, sadri:

argumente funkcije;

lokalne promenljive (promenljive deklarisane unutar funkcije);

meurezultate izraunavanja;

223

9. Organizacija izvornog i izvrnog programa

adresu povratka (koja ukazuje na to odakle treba nastaviti izvravanje


programa nakon povratka iz funkcije);

adresu stek okvira funkcije pozivaoca.

12 . To znai da

Stek poziva je struktura tipa LIFO ("last in - first out")

se stek okvir moe dodati samo na vrh steka i da se sa steka moe ukloniti

(2
01
5)

samo okvir koji je na vrhu. Stek okvir za instancu funkcije se kreira onda kada
funkcija treba da se izvri i taj stek okvir se oslobaa (preciznije, smatra se
nepostojeim) onda kada se zavri izvravanje funkcije.

Ako izvravanje programa poinje izvravanjem funkcije


okvir se kreira za ovu funkciju.

Ako funkcija

main,

na vrhu steka, iznad stek okvira funkcije


ovu funkciju (ilustrovano na slici 9.1).

main

main,

prvi stek

poziva neku funkciju

Ukoliko funkcija

poziva neku treu

funkciju, onda e za nju biti kreiran stek okvir na novom vrhu steka.

f,

Kada

onda se vrh steka vraa na prethodno stanje i

f se smatra slobodnim (iako on nee biti

an

prostor koji je zauzimao stek okvir za

je

se zavri izvravanje funkcije

f,

kreira se novi stek okvir za

iz

zaista obrisan).

sk
o

Vrh steka

f(),

njeni argumenti,

Vrh steka

ro
n

main(),

lokalne promenljive,

Vrh steka

...

main(),

main(),
njeni argumenti,

njeni argumenti,

lokalne promenljive,

lokalne promenljive,

...

...

...

le

kt

njeni argumenti,

lokalne promenljive,

Levo: tokom

izvravanja

funkcije

Slika 9.1: Organizacija steka i ilustracija izvravanja funkcije.


funkcije

main().

neposredno pozvane iz funkcije

f()

nazad u funkciju

main().

Sredina:

main().

tokom
Desno:

izvravanja

f()

nakon povratka iz funkcije

Veliina stek segmenta obino je ograniena. Zbog toga je poeljno izbegavati smetanje jako velikih podataka na segment steka. Na primer, sasvim
je mogue da u programu u nastavku, sa leve strane, niz

nee biti uspeno

alociran i doi e do greke prilikom izvravanja programa, dok e u programu

12 Ime
pristupa.

stack je zajedniko ime za strukture podataka koje su okarakterisane ovim nainom

224

9. Organizacija izvornog i izvrnog programa

sa desne strane niz biti smeten u segment podataka i sve e tei oekivano.
Predefinisana veliina steka C prevodioca se moe promeniti zadavanjem odgovarajue opcije.

int a[1000000];
int main() {
...
}

(2
01
5)

int main() {
int a[1000000];
...
}

Opisana organizacija steka omoguava jednostavan mehanizam meusobnog


pozivanja funkcija, kao i rekurzivnih poziva.

Prenos argumenata u funkciju preko steka.

Ilustrujmo prenos argume-

nata u funkciju na sledeem jednostavnom primeru.

je

Program 9.8.

iz

an

int f(int a[], int n) {


int i, s = 0;
for (i = 0; i < n; i++)
s += ++a[i];
return s;
}

kt

ro
n

sk
o

int main() {
int a[] = {1, 2, 3};
int s;
s = f(a, sizeof(a)/sizeof(int));
printf("s = %d, a = {%d, %d, %d}\n",
s, a[0], a[1], a[2]);
return 0;
}

le

U funkciji

main

sledeeg oblika

main:

13 :

114:
112:
108:
104:
100:

...
?
3
2
1

Nakon poziva funkcije


okvir funkcije

13 U

f.

a i ceo broj s.
main na steku se nalazi samo jedan stek okvir

deklarisane su dve lokalne promenljive: niz

Na poetku izvravanja funkcije

<- s
<- a
f,

iznad stek okvira funkcije

main

postavlja se stek

Ona ima etiri lokalne promenljive (od ega dve potiu od

tekstu se pretpostavlja da se sve lokalne promenljive uvaju na steku, mada u realnoj

situaciji kompilator moe da odlui da se neke promenljive uvaju u registrima procesora.

225

9. Organizacija izvornog i izvrnog programa

argumenta).
likom poziva.

Argumenti se inicijalizuju na vrednosti koje su prosleene priPrimetimo da je umesto niza preneta samo adresa njegovog

n postavljena na 3 jer je to vrednost izraza


sizeof(a)/sizeof(int) u funkciji main (iako se sintaksiki ovaj izraz nalazi
u okviru poziva funkcije f, on nema nikakve veze sa funkcijom i izraunava se
u funkciji main).
f: 134: ...
130: 0
<- s
126: ?
<- i
122: 3
<- n
118: 100 <- a
main: 114: ...
112: ?
<- s
108: 3
104: 2
100: 1
<- a

je

(2
01
5)

poetka, dok je vrednost parametra

<- s

f:

kt
le

main:

<- a

main:

f:

s
i
n
a

<<<<-

iz

...
2
0
3
100
...
?
3
2
2

ro
n

main:

134:
130:
126:
122:
118:
114:
112:
108:
104:
100:

sk
o

f:

an

Nakon izvravanja koraka petlje, stanje steka je sledee.

134:
130:
126:
122:
118:
114:
112:
108:
104:
100:

...
9
2
3
100
...
?
4
3
2

134:
130:
126:
122:
118:
114:
112:
108:
104:
100:
<<<<-

...
5
1
3
100
...
?
3
3
2

<<<<-

<- s
<- a

s
i
n
a

<- s
<- a

a u funkciji main menja tokom


f, zato to se niz ne kopira ve se u funkciju prenosi adresa

Primetimo da originalna vrednost niza


izvravanja funkcije
njegovog poetka.
Kada funkcija

s
i
n
a

zavi svoje izvravanje, njen stek okvir je:

226

9. Organizacija izvornog i izvrnog programa

f:

134:
130:
126:
122:
118:

...
9
3
3
100

<<<<-

s
i
n
a

s pozivaocu (u ovom sluaju funkciji main).


s upie u registar ax
(preciznije, eax ili rax), odakle je main preuzima i naredbom dodele upisuje u
svoju promenljivu s. Kada funkcija f zavri svoje izvravanje, stanje steka je:
main: 114: ...
112: 9
<- s
108: 4
104: 3
100: 2
<- a
Nakon toga dolazi do poziva funkcije printf. Na stek okvir funkcije main

i tada je potrebno vratiti vrednost

je

(2
01
5)

Ovo se najee postie tako to se vrednost promenljive

postavlja se njen stek okvir i prosleuju se argumenti. Prvi argument je adresa

an

konstantne niske (koja se nalazi negde u segmentu podataka), a ostali su kopije

main. Nakon
main, poto se

printf,

a zatim i funkcije

Implementacija rekurzije.

iz

funkcije

etiri navedene vrednosti iz funkcije

ispisa, uklanja se stek okvir

dolo do njenog kraja.

Navedeno je da je rekurzija situacija u kojoj

jedna funkcija poziva sebe samu direktno ili indirektno.

Razmotrimo, kao

14

Program 9.9.

sk
o

primer, funkciju koja rekurzivno izraunava faktorijel:

ro
n

#include <stdio.h>

le

kt

int faktorijel(int n) {
if (n <= 0)
return 1;
else
return n*faktorijel(n-1);
}
int main() {
int n;
while(scanf("%d",&n) == 1)
printf("%d! = %d\n", n, faktorijel(n));
return 0;
}
Ukoliko je funkcija

faktorijel

pozvana za argument

5,

onda e na steku

poziva da se formira isto toliko stek okvira, za pet nezavisnih instanci funkcije.

14 Vrednost

faktorijela se, naravno, moe izraunati i iterativno, bez korienja rekurzije.

227

9. Organizacija izvornog i izvrnog programa

n. No, iako u jednom


faktorijel, postoji i koristi se samo

U svakom stek okviru je drugaija vrednost argumenta


trenutku ima 5 aktivnih instanci funkcije

jedan primerak izvrnog kda ove funkcije (u kd segmentu), a svaki stek okvir
pamti za svoju instancu dokle je stiglo izvravanje funkcije, tj. koja je naredba
u kd segmentu tekua.

Primer organizacije objektnih modula i izvrnog programa

(2
01
5)

9.3.4

U ovom poglavlju emo pokuati da proces kompilacije i povezivanja ogolimo


do krajnjih granica tako to emo pokazati kako je mogue videti mainski

kd tj. sadraj objektnih modula i izvrnog programa nastalih kompilacijom

15 . Detalji ovog primera svakako u velikoj meri

sledeeg jednostavnog programa

prevazilaze osnove programiranja u programskom jeziku C, ali zainteresovanom


itaocu mogu da poslue da prilino demistifikuje proces prevoenja i izvra-

je

vanja C programa.

an

Program 9.10.

#include <stdio.h>
int n = 10, sum;

ro
n

sk
o

iz

int main() {
int i;
for (i = 0; i < n; i++)
sum += i;
printf("sum = %d\n", sum);
return 0;
}

itav izvorni program sadran je u jednoj jedinici prevoenja, tako da je za

kt

dobijanje izvrnog kda potrebno prevesti tu jedinicu i povezati nastali objektni modul sa potrebnim delovima (objektnim modulima) unapred kompilirane
standardne biblioteke.

le

Nakon kompilacije sa

program.o
objdump.

ula

Na primer,

gcc -c program.c, sadraj dobijenog objektnog modnm ili

moe se ispitati korienjem pomonih programa poput

nm --format sysv program.o

Name
Value
Class
main
|00000000|
T
n
|00000000| D
printf |
| U
sum
|00000004|
C
15 Primer

|
|
|
|

Type
FUNC
OBJECT
NOTYPE
OBJECT

Size
|00000050|
|00000004|
|
|
|00000004|

daje rezultat

Section
.text
.data
*UND*
*COM*

podrazumeva korienje GCC prevodioca na 32-bitnom Linux sistemu. Ve na

64-bitnim Linux sistemima stvari izgledaju donekle drugaije.

228

9. Organizacija izvornog i izvrnog programa

Tabela pokazuje da u objektnom modulu postoje etiri imenovana simbola.

main je funkcija, nalazi se u segmentu kda (na ta ukazuju sekcija


.text i klasa T) i to na njegovom samom poetku (na ta ukazuje vrednost
00000000) i mainske instrukcije dobijene njegovim prevoenjem zauzimaju
(50)16 bajtova. Simbol n nalazi se u segmentu podataka (na ta ukazuje sekcija .data), na njegovom samom poetku (na ta ukazuje vrednost 00000000)
i inicijalizovan je (na ta ukazuje klasa D). Simbol printf je simbol ija je
definicija nepoznata (na ta ukazuje oznaka sekcije *UND*, i klase U). Simbol
sum se nalazi u zoni neinicijalizovanih podataka (na ta ukazuje klasa C i sekcija
*COM*) naime, u ranijim razmatranjima smatrali smo da se neinicijalizovani

(2
01
5)

Simbol

podaci nalaze u istom segmentu podataka kao i inicijalizovani, to je tano,


ali dublji uvid pokazuje da se oni cuvaju u posebnom delu segmenta podataka
(esto se ovaj segment naziva

.bss segment).

S obzirom na to da ovaj segment

podrazumevano treba da bude ispunjen nulama, za razliku od inicijalizovanih

je

podataka koji moraju biti upisani u izvrnu datoteku, kod neinicijalizovanih podataka, umesto da se nule upisuju u izvrnu datoteku, u njoj se samo naglaava
vanja funkcije

main

an

njegova veliina. Prilikom uitavanja programa u glavnu memoriju, pre pozivri se inicijalizacija ovog segmenta na nulu. Primetimo

i da ime lokalne automatske promenljive

uopte nije vidljivo u objektnom

ebp
ebp,esp
esp,0xfffffff0
esp,0x20
DWORD PTR [esp+0x1c],0x0

16
15
44
d0
00
44
00
44
df
00
44
04
fc
00

29 <main+0x29>
edx,DWORD PTR ds:0x0
eax,DWORD PTR [esp+0x1c]
eax,edx
ds:0x0,eax
DWORD PTR [esp+0x1c],0x1
eax,ds:0x0
DWORD PTR [esp+0x1c],eax
13 <main+0x13>
eax,ds:0x0
DWORD PTR [esp+0x4],eax
DWORD PTR [esp],0x0
45 <main+0x45>
eax,0x0

ro
n

push
e5
mov
e4 f0
and
ec 20
sub
44 24 1c 00 00 00 mov

le
E

moe da se vidi, na primer, komandom

sk
o

<main>:

jmp
mov
mov
add
00 00
mov
1c 01
add
00 00
mov
1c
cmp
jl
00 00
mov
04
mov
00 00 00 00 mov
ff ff
call
00 00
mov
leave
ret

00 00 00 00
24 1c

kt

00000000
0: 55
1: 89
3: 83
6: 83
9: c7
10: 00
11: eb
13: 8b
19: 8b
1d: 01
1f: a3
24: 83
29: a1
2e: 39
32: 7c
34: a1
39: 89
3d: c7
44: e8
49: b8
4e: c9
4f: c3

main

iz

Mainski kd funkcije

objdump -d program.o.

modulu (to se i moglo oekivati, jer je ova promenljiva bez povezanosti).

00
24
00
24
00
24
24
ff
00

229

9. Organizacija izvornog i izvrnog programa

Adrese u generisanom kdu su relativne (npr. adrese skokova su sve date u


odnosu na poetak funkcije

main)

izvravanja biti promenjene.

i neke od njih e nakon povezivanja i tokom

Na primer, u instrukciji

29: mov eax,ds:0x0


eax. Trenutni kd

vri se kopiranje odreene vrednosti iz memorije u registar

govori da je to sadraj sa adrese 0 (u odnosu na poetak segmenta podataka


ali u izvrnom programu to nee ostati tako.

Zadatak linkera je da na

ovom mestu adresu 0 zameni adresom promenljive


strukcije upravo da vrednost promenljive
tome, na mesto poziva funkcije

44: call 45 <main+0x45>

printf

(jer je zadatak ove in-

prepie u registar

eax).

Slino

(2
01
5)

ds),

u mainskom kdu generisan je poziv

koji nije ispravan i nema smisla jer ukazuje up-

ravo na adresu argumenta tog poziva (koji je na

44).

Zadatak linkera je da

ovaj poziv korektno razrei. Spisak stavki koje linker treba da razrei mogu da
se vide komandom

objdump -r program.o

(tzv. relokacije) i sam kd nema

nikakvo smisleno znaenje dok se u obzir ne uzme tabela relokacije i dok se sve

an
d

sk
o

iz

RELOCATION RECORDS FOR [.text]:


OFFSET TYPE
VALUE
00000015 R_386_32
sum
00000020 R_386_32
sum
0000002a R_386_32
n
00000035 R_386_32
sum
00000040 R_386_32
.rodata
00000045 R_386_PC32
printf

je

navedene stavke ne razree (to je zadatak linkera).

ro
n

RELOCATION RECORDS FOR [.eh_frame]:


OFFSET TYPE
VALUE
00000020 R_386_PC32
.text
Iz ovoga se vidi se da je jedan od zadataka linkera da korektnu adresu mainskog
kda funkcije

poziv funkcije

na adresu

promenljive

45

u segment kda (.text) ime e

ispravan. Slino, potrebno je razreiti i adresu

kt

printf umetne
printf postati

koja se koristi na mestu

2a

u maniskom kdu (za koju je, kao

to smo opisali, trenutno pretpostavljeno da se nalazi na adresi

u segmentu

le

podataka, to ne mora biti sluaj u konanom kdu), adresu promenljive


i to na tri mesta na kojima joj se pristupa (15,

20

35)

sum

i adresu poetka

.rodata (engl. read only data) u kome se nalazi konstantna niska


sum = %d\n, za koji se trenutno pretpostavlja da je 0, a koja se koristi na
mestu 40 u mainskom kdu. Takoe, potrebno je da linker postavi i pravu
adresu segmenta kda (.text) u zaglavlju izvrne datoteke (.eh_frame).

segmenta

Iako nije od presudnog znaaja za programiranje u C-u, analiza prethodnog


kda moe biti zanimljiva i pokazuje kako se pojednostavljeno opisani mehanizmi funkcionisanja izvrnog okruenja, realno odvijaju u praksi. Prevedeni
mainski kd podrazumeva da stek u memoriji raste od viih ka niim adresama
(engl. downward growing). Registar
istar

ebp

esp sadri uvek adresu vrha steka, dok reg-

sadri adresu poetka stek okvira tekue funkcije (koja je potrebna

pri zavretku funkcije da bi stek okvir mogao da se ukloni).

Prve etiri in-

230

9. Organizacija izvornog i izvrnog programa

strukcije predstavljaju tzv. prolog tekue funkcije i slue da pripreme novi stek
okvir (uva se adresa poetka starog stek okvira i to opet na steku, adresa
poetka novog stek okvira postaje adresa tekueg vrha steka, a vrh steka se
podie (ka manjim adresama) da bi se napravio prostor za uvanje lokalnih
promenljivih i slinih podataka na steku). Prevedeni kd podrazumeva da se

nalazi na steku i to odmah iznad sauvane vrednosti poetka

prvobitnog stek okvira (to je adresa


Naredba u liniji

na proveru uslova u liniji

eax,

esp+0x1c

nakon pomeranja vrha steka).

je inicijalizacija petlje na vrednost 0. Nakon nje, skae se

29.

Prvo se kopira vrednost promenljive

a zatim se vri poreenje vrednosti promenljive


sa registrom

eax.

u registar

(smetene u steku na

i manje od n, vri se povratak


13 do 23) i korak (instrukcija 24). Telo
petlje kopira vrednost promenljive sum (sa adrese koja e biti promenjena) u
registar edx, kopira vrednost promenljive i (sa adrese esp+0x1c) u registar
eax, sabira dva registra i rezultat iz registra eax kopira nazad na adresu promenljive sum. Korak uveava vrednost promenljive i (na adresi esp+0x1c) za
adresi

esp+0x1c)

(2
01
5)

promenljiva

Ukoliko je

je

na telo petlje (instrukcije od linije

poziv funkcije

an

jedan. Po zavretku petlje, kada uslov petlje vie nije ispunjen prelazi se na

printf (instrukcije od adrese 34 do 48).

Poziv funkcije tee tako

to se na stek (u dva mesta ispod njegovog vrha) upisuju argumenti poziva (u

sum koja se kopira preko registra x),

obratnom poretku vrednost promenljive

iz

i zatim adresa format niske (iako je u trenutnom kdu za obe adrese upisana
to e biti promenjeno tokom povezivanja). Poziv

call

iznad ova 3 argume-

nata postavlja adresu povratka i prenosi kontrolu izvravanja na odgovarajuu

main

sk
o

adresu kda (koju e biti ispravno postavljena tokom povezivanja). Funkcija

49 upisuje u registar eax.


main. Instrukcija leave
skida stek okvir tako to u registar esp upisuje vrednost koja se nalazi u ebp, i
vraa povratnu vrednost tako to je u liniji

leave i ret

predstavljaju epilog funkcije

ro
n

Instrukcije

zatim restaurie vrednost poetka prethodnog stek okvira tako to je skida sa


steka (jer se pretpostavlja da je u prologu funkcije ova vrednost postavljena na
stek). Instrukcija

ret

zatim tok izvravanja prenosi na adresu povratka (koja

kt

se sada nalazi na vrhu steka).


Dakle, u fazi prevoenja se svaki poziv spoljanje funkcije i svako referisanje

le

na spoljanje promenljive i konstante ostavlja nerazreenim i od linkera se


oekuje da ovakve reference razrei. Ako se u datoteci sa ulaznim programom

poziva funkcija ili koristi promenljiva koja nije u njoj definisana (ve samo
deklarisana, kao to je sluaj sa funkcijom

printf

u prethodnom primeru),

kreiranje objektnog modula bie uspeno, ali samo od tog objektnog modula
nije mogue kreirati izvrni program (jer postoje pozivi funkcije iji mainski kd nije poznat usled nedostatka definicije ili postoje promenljive za koju
nije odvojena memorija, tako da referisanje na njih u objekntim modulima nisu
ispravna). U fazi povezivanja, linker razreava pozive funkcija i adrese promenljivih i konstanti traei u svim navedenim objektnim modulima (ukljuujui i
objektne module standardne biblioteke) odgovarajuu definiciju (maniski kd)
takve funkcije tj. definiciju (dodeljenu adresu) takve promenljive.

231

9. Organizacija izvornog i izvrnog programa

Ukoliko su svi takvi zahtevi uspeni, linker za sve pozive funkcija upisuje
adrese konkretne funkcije koje treba koristiti, za sva korienja promenljivih
ukazuje na odgovarajue konkretne promenljive i povezuje sve objektne module
u jedan izvrni program.
Kd dobijen povezivanjem obino i dalje nije u stanju da se autonomno
izvrava.

Naime, funkcije standardne biblioteke su implementirane tako da

koriste odreen broj rutina niskog nivoa, ali se sve te rutine ne ugrauju u
Umesto da se te rutine ugrauju u

(2
01
5)

izvrni kd jer bi on tako bio ogroman.

izvrni kd programa, one ine tzv. rantajm biblioteku i pozivaju se dinamiki,


tek u fazi izvravanja (videti poglavlje 9.3.1).

Pretpostavimo da je prethodno opisani objektni modul povezan na sledei

gcc -o program program.o, dajui izvrni program program. Ako se


nm), moe da se vidi da postoji znatno vie imenovanih simbola (npr. _start, printf@@GLIBC_2.0 itd.). Ako se pogleda mainski kd funkcije main (npr. komandom objdump), moe da se vidi da su sporne
adrese uspeno razreene. Meutim, na mestu poziva funkcije printf poziva se
funkcija printf@plt, a ona poziva nedefinisanu funkciju printf@@GLIBC_2.0.
nain:

an

je

on pregleda (npr. komandom

Naime, ova funkcija implementirana je u rantajm biblioteci i njena adresa bie

9.3.5

iz

povezana dinamiki, na poetku izvravanja programa.

Greke u fazi izvravanja

U fazi pisanja izvornog i generisanja izvrnog programa od izvornog nije

sk
o

mogue predvideti neke greke koje se mogu javiti u fazi izvravanja programa.
Osim to je mogue da daje pogrean rezultat (emu je najei razlog pogrean
algoritam ili njegova implementacija), mogue je i da uspeno kompiliran provanja.

ro
n

gram prouzrokuje greke tokom rada koje uzrokuju prekid njegovog izvraTe greke mogu biti posledica greke programera koji nije predvideo

neku moguu situaciju a mogu biti i greke koje zavise od okruenja u kojem

kt

se program izvrava.

Jedna od najeih greaka u fazi izvravanja je nedozvoljeni pristup memoriji. Ona se, na primer, javlja ako se pokua pristup memoriji koja nije dodel-

le

jena programu ili ako se pokua izmena memorije koja je dodeljena programu,
ali samo za itanje (engl. read only).

Operativni sistem detektuje ovakve

situacije i signalizira, to najee prouzrokuje prekid programa uz poruku

Segmentation fault
Najei uzrok nastanka ovakve greke je pristup neadekvatno alociranom bloku
memorije (npr. ako je niz definisan sa
ementu

a[1000]

int a[10];,

a pokua se pristup el-

ili se pokua pristup nealociranoj bloku memorije za koji

je predviena dinamika alokacija o emu e biti rei u glavi 10), dereferenciranje

NULL

pokazivaa (o emu e biti rei u glavi 10), ili prepunjenje

steka usled velikog broja funkcijskih poziva (nastalih najee neadekvatno

232

9. Organizacija izvornog i izvrnog programa

obraenim izlaskom iz rekurzije ili definisanjem prevelikih lokalnih automatskih


promenljivih). Odgovornost za nastanak ovakve greke obino je na progameru.
Ukoliko tokom izvravanja programa doe do (celobrojnog) deljenja nulom,
bie prijavljena greka:

Floating point exception

(2
01
5)

i program e prekinuti rad. Neposredna odgovornost za ovu greku pripada au-

toru programa jer je prevideo da moe doi do deljenja nulom i nije u programu
predvideo akciju koja to spreava.

U fazi izvravanja moe doi i do greaka u komunikaciji sa periferijama (na


primer, pokuaj itanja iz nepostojee datoteke na disku) itd.

Pitanje 9.3.1.

je

Pitanja i zadaci za vebu

Opisati ukratko memorijske segmente koji se dodeljuju svakom

an

programu koji se izvrava. ta se, tokom izvravanja programa, uva: u stek


segmentu, u hip segmentu, u segmentu podataka?

U kom segmentu memorije se tokom izvravanja programa u-

Pitanje 9.3.2.
Pitanje 9.3.3.

iz

vaju: lokalne promenljive;

Da li se memorijski prostor za neku promenljivu moe nalaziti

Pitanje 9.3.4.

sk
o

u stek segmentu?

Navesti barem tri vrste podataka koje se uvaju u svakom stek

okviru.

Pitanje 9.3.5.

ro
n

Kako se u prenose argumenti funkcija? Objasniti kako se taj

proces odvija u memoriji raunara?

Pitanje 9.3.6.
f,

Ukoliko se na steku poziva istovremeno nae vie instanci neke

kt

funkcije

kakva mora biti ta funkcija

le

Pitanje 9.3.7.

f?

Da li se za svaku instancu rekurzivne funkcije stvara novi stek

okvir? Da li se za svaku instancu rekurzivne funkcije stvara nova kopija funkcije

u kd segmentu?

Pitanje 9.3.8.

Da li se tokom izvravanja programa menja sadraj: (a) seg-

menta kda, (b) segmenta podataka, (c) stek segmenta?

Pitanje 9.3.9.

U kom segmentu memorije ima izmena prilikom pozivanja

funkcija? Ukoliko se umesto funkcija koriste makroi, da li e u tom segmentu


memorije biti izmena u fazi izvravanja?

Pitanje 9.3.10.

U kom segmentu memorije se uva izvrni mainski kd pro-

grama? U kojim segmentima memorije se uvaju podaci? Kakva je veza izmeu


ivotnog veka promenljivih i segmenata memorije u kojima se uvaju? U kom

233

9. Organizacija izvornog i izvrnog programa

segmentu memorije se uvaju automatske promenljive, u kom statike promenljive, a u kom dinamike?

Pitanje 9.3.11.

U kom segmentu memorije se uvaju argumenti funkcija i

kakav im je ivotni vek? U kom segmentu memorije se uvaju mainske instrukcije prevedenog C programa?
Za svaku promenljivu u narednom kdu rei koji joj je nivo

(2
01
5)

Pitanje 9.3.12.

dosega, kakav joj je ivotni vek u kom memorijskom segmentu je smetena i


kakva joj je inicijalna vrednost.

le

kt

ro
n

sk
o

iz

an

je

int a;
int f() {
double b; static float c;
}

(2
01
5)

Glava 10

an

je

Pokazivai i dinamika alokacija


memorije

U jeziku C, pokazivai imaju veoma znaajnu ulogu i teko je napisati iole

kompleksniji program bez upotrebe pokazivaa. Dodatne mogunosti u radu


sa pokazivaima daje dinamika alokacija memorije.

Programer, u radu sa

iz

pokazivaima, ima veliku slobodu i irok spektar mogunosti.

To otvara i

veliki prostor za efikasno programiranje ali i za greke.

sk
o

10.1 Pokazivai i adrese

Memorija raunara organizovana je u niz uzastopnih bajtova.

Uzastopni

ro
n

bajtovi mogu se tretirati kao jedinstven podatak. Na primer, dva (ili etiri, u
zavisnosti od sistema) uzastopna bajta mogu se tretirati kao jedinstven podatak
celobrojnog tipa. Pokazivai (engl. pointer) predstavljaju tip podataka u C-u

kt

ije su vrednosti memorijske adrese. Na 16-bitnim sistemima adrese zauzimaju


dva bajta, na 32-bitnim sistemima etiri, na 64-bitnim osam, i slino.

Iako

le

su, sutinski, pokazivake vrednosti (adrese) celi brojevi, pokazivaki tipovi


se razlikuju od celobrojnih i ne mogu se meati sa njima.

Jezik C razlikuje

vie pokazivakih tipova. Za svaki tip podataka (i osnovni i korisniki) postoji


odgovarajui pokazivaki tip. Pokazivai implicitno uvaju informaciju o tipu

onoga na ta ukazuju . Ipak, informacija o tipu pokazivaa (kao i za sve os-

novne tipove) ne postoji tokom izvravanja programa tu informaciju iskoristi


kompilator tokom kompilacije da u mainskom kdu generie instrukcije koje
odgovaraju konkretnim tipovima. Dakle, tokom izvravanja programa, pokazivaka promenljiva zauzima samo onoliko bajtova koliko zauzima podatak o
adresi.

1 Jedino

pokaziva tipa

void*

nema informaciju o tipu podataka na koji ukazuje, i o tom

tipu e biti rei u nastavku.

234

235

10. Pokazivai i dinamika alokacija memorije

Tip pokazivaa koji ukazuje na podatak tipa


vai i za druge tipove.

int

zapisuje se

int *.

Slino

Prilikom deklaracije, nije bitno da li postoji razmak

izmeu zvezdice i tipa ili zvezdice i identifikatora i kako god da je napisano,


zvezdica se vezuje uz identifikator. U narednom primeru,
vai koji ukazuju na

int

dok je

p4

tipa

int:

(2
01
5)

int *p1;
int* p2;
int* p3, p4;

p1, p2 i p3 su pokazi-

Pokazivaka promenljiva moe da sadri adrese promenljivih ili elemenata

2 i za to se koristi operator &. Unarni operator &, operator referenciranja ili

niza

adresni operator vraa adresu svog operanda. On moe biti primenjen samo na

promenljive i elemente niza, a ne i na izraze ili konstante. Na primer, ukoliko

int a=10, *p;


p = &a;

an

je

je naredni kd deo neke funkcije

a i p rezervie prostor
10, a u prostor za p
da pokazuje na a.

onda se prilikom izvravanja te funkcije, za promenljive

Unarni operator

se upisuje vrednost

a. Za promenljivu p tada kaemo


* (koji zovemo operator dereferenciranja 3 ) se primenjuje

iz

adresa promenljive

u njenom stek okviru. U prostor za

sk
o

na pokazivaku promenljivu i vraa sadraj lokacije na koju ta promenljiva


pokazuje, vodei rauna o tipu. Dereferencirani pokaziva moe biti l-vrednost
i u tom sluaju izmene dereferenciranog pokazivaa utiu neposredno na prostor

ro
n

na koji se ukazuje. Na primer, nakon kda

kt

int a=10, *p;


p = &a;
*p = 5;
promenljiva

p ukazuje na a, a u lokaciju na koju ukazuje p je upisana vrednost


a postala jednaka 5.

Time je i vrednost promenljive

le

5.

Dereferencirani pokaziva nekog tipa, moe se pojaviti u bilo kom kontekstu

u kojem se moe pojaviti podatak tog tipa.


ispravna bi bila i naredba

*p = *p+a+3;.

Na primer, u datom primeru

Kao to je ve reeno, pokazivaki i celobrojni tipovi su razliiti.

Tako

int *pa, a;, naredni kd neispravan:


pa = a;. Takoe, neispravno je i a = pa;, kao i pa = 1234. Mogue je koristiti eksplicitne konverzije (na primer a = (int)pa; ili pa = (int*)a;), ali
je, na primer, ako je data deklaracija

ove mogunosti treba veoma oprezno koristiti i iskljuivo sa jasnim ciljem (koji

2 Postoje

i pokazivai na funkcije i u tom sluaju pokazivaka promenljiva ukazuje na

adresu funkcije u segmentu koda, u emu e vie rei biti u poglavlju 10.8.

3 Simbol *

koristi se i za oznaavanje pokazivakih tipova i za operator dereferenciranja i

treba razlikovati ove njegove dve razliite uloge.

236

10. Pokazivai i dinamika alokacija memorije

ne moe da se pogodno ostvari drugaije). Jedina celobrojna vrednost koja se


moe koristiti i kao pokazivaka vrednost je vrednost

mogue je dodeliti

nulu pokazivakoj promenljivoj i porediti pokaziva sa nulom. Uvek se podrazu-

0 ne moe da pokazuje ni na ta smisleno


0 nije mogue

meva da pokaziva koji ima vrednost


(tj. adresa

0 ne smatra se moguom).

Pokaziva koji ima vrednost

dereferencirati, tj. pokuaj dereferenciranja dovodi do greke tokom izvravanja

0 obino
<stdio.h>, kao

se ko-

risti simbolika konstanta

jasniji

NULL,

definisana u zaglavlju

(2
01
5)

programa (najee segmentation fault). Umesto konstante


pokazatelj da je u pitanju specijalna pokazivaka vrednost.

Pokazivai se mogu eksplicitno (pa ak i implicitno) konvertovati iz jednog


u drugi pokazivaki tip.

int a; char* p = &a;,


zorenje.

Na primer

int a; char* p = (char*)&a;

ili ak

pri emu prevoenjem drugog kda dobijamo upo-

Meutim, prilikom konverzije pokazivaa vri se samo prosta do-

dela adrese, bez ikakve konverzije podataka na koje pokaziva ukazuje, to

je

esto moe dovesti do neeljenih efekata, te stoga ovakve konverzije pokazivaa


neemo esto koristiti. Konverzije izmeu pokazivaa na podatke i pokazivaa
do nedefinisanog ponaanja programa).

an

na funkcije (o kojima e vie biti rei u poglavlju 10.8) nisu doputene (dovode
U nekim sluajevima, poeljno je imati mogunost opteg pokazivaa,

void*.

Za to

Izraze ovog tipa je mogue eksplicitno konvertovati u

iz

se koristi tip

tj. pokazivaa koji moe da ukazuje na promenljive razliitih tipova.

bilo koji konkretni pokazivaki tip, a i ukoliko je potrebno, a nije upotrebljena


eksplicitna konverzija bie primenjena implicitna konverzija prilikom dodele.

sk
o

Naravno, nije mogue vriti dereferenciranje pokazivaa tipa

void*

jer nije

mogue odrediti tip takvog izraza kao ni broj bajtova u memoriji koji predstavljaju njegovu vrednost.

Pre dereferenciranja, neophodno je konvertovati

ro
n

vrednost ovog pokazivakog tipa u neki konkretan pokazivaki tip.


za razliku od ostalih pokazivakih tipova, nad pokazavaima tipa

Takoe,

void*

nije

mogue vriti aritmetike operacije (o kojima e vie rei biti u poglavlju 10.4).

const. Tako const int* p


int, int *const p oznaava konstantni pokaziva na promenljivu tipa int, dok const int *const p
oznaava konstantni pokaziva na konstantnu promenljivu tipa int. U prvom
I na pokazivae se moe primeniti kljuna re

le

kt

oznaava pokaziva na konstantnu promenljivu tipa

sluaju mogue je menjati pokaziva, ali ne i ono na ta on pokazuje, u dru-

gom je mogue menjati ono na ta ukazuje pokaziva, ali ne i sam pokaziva,


dok u treem sluaju nije mogue menjati ni jedno ni drugo. Trik koji pomae u razumevanju ovakvih deklaracija je da se tip ita unatrag.

Tako bi

prva deklaracija oznaavala pokaziva na int koji je konstantan (konstantan


je

int,

a ne pokaziva), druga konstantni pokaziva na int (konstantan je

pokaziva, a ne

int),

a trea konstantni pokaziva na

int

koji je konstantan

(konstantna su oba).
Vrednost pokazivaa moe se dodeliti pokazivau istog tipa.
vrednost pokazivaa

dodeli pokazivau

Ukoliko se

nee na adresu na koju ukazuje

p, nego e samo promenljiva q dobiti


p i obe e ukazivati na prostor na koji je pre toga ukazivao

biti iskopiran sadraj na koji ukazuje

vrednost promenljive

q,

237

10. Pokazivai i dinamika alokacija memorije

pokaziva

p.

Taj nain kopiranja nekada se naziva plitko kopiranje. Nasuprot

njemu, duboko kopiranje podrazumeva da se napravi kopija sadraja koji nalazi


na adresi na koju pokaziva pokazuje, a da se pokaziva

usmeri ka kopiji tog

sadraja (slika 10.1). Plitko kopiranje je est uzrok greaka jer nakon plitkog
kopiranja oba pokazivaa ukazuju isti sadraj i izmenom sadraja preko jednog
pokazivaa, moda neoekivano, biva izmenjen sadraj na koji ukazuje i drugi

originalni pokaziva

(2
01
5)

pokaziva.

sadraj

originalni pokaziva

sadraj

novi pokaziva

kopija sadraja

an

je

kopija pokazivaa

Slika 10.1: Ilustracija plitkog i dubokog kopiranja

Korienjem pokazivaa mogue je stei uvid u nain smetanja promenlji-

iz

vih u memoriju raunara. esto se zahteva da podaci u memoriji budu porav-

nati (engl. aligned), to znai, na primer, da svaki podatak koji zauzima etiri
bajta u memoriji mora poinjati na memorijskoj adresi koja je deljiva sa etiri

sk
o

(ovo je u vezi sa nainom na koji savremeni procesori preuzimaju podatke iz


memorije, jer se ne prebacuju pojedinani bajtovi ve ire binarne rei). Poravnanje dodatno moe da otea konverzije pokazivaa (npr. tip

char*

char zauzima

moe da ukae na bilo koju adresu, pa njegova ek-

ro
n

uvek jedan bajt i

int* moe dovesti do problema na sistemu gde se, na


int* moraju biti
deljive sa etiri, dok vrednosti char* ne moraju).
Primetimo da se u primeru int a=10, *p=&a; sadraju iste memorijske
lokacije moe pristupiti na dva razliita naina (i preko promenljive a i preko
dereferenciranja pokazivaa *p). Ta pojava se naziva alijasovanje (preklapanje)
(engl. aliasing). U primeru, *p predstavlja alijas (drugo ime) promenljive a i

splicitna konverzija u tip

int

poravnava na etiri bajta jer tada vrednosti

le

kt

primer, tip

sadraji te dve promenljive su isti. Programi u kojima se alijasovanje intenzivno


koristi mogu biti tei za analizu i debagovanje, pa bi ovo svojstvo programskog
jezika trebalo koristiti oprezno. Alijasovanje oteava optimizaciju koda tokom
kompilacije i stoga standardi jezika C uvode odreena ogranienja na tip alijasovanja koji je doputen. Na primer, jedno od pravila striktnog alijasovanja
(engl. strict aliasing rule) je da se ne doputa da dva pokazivaa razliitog tipa
ukazuju na isti sadraj (pokazivaki tipovi koji se razlikuju samo po nekom
od kvalifikatora
i

void*

const, signed, unsigned

se ne smatraju razliiti, dok

char*

i u odreenoj meri pokazivai na strukture ili unije ine odreene

izuzetke od ovog pravila). Pod tim pravilom kompilator pretpostavlja da e se


dereferenciranjem pokazivaa razliitih tipova dobiti memorijski sadraji koji

238

10. Pokazivai i dinamika alokacija memorije

se ne preklapaju (koji nisu alijasovani), to mu daje mogunost da agresivnije


vri neke optimizacije koda.

Konverzija pokazivaa u neki drugi pokazivaki

tip i njegovo dereferenciranje dovode do naruavanja ovog pravila striktnog


alijasovanja. Na primer, prilikom kompilacije pomou

gcc -Wall -O2

dobija

se upozorenje da naredni kd kojim se pokuava ispisati heksadekadni sadraj


promenljive tipa

float

(ime bi se odredio njegov binarni memorijski zapis)

(2
01
5)

naruava pravila striktnog alijasovanja.

float f = 3.5f;
printf("%x\n", *( ( unsigned* )&f ));

Pravi nain da se ovaj zadatak rei je korienje unije, koja vri alijasovanje

promenljivih, ali na standardom doputeni nain jer kompilator prilikom or-

ganizovanja unije vodi rauna o pitanjima koja mogu naruiti ispravnost rada

an

union { float x; unsigned y } u;


u.x = 3.5f;
printf("%x", u.y);

je

programa (na primer, vodi se rauna o poravnanju elemenata unije).

iz

ro
n

sk
o

int a;
void f(double *p) {
a = 1;
*p = 1.234;
g(a);
}

I sledei primer ilustruje pravila striktnog alijasovanja.

Pod pravilima striktnog alijasovanja, moe se pretpostaviti da se izmenom vred-

kt

nosti *p u prethodnom kdu ne vri posredno izmena promenljive i (jer su *p i


a drugog tipa i ne mogu biti alijasovani i preklopljeni u memoriji). Zato se moe
izvriti optimizacija koda koja pretpostavlja da se funkciji g uvek alje vrednost
1. Ako bi neko pokuao poziv f((double*)&a) koji bi doveo do alijasovanja

le

ova dva objekta, iako je sintaksno ovakva konverzija pokazivaa doputena,

kompilator bi ga upozorio da time naruava pravila striktnog alijasovanja i


da takav poziv moe naruiti ispravnost koda u svetlu pomenute optimizacije.
Pre uvoenja pravila striktnog alijasovanja, kompilatori su veoma restriktivno
vrili optimizaciju koda, dok pravila striktnog alijasovanja daju mogunosti
mnogo veih optimizacija i dovode do znatno breg koda (koji je ispravan ako
programer potuje pravila striktnog alijasovanja).

Pitanja i zadaci za vebu


Pitanje 10.1.1.

Koje su informacije pridruene pokazivau?

Koje od ovih

informacija se u fazi izvravanja uvaju u memoriji dodeljenoj pokazivakoj


promenljivoj?

239

10. Pokazivai i dinamika alokacija memorije

Pitanje 10.1.2.

Koliko bajtova zauzima podatak tipa

bajtova zauzima podatak tipa

Pitanje 10.1.3.

unsigned char*?

unsigned char?

Ako je veliina koju zauzima element nekog tipa

koliko onda bajtova zauzima pokaziva na vrednost tipa

t:

Koliko

8 bajtova,

(a) 4; (b) 8; (c) 16;

(d) zavisi od sistema?

double *

Ako je promenljiva tipa

na konkretnom sistemu

(2
01
5)

Pitanje 10.1.4.

zauzima 4 bajta, koliko bajtova na istom sistemu zauzima promenljiva tipa

unsigned char *?

Pitanje 10.1.5.

Na ta se moe primeniti operator referenciranja? Na ta se

moe primeniti operator dereferenciranja? Kako se oznaavaju ovi operatori?


ta je njihovo dejstvo? Kakav im je prioritet?

Pitanje 10.1.6.

Ako je promenljiva p pokazivakog tipa, da li je dozvoljeno


&p? Da li se umesto vrednosti p moe pisati i *(&p)? Da li se
vrednosti p moe pisati i &(*p)?

an

umesto

je

koristiti izraz

Pitanje 10.1.7.

Kako se oznaava generiki pokazivaki tip?

Za ta se on

koristi? Da li se pokaziva ovog tipa moe referencirati? Zato?

Pitanje 10.1.8.

sk
o

celobrojna vrednost?

Pitanje 10.1.9.

Kog tipa je promenljiva a, a kog tipa promenljiva b nakon


short* a, b;? Koju vrednost ima promenljiva b nakon izvravanja
b = 2; a = &b; *a = 3; b++;?

deklaracije

ro
n

naredbi

int*, da li joj se moe dodeliti celodouble*, da li joj se moe dodeliti

iz

Ako je promenjliva tipa

brojna vrednost? Ako je promenjliva tipa

10.2 Pokazivai i argumenti funkcija


4

kt

U jeziku C argumenti funkcija se uvek prenose po vrednosti . To znai da


promenljiva koja je upotrebljena kao argument funkcije ostaje nepromenjena

le

nakon poziva funkcije. Na primer, ako je definisana sledea funkcija

void swap(int a, int b) {


int tmp = a;
a = b;
b = tmp;
}

i ukoliko je ona pozvana iz neke druge funkcije na sledei nain:


(pri emu su

4 Kao

promenljive tipa

int),

swap(x, y)
swap,

onda se kreira stek okvir za

to je reeno, u sluaju nizova, po vrednosti se ne prenosi itav niz, ve samo adresa

njegovog poetka.

240

10. Pokazivai i dinamika alokacija memorije

obezbeuje se prostor za argumente

a i b, vrednosti x i y se kopiraju u taj pros-

tor i funkcija se izvrava koristei samo te kopije. Nakon povratka iz funkcije,


vrednosti

xiy

ostaju nepromenjene.

Ukoliko se eli da funkcija

swap zaista zameni vrednosti argumentima, onda

void swap(int *pa, int *pb) {


int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
Zbog drugaijeg tipa argumenata, funkcija

swap

vie ne moe biti pozvana

int, ve su
int*. Zato se kao argumenti ne mogu koristiti vrednosti x i y
ve njihove adrese &x i &y. Nakon poziva swap(&x, &y), kreira se stek okvir
za swap, obezbeuje se prostor za argumente pokazivakog tipa pa i pb i zatim
se vrednosti &x i &y kopiraju u taj prostor. Time se prenos argumenata vri po

na isti nain kao ranije

swap(x, y).

(2
01
5)

ona mora biti definisana drugaije:

Njeni argumenti nisu tipa

an

je

pokazivakog tipa

vrednosti, kao i uvek. Funkcija se izvrava koristei samo kopije pokazivaa,

ali zahvaljujui njima ona zaista pristupa promenljivama

iz

vrednosti. Nakon povratka iz funkcije, vrednosti

xiy

xiy

i razmenjuje im

su razmenjene. Na ovaj

nain, prenoenjem adrese promenljive, mogue je njeno menjanje u okviru


funkcije. Isti taj mehanizam koristi se i u funkciji

scanf

koja je ve koriena.

sk
o

Prenos pokazivaa moe da se iskoristi i da funkcija vrati vie razliitih


vrednosti (preko argumenata). Na primer, naredna funkcija rauna kolinik i
ostatak pri deljenju dva cela broja (ne koristei pritom operatore

ro
n

Program 10.1.

#include <stdio.h>

le

kt

void deljenje(unsigned a, unsigned b,


unsigned* pk, unsigned* po) {
*pk = 0; *po = a;
while (*po >= b) {
(*pk)++;
*po -= b;
}
}
int main() {
unsigned k, o;
deljenje(14, 3, &k, &o);
printf("%d %d\n", k, o);
return 0;
}

/ i %):

241

10. Pokazivai i dinamika alokacija memorije

Pitanja i zadaci za vebu


Pitanje 10.2.1.

Kako se prenose argumenti pokazivakog tipa? ta to znai?

Objasniti na primeru.

Pitanje 10.2.2.

ta ispisuje naredni program?

int a = 1, b = 2;
void f(int* p) {
p = &b;
}
int main() {
int *p = &a
f(p);
printf("%d\n", *p);
}

2.

#include<stdio.h>
void f(int* p) { p++; p += 2; p--; p = p + 1; }

an

je

(2
01
5)

1.

Pitanje 10.2.3.

sk
o

iz

int main() {
int a[] = {1, 2, 3, 4, 5}, *p = a, *q = a;
f(p); printf("%d\n", *p);
q++; q += 2; q--; q = q + 1; printf("%d\n", *q);
}
Ukoliko je potrebno da funkcija vrati vie od jedne vrednosti,

ro
n

kako se to moe postii?

Pitanje 10.2.4.

f sa povratnim tipom void koja ima


int i vraa ga udvostruenog.
funkciju f sa povratnim tipom void koja ima tano jedan
Napisati funkciju

samo

jedan argument tipa

kt

Napisati

argu-

ment, a koja prosleenu celobrojnu vrednost vraa sa promenjenim znakom.

le

Napisati funkciju sa tipom povratne vrednosti

void

koja slui za izrauna-

vanje zbira i razlike svoja prva dva argumenta.

Zadatak 10.2.1.

Napisati funkciju koja za uneti broj sekundi (0

< 86400)

proteklih od prethodne ponoi izraunava trenutno vreme tj. broj sati, minuta i

sekundi.

10.3 Pokazivai i nizovi


Postoji vrsta veza izmeu pokazivaa i nizova.

Operacije nad nizovima

mogu se iskazati i u terminima korienja pokazivaa i u daljem tekstu esto


neemo praviti razliku izmeu dva naina za pristupanje elementima niza.
Deklaracija

sizeof(a)

int a[10];

deklarie niz od 10 elemenata tipa

imae istu vrednost kao izraz

10*sizeof(int).

int.

Izraz

Poetni element

242

10. Pokazivai i dinamika alokacija memorije

niza je

a[0],

a[9] i oni su u memoriji poreani uzastopno.


a pridruena je informacija o adresi poetnog

a deseti element je

U fazi kompilacije, imenu niza

elementa niza, o tipu elemenata niza, kao i o broju elemenata niza. Poslednje
dve informacije koriste se samo tokom kompilacije i ne zauzimaju memorijski
prostor u fazi izvravanja.
Za razliku od pokazivaa koji jesu l-vrednosti, imena nizova (u navedenom

a uvek ukazuje na isti prostor koji je rezervisan za


a nije pokazivakog tipa, ali mu je vrlo bliska. Izuzev
u sluaju kada je u pitanju argument operatora sizeof ili operatora &, ime niza
tipa T konvertuje se u pokaziva na T. Dakle, ime jednodimenzionog niza (na
primer, a za deklaraciju int a[10]) bie, sem ako je navedeno kao argument
sizeof ili & operatora, implicitno konvertovano u pokaziva (tipa int*) na prvi
element niza. Vrednosti a odgovara pokaziva na prvi element niza, vrednosti
a+1 odgovara pokaziva na drugi element niza, itd. Dakle, umesto &a[i] moe
se pisati a+i, a umesto a[i] moe se pisati *(a+i) (o tim izrazima se koristi
primeru ime

a)

to nisu (jer

je

(2
01
5)

elemente niza). Vrednost

tzv. pokazivaka aritmetika o kojoj e biti rei u narednom poglavlju). Naravno,


fazu prevoenja) i
samo 10.

an

kao i obino, nema provere granica niza, pa je dozvoljeno pisati (tj. prolazi

a[100], *(a+100), a[-100], *(a-100), iako je veliina niza

U fazi izvravanja, pristupanje ovim lokacijama moe da promeni

vrednost podataka koji se nalaze na tim lokacijama ili da dovede do prekida

iz

rada programa zbog pristupanja memoriji koja mu nije dodeljena.


Kao to se elementima niza moe pristupati korienjem pokazivake aritmetike, ako je

pokaziva nekog tipa (npr.

int* p)
p[3]).

sk
o

menjen nizovski indeksni pristup (na primer,

na njega moe biti priVrednost takvog izraza

odreuje se tako da se poklapa sa odgovarajuim elementom niza koji bi poinjao na adresi

p nije niz nego pokaziva). Na primer, ako bi


sizeof(int) jednako 4 pokaziva p ukazivao na adresu
niz celih brojeva, tada bi p[3] bio ceo broj koji se nalazi
poevi adrese 112. Isti broj bio bi dobijen i izrazom

(bez obzira to

100

ro
n

na sistemu na kojem je
na kojoj poinje

smeten u memoriji

*(p+3)

u kome se koristi pokazivaka aritmetika.

tj.

kt

Dakle, bez obzira da li je

x+n

isto je to i

&x[n].

pokaziva ili niz,

x[n]

isto je to i

*(x+n),

Ovako tesna veza pokazivaa i nizova daje puno

le

prednosti (na primer, iako funkcije ne primaju niz ve samo pokaziva na prvi
element, implementacija tih funkcija moe to da zanemari i sve vreme da koristi

indeksni pristup kao da je u pitanju niz, a ne pokaziva, to je korieno u


ranijim poglavljima). Meutim, ovo je i est izvor greaka, najee prilikom
alokacije memorije. Na primer,

int a[10];
int *b;
a[3] = 5; b[3] = 8;
a je ispravno deklarisan i mogue je pristupiti njegovom elementu na poziciji
b nije izvrena alokacija elemenata na koje se
pokazuje i, iako se pristup b[3] ispravno prevodi, on bi najverovatnije doveo do
niz

3,

dok u sluaju pokazivaa

243

10. Pokazivai i dinamika alokacija memorije

greke prilikom izvravanja programa. Zato, svaki put kada se koristi operator
indeksnog pristupa, potrebno je osigurati ili proveriti da je memorija alocirana
na odgovarajui nain (jer kompilator ne vri takve provere).
Kao to je reeno, izraz

int [10]

ima vrednost adrese poetnog elementa i tip

koji se, po potrebi, moe konvertovati u

a,

vrednost (tj. sadri istu adresu) kao i

int *.

c:

narednom primeru promenljiva

int a[10];
int *b[10];
int (*c)[10];
U navedenom primeru, promenljiva
ima 10 bajtova. Promenljiva

je niz

int.

Taj tip ima u

(2
01
5)

to je tip pokazivaa na niz od 10 elemenata koji su tipa

&a ima istu


int (*)[10]

Izraz

ali drugaiji tip tip

je niz od 10 elemenata tipa

10

pokazivaa na

char

char

i zauz-

i zauzima prostor

je

c je (jedan) pokaziva na
10 elemenata tipa char i zauzima onoliko prostora koliko i bilo koji drugi
pokaziva. Vrednost se promenljivoj c moe pridruiti, na primer, naredbom
c=&a;. Tada je (*c)[0] isto to i a[0]. Ukoliko je promenljiva c deklarisana, na primer, sa char (*c)[5];, u dodeli c=&a; e biti izvrena implicitna

potreban za smetanje 10 pokazivaa. Promenljiva

an

niz od

iz

konverzija i ova naredba e proi kompilaciju (uz upozorenje da je izvrena


konverzija neusaglaenih tipova), ali to bi trebalo izbegavati.
Kao to je reeno u poglavlju 8.4, niz se ne moe preneti kao argument

sk
o

funkcije. Umesto toga, kao argument funkcije se moe navesti ime niza i time
se prenosi samo pokaziva koji ukazuje na poetak niza. Funkcija koja prihvata
takav argument za njegov tip moe da ima

char a[]

ili

char *a.

Ovim se u

ro
n

funkciju kao argument prenosi (kao i uvek po vrednosti) samo adresa poetka
niza, ali ne i informacija o duini niza.
Kako se kao argument nikada ne prenosi itav niz, ve samo adresa poetka,
mogue je umesto adrese poetka proslediti i pokaziva na bilo koji element

kt

niza, kao i bilo koji drugi pokaziva odgovarajueg tipa. Na primer, ukoliko je

f ima prototip int f(int x[]); (ili ekvivalentno


int f(int *x);), onda se funkcija moe pozivati i za poetak niza (sa
f(a)) ili za pokaziva na neki drugi element niza (na primer, f(&a[2]) ili
ekvivalentno f(a+2)). Naravno, ni u jednom od ovih sluajeva funkcija f
ime niza i ako funkcija

le

nema informaciju o tome koliko elemenata niza ima nakon prosleene adrese.

Pitanja i zadaci za vebu


Pitanje 10.3.1.

Ako je u okviru funkcije deklarisan niz sa

koji deo memorije ukazuje

Pitanje 10.3.2.
a?

a+9?

Ako je niz deklarisan sa

ta je vrednost izraza

a + 3?

int a[10];,

ta je vrednost izraza

char a[10];

na

ta je vrednost izraza

*(a+3)?

244

10. Pokazivai i dinamika alokacija memorije

Pitanje 10.3.3.

Da li se komanda

(odgovoriti za svaku pojedinano) (a)

ip = *a[0]?

Pitanje 10.3.4.

a[i] ista to i (odgovoriti


*(a+i); (d) &(a+i)?

za svaku pojedi-

Ukoliko je niz deklarisan na sledei nain:

float* x[10],

Da li je vrednost

a[0]+i;

nano) (a)

Pitanje 10.3.5.

(b)

a+i;

(c)

kako se moe dobiti adresa drugog elementa niza?

Pitanje 10.3.6.
tipa

int*.

a deklarisan sa int a[10], i neka je p pokaziva


a = p; ispravna? Da li je naredba p = a; ispravna?
sizeof(p) nakon naredbe p = a;, ako int* zauzima

Neka je niz

Da li je naredba

Koja je vrednost izraza


etiri bajta?

Pitanje 10.3.7.

int a[10];. Da li je a+3 ispravan izraz?


a[3], &a[3], *a[3] ili a[10]? Da li je
vrednost ista kao i vrednost a[3], a[10],

Niz je deklarisan sa

an

Pitanje 10.3.8.

Da li mu je

je

Da li mu je vrednost ista kao i vrednost

*(a+3) ispravan izraz?


*a[3] ili *a[10]?

(2
01
5)

(d)

ip = &a[0] moe zameniti komandom


ip = a[0]; (b) ip = a; (c) ip = *a;

ta ispisuje naredni kd:

*d = b + 2; *c = d[-1];

iz

int a = 3, b[] = {8, 6, 4, 2}, *c = &a,


printf("%d\n", a);

sk
o

int a[] = {7, 8, 9}; int *p; p = a;


printf("%d %d\n", *(p+2), sizeof(p));

Pitanje 10.3.9.

Ako je kao argument funkcije navedeno ime niza, ta se sve

ro
n

prenosi u funkciju: (i) adresa poetka niza; (ii) elementi niza; (iii) podatak o
broju elemenata niza; (iv) adresa kraja niza?

kt

Pitanje 10.3.10.

int f(char s[])?


void f(char *x); i void f(char x[]);?
deklaracija char* x; i char x[];? Da li su obe is-

Koji prototip je ekvivalentan prototipu

Da li ima razlike izmeu prototipova


Da li ima razlike izmeu

le

pravne?

10.4 Pokazivaka aritmetika


int a[10];, vreda odgovara pokaziva na prvi element niza, vrednosti a+1 odgovara pokazina drugi element niza, itd. Izraz p+1 i slini ukljuuju izraunavanje koje

U prethodnom poglavlju je reeno da nakon deklaracije


nosti
va

koristi pokazivaku aritmetiku i koje se razlikuje od obinog izraunavanja.


Naime, izraz

p+1 ne oznaava dodavanje vrednosti 1 na p, ve dodavanje duine


p. Na primer, ako p ukazuje na int, onda

jednog objekta tipa na koji ukazuje

p+1

mogu da se razlikuju za dva ili etiri za onoliko koliko bajtova

na tom sistemu zauzima podatak tipa


za

sizeof(int)

bajtova).

int

(tj. vrednosti

Na primer, ako je

p+1

pokaziva na

p se razlikuju
int koji sadri

245

10. Pokazivai i dinamika alokacija memorije

adresu
adresa

100, na sistemu na kojem int zauzima 4 bajta,


100 + 3 4 = 112. Analogno vai za druge tipove.

vrednost

p+3

e biti

p-n), pri emu

Od pokazivaa je mogue oduzimati cele brojeve (na primer,

je znaenje ovih izraza analogno znaenju u sluaju sabiranja. Na pokazivae


je mogue primenjivati prefiksne i postfiksne operatore
semantikom.

Dva pokazivaa je mogue oduzimati.

++

--,

sa slinom

I u tom sluaju se ne

vri prosto oduzimanje dve adrese, ve se razmatra veliina tipa pokazivaa, sa

(2
01
5)

kojom se razlika deli. Dva pokazivaa nije mogue sabirati.

Pored dereferenciranja, dodavanja i oduzimanja celih brojeva, i oduzimanja


pokazivaa, nad pokazivaima se (samo ako su istog tipa) mogu primenjivati i
relacijski operatori (na primer,
tano akko

p1

memorije) niza od pokazivaa


Unarni operatori
tori.

p1 < p2, p1 == p2,

&i*

p2.

imaju vii prioritet nego binarni aritmetiki opera-

Zato je znaenje izraza

*p+1

vrednosti 1 (a ne sadraj na adresi

zbir sadraja lokacije na koju ukazuje

p+1).

Unarni operatori

Postfiksni operator

an

p.

&, *,

i prefiksni

pi
++

++*p; inkrementira sadraj lokacije


++, kao i svi unarni operatori koji se

se primenjuju zdesna nalevo, pa naredba


na koju ukazuje

. . . ). Tako je, na primer,

ukazuje na raniji element (u smislu linearno ureene

je

p1 < p2

primenjuju sleva na desno, imaju vii prioritet od unarnih operatora koji se priinkrementira.

*p++

vraa sadraj na lokaciji

p,

dok se kao boni

iz

menjuju zdesna nalevo, pa


efekat

Vezu pokazivaa i nizova i pokazivaku aritmetiku ilustruje naredni jednos-

Program 10.2.

sk
o

tavni primer.

kt

ro
n

#include <stdio.h>
int main() {
int a[] = {8, 7, 6, 5, 4, 3, 2, 1};
int *p1, *p2, *p3;
/* Ispis elemenata niza */
printf("%d %d %d\n", a[0], a[3], a[5]);

le

/* Inicijalizacija pokazivaca ime niza se konvertuje u pokazivac */


p1 = a; p2 = &a[3]; p3 = a + 5;
printf("%d %d %d\n", *p1, *p2, *p3);
/* Pokazivaci se koristi u nizovskoj sintaksi */
printf("%d %d %d\n", p1[1], p2[2], p3[-1]);
/* Pokazivacka aritmetika */
p1++; --p2; p3 += 2; /* a++ nije dozvoljeno */
printf("%d %d %d %lu\n", *p1, *p2, *p3, p3 - p1);
/* Odnos izmedju prioriteta * i ++ */

246

10. Pokazivai i dinamika alokacija memorije

*p1++; printf("%d ", *p1);


*(p1++); printf("%d ", *p1);
(*p1)++; printf("%d\n", *p1);
return 0;

8
8
7
7
6

5
5
3
6
5

3
3
4
1 6
6

(2
01
5)

Ako je

p += 5;?

Pitanje 10.4.2.

int*,

Ako su promenljive

zlikovati vrednosti

ta je efekat naredbe

nakon komande

*p += 5;

q tipa double *, za
p = q+n (pri emu

a ta

koliko e se raje

celobrojna

iz

promenljiva)?

Pitanje 10.4.3.

tipa

efekat naredbe

an

Pitanje 10.4.1.

je

Pitanja i zadaci za vebu

p tipa double *, za koliko e se promeniti


++*p;? (b) nakon komande ++(*p);? (c)
nakon komande *p++;? (d) nakon komande (*p)++;?
Da li postoji razlika izmeu komandi (*p)++ i *(p++)?
Ako je promenljiva

Koje binarne operacije su dozvoljene nad vrednostima istog

ro
n

Pitanje 10.4.4.

sk
o

njena vrednost (a) nakon komande

pokazivakog tipa (npr. nad promenljivima

Pitanje 10.4.5.

p1 i p2

kt

tipa

int*)?

Koje binarne aritmetike operacije se mogu primeniti nad

pokazivaem i celim brojem (npr. nad promenljivom

tipa

int)?

p tipa int* i promenljivom

Pitanje 10.4.6.

Ako su p1, p2 pokazivai istog tipa, da li postoji razlika izmeu


(p1-p2)+d i p1-(p2-d) ? Kog su tipa navedene vrednosti?

le
E

vrednosti:

Pitanje 10.4.7.

Ako su

konstrucija ispravna:

p=NULL;
p1=p1+10;
(7) p1=(p1-p1)+0;
(10) p1=p1-(p2+10);
(13) p1=p1+(p2-p3);
(16) p1=p1+(p2+p3);
(1)

(4)

Pitanje 10.4.8.

p1, p2, p3

pokazivai istog tipa, da li je naredna

p=10;
p1=(p1+p1)+0;
(8) p1=(p1-p1)+10;
(11) p1=p1+(p1-p2);
(14) p1=(p1+p2)-p3;
(2)

(5)

p1=p1+0;
p1=(p1+p1)+10;
(9) p1=(p1-p2)+10;
(12) p1=p1-(p1-p2);
(15) p1=(p1+p2)+p3;
(3)

(6)

247

10. Pokazivai i dinamika alokacija memorije

1. Za koliko bajtova se menja vrednost pokazivaa

p += 2;?

2. Ako je

tipa

float*,

p tipa int * nakon naredbe

za koliko se razlikuju vrednosti

3. Za koliko bajtova se menja vrednost pokazivaa

4. Ako je

pokaziva tipa

T,

p += 2;?

emu je jednako

Pitanje 10.4.10.

b nakon
a+b i a-b?

Da li nakon

Da li su

int* a, b;?

Da li su

10.5 Pokazivai i niske

(b)

int *x, *y;?

deklaracije

iz

*(p++);

neki

int n[] = {1, 2, 3, 4, 5}; int* p = n;,


n, vrednost pokazivaa p, ili ni jedno ni
(*p)++; (c) *p++;?

sledee naredbe menjaju sadraj niza


drugo ili oba: (a)

deklaracije

a kog tipa

dozvoljene operacije

an

a,

2. Kog je tipa

y nakon
x+y i x-y?

a kog tipa

(gde je

je

x,

dozvoljene operacije

T *

p + 3?

Pitanje 10.4.9.
1. Kog je tipa

tipa

(2
01
5)

konkretan tip), nakon naredbe

p+5 i p?

Doslovne tj. konstantne niske (engl. string literal), na primer

"informatika",

sk
o

u memoriji su realizovane slino kao nizovi karaktera: karakteri su poreani redom na uzastopnim memorijskim lokacijama i iza njih se nalazi zavrna nula
(\0) koja oznaava kraj niske. Konstantne niske se u memoriji uvek uvaju
u segmentu podataka.

Kada se u pozivu funkcije navede konstantna niska

printf("%d", x);),

ro
n

(na primer, u pozivu

funkcija umesto niske prihvata kao

argument zapravo adresu poetka konstantne niske u segmentu podataka.


Razmotrimo, kao primer, deklaraciju

char *p = "informatika";.

Uko-

kt

liko je takva deklaracija navedena u okviru neke funkcije, onda se u njenom stek

p ali ne i za nisku "informatika"


p ukazuje na nju. Situacija je slina
char *p = "informatika"; spoljanja

okviru rezervie prostor samo za promenljivu

le

ona se uva u segmentu podataka i

ako je deklaracija sa inicijalizacijom

(tj. globalna): promenljiva


nisku

"informatika"

oba sluaja, promenljiva


jednako

i, p[1]

e se uvati u segmentu podataka i ukazivati na

koja se uva negde drugde u segmentu podataka. U

ukazuje na poetak niske

je jednako

lokacije na koji ukazuje

"informatika" i p[0]

je

i tako dalje. Pokuaj da se promeni sadraj

(na primer,

p[0]=x;

p[1]=x;)

ili

prolazi fazu

prevoenja, ali u fazi izvravanja dovodi do nedefinisanog ponaanja (najee


do greke u fazi izvravanja i prekida izvravanja programa). S druge strane,
promena vrednosti samog pokazivaa
dozvoljena. Dakle,

p++;) je u oba sluaja


p[0] nije.
pokaziva p tipa char*. Znaenje

(na primer,

jeste l-vrednost, ali, na primer,

U gore navedenim primerima koristi se

inicijalizacije je bitno drugaije ako se koristi niz.

Na primer, deklaracijom

248

10. Pokazivai i dinamika alokacija memorije

a duine 12 i
"informatika". U
ovoj situaciji, dozvoljeno je menjanje vrednosti a[0], a[1], ..., a[9], ali nije
dozvoljeno menjanje vrednosti a. Dakle, a nije l-vrednost, ali, na primer, a[0]
sa inicijalizacijom

char a[] = "informatika";

kreira se niz

prilikom inicijalizacije on se popunjava karakterima niske

jeste.
Razmotrimo kao ilustraciju rada sa pokazivaima na karaktere nekoliko

strlen koja vraa duinu zadate niske. Njen


s je pokaziva na poetak niske (koja se, kao i obino, moe tretirati
kao niz). Ukoliko se funkcija pozove sa strlen(p), promenljiva s nakon poziva
predstavlja kopiju tog pokazivaa p i moe se menjati bez uticaja na originalni

moguih implementacija funkcije

(2
01
5)

argument

an

size_t strlen(const char *s) {


size_t n;
for (n = 0; *s != \0; s++)
n++;
return n;
}

je

pokaziva koji je prosleen kao argument:

korien je krai, a ekvivalentan izraz

iz

*s != \0,

Jo jedna verzija ove funkcije koristi mogunost oduzimanja pokazivaa


(umesto

*s):

ro
n

sk
o

size_t strlen(const char *s) {


const char* t = s;
while(*s)
s++;
return s - t;
}

Zbog neposrednih veza izmeu nizova i pokazivaa, kao i naina na koji

strlen moe se pozvati za argument koji je


strlen("informatika");, za argument koji je
ime niza (na primer, strlen(a); za niz deklarisan sa char a[10];), kao i za
pokaziva tipa char* (na primer, strlen(p); za promenljivu p deklarisanu sa
char *p;.

kt

se obrauju, navedena funkcija

le

konstantna niska (na primer,

Kao drugi primer, razmotrimo nekoliko moguih implementacija funkcije

strcpy koja prihvata dva karakterska pokazivaa (ili dve niske) i sadraj druge
kopira u prvu. Da bi jedna niska bila iskopirana u drugu nije, naravno, dovoljno
prekopirati pokaziva, ve je neophodno prekopirati svaki karakter druge niske
pojedinano.

Na primer, naredna dodela je sintaksno ispravna, ali njome se

samo pokaziva

t usmerava ka postojeoj niski s,

bez kopiranja sadraja. Ovo

je plitko kopiranje i to esto nije ono to programer eli (npr. bilo kakva izmena
sadraja putem pokazivaa

menja sadraj niske

s).

249

10. Pokazivai i dinamika alokacija memorije

char s[] = "abcd";


char *t;
...
t = s;
Slino, naredna dodela nije doputena, jer nizove nije mogue dodeljivati.

(2
01
5)

char s[] = "abcd";


char t[5];
...
t = s;

s dodeli niski t
strcpy, iju emo jednu moguu implementaciju

Dakle, kao to je i ranije reeno, ispravan nain da se niska


nije dodela, ve poziv funkcije

je

opisati.

iz

an

char s[] = "abcd";


char t[5];
...
strcpy(t, s);

U narednom kdu, oba pokazivaa se poveavaju za po jedan (operatorom


inkrementiranja), sve dok drugi pokaziva ne doe do zavrne nule, tj. do kraja

sk
o

niske (kako se argumenti prenose po vrednosti, promenljivama

se moe

menjati vrednost, a da to ne utie na originalne pokazivae ili nizove koji su


prosleeni kao argumenti):

le

kt

ro
n

void strcpy(char *s, const char *t) {


while ((*s = *t) != \0) {
s++;
t++;
}
}

Inkrementiranje koje se koristi u navedenom kdu, moe se izvriti (u post-

fiksnom obliku) i u okviru same

while

petlje:

void strcpy(char *s, const char *t) {


while ((*s++ = *t++) != \0);
}
Konano, poreenje sa nulom moe biti izostavljeno jer svaka ne-nula vred-

nost ima istinitosnu vrednost tano:

void strcpy(char *s, const char *t) {


while (*s++ = *t++);

250

10. Pokazivai i dinamika alokacija memorije

}
U navedenoj implementaciji funkcije
je da se sadraj lokacija na koje ukazuje

strcpy kvalifikatorom const obezbeeno


t nee menjati (u protivnom dolazi do

greke u fazi prevoenja.

Pitanje 10.5.1.

(2
01
5)

Pitanja i zadaci za vebu


U kom segmentu memorije se tokom izvravanja programa

uvaju: konstantne niske?

Pitanje 10.5.2.

Nakon koda

an

je

void f() {
char* a = "Zdravo";
char b[] = "Zdravo";
...
}

u kom segmentu memorije je smetena promenljiva

Pitanje 10.5.3.

aib

a?

u kom je segmentu ono

b?
p?

U kom segmentu su smeteni elementi niza

mogu menjati? Koliko bajtova zauzima

iz

Da li se vrednosti

a?

na ta pokazuje promenljiva

Koju vrednost ima promenljiva

a,

a koliko

nakon naredbi:

Razmotriti funkciju:

ro
n

Pitanje 10.5.4.

sk
o

int i;
char a[] = "informatika";
i = strlen(a+2) ? strlen(a+4) : strlen(a+6);

le

kt

char *dan(int n) {
static char *ime[] = {
"neispravna vrednost", "ponedeljak", "utorak", "sreda",
"cetvrtak", "petak","subota", "nedelja"
};
return (n < 1 || n > 7) ? ime[0] : ime[n];
}
ta se postie navedenim kvalifikatorom
Koliko bajtova zauzima niz

ime

static?

i u kom delu memorije?

U kojem delu memorije bi se nalazio niz

static?

Na koji deo memorije ukazuje

Zadatak 10.5.1.

ime

da nije naveden kvalifikator

ime[0]?

Navesti jednu moguu implementaciju funkcije

jednu moguu implementaciju funkcije


mentaciju funkcije

strcmp.

strcpy.

strlen.

Navesti

Navesti jednu moguu imple-

Navesti jednu moguu implementaciju funkcije

251

10. Pokazivai i dinamika alokacija memorije

strrev.

Navesti jednu moguu implementaciju funkcije

moguu implementaciju funkcije

strstr.

strchr.

Navesti jednu

Napomena: sve vreme koristiti pokazi-

vaku sintaksu.

10.6 Nizovi pokazivaa i viedimenzioni nizovi


Kao to je reeno u poglavlju 10.3, izuzev u sluaju ako je u pitanju argu-

(2
01
5)

sizeof ili & operatora, ime niza tipa T se konvertuje u pokaziva na T. To


T a[d1][d2]...[dn] se konvertuje u pokaziva na n-1-dimenzioni niz, tj. u pokaziva tipa T (*)[d2]...[dn].
ment

vai i za viedimenzione nizove. Ime niza tipa

Ovako neto se, na primer, deava prilikom prenosa viedimenzionih nizova u


funkcije, o emu je ve bilo rei u poglavlju 8.7. Razmotrimo dalje, na primer,
deklaraciju dvodimenzionog niza:

je

int a[10][20];

a[0], a[1], a[2], ... oznaava niz od 20 elemenata tipa int,


int [20] (koji se, po potrebi, implicitno konvertuje u tip int*).
Dodatno, a[0] sadri adresu elementa a[0][0] i, optije, a[i] sadri adresu
elementa a[i][0]. Sem u sluaju kada je argument sizeof ili & operatora,
vrednost a se konvertuje u vrednost tipa int (*)[20] ovo je tip pokazivaa
na niz od 20 elemenata. Slino, izrazi &a[0], &a[1], ... su tipa pokazivaa
na niz od 20 elemenata, tj. int (*)[20]. Izrazi a i a[0] imaju istu vrednost

an

Svaki od izraza

iz

te ima tip

ima tip

sk
o

(adresu poetnog elementa dvodimenzionalnog niza), ali razliite tipove: prvi

int (*)[20],

a drugi tip

int*.

optim pravilima pokazivake aritmetike.


a

a[0]+i

je jednako

ro
n

a[i],

&a[0][i].

Ovi tipovi ponaaju se u skladu sa


Tako je, na primer,

a+i

jednako

Razmotrimo razliku izmeu dvodimenzionog niza i niza pokazivaa.

Ako

su date deklaracije

kt

int a[10][20];
int *b[10];

le

a[3][4] i b[3][4] su sintaksiki ispravna referisanja na pojedinani int. Ali


je pravi dvodimenzioni niz: 200 lokacija za podatak tipa int je rezervisano
tj. alocirano i uobiajena raunica 20 * v + k se koristi da bi se pristupilo
elementu a[v][k]. Za niz b, meutim, nije alociran prostor za smetanje elei

menata niza, ve deklaracija alocira samo 10 pokazivaa i ne inicijalizuje ih


inicijalizacija se mora izvriti eksplicitno, bilo statiki (navoenjem inicijalizatora) ili dinamiki (tokom izvravanja programa). Pod pretpostavkom da svaki
element niza

zaista pokazuje na niz od 20 elemenata, u memoriji e biti 200

int i jo dodatno 10 lokacija za pokazivae. Elementi


a su sigurno smeteni na uzastopnim memorijskim lokacijama, dok lokacije
koje ukazuju elementi niza b ne moraju da budu. Kljuna prednost niza

lokacija za podataka tipa


niza
na

pokazivaa nad dvodimenzionim nizom je injenica da vrste na koje pokazuju

252

10. Pokazivai i dinamika alokacija memorije

ovi pokazivai mogu biti razliite duine. Tako, svaki element niza

ne mora

da pokazuje na 20-to elementni niz neki mogu da pokazuju na 2-elementni


niz, neki na 50-elementi niz, a neki mogu da budu

NULL i da ne pokazuju nigde.

Razmotrimo primer niza koji treba da sadri imena meseci. Jedno reenje
je zasnovano na dvodimenzionom nizu (u koji se, prilikom inicijalizacije upisuju
imena meseci):

(2
01
5)

char meseci[][10] = {
"Greska", "Januar", "Februar", "Mart", "April",
"Maj", "Jun", "Jul", "Avgust", "Septembar",
"Oktobar", "Novembar", "Decembar"};

Poto meseci imaju imena razliite duine, bolje reenje je napraviti niz
pokazivaa na karaktere i inicijalizovati ga da pokazuje na konstantne niske
menata niza poto je izvrena inicijalizacija):

je

smetene u segmentu podataka (primetimo da nije potrebno navesti broj ele-

iz

an

char *meseci[] = {
"Greska", "Januar", "Februar", "Mart", "April",
"Maj", "Jun", "Jul", "Avgust", "Septembar",
"Oktobar", "Novembar", "Decembar"};
Slika 10.2 ilustruje slian primer memoriju koja odgovara nizovima

aib

sk
o

deklarisanim u okviru neke funkcije:

ro
n

char a[][5] = {"abcd", "ef", "ghi"};


char* b[] = {"abcd", "ef", "ghi"};

Pitanja i zadaci za vebu


int.

Navesti primer inicijalizacije dvodimenzionog niza brojeva

Navesti primer deklaracije trodimenzionog niza brojeva tipa

le

tipa

kt

Pitanje 10.6.1.
Pitanje 10.6.2.

Da li se matrica

a[3][3];

(e)

Pitanje 10.6.3.
deklaracije

a[3*3]?

Nakon deklaracije

int b[10][20];

3 3 deklarie na sledei nain


a[3][3][3]; (b) a[3,3,3]; (c) a[3,3];

dimenzije

(odgovoriti za svaku pojedinano): (a)


(d)

float.

int a[10]; kog tipa je vrednost a? Nakon


b? a kog vrednost b[0]?

kog tipa je vrednost

Pitanje 10.6.4.

Objasniti naredne dve deklaracije i u emu se razlikuju:

Pitanje 10.6.5.

Kako se deklarie trodimenzioni niz

char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };


char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };
a

dimenzija 10, 9, 8?

253

10. Pokazivai i dinamika alokacija memorije

Segment podataka

a b c d
0

g h i

(2
01
5)

e f

Stek segment

b
[0] [1] [2]
a a b c d

e f

g h i

an

je

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

iz

Pitanje 10.6.6.

Slika 10.2: Niz pokazivaa i dvodimenzioni niz u memoriji

Koliko bajtova e biti rezervisano za naredne nizove:

sk
o

char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };


char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };

Pitanje 10.6.7.

ro
n

1. Da li je nakon deklaracije

char a[3][3],

naredba

a[0][0] = a;

(a)

a[0][0] = a;

(a)

sintaksiki ispravna? (b) semantiki ispravna?


2. Da li je nakon deklaracije

char* a[3];,

naredba

kt

sintaksiki ispravna? (b) semantiki ispravna?

le

Pitanje 10.6.8.

Koliko bajtova zauzima i u kom delu memorije niz koji je u

okviru neke funkcije deklarisan sa

Pitanje 10.6.9.
(a)
(c)

char* a[10];

Koja inicijalizacija dvodimenzionog niza je ispravna:

int a[][2]=(1,2,3,4);
int a[][2]={1,2,3,4};

Pitanje 10.6.10.

(b)
(d)

int a[2][]=(1,2,3,4);
int a[2][]={1,2,3,4};

Koliko je, na 32-bitnim sistemima,

sizeof(a) i sizeof(b)

nakon deklaracija

int* a[4]; int b[3][3];?

Pitanje 10.6.11.

Navesti primer inicijalizacije niza pokazivaa. Opisati efekat

narednih deklaracija:

Pitanje 10.6.12.
temu.

Koliko je u optem sluaju?

int a[10][20]; int *b[10];

Pretpostavimo da se naredni kd izvrava na 32-bitnom sis-

254

10. Pokazivai i dinamika alokacija memorije

char* a[] = {"Dobar dan!", "Zdravo, zdravo"};


char b[][15] = {"Dobar dan!", "Zdravo, zdravo"};
sizeof(a)

Pitanje 10.6.13.

a emu

sizeof(b)?

Razmotriti naredni kd:

void f() {
char* a = "Zdravo";
char b[] = "Zdravo";
...
}
U kom segmentu memorije se nalazi promenljiva
je ono na ta pokazuje promenljiva
ta pokazuje promenljiva

a?

U kom segmentu memorije

U kom segmentu memorije je ono na

Koliko bajtova e na steku biti rezervisano za niz

je

Pitanje 10.6.14.

b?

a?

(2
01
5)

emu je jednako

koji je lokalna promenljiva?

an

char *s[] = { "jedan", "dva", "tri" };

10.7 Pokazivai i strukture

Mogue je definisati i pokazivae na strukture. U sluaju da se lanovima

iz

* i ., mogue
->. I operator -> je operator najvieg prioriteta. Na
(*pa).imenilac moe se pisati pa->imenilac:

strukture pristupa preko pokazivaa, umesto kombinacije operatora


primer, umesto

sk
o

je koristiti operator

ro
n

struct razlomak *pa = &a;


printf("%d/%d", pa->brojilac, pa->imenilac);
Prilikom dodele struktura, vri se plitko kopiranje pokazivaa koji se u njima
nalaze. Neka su
iz

p.

a,

promenljive istog tipa strukture koja ima lan pokazi-

Dodelom

kt

vakog tipa

a=b;

bie iskopirane vrednosti svih lanova strukture

ukljuujui i vrednost lana

b.p.

p,

ali nee biti iskopiran sadraj na koji

Umesto toga, nakon

le

je ukazivao pokaziva

istu adresu (na onu na koju je ukazivao

b.p).

a=b; i a.p i b.p

ukazivae na

Iako se takvo plitko kopranje

koristi (pre svega zbog utede memorije), ono je est uzrok greaka i pokazivae sadrane u strukturama esto je poeljnije duboko kopirati (to zahteva
dodatan trud programera).
Strukture se kao argumenti u funkciju prenose po vrednosti.

S obzirom

na to da strukture esto zauzimaju vie prostora od elementarnih tipova podataka, est je obiaj da se umesto struktura u funkcije proslede njihove adrese,
tj. pokazivai na strukture. Na primer,

void saberi_razlomke(struct razlomak *pa, struct razlomak *pb,


struct razlomak *pc)
{
pc->brojilac = pa->brojilac*pb->imenilac +

255

10. Pokazivai i dinamika alokacija memorije

pa->imenilac*pb->brojilac;
pc->imenilac = pa->imenilac*pb->imenilac;

10.8 Pokazivai na funkcije

(2
01
5)

Funkcije se ne mogu direktno prosleivati kao argumenti drugim funkci-

jama, vraati kao rezultat funkcija i ne mogu se dodeljivati promenljivima.


Ipak, ove operacije je mogue posredno izvriti ukoliko se koriste pokazivai na
funkcije. Razmotrimo naredni ilustrativni primer.

Program 10.3.

an

void inc1(int a[], int n, int b[]) {


int i;
for (i = 0; i < n; i++)
b[i] = a[i] + 1;
}

je

#include <stdio.h>

sk
o

iz

void mul2(int a[], int n, int b[]) {


int i;
for (i = 0; i < n; i++)
b[i] = a[i] * 2;
}

le

kt

ro
n

void even0(int a[], int n, int b[]) {


int i;
for (i = 0; i < n; i++)
b[i] = a[i] % 2 == 0 ? 0 : a[i];
}

void print(int a[], int n) {


int i;
for (i = 0; i < n; i++)
printf("%d ", a[i]);
putchar(\n);
}
#define N 8
int main() {
int a[N] = {1, 2, 3, 4, 5, 6, 7, 8}, b[N];
inc1(a, N, b);

print(b, N);

256

10. Pokazivai i dinamika alokacija memorije

mul2(a, N, b);
even0(a, N, b);

print(b, N);
print(b, N);

return 0;

Sve funkcije u prethodnom programu kopiraju elemente niza

u niz

b,

(2
01
5)

prethodno ih transformiui na neki nain. Mogue je izdvojiti ovaj zajedniki


postupak u zasebnu funkciju koja bi bila parametrizovana operacijom transformacije koja se primenjuje na elemente niza

a:

#include <stdio.h>

an

je

void map(int a[], int n, int b[], int (*f) (int)) {


int i;
for (i = 0; i < n; i++)
b[i] = (*f)(a[i]);
}

iz

int inc1(int x) { return x + 1; }


int mul2(int x) { return 2 * x; }
int parni0(int x) { return x % 2 == 0 ? 0 : x; }

ro
n

sk
o

void ispisi(int a[], int n) {


int i;
for (i = 0; i < n; i++)
printf("%d ", a[i]);
putchar(\n);
}

le

kt

#define N 8
int main() {
int a[N] = {1, 2, 3, 4, 5, 6, 7, 8}, b[N];

map(a, N, b, &inc1);
ispisi(b, N);
map(a, N, b, &mul2);
ispisi(b, N);
map(a, N, b, &parni0); ispisi(b, N);
return 0;

Funkcija

map

ima poslednji argument tipa

int (*)(int), to oznaava


int i vraa argument

pokaziva na funkciju koja prima jedan argument tipa


tipa

int.

Pokazivai na funkcije se razlikuju po tipu funkcije na koje ukazuju (po


tipovima argumenata i tipu povratne vrednosti). Deklaracija promenljive tipa

257

10. Pokazivai i dinamika alokacija memorije

pokazivaa na funkciju se vri tako to se ime promenljive kojem prethodi karakter

* navede u zagradama kojima prethodi tip povratne vrednosti funkcije, a za

kojima sledi lista tipova parametara funkcije. Prisustvo zagrada je neophodno


da bi se napravila razlika izmeu pokazivaa na funkcije i samih funkcija. U
primeru

*double, a prima
double i int, dok promenljiva b oznaava pokaziva na funkciju
rezultat tipa double, a prima argumente tipa double i int.

promenljiva

(2
01
5)

double *a(double, int);


double (*b)(double, int);

oznaava funkciju koja vraa rezultat tipa

argumente tipa
koja vraa

Najee koriene operacije sa pokazivaima na funkcije su, naravno, ref-

erenciranje (&) i dereferenciranje (*).

Ovi nizovi se mogu i

je

Mogue je kreirati i nizove pokazivaa na funkcije.


incijalizovati (na uobiajeni nain). U primeru

an

int (*a[3]) (int) = {&inc1, &mul2, &parni0};

a predstavlja niz od 3 pokazivaa na funkcije koje vraaju int, i primaju arguint. Funkcije ije se adrese nalaze u nizu se mogu direktno i pozvati.
Na primer, naredni kd ispisuje vrednost 4:

iz

ment tipa

sk
o

printf("%d", (*a[0])(3));

ro
n

Pitanja i zadaci za vebu


Pitanje 10.8.1.

Deklarisati funkciju

float.

kt

argument tipa

Pitanje 10.8.2.
strcmp

le

gde je

Pitanje 10.8.3.

koja kao argument


ima (samo jedan)

moe da bude

f(strcmp),

int faktorijel(int n) moe koristi


float, kako je deklarisana funkcija f?

Ako se funkcija

(jedini) argument funkcije

Pitanje 10.8.4.

f iji poziv
string.h.

Deklarisati funkciju

funkcija deklarisana u

int
char i

povratnog tipa

ima pokaziva na funkciju koja je povratnog tipa

tipa

kao

Da li je ispravan sledei prototip funkcije iji je prvi od dva

argumenta pokaziva na funkciju koja ima jedan argument:


(a)
(b)
(c)
(d)

5 Iako

int
int
int
int

f(int* g(char), int x);


f(void g(char), int x);
f(int (*g)(char), int x);
f(int (*g)(void), int x);

kod nekih kompilatora oznake ovih operacija mogu da se izostave i da se koristi

samo ime pokazivaa (na primer, u prethodnom programu je bilo mogue navesti

b, inc1) i b[i] = f(a[i])),

ovo se ne preporuuje zbog prenosivosti programa.

map(a, N,

258

10. Pokazivai i dinamika alokacija memorije

Pitanje 10.8.5.

Da li je ispravan sledei prototip funkcije:

int poredi(char *a, char *b, (*comp)(char *, char *));

Obrazloiti odgovor.

Pitanje 10.8.6.

Date su deklaracije:

a kog

Pitanje 10.8.7.

a2?

Kog je tipa

deklarisano sa:

double (*x[3])(int);

2.

int (*x) (double);

3.

int *x (double);

4.

double* (*x) (float*);

5.

int (*f) (float*);

Napisati funkciju koja u nizu odreuje najduu seriju el-

iz

Zadatak 10.8.1.

1.

je

a1,

an

Kog je tipa

(2
01
5)

int *a1 (int* b1);


int (*a2) (int *b2);

emenata koji zadovoljavaju dato svojstvo.

Svojstvo dostaviti kao parametar

funkcije. Iskoristiti je da bi se nala najdua serija parnih kao i najdua serija

sk
o

pozitivnih elemenata niza.

ro
n

10.9 Dinamika alokacija memorije


U veini realnih aplikacija, u trenutku pisanja programa nije mogue precizno predvideti memorijske zahteve programa.

Naime, memorijski zahtevi

zavise od interakcije sa korisnikom i tek u fazi izvravanja programa korisnik

kt

svojim akcijama implicitno odreuje potrebne memorijske zahteve (na primer,


koliko elemenata nekog niza e biti korieno). U nekim sluajevima, mogue je

le

predvideti neko gornje ogranienje, ali ni to nije uvek zadovoljavajue. Ukoliko


je ogranienje premalo, program nije u stanju da obrauje vee ulaze, a ukoliko

je preveliko, program zauzima vie memorije nego to mu je stvarno potrebno.


Reenje ovih problema je dinamika alokacija memorije koja omoguava da
program u toku svog rada, u fazi izvravanja, zahteva (od operativnog sistema) odreenu koliinu memorije. U trenutku kada mu memorija koja je dinamiki alocirana vie nije potrebna, program moe i duan je da je oslobodi i
tako je vrati operativnom sistemu na upravljanje. Alociranje i oslobaanje vri
se funkcijama iz standardne biblioteke i pozivima rantajm biblioteke. U fazi
izvravanja, vodi se evidencija i o raspoloivim i zauzetim blokovima memorije.

259

10. Pokazivai i dinamika alokacija memorije

10.9.1

Funkcije standardne biblioteke za rad sa dinamikom


memorijom

Standardna biblioteka jezika C podrava dinamiko upravljanje memorijom


kroz nekoliko funkcija (sve su deklarisane u zaglavlju

<stdlib.h>).

Prostor za

dinamiki alociranu memoriju nalazi se u segmentu memorije koji se zove hip


Funkcija

malloc

ima sledei prototip:

(2
01
5)

(engl. heap).

void *malloc(size_t n);

Ona alocira blok memorije (tj. niz uzastopnih bajtova) veliine

vraa adresu alociranog bloka u vidu generikog pokazivaa (tipa

n bajtova i
void*). U

sluaju da zahtev za memorijom nije mogue ispuniti (na primer, zahteva se


vie memorije nego to je na raspolaganju), ova funkcija vraa

malloc

NULL. Memorija

vrati pokaziva nije inicijalizovana i njen sadraj je,

je

na koju funkcija

u principu, nedefinisan (tj. zavisi od podataka koji su ranije bili uvani u tom
Funkcija

an

delu memorije).

malloc oekuje argument tipa size_t.

Podsetimo se, ovo je neneg-

ativni celobrojni tip za ije vrednosti je rezervisano najmanje dva bajta. Ovaj

unsigned int, ali su meusobne konverzije mogue i,


size_t moe da se koristi za uvanje bilo kog indeksa
niza, a on je i tip povratne vrednosti operatora sizeof.
Funkcija calloc ima sledei prototip:
tip se razlikuje od tipa

sk
o

iz

zapravo, trivijalne. Tip

void *calloc(size_t n, size_t size)

ro
n

Ona vraa pokaziva na blok memorije veliine n objekata navedene veliine


size. U sluaju za zahtev nije mogue ispuniti, vraa se NULL. Za razliku od
malloc, alocirana memorija je inicijalizovana na nulu.
Dinamiki objekti alocirani navedenim funkcijama su neimenovani i bitno

kt

su razliiti od promenljivih. Ipak, dinamiki alociranim blokovima se pristupa


na slian nain kao nizovima.

le

Navedene funkcije su generike i koriste se za dinamiku alokaciju memorije

za podatke bilo kog tipa. Da bi se dobijenoj memoriji moglo pristupati slino

kao u sluaju nizova, potrebno je (poeljno eksplicitno) konvertovati dobijeni


pokaziva tipa

void*

u neki konkretni pokazivaki tip.

Nakon poziva funkcije

malloc() ili calloc() obavezno treba proveriti pov-

ratnu vrednost da bi se utvrdilo da li je alokacija uspela. Ukoliko alokacija ne


uspe, pokuaj pristupa memoriji na koju ukazuje dobijeni pokaziva dovodi do

NULL pokazivaa i greke. Ukoliko se


calloc()) vratila vrednost NULL, moe

dereferenciranja

malloc()

(ili

utvrdi da je funkcija
se prijaviti korisniku

odgovarajua poruka ili pokuati neki metod oporavka od greke. Dakle, najei scenario upotrebe funkcije

malloc

je sledei:

260

10. Pokazivai i dinamika alokacija memorije

int* p = (int*) malloc(n*sizeof(int));


if (p == NULL)
/* pokusati oporavak od greske ili prijaviti gresku */
Ponekad se podrazumeva da e alokacija biti uspena i ne preduzima se
oporavak od greke i takvo mesta se u kdu oznaavaju funkcijom

assert

(2
01
5)

(videti poglavlje 11.5).


U gore navedenom primeru, nakon uspene alokacije, u nastavku programa

se

moe koristiti kao (statiki alociran) niz celih brojeva. Napomenimo da

raunanje izraza
vrednosti

calloc).

n*sizeof(int) moe dovesti do prekoraenja za veoma velike

(ukoliko je prekoraenje problem, savetuje se upotreba funkcije

U trenutku kada dinamiki alociran blok memorije vie nije potreban, poeljno
je osloboditi ga. To se postie funkcijom

free:

an

je

void free(void* p);

free(p) oslobaa memoriju na koju ukazuje pokaziva p (a ne memp), pri emu je neophodno da p
pokazuje na blok memorije koji je alociran pozivom funkcije malloc ili calloc.
Poziv

orijski prostor koji sadri sm pokaziva

iz

Oslobaanje memorije koja nije alocirana na ovaj nain dovodi do nedefinisanog


ponaanja (najee do greke prilikom izvravanja programa). Slino, ne sme
se koristiti neto to je ve osloboeno niti se sme dva puta oslobaati ista

sk
o

memorija jer je i u tim sluajevima ponaanje programa nedefinisano.

Re-

dosled oslobaanja memorije ne mora da odgovara redosledu alociranja.


Ukoliko neki dinamiki alociran blok nije osloboen ranije, on e biti osloboen

ro
n

prilikom zavretka rada programa, zajedno sa svom drugom memorijom koja je


dodeljena programu. Ipak, ne treba se oslanjati na to i preporueno je eksplicitno oslobaanje sve dinamiki alocirane memorije pre kraja rada programa, a
poeljno im taj prostor nije potreban.

kt

Upotrebu ovih funkcija ilustruje naredni primer u kojem se unosi i obrnuto


ispisuje niz iji broj elemenata nije unapred poznat (niti je poznato njegovo

le

gornje ogranienje), ve se unosi sa ulaza tokom izvravanja programa.

Program 10.4.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, i, *a;
/* Unos broja elemenata */
scanf("%d", &n);
/* Alocira se memorija */
if ((a = (int*)malloc(n*sizeof(int))) == NULL) {

261

10. Pokazivai i dinamika alokacija memorije

printf("Greska prilikom alokacije memorije\n");


return 1;

return 0;

(2
01
5)

}
/* Unos elemenata */
for (i = 0; i < n; i++) scanf("%d",&a[i]);
/* Ispis elemenata u obrnutom poretku */
for (i = n-1; i >= 0; i--) printf("%d ",a[i]);
/* Oslobadjanje memorije */
free(a);

U nekim sluajevima potrebno je promeniti veliinu ve alociranog bloka


memorije. To se postie korienjem funkcije

realloc,

iji je prototip:

an

je

void *realloc(void *memblock, size_t size);

memblock je pokaziva na prethodno alocirani blok memorije, a


size je nova veliina u bajtovima. Funkcija realloc vraa pokaziva tipa void* na realociran blok memorije, a NULL u sluaju da zahtev ne moe

Parametar

parametar

iz

biti ispunjen. Zahtev za smanjivanje veliine alociranog bloka memorije uvek


uspeva. U sluaju da se zahteva poveanje veliine alociranog bloka memorije,
pri emu iza postojeeg bloka postoji dovoljno slobodnog prostora, taj prostor

sk
o

se jednostavno koristi za proirivanje. Meutim, ukoliko iza postojeeg bloka


ne postoji dovoljno slobodnog prostora, onda se u memoriji trai drugo mesto
dovoljno da prihvati proireni blok i, ako se nae, sadraj postojeeg bloka se

ro
n

kopira na to novo mesto i zatim se stari blok memorije oslobaa. Ova operacija
moe biti vremenski zahtevna.
Upotreba funkcije

realloc ilustrovana je programom koji uitava cele bro-1 za kraj. S obzirom na to da

jeve i smeta ih u memoriju, sve dok se ne unese

kt

se broj elemenata ne zna unapred, a ne zna se ni gornje ogranienje, neophodno


je postepeno poveavati skladini prostor tokom rada programa.

Kako esta

le

realokacija moe biti neefikasna, u narednom programu se izbegava realokacija


prilikom unosa svakog sledeeg elementa, ve se vri nakon unoenja svakog

desetog elementa.

Naravno, ni ovo nije optimalna strategija u praksi se

obino koristi pristup da se na poetku realokacije vre relativno esto, a onda


sve ree i ree (na primer, svaki put se veliina niza dvostruko uvea).

Program 10.5.
#include <stdio.h>
#include <stdlib.h>
#define KORAK 256
int main() {
int* a = NULL;

/* Niz je u pocetku prazan */

262

10. Pokazivai i dinamika alokacija memorije

int duzina = 0;
/* broj popunjenih elemenata niza */
int alocirano = 0; /* broj elemenata koji mogu biti smesteni */
int i;
do {
printf("Unesi ceo broj (-1 za kraj): ");
scanf("%d", &i);

je

(2
01
5)

/* Ako nema vise slobodnih mesta, vrsi se prosirivanje */


if (duzina == alocirano) {
alocirano += KORAK;
a = realloc(a, alocirano*sizeof(int));
if (a == NULL) return 1;
}
a[duzina++] = i;
} while (i != -1);

iz

an

/* Ispis elemenata */
printf("Uneto je %d brojeva. Alocirano je %d bajtova\n",
duzina, alocirano*sizeof(int));
printf("Brojevi su : ");
for (i = 0; i<duzina; i++)
printf("%d ", a[i]);

return 0;

ro
n

sk
o

/* Oslobadjanje memorije */
free(a);

Bez upotrebe funkcije

realloc

centralni blok navedene funkcije

main

bi

mogao da izgleda ovako:

le

kt

if (duzina == alocirano) {
/* Kreira se novi niz */
int* new_a;
alocirano += KORAK;
new_a = malloc(alocirano*sizeof(int));
/* Kopira se sadrzaj starog niza u novi */
for (i = 0; i < duzina; i++) new_a[i] = a[i];
/* Oslobadja se stari niz */
free(a);
/* a ukazuje na novi niz */
a = new_a;
}
U ovoj implementaciji, prilikom svake realokacije vri se premetanje mem-

orije, tako da je ona neefikasnija od verzije sa

realloc.

U gore navedenom primeru koristi se konstrukcija:

263

10. Pokazivai i dinamika alokacija memorije

a = realloc(a, alocirano*sizeof(int));
U nekim sluajevima ova konstrukcija moe da bude neadekvatna ili opasna.
Naime, ukoliko zahtev za proirenje memorijskog bloka ne uspe, vraa se vred-

NULL,

nost

upisuje u promenljivu

i time se gubi jedina veza sa prethodno

10.9.2

(2
01
5)

alociranim blokom (i on, na primer, ne moe ubudue da bude osloboen).

Greke u radu sa dinamikom memorijom

Dinamiki alocirana memorija nudi mnoge mogunosti i dobra reenja ali


esto je i uzrok problema. Neki od najeih problema opisani su u nastavku.

Curenje memorije.

Jedna od najopasnijih greaka u radu sa dinamiki

alociranom memorijom je tzv. curenje memorije (engl. memory leak). Curenje

je

memorije je situacija kada se u tekuem stanju programa izgubi informacija o


lokaciji dinamiki alociranog, a neosloboenog bloka memorije. U tom sluaju,

an

program vie nema mogunost da oslobodi taj blok memorije i on biva zauvek
(zapravo do kraja izvravanja programa) izgubljen (rezervisan za korienje

od strane programa koji vie nema naina da mu pristupi). Curenje memorije

iz

ilustruje naredni primer.

sk
o

char* p;
p = (char*) malloc(1000);
....
p = (char*) malloc(5000);

ro
n

Inicijalno je 1000 bajtova dinamiki alocirano i adresa poetka ovog bloka memorije smetena je u pokazivaku promenljivu

p.

Kasnije je dinamiki aloci-

rano 5000 bajtova i adresa poetka tog bloka memorije je opet smetena u
promenljivu

p.

Meutim, poto originalnih 1000 bajtova nije osloboeno ko-

kt

rienjem funkcije

free,

a adresa poetka tog bloka memorije je izgubljena

promenom vrednosti pokazivake promenljive

p,

tih 1000 bajtova biva nepov-

le

ratno izgubljeno za program.


Naroito su opasna curenja memorije koja se dogaaju u okviru neke petlje.

U takvim situacijama moe da se gubi malo po malo memorije, ali tokom dugtrajnog izvravanja programa, pa ukupna koliina izgubljene memorije moe
da bude veoma velika.

Mogue je da u nekom trenutku program iscrpi svu

raspoloivu memoriju i onda e njegovo izvravanje biti prekinuto od strane


operativnog sistema. ak i da se to ne desi, mogue je da se iscrpi raspoloivi
prostor u glavnoj memoriji i da se, zbog toga, sadraj glavne memorije prebacuje na disk i obratno (tzv. swapping), to onda ekstremno usporava rad
programa.
Curenje memorije je naroito opasno zbog toga to esto ne biva odmah
uoeno.

Obino se tokom razvoja program testira kratkotrajno i na malim

ulazima. Meutim, kada se program pusti u rad i kada pone da radi dui vre-

264

10. Pokazivai i dinamika alokacija memorije

menski period (moda i bez prestanka) i da obrauje vee koliine ulaza, curenje
memorije postaje vidljivo, ini program neupotrebljivim i moe da uzrokuje velike tete.
Veina programa za otkrivanje greaka (debagera) detektuje da u programu
postoji curenje memorije, ali ne moe da pomogne u lociranju odgovarajue
greke u kdu.

rije (engl.

Postoje specijalizovani programi profajleri za curenje memo-

memory leaks profilers) koji olakavaju otkrivanje uzroka curenja

(2
01
5)

memorije.

Pristup osloboenoj memoriji.

Nakon poziva free(p), memorija na koju


p se oslobaa i ona vie ne bi trebalo da se koristi. Meutim, poziv free(p) ne menja sadraj pokazivaa p. Mogue je da naredni
poziv funkcije malloc vrati blok memorije upravo na toj poziciji. Naravno,

pokazuje pokaziva

ovo ne mora da se desi i nije predvidljivo u kom e se trenutku desiti, tako

free(p),

odmah

p,

mogue je da

Zbog toga, preporuuje se da se nakon poziva

postavi na

NULL.

Tako se osigurava da e svaki pokuaj

an

e greka proi neopaeno.

je

da ukoliko programer nastavi da koristi memoriju na adresi

pristupa osloboenoj memoriji biti odmah prepoznat tokom izvravanja programa i operativni sistem e zaustaviti izvravanje programa sa porukom o

segmentation fault).

iz

greci (najee

Oslobaanje istog bloka vie puta.


free(p)

Nakon poziva

za istu vrednost pokazivaa

sk
o

poziv

free(p), svaki naredni

prouzrokuje nedefinisano pon-

aanje programa i trebalo bi ga izbegavati. Takozvana viestruka oslobaanja


mogu da dovedu do pada programa a poznato je da mogu da budu i izvor

ro
n

bezbednosnih problema.

Oslobaanje neispravnog pokazivaa.

free(p) doputeno je prosmalloc, calloc ili realloc.

Funkciji

lediti iskljuivo adresu vraenu od strane funkcije

kt

ak i prosleivanje pokazivaa na lokaciju koja pripada alociranom bloku (a


nije njegov poetak) uzrokuje probleme. Na primer,

le

free(p+10); /* Oslobodi sve osim prvih 10 elemenata bloka */

nee osloboditi sve osim prvih 10 elemenata bloka i sasvim je mogue da e


dovesti do neprijatnih posledica, pa ak i do pada programa.

Prekoraenja i potkoraenja bafera.

Nakon dinamike alokacije, pristup

memoriji je dozvoljen samo u okviru granica bloka koji je dobijen.

Kao i u

sluaju statiki alociranih nizova, pristup elementima van granice moe da


prouzrokuje ozbiljne probleme u radu programa. Upis van granica bloka najee je opasniji od itanja. U sluaju dinamiki alociranih blokova memorije,
obino se nakon samog bloka smetaju dodatne informacije potrebne alokatoru
memorije da bi uspeno vodio evidenciju koji delovi memorije su zauzeti, a

265

10. Pokazivai i dinamika alokacija memorije

koji slobodni. Zato, i malo prekoraenje granice bloka prilikom upisa moe da
promeni te dodatne informacije i da uzrokuje pad sistema za dinamiko upravljanje memorijom. Postoje i mnogi drugi sluajevi u kojima prekoraenje i
potkoraenje bafera mogu da narue ispravno izvravanje programa ili dovedu
do njegovog pada.

Fragmentisanje memorije

(2
01
5)

10.9.3

est je sluaj da ispravne aplikacije u kojima ne postoji curenje memorije (a

koje esto vre dinamiku alokaciju i dealokacije memorije) tokom dugog rada
pokazuju degradaciju u performansama i na kraju prekidaju svoj rad na nepredvieni nain.

Uzrok ovome je najee fragmentisanje memorije.

U sluaju

fragmentisane memorije, u memoriji se esto nalazi dosta slobodnog prostora,


ali on je rascepkan na male, nepovezane parie. Razmotrimo naredni (mini-

Ukoliko 0 oznaava slobodni bajt i 1 oznaava zauzeti

bajt, a memorija trenutno ima sadraj

je

jaturizovan) primer.

100101011000011101010110,

postoji

an

ukupno 12 slobodnih bajtova. Meutim, pokuaj alokacije 5 bajtova ne moe


da uspe, jer u memoriji ne postoji prostor dovoljan za smetanje 5 povezanih ba-

jtova. S druge strane, memorija koja ima sadraj

111111111111111100000000

ima samo 8 slobodnih bajtova, ali jeste u stanju da izvri alokaciju 5 traenih

iz

bajtova. Memoriju na hipu dodeljenu programu nije mogue automatski reorganizovati u fazi izvravanja, jer nije mogue u toj fazi aurirati sve pokazivae

sk
o

koji ukazuju na objekte na hipu.


Postoji nekoliko pristupa za izbegavanje fragmentisanja memorije. Ukoliko
je mogue, poeljno je izbegavati dinamiku alokaciju memorije. Naime, alociranje svih struktura podataka statiki (u sluajevima kada je to mogue) dovodi

ro
n

do breg i predvidljivijeg rada programa (po cenu veeg utroka memorije).


Alternativno, ukoliko se ipak koristi dinamika alokacija memorije, poeljno je
memoriju alocirati u veim blokovima i umesto alokacije jednog objekta aloci-

kt

rati prostor za nekoliko njih odjednom (kao to je to, na primer, bilo raeno
u primeru datom prilikom opisa funkcije

realloc).

Na kraju, postoje tehnike

efikasnijeg rukovanja memorijom (na primer, memory pooling ), u kojima se

le

programer manje oslanja na sistemsko reenje, a vie na svoje reenje koje je

prilagoeno specifinim potrebama.

10.9.4

Hip i dinamiki ivotni vek

U poglavlju 9.3.3, reeno je da je memorija dodeljena programu organizovana u segment kda, segment podataka, stek segment i hip segment.

Hip

segment predstavlja tzv. slobodnu memoriju iz koje se crpi memorija koja se


dinamiki alocira. Dakle, funkcije

malloc, calloc ili realloc, ukoliko uspeju,

vraaju adresu u hip segmentu. Objekti koji su alocirani u slobodnom memorijskom prostoru nisu imenovani, ve im se pristupa iskljuivo preko adresa.
Poto ovi objekti nisu imenovani, oni nemaju definisan doseg (a doseg pokazi-

266

10. Pokazivai i dinamika alokacija memorije

vaa putem kojih se pristupa dinamikim objektima podlee standardnim pravilima). Svi objekti koji su dinamiki alocirani imaju dinamiki ivotni vek. Ovo
znai da se memorija i alocira i oslobaa iskljuivo na eksplicitni zahtev i to
tokom rada programa.
Hip segment obino poinje neposredno nakon segmenta podataka, a na
suprotnom kraju memorije od stek segmenta. Obino se podaci na hipu slau
od manjih ka veim adresama (engl. upward growing), dok se na steku slau

(2
01
5)

od veih ka manjim adresama (eng;. downward growing). Ovo znai da se u

trenutku kada se iscrpi memorijski prostor dodeljen programu, hip i stek po-

tencijalno sudaraju, ali operativni sistemi obino to spreavaju i tada obino


dolazi do nasilnog prekida rada programa.

Pitanja i zadaci za vebu

je

Pitanje 10.9.1.

an

Navesti prototip, opisati njeno ponaanje i primer korienja funkcije:

malloc;

calloc;

iz

realloc;

sk
o

free.

U kom zaglavlju su deklarisane ove funkcije?

Pitanje 10.9.2.

realloc

ima isti efekat kao funkcija

free

ako je:

ro
n

Fukcija

vrednost njenog prvog argumenta nula;

vrednost njenog drugog argumenta nula;

kt

vrednost oba njena argumenta nula;

vrednost oba njena argumenta razliita od nule.

le

Pitanje 10.9.3.

Kada je, nakon komandi

char *p;
p = (char*)malloc(n);
komanda

strcpy(p,"test");

Pitanje 10.9.4.

bezbedna?

U kom segmentu memorije se tokom izvravanja programa

uvaju dinamiki alocirani blokovi memorije.

Pitanje 10.9.5.

Kako se zove pojava kada se izgubi vrednost poslednjeg pokazi-

vaa na neki dinamiki alocirani blok memorije? Zato je ova pojava opasna?

267

10. Pokazivai i dinamika alokacija memorije

Pitanje 10.9.6.

Da li e doi do curenja memorije ako nakon komande

p = (int*)malloc(sizeof(int)*5)
slede komanda/komande:

q = (int*)malloc(sizeof(int)*5);
p = (int*)malloc(sizeof(int)*5);

(2
01
5)

free(p); free(p);
free(p+1);

Pitanje 10.9.7.

Zaokruiti komandu u narednom kdu koja dovodi do greke?

an

Pitanje 10.9.8.

je

int *f = malloc(4*sizeof(int));
int* g = f;
free(g);
free(f);
f=g;

Koje su prednosti korienja dinamike alokacije memorije

*p?

Pitanje 10.9.10.

free(p);?

free(p),vrednost

iz

vrednost

ta je, nakon poziva

pokazivaa

p,

a ta

sk
o

Pitanje 10.9.9.

(u odnosu na statiku i automatsku alokaciju)? Koji su nedostaci?

Koja naredba treba da se, prema dobroj praksi, izvri nakon

ta se time postie?

Kako sistem upravlja dinamikom memorijom? Zato se ne

ro
n

Pitanje 10.9.11.

sme dinamiki alociran prostor osloboditi dva puta?

Pitanje 10.9.12.

Opisati ukratko bar etiri este greke koje se javljaju u vezi

kt

sa dinamikom alokacijom memorije.

le

Pitanje 10.9.13.

Pitanje 10.9.14.

free
malloc, calloc i realloc?

Da li je u nekoj situaciji dozvoljeno funkciji

pokaziva koji nije dobijen funkcijama

proslediti

Kako se zove situacija u kojoj je memorija na hipu podeljena

na mnotvo malih i nepovezanih blokova delova?

Pitanje 10.9.15.

Da li se fragmentisanje memorije moe umanjiti ako se

ne koristi rekurzija?

ne koristi memorija na hipu?

koristi to manje lokalnih promenljivih?

koristi to manje globalnih promenljivih?

268

10. Pokazivai i dinamika alokacija memorije

Zadatak 10.9.1.

,
sa standardnog ulaza.
Program treba da vrati indeks broja u nizu (ako se nalazi u ) ili indeks

elementa niza koji je po apsolutnoj vrednosti najblii broju .


a zatim i niz

od

Zadatak 10.9.2.

Napisati program koji sa standardnog ulaza uitava broj

celih brojeva, pa zatim i ceo broj

Napisati program koji sa standardnog ulaza uitava cele bro-

jeve dok ne uita nulu kao oznaku za kraj.

Na standardni izlaz ispisati koji

pojave brojevi:

5.

2 5 12 4 5 2 3 12 15 5 6 6 5

(2
01
5)

broj se pojavio najvie puta meu tim brojevima. Na primer, ako se na ulazu
program treba da vrati broj

Zadatak reiti korienjem niza koji se dinamiki realokacira.

Zadatak 10.9.3.

Napisati program koji sa standardnog ulaza uitava prvo

dimenzije matrice ( i

a zatim redom i elemente matrice (ne postoje pret-

postavke o dimenziji matrice), a zatim ispisuje matricu spiralno, krenuvi od

gornjeg levog ugla.

je

Zadatak 10.9.4.

int skalarni_proizvod(int* a,int* b, int n) koja

an

1. Napisati funkciju

rauna skalarni proizvod vektora a i b duine n. (Sklarni proizvod dva vek-

= (1 , . . . , ) i = (1 , . . . , )
)

je suma

2. Napisati funkciju

= 1 1 + 2 2 + . . . +

iz

tora

int ortonormirana(int** A, int n) kojom se prover ortonormirana.

sk
o

ava da li je zadata kvadratna matrica A dimenzije

Za matricu emo rei da je ortonormirana ako je skalarni proizvod svakog


para razliitih vrsta jednak 0, a skalarni proizvod vrste sa samom sobom

ro
n

1. Funkcija vraa 1 ukoliko je matrica ortonormirana, 0 u suprotnom.


3. Napisati glavni program u kome uitava dimenzija kvadratne matrice

n, a

le

kt

zatim i elementi i pozivom funkcije se utvru


. je da li je matrica ortonormirana. Maksimalna dimenzija matrice nije unapred poznata.

(2
01
5)

Glava 11

je

Pregled standardne biblioteke

Jezik C ima mali broj naredbi i mnoge funkcionalnosti obezbeene su kroz

an

funkcije standardne biblioteke (engl. standard library). Standardna biblioteka


obezbeuje funkcije, ali i makroe i definicije tipova za potrebe rada sa daStandardna C biblioteka

totekama, niskama, alokacijom memorije i slino.

nije jedna, konkretna biblioteka koja se koristi za povezivanje sa programima


svaki C prevodilac.

iz

napisanom u jeziku C, ve ona pre predstavlja standard koji mora da potuje


Kako je implementirana standardna biblioteka zavisi od

sk
o

konkretnog sistema.

Programski interfejs za pisanje aplikacija (API) za standardnu biblioteku


dat je u vidu datoteka zaglavlja, od kojih svaka sadri deklaracije funkcije,
definicije tipova i makroa. Skupu petnaest datoteka zaglavlja propisanih stan-

ro
n

dardom ANSI C (C89), dokument Normative Addendum 1 (NA1) dodao je tri


datoteke 1995. godine. Verzija C99 uvela je jo est datoteka zaglavlja, a verzija C11 jo pet (od kojih tri mogu da ne budu podrane od implementacija, a

kt

da se te implementacije i dalje smatraju standardnim).

U tabeli 11.1 dat je

pregled svih dvadeset devet zaglavlja. Ove datoteke, zajedno sa izvornim kdom programa bivaju ukljuene u proces kompilacije (korienjem pretproce-

le

sora i njegove direktive

#include).

Pored ovih datoteka, standardna biblioteka

sadri i definicije funkcija koje obino nisu raspoloive u izvornom, ve samo u


prevedenom, objektnom (mainskom) obliku, spremnom za povezivanje sa objektnim modulima programa korisnika. Ovaj (vei) deo standardne biblioteke
biva ukljuen u fazi povezivanja (i ne obrauje se tokom kompilacije).
U daljem tekstu e biti ukratko opisane neke od funkcija deklarisanih u
nekim od ovih zaglavlja.

Najkompleksnije zaglavlje

narednoj glavi, posveenoj ulazu i izlazu C programa.

11.1 Zaglavlje string.h

269

stdio.h

bie opisano u

270

11. Pregled standardne biblioteke

Datoteka zaglavlja

Od

Deklaracije i definicije koje sadri

<assert.h>
<complex.h>
<ctype.h>

C89

Makro

C99

Funkcije za rad sa kompleksnim brojevima.

C89

Funkcije za klasifikovanje i konvertovanje karaktera,

(2
01
5)

assert.

nezavisno od karakterske tabele koja se koristi (ASCII


ili neke druge);

<errno.h>

C89

<fenv.h>

C99

<float.h>

C89

<inttypes.h>
<iso646.h>
<limits.h>

C99

Proirena podrka za celobrojne tipovi fiksne irine.

NA1

Makroi za opisivanje standardnih tokena.

C89

Konstante koje specifikuju svojstva celih brojeva zav-

<locale.h>
<math.h>
<setjmp.h>
<signal.h>
<stdalign.h>
<stdarg.h>

C89

Funkcije za lokalizaciju.

C89

esto korie matematike funkcije.

C89

Makroi

C89

Funkcije za upravljanje signalima.

C11

Podrka sa ravnanje objekata.

C89

Podrka za funkcije sa promenljivim brojem param-

<stdatomic.h>

C11

lioteke funkcije.

<stdnoreturn.h>
<string.h>
<tgmath.h>
<threads.h>
<time.h>
<uchar.h>
<wchar.h>
<wctype.h>

Konstante koje specifikuju svojstva brojeva u pokret-

je

nom zarezu zavisna od implementacije.

an

isna od implementacije.

iz

setjmp i longjmp.

etara

sk
o

Podrka za atomike operacije nad podacima deljenim


izmeu niti.

bool.

C99

Tip

C89

Nekoliko raznorodnih tipova i konstanti (ukljuujui

ro
n

kt

<stdint.h>
<stdio.h>
<stdlib.h>

le

Funkcije za kontrolu okruenja za brojeve u pokretnom


zarezu.

<stdbool.h>
<stddef.h>

Podrka za rad sa kdovima greaka koje vraaju bib-

NULL i

size_t).

C99

Podrka za celobrojne tipove fiksne irine.

C89

Deklaracije osnovnih ulazno/izlaznih funkcija;

C89

Deklaracije funkcija za konverzije, za generisanje pseudosluajnih brojeva, za dinamiku alokaciju memorije,


prekid programa itd.

C11

Podrka za specifikovanje funkcija bez povratka

C89

Funkcije za obradu niski.

C99

Matematike funkcije generikog tipa.

C11

Funkcije za upravljanje nitima.

C89

Funkcije za rad sa datumima i vremenom

C11

Tipovi i deklaracije za rad sa Unicode karakterima.

NA1

Funkcije za rad sa niskama karaktera vee irine.

NA1

Funkcije za klasifikovanje i konvertovanje karaktera


vee irine.

Tabela 11.1: Pregled zaglavlja standardne biblioteke

271

11. Pregled standardne biblioteke

size_t strlen

(char* str);

char*
char*
char*
char*

strcpy
strncpy
strcat
strncat

(char*
(char*
(char*
(char*

int
int

strcmp (char* str1, char* str2);


strncmp (char* str1, char* str2, size_t num);

char*
char*
char*

strchr (char* str, int character);


strrchr (char* str, int character);
strstr (char* str1, char * str2);

char*
char*
char*
char*

source);
source, size_t num);
source);
source, size_t num);

(2
01
5)

destination,
destination,
destination,
destination,

strtok

(char * str, char* delimiters);

strlen

Funkcija

strlen izraunava duinu prosleene niske karaktera (termi-

sk
o

nalna nula se ne rauna).

strcpy

iz

char*

an

je

size_t strspn (char* str1, char* str2);


size_t strcspn (char* str1, char* str2);
char* strpbrk (char* str1, char* str2);

strcpy

Funkcija

kopira drugu navedenu nisku u prvu (pretpostavlja-

jui da u prvoj ima dovoljno mesta za sve karaktere druge, ukljuujui i

strncpy takoe vri kopiranje, ali se dodatn kontrolie najvei broj karaktera koji moe biti kopiran (u sluaju da je niska koja se kopira kraa od broja n ostatak se popunjava nulama, a ukoliko je dua od broja n terminalna nula se ne dodaje
automatski na kraj). Korienje funkcije strncpy smatra se bezbednijim
od strcpy jer je mogue kontrolisati mogunost prekoraenja bafera.

ro
n

terminalnu nulu). Funkcija

kt

nim parameterom

Funkcija

le

strcat

strcat nadovezuje drugu navedenu nisku na prvu, pretpostavl-

jajui da prva niska ima dovoljno prostora da smesti i sve karaktere druge,
ukljuujui i njenu terminalnu nulu (terminalna nula prve niske se brie).
Funkcija

strncat

dodatnim parametrom

kontrolie najvei broj druge

niske koji e biti nadovezan na prvu.

strchr

strchr proverava da li data niska sadri dati karakter i vraa


NULL ako karaknaen. Funkcija strrchr radi slino, ali vraa pokaziva na

Funkcija

pokaziva na prvu poziciju na kojoj je karakter naen ili


ter nije

poslednje pojavljivanje karaktera.

strpbrk

Funkcija

strpbrk vraa pokaziva na prvo pojavljivanje nekog karakNULL pokaziva

tera iz druge navedene niske u prvoj navedenoj niski ili


ako takvog karaktera nema.

272

11. Pregled standardne biblioteke

strstr

strstr

Funkcija

proverava da li je druga navedena niska podniska

prve. Ako jeste, vraa se pokaziva na prvo njeno pojavljivanje unutar


prve niske, a ako nije, vraa se pokaziva

strspn

Funkcija

strspn

NULL.

vraa duinu poetnog dela prve navedene niske koji

se sastoji samo od karaktera sadranih u drugoj navedenoj niski. Slino,


funkcija

strcspn vraa duinu poetnog dela prve navedene niske koji se

strtok

Niz poziva funkcije

(2
01
5)

sastoji samo od karaktera koji nisu sadrani u drugoj navedenoj niski.

strtok slue da podele nisku u tokene koji su niske

uzastopnih karaktera razdeljene karakterima navedenim u drugoj niski.

U prvom pozivu funkcije kao prvi argument navodi se niska koja se deli,
a u drugom navodi se

NULL.

Na primer, kd

iz

an

je

char str[] ="- Ovo, je jedna niska.", delims[] = " ,.-";


char *s = strtok (str, delims);
while (s != NULL) {
printf ("%s\n", s);
s = strtok (NULL, delims);
}

ro
n

Ovo
je
jedna
niska

sk
o

ispisuje

kt

11.2 Zaglavlje stdlib.h


*malloc(size_t n);
*calloc(size_t n, size_t size);
*realloc(void *memblock, size_t size);
free(void* p);

le

void
void
void
void

int rand(void);
void srand(unsigned int);
int system(char* command);
void exit(int);
Ve smo naveli da se u zaglavlju

calloc, realloc i free

stdlib.h nalaze deklaracije funkcija malloc,

koje slue za dinamiku alokaciju i oslobaanje mem-

orije. Pored njih najznaajnije funkcije ovog zaglavlja su i sledee.

273

11. Pregled standardne biblioteke

rand

int rand(void); generie pseudo-sluajne cele brojeve u interRAND_MAX (koja je takoe definisana u zaglavlju
<stdlib.h>). Termin pseudo-sluajni se koristi da se naglasi da ovako
Funkcija

valu od 0 do vrednosti

dobijeni brojevi nisu zaista sluajni, ve su dobijeni specifinim izraunavanjima koja proizvode nizove brojeva nalik na sluajne. Funkcija

rand()

vraa sledei pseudo-sluajan broj u svom nizu. Pseudo-sluajni brojevi

[0, 1)

mogu se dobiti na sledei

nain:

((double) rand() / (RAND_MAX+1.0))


Funkcija

(2
01
5)

brojevi u pokretnom zarezu iz intervala

rand() moe biti jednostavno upotrebljena za generisanje pseudo[, ]:

sluajnih brojeva u celobrojnom intervalu

an

je

n+rand()%(m-n+1)

Ipak, bolja svojstva (bolju raspodelu) imaju brojevi koji se dobijaju na

sledei nain:

iz

n+(m-n+1)*((double) rand() / (RAND_MAX+1.0))


Funkcija

rand niz pseudo-sluajnih brojeva generie uvek poev od iste


1). To znai da e se u svakom

sk
o

srand

podrazumevane vrednosti (koja je jednaka

pokretanju programa dobiti isti niz pseudo-sluajnih brojeva. Funkcija

ro
n

void srand(unsigned); postavlja vrednost koja se u sledeem pozivu


rand (a time, indirektno, i u svim narednim) koristi u generisanju tog niza. Za bilo koju vrednost funkcije srand, itav niz brojeva
koji vraa funkcija rand je uvek isti. To je pogodno za ponavljanje (na

kt

funkcije

primer, radi debagovanja) procesa u kojima se koriste pseudo-sluajni

srand navodi trenutno


srand(time(NULL)), gde se koristi funkcija time iz zaglavlja

brojevi. esto se kao argument u pozivu funkcije

le

vreme (npr.

<time.h>) da bi se postiglo da se pri svakom pokretanju programa dobije


razliit niz vrednosti.

system Prototip funkcije system je int system(char* command); Pozivom


system(komanda), izvrava se navedena komanda komanda (potencijalno
sa argumentima) kao sistemski poziv kojim se izvrava komanda operativnog sistema ili neki drugi program (u okviru tekueg programa, a ne
iz komandne linije). Nakon toga, nastavlja se izvravanje programa.
Na primer, pozivom

system("date");

aktivira se program

date

koji

ispisuje tekui datum i koji je esto prisutan na razliitim operativnim


sistemima.

274

11. Pregled standardne biblioteke

Ukoliko je argument funkcije

system vrednost NULL, onda se samo prover-

ava da li je raspoloiv komandni interpretator koji bi mogao da izvrava


zadate komande. U ovom sluaju, funkcija

system

vraa ne-nulu, ako je

komandni interpretator raspoloiv i nulu inae.


Ukoliko argument funkcije

system

nije vrednost

NULL,

onda funkcija

vraa istu vrednost koju je vratio komandni interpretator (obino nulu

1 vraa se u sluaju

(2
01
5)

ukoliko je komanda izvrena bez greaka). Vrednost

greke (na primer, komandni interpretator nije rasploiv, nema dovoljno


memorije da se izvri komanda, lista argumenata nije ispravna).

exit

Funkcija

void exit(int);

zaustavlja rad programa (bez obzira iz koje

funkcije je pozvana) i vraa svoj argument kao povratnu vrednost programa. Obino povratna vrednost nula oznaava uspeno izvrenje pro-

grama, a vrednost ne-nula ukazuje na neku greku tokom izvravanja.

EXIT_SUCCESS EXIT_FAILURE za
exit(e); u okviru funkcije main ekvivanaredbi return e;. Funkcija exit automatski poziva fclose
datoteku otvorenu u okviru programa (vie o funkciji fclose

je

esto se koriste i simbolike konstante


lentna je
za svaku

an

uspeh i za neuspeh. Naredba

c);
c);
c);
c);

int
int
int
int

isdigit(int
isspace(int
islower(int
tolower(int

sk
o

isalpha(int
isalnum(int
isupper(int
toupper(int

c);
c);
c);
c);

ro
n

int
int
int
int

iz

11.3 Zaglavlje ctype.h

bie reeno u glavi 12).

Zaglavlje

ctype.h

sadri deklaracije nekoliko funkcija za ispitivanje i kon-

vertovanje karaktera. Sve funkcije navedene u nastavku imaju argument tipa


i imaju

int

kao tip povratne vrednosti.

kt

int

vraa ne-nula vrednost ako je

isupper(c)

vraa ne-nula vrednost ako je slovo

veliko, nulu inae;

islower(c)

vraa ne-nula vrednost ako je slovo

malo, nulu inae;

isdigit(c)

vraa ne-nula vrednost ako je

cifra, nulu inae;

isalnum(c)

vraa ne-nula vrednost ako je

slovo ili cifra, nulu inae;

isspace(c)

vraa ne-nula vrednost ako je

le

isalpha(c)

slovo, nulu inae;

belina (razmak, tab, novi red,

itd), nulu inae;

toupper(c)

vraa karakter

sm karakter

c;

c konvertovan u veliko slovo ili, ukoliko je to nemogue

275

11. Pregled standardne biblioteke

tolower(c)

vraa karakter

sm karakter

c;

c konvertovan u malo slovo ili, ukoliko je to nemogue

11.4 Zaglavlje math.h


sin(double);
cos(double);
tan(double);
log(double);
pow(double);

Zaglavlje

double
double
double
double
double

asin(double);
acos(double);
atan(double); double atan2(double);
log10(double); double log2(double);
exp(double); double sqrt(double);

(2
01
5)

double
double
double
double
double

math.h sadri deklaracije vie od dvadeset esto korienih matemdouble i ima

atikih funkcija. Svaka od njih ima jedan ili dva argumenta tipa
kao tip povratne vrednosti.

sin(x)

vraa vrednost funkcije

sin(),

smatra se da je

cos(x)

vraa vrednost funkcije

cos(),

smatra se da je

koordinatni poetak.

an

zadato u radijanima;

zadato u radijanima;

-osu take , .

Vrednost nije definisana za

sk
o

vraa vrednost

(, ].

iz

Ugao je u radijanima iz intervala

exp(x)

vraa vrednost koja odgovara uglu u odnosu na

atan2(y, x)

je

double

log10(x)
log2(x)

ro
n

log(x) vraa vrednost ln (mora da vai > 0); logaritam log (za , > 0,
= 1) moe se izraunati kao log(b)/log(a).
vraa vrednost

vraa vrednost

pow(x,y)

log10

log12

(mora da vai

(mora da vai

kt

sqrt(x) vraa vrednost (mora


izraunati kao pow(x, 1/n).

> 0);

vraa vrednost

le
E

fabs(x)

> 0);

da vai

vraa apsolutnu vrednost od

> 0);

vrednost

moe se

Pored funkcija u ovom zaglavlju su definisane mnoge vane matematike


konstante. Na primer,

itd.

M_PI

ima vrednost broja

, M_E

broja

, M_SQRT2

broja

276

11. Pregled standardne biblioteke

11.5 Zaglavlje assert.h


void assert(int)
assert

assert koristi se u fazi razvoja programa da ukae na mogue


assert(izraz) vrednost celobrojnog izraza
izraz jednaka nuli, onda e na standardni tok za greke (stderr) biti
Funkcija

(2
01
5)

greke. Ukoliko je pri pozivu

ispisana poruka nalik sledeoj:

Assertion failed: expression, file filename, line nnn

i bie prekinuto izvravanje programa. Ukoliko je definisano simboliko

NDEBUG (direktivom #define) pre nego to je ukljueno zaglavlje


<assert.h>, pozivi funkcije assert se ignoriu. Funkcija assert se

je

ime

an

obino koristi u toku razvoja programa, u takozvanoj debug verziji. Kada


je program spreman za korienje, proizvodi se release verzija i tada se
pozivi funkcije

assert ignoriu (jer je tada obino definisano ime NDEBUG).


assert ukazuju na

U fazi razvoja programa, upozorenja koja generie

iz

krupne propuste u programu, ukazuju da tekui podaci ne zadovoljavaju


neki uslov koji je podrazumevan, te pomau u ispravljanju tih propusta.
Funkcija

assert

ne koristi se da ukae na greke u fazi izvravanja pro-

sk
o

grama koje nisu logike (na primer, neka datoteka ne moe da se otvori)
ve samo na one logike greke koje ne smeju da se dogode. U zavrnoj
verziji programa, pozivi funkcije

assert

imaju i dokumentacionu ulogu

ro
n

oni itaocu programa ukazuju na uslove za koje je autor programa


podrazumevao da moraju da vae u nekoj taki programa.

kt

Pitanja i zadaci za vebu


Pitanje 11.5.1.

U kojoj datoteci zaglavlja je deklarisana funkcija

le

se u programu moe dobiti vrednost konstanti

Pitanje 11.5.2.

cos?

Kako

Navesti prototip i opisati dejstvo funkcije

strcpy.

Navesti i

jednu moguu implementaciju.

Pitanje 11.5.3.
rand?

U kom zaglavlju standardne C biblioteke je deklarisana funkcija

Kako se moe, korienjem funkcije iz standardne biblioteke, dobiti pseu-

dosluajan ceo broj iz intervala [10,20]? Kako se moe dobiti pseudosluajan


ceo broj izmeu

nim

Pitanje 11.5.4.
Pitanje 11.5.5.
efekat makroa

(pri emu vai

n<m)?

ta je efekat funkcije

exit?

U kojim situacijama se koristi makro

assert

u release izvrnoj verziji?

assert?

Kakav je

(2
01
5)

Glava 12

je

Ulaz i izlaz programa

Jezik C je dizajniran kao mali jezik i ulazno/izlazne operacije nisu direktno

an

podrane samim jezikom, ve specijalizovanim funkcijama iz standardne biblioteke jezika (koja je prisutna u svakom C okruenju). Poto su ove funkcije

deo standarda jezika C, mogu se koristiti u programima uz garantovanu prenosivost programa izmeu razliitih sistema.

Svaka izvorna datoteka u kojoj

iz

se koriste ulazno/izlazne funkcije, trebalo bi da ukljui standardno zaglavlje

<stdio.h>.

sk
o

12.1 Standardni tokovi

Standardna biblioteka implementira jednostavan model tekstualnog ulaza i

ro
n

izlaza. Ulaz i izlaz se modeluju tzv. tokovima (engl. stream) podataka (obino
pojedinanih bajtova ili karaktera).
se unose sa tastature.

kt

prikazuju na ekranu.

Standardni ulaz obino ine podaci koji

Podaci koji se upuuju na standardni izlaz se obino

Pored standardnog izlaza, postoji i standardni izlaz za

greke na koji se obino upuuju poruke o grekama nastalim tokom rada pro-

le

grama i koji se, takoe, obino prikazuje na ekranu.


U mnogim okruenjima, mogue je izvriti preusmeravanje (redirekciju)

standardnog ulaza tako da se, umesto sa tastature, karakteri itaju iz neke


datoteke. Na primer, ukoliko se program pokrene sa

./prog < infile

onda program

prog

ita karaktere iz datoteke

infile,

umesto sa tastature.

Takoe, mnoga okruenja omoguavaju da se izvri preusmeravanje (redirekcija) standardnog izlaza u neku datoteku. Na primer, ukoliko se program
pokrene sa

./prog > outfile

277

278

12. Ulaz i izlaz programa

onda program

prog

upisuje karaktere u datoteku

outfile,

umesto na ekran.

Ukoliko bi se poruke o grekama tampale na standardni izlaz, zajedno sa


ostalim rezultatima rada programa, onda, u sluaju preusmeravanja standardnog izlaza u datoteku, poruke o grekama korisniku ne bi bile prikazane na
ekranu i korisnik ih ne bi video. Ovo je glavni razlog uvoenja standardnog
izlaza za greke koji se obino prikazuje na ekranu. Mogue je izvriti redirek-

(2
01
5)

ciju i standardnog izlaza za greke u datoteku, na primer:

./prog 2> errorfile

12.1.1

Ulaz i izlaz pojedinanih karaktera

Najjednostavniji mehanizam itanja sa standardnog ulaza je itanje jednog

getchar:

je

po jednog karaktera korienjem funkcije

an

int getchar(void);

getchar vraa sledei karakter sa ulaza, svaki put kada se pozove, ili
EOF kada doe do kraja toka. Simbolika konstanta EOF je definisana u zaglavlju
<stdio.h>. Njena vrednost je obino -1, ali umesto ove konkretne vrednosti
ipak treba koristiti ime EOF. Funkcija getchar (kao i jo neke srodne funkcije)
umesto tipa char koristi tip int koji je dovoljno irok da u njega mogu da se
smeste kako ASCII vrednosti od 0 do 127, tako i specijalna vrednost EOF, tj. -1.
Ako bi povratni tip funkcije getchar bio char, a povratna vrednost u nekom
konkretnom sluaju jednaka EOF (tj. konstantna vrednost -1), na sistemima na
kojima je tip char podrazumevano neoznaen, vrednost EOF bi se konvertovala
u 255, pa bi poreenje getchar() == EOF bilo netano (jer bi sa leve strane
bila vrednost 255 koja bi pre poreenja sa -1 bila promovisana u tip int).
Funkcija getchar() najee se realizuje tako to karaktere uzima iz privre-

ro
n

sk
o

iz

Funkcija

kt

menog bafera koji se puni itanjem jedne po jedne linije ulaza. Dakle, u interaktivnom radu sa programom,

getchar()

nee imati efekta sve dok se ne

le

unese prelazak u novi red ili oznaka za kraj datoteke.

Najjednostavniji mehanizam pisanja na standardni izlaz je pisanje jednog

po jednog karaktera korienjem funkcije

putchar:

int putchar(int);

Funkcija

putchar(c)
EOF

koji je ispisala ili

tampa karakter

na standardni izlaz, a vraa karakter

ukoliko je dolo do greke.

Kao primer rada sa pojedinanim karakterima, razmotrimo program koji


prepisuje standardni ulaz na standardni izlaz, pretvarajui pri tom velika u

1U

standardnoj biblioteci ne postoji funkcija koja ita samo jedan karakter, ne cekajuci

kraj ulaza.

279

12. Ulaz i izlaz programa

mala slova.

Program 12.1.
#include <stdio.h>
#include <ctype.h>

tolower deklarisana je u zaglavlju <ctype.h> i prevodi karaktere

je

Funkcija

(2
01
5)

int main()
{
int c;
while ((c = getchar()) != EOF)
putchar(tolower(c));
return 0;
}

velikih slova u karaktere malih slova, ne menjajui pri tom ostale karaktere.

getchar i putchar

iz

<stdio.h> i tolower

an

Funkcije poput

iz

<ctype.h>

su u mnogim implementacijama zapravo makroi (zasnovani na drugim funkci-

jama iz standardne biblioteke), ime se izbegava dodatno vreme i prostor potre-

Linijski ulaz i izlaz

gets:

sk
o

12.1.2

iz

ban za realizaciju funkcijskog poziva.

Biblioteka funkcija

ro
n

char* gets(char* s);

ita karaktere sa standardnog ulaza do kraja tekue linije ili do kraja datoteke
i karaktere smeta u nisku s. Oznaka kraja reda se ne smeta u nisku, a niska

s sadri
gets ini veoma
proitan, gets vraa s, a

se automatski zavrava nulom. Ne vri se nikakva provera da li niska

kt

dovoljno prostora da prihvati proitani sadraj i ovo funkciju


opasnom za korienje. U sluaju da je ulaz uspeno

le

inae vraa

NULL

pokaziva.

fputs:

Biblioteka funkcija

int puts(const char* s);

ispisuje nisku na koju ukazuje

na standardni izlaz, dodajui pri tom oznaku

za kraj reda. Zavrna nula se ne ispisuje. Funkcija


da je dolo do greke, a nenegativnu vrednost inae.

puts

vraa

EOF

u sluaju

280

12. Ulaz i izlaz programa

12.1.3

Formatirani izlaz

printf

Funkcija

printf

ve je koriena u prethodnom tekstu. Njen prototip je:

int printf(const char *format, arg1, arg2, ...);


printf

Funkcija

prevodi vrednosti osnovnih tipova podataka u serije ka-

(2
01
5)

raktera i usmerava ih na standardni izlaz. Funkcija vraa broj odtampanih


karaktera. Sluajevi korienja ove funkcije iz prethodnih glava jesu najuobiajeniji, ali svakako nisu potpuni. Pozivi funkcija

putchar

printf

mogu biti

isprepletani izlaz se vri u istom redosledu u kojem su ove funkcije pozvane.

printf

Funkcija

prevodi, formatira i tampa svoje argumente na stan-

dardni izlaz pod kontrolom date format niske . Format niska sadri dve vrste
objekata:

obine karaktere, koji se doslovno prepisuju na standardni izlaz i

specifikacije konverzija od kojih svaka uzrokuje konverziju i tampanje sledeeg

printf.

Svaka specifikacija konverzije poinje

je

uzastopnog argumenta funkcije

konverzije mogue je da se redom nau:

Znak minus (-), koji prouzrokuje levo poravnanje konvertovanog argu-

iz

menta.

Izmeu % i karaktera

an

karakterom % i zavrava se karakterima konverzije.

Broj koji specifikuje najmanju irinu polja.

Konvertovani argument se

tampa u polju koje je barem ovoliko iroko. Ukoliko je potrebno, polje

sk
o

se dopunjava razmacima sa leve (odnosno desne strane, ukoliko se trai


levo poravnanje).

.,

Taka

Broj za preciznost, koji specifikuje najvei broj karaktera koje treba tam-

ro
n

koja odvaja irinu polja od preciznosti.

pati iz niske u sluaju tampanja niske ili broj taaka iza decimalne take
u sluaju broja u pokretnom zarezu ili najmanji broj cifara u sluaju

kt

celog broja.
Karakter

le

h, ako ceo broj treba da se tampa kao short, ili l ako ceo broj
long.

treba da se tampa kao

Konverzioni karakteri
Konverzioni karakteri su prikazani u narednoj tabeli. Ukoliko se nakon %
navede pogrean konverzioni karakter, ponaanje je nedefinisano.

2 Funkcija printf

je jedna od funkcija iz standardne biblioteke koja ima promenljiv broj

argumenata (tj. broj argumenata u pozivima ne mora uvek da bude isti). Programer moe

definisati svoje funkcije sa promenljivim brojem argumenata koristei funkcije deklarisane u


standardnom zaglavlju

stdarg.h.

281

12. Ulaz i izlaz programa

Karakter

Tip

d,i
o
x,X

int
int
int

tampa se kao
dekadni broj
neoznaeni oktalni broj (bez vodeeg simbola 0)
neoznaeni heksadekadni broj (bez vodeih 0x ili 0X),
korienjem abcdef ili ABCDEF za 10, ...,15

int
int
char *

neoznaeni dekadni broj


pojedinani karakter

(2
01
5)

u
c
s

tampa karaktere niske do karaktera

\0

ili broja

karaktera navedenog u okviru preciznosti.

double

[-]m.dddddd, gde je broj d-ova odreen preciznou


(podrazumevano 6)

e,E

double

g,G

double

[-]m.dddddde+/-xx ili [-]m.ddddddE+/-xx, gde je

broj d-ova odreen preciznou (podrazumevano 6)

koristi %e ili %E ako je eksponent manji od -4 ili vei

je

ili jednak preciznosti; inae koristi %f. Zavrne nule i


zavrna decimalna taka se ne tampaju

void *

pokaziva (reprezntacija zavisna od implementacije)


nijedan argument se ne konvertuje; tampa %

an

h (za
short), l (za celobrojne tipove, za long), L (za brojeve
u pokretnom zarezu, za long double). Tako, na primer, sekvenca hd moe se
koristiti za ispisivanje podatka tipa short int, sekvenca ld moe se koristiti
za ispisivanje podatka tipa long int, a sekvenca Lf za ispisivanje podatka tipa
long double.
Primetimo da za format float ne postoji zaseban konverzioni karakter. To
je zbog toga to se svi argumenti tipa float implicitno konvertuju u tip double
prilikom poziva funkcije printf (jer je printf funkcija sa promenljivim brojem

iz

Za navedene konverzione karaktere postoje i modifikatori duine:

ro
n

sk
o

celobrojne tipove, za

argumenata kod kojih je ova promocija podrazumevana). Poevi od standarda

%f doputeno je navoditi i %lf (zanimljivo, kompilator GCC


double).
irina polja ili preciznost se mogu zadati i kao *, i tada se njihova vrednost
odreuje na osnovu vrednosti narednog argumenta (koji mora biti int). Na
primer, da se odtampa najvie max karaktera iz niske s, moe se navesti:

kt

C99 pored formata

le

to i zahteva za tip

printf("%.*s", max, s);


Prilikom poziva funkcije

printf na osnovu prvog argumenta (format niske)

odreuje se koliko jo argumenata sledi i koji su njihovi tipovi. Ukoliko se ne


navede odgovarajui broj argumenata ili se navedu argumenti neodgovarajuih
tipova, dolazi do greke. Takoe, treba razlikovati naredna dva poziva:

printf(s);
printf("%s", s);

/* pogresno ako s sadrzi karakter % */


/* bezbedno */

282

12. Ulaz i izlaz programa

Primer prikaza celih brojeva:

(2
01
5)

int
count = -9234;
printf("Celobrojni formati:\n"
"\tDekadni: %d Poravnat: %.6d Neoznacen: %u\n",
count, count, count);
printf("Broj %d prikazan kao:\n\tHex: %Xh C hex: 0x%x Oct: %o\n",
count, count, count, count );

je

Celobrojni formati:
Dekadni: -9234 Poravnat: -009234 Neoznacen: 4294958062
Broj -9234 prikazan kao:
Hex: FFFFDBEEh C hex: 0xffffdbee Oct: 37777755756

iz

an

/* Prikaz konstanti zapisanih u razlicitim osnovama. */


printf("Cifre 10 predstavljaju:\n");
printf("\tHex: %i Octal: %i Decimal: %i\n",
0x10, 010, 10);

sk
o

Cifre 10 predstavljaju:
Hex: 16 Octal: 8 Decimal: 10

ro
n

Primer prikaza karaktera:

kt

char ch = h;
printf("Karakteri u polju date sirine:\n%10c%c\n", ch, ch);

le

Karakteri u polju date sirine:


hh

Primer prikaza brojeva u pokretnom zarezu:


double fp = 251.7366;
printf("Brojevi u pokretnom zarezu:\n\t%f %.2f %e %E\n",
fp, fp, fp, fp);
Realni brojevi:
251.736600 251.74 2.517366e+002 2.517366E+002

283

12. Ulaz i izlaz programa

Primer prikaza niski:


Ovaj primer prikazuje navoenje irine polja, poravnanja i preciznosti prilikom
tampanja niski.
tampanje niske

U narednoj tabeli dat je efekat razliitih format niski na

"hello, world"

(12 karaktera). Dvotake su stavljene radi

boljeg ilustrovanja efekta raznih formata.

Formatirani ulaz

Funkcija

scanf

(2
01
5)

scanf

an

12.1.4

:hello, world:
:hello, world:
:hello, wor:
:hello, world:
:hello, world:
:hello, world
:
:
hello, wor:
:hello, wor
:

je

:%s:
:%10s:
:%.10s:
:%-10s:
:%.15s:
:%-15s:
:%15.10s:
:%-15.10s:

je ulazni analogon funkcije

printf.

Funkcija

scanf

ita

karaktere sa standardnog ulaza, interpretira ih na osnovu specifikacije navedene

format niskom i smeta rezultat na mesta odreena ostalim argumentima:

iz

int scanf(const char *format, ...)

sk
o

Opis format niske dat je u nastavku. Ostali argumenti moraju biti pokazivai i odreuju lokacije na koje se smeta konvertovani ulaz. Kao i u sluaju
funkcije

printf,

ovde e biti dat samo prikaz najeih naina korienja ove

scanf

prestaje sa radom kada iscrpi svoju format nisku ili

ro
n

funkcije. Funkcija

kada neki deo ulaza ne moe da se uklopi u shemu navedenu format niskom.
Funkcija vraa broj uspeno uklopljenih i dodeljenih izlaznih podataka.
sluaju kraja datoteke, funkcija vraa

EOF.

Ova vrednost je razliita od vred-

kt

nosti 0 koja se vraa u sluaju da tekui karakter sa ulaza ne moe da se uklopi


u prvu specifikaciju zadatu format niskom. Svaki naredni poziv funkcije

scanf

le

nastavlja tano od mesta na ulazu na kojem je prethodni poziv stao.


Format niska sadri specifikacije konverzija kojima se kontrolie konverzija

teksta proitanog sa ulaza. Format niska moe da sadri:

Praznine ili tabulatore koji se ne zanemaruju.

Obine karaktere (ne %), za koje se oekuje da se poklope sa sledeim


ne-belinama sa standardnog ulaza.

Specifikacije konverzija, koje se sastoje od karaktera %, opcionog karaktera

koji spreava dodeljivanje, opcionog broja kojim se navodi maksi-

malna irina polja, kao i od konverzionog karaktera.

Specifikacija konverzije odreuje konverziju narednog ulaznog polja. Obino


se rezultat ove konverzije upisuje u promenljivu na koju pokazuje naredni

284

12. Ulaz i izlaz programa

ulazni argument. Ipak, ako se navede karakter

*,

konvertovana vrednost

se preskae i nigde ne dodeljuje. Ulazno polje se definie kao niska karaktera koji nisu beline.

Ono se prostire ili do narednog karaktera beline

ili do irine polja, ako je ona eksplicitno zadana. Ovo znai da funkcija

scanf moe da ita ulaz i iz nekoliko razliitih linija sa standardnog ulaza,


3

jer se prelasci u novi red tretiraju kao beline .


Konverzioni karakter upuuje na eljenu interpretaciju ulaznog polja.

(2
01
5)

U narednoj tabeli navedeni su konverzioni karakteri.


Karakter

Tip

Ulazni podatak

int*
int*

d
i

dekadni ceo broj

ceo broj, moe biti i oktalan (ako ima vodeu 0)


ili heksadekadan (vodei 0x ili 0X)

x
c

oktalni ceo broj (sa ili bez vodee nule)

je

neoznaeni dekadni broj

heksadekadni broj (sa ili bez vodeih 0x ili 0X)

an

int*
unsigned*
int*
char*

karakter, naredni karakter sa ulaza se smeta na


navedenu lokaciju; uobiajeno preskakanje belina

se ne vri u ovom sluaju; Za itanje prvog ne-

iz

belog karaktera, koristi se

char*

%1s

niska (bez navodnika), ukazuje na niz karaktera


dovoljno dugaak za nisku ukljuujui i termi-

\0

sk
o

nalnu

double*

e,f,g

koja se automatski dopisuje

broj u pokretnom zarezu sa opcionim znakom, op-

ro
n

cionom decimalnom takom i opcionim eksponen-

tom

doslovno %; ne vri se dodela

printf, ispred karaktera konverzije d, i, o, u, i x


h koji ukazuje da se u listi argumenata oekuje
pokaziva na short, karakter l koji ukazuje da se u listi argumenata oekuje
pokaziva na long ili karakter L koji ukazuje da se u listi argumenata oekuje
pokaziva na long double.
Kao to je ve reeno, argumenti funkcije scanf moraju biti pokazivai.
Slino kao kod funkcije

le

kt

mogue je navesti i karakter

Ubedljivo najei oblik pogrenog korienja ove funkcije je:

scanf("%d", n);
umesto

scanf("%d", &n);
3 Pod

belinama se podrazumevaju razmaci, tabulatori, prelasci u novi redovi (carriage

return i/ili line feed), vertikalni tabulatori i formfeed.

285

12. Ulaz i izlaz programa

Ova greka se obino ne otkriva tokom kompilacije.


Funkcija

scanf

ignorie beline u okviru format niske.

se beline tokom itanja ulaznih vrednosti.

Pozivi funkcije

Takoe, preskau

scanf

mogu biti

pomeani sa pozivima drugih funkcija koje itaju standardni ulaz.

Naredni

poziv bilo koje ulazne funkcije e proitati prvi karakter koji nije proitan

scanf.

Primeri
U narednom primeru, korienjem funkcije

scanf

implementiran je jednos-

tavni kalkulator:

Program 12.2.
#include <stdio.h>

an

je

int main()
{
double sum, v;

(2
01
5)

tokom poziva funkcije

iz

sum = 0.0;
while (scanf("%f", &v) == 1)
printf("\t%.2f\n", sum += v);
return 0;

sk
o

Datume sa ulaza koji su u formatu

25 Dec 1988, mogue je itati korien-

ro
n

jem:

kt

int day, year;


char monthname[20];

scanf("%d %s %d", &day, monthname, &year);


monthname nema potrebe navesti simbol &, jer je ime niza ve pokazi-

le
Ispred

va. Doslovni karakteri se mogu pojaviti u okviru format niske i u tom sluaju
se oni oekuju i na ulazu. Tako, za itanje datuma sa ulaza koji su u formatu

12/25/1988,

mogue je koristiti:

int day, month, year;


scanf("%d/%d/%d", &month, &day, &year);

12.2 Ulaz iz niske i izlaz u nisku


Funkcija

printf

vri ispis formatiranog teksta na standardni izlaz. Stan-

dardna biblioteka jezika C definie funkciju

sprintf

koja je veoma slina

286

12. Ulaz i izlaz programa

funkciji

printf,

ali rezultat njenog rada je popunjavanje niske karaktera for-

matiranim tekstom. Prototip funkcije je:

int sprintf(char *string, const char *format, arg1, arg2, ...);


Ova funkcija formatira argumente

arg1, arg2,

. . . na osnovu format niske,

vajui da je ona dovoljno velika da smesti rezultat.


Slino funkciji

sprintf

(2
01
5)

a rezultat smeta u nisku karaktera prosleenu kao prvi argument, podrazumekoja vri ispis u nisku karaktera umesto na stan-

dardni izlaz, standardna biblioteka jezika C definie i funkciju


analogna funkciji

scanf,

sscanf

koja je

osim to ulaz ita iz date niske karaktera, umesto sa

standardnog ulaza.

int sscanf(const char* input, char* format, ...)

je

Navedimo primer korienja ove funkcije. Da bi se proitao ulaz iji format


nije fiksiran, najee je dobro proitati celu liniju sa ulaza, a zatim je analizirati

sscanf.

Da bi se proitao datum sa ulaza u nekom od prethodno

an

korienjem

navedena formata, mogue je koristiti:

ro
n

sk
o

iz

while (getline(line, sizeof(line)) > 0) {


if (sscanf(line, "%d %s %d", &day, monthname, &year) == 3)
printf("valid: %s\n", line); /* 25 Dec 1988 */
else if (sscanf(line, "%d/%d/%d", &month, &day, &year) == 3)
printf("valid: %s\n", line); /* 12/25/1988 */
else
printf("invalid: %s\n", line); /* pogresan oblik */
}

kt

12.3 Ulaz iz datoteka i izlaz u datoteke


Do sada opisane funkcije za ulaz i izlaz su uglavnom itale sa standardnog

le

ulaza i pisale na standardni izlaz, koji su automatski definisani i od strane


Iako je, me-

operativnog sistema i kojima program automatski ima pristup.

hanizmima preusmeravanja, bilo mogue izvesti programski pristup lokalnim


datotekama, mehanizam preusmeravanja je veoma ogranien jer ne daje mogunost istovremenog itanja (ili pisanja) datoteke i standardnog ulaza kao ni mogunost istovremenog itanja (ili pisanja) vie datoteka. Zbog toga, jezik C nudi
direktnu podrku za rad sa lokalnim datotekama, bez potrebe za korienjem
usluga preusmeravanja operativnog sistema. Sve potrebne deklaracije i za rad
sa datotekama nalaze u zaglavlju

<stdio.h>.

287

12. Ulaz i izlaz programa

12.3.1

Tekstualne i binarne datoteke

Iako se svaka datoteka moe razmatrati kao niz bajtova, obino razlikujemo
datoteke koje sadre tekstualni sadraj od datoteka koje sadre binarni sadraj.
U zavisnosti od toga da li se u datoteci nalazi tekstualni ili binarni sadraj,
razlikuju se dva razliita naina pristupa.
Prvi nain je prilagoen tekstualnim datotekama iji sadraj u principu

(2
01
5)

ine vidljivi karakteri, sa dodatkom oznake kraja reda i horizontalnog tabulatora. Ovakve datoteke se obino obrauju liniju po liniju, to je karakteristino
za tekst.

Na primer, iz datoteke se ita linija po linija ili se u datoteku up-

isuje linija po linija. Oigledno, u ovom sluaju oznaka za kraj linije je veoma
relevantna i znaajna. Meutim, na razliitim sistemima tekst se kodira na ra-

zliite naine i na nekim sistemima kraj reda u tekstualnoj datoteci se zapisuje


sa dva karaktera (na primer, sa

\r\n

na sistemima Windows), a na nekim

sa samo jednim karakterom (na primer, sa

\n

na sistemu Linux).

Da bi se

je

ovakvi detalji sakrili od programera i kako programer ne bi morao da se stara


o ovakvim specifinostima, C jezik nudi tekstualni mod rada sa datotekama.

an

Ukoliko se datoteka otvori u tekstualnom modu, prilikom svakog itanja i upisa u datoteku vri se konverzija iz podrazumevanog formata oznaavanja kraja

\n.

Tako e na Windows sistemima dva karaktera

na kraju reda biti proitana samo kao

\n bie upisana dva karaktera \r\n.

iz

upisuje

\n

reda u jedinstven karakter

\r\n

i, obratno, kada se u datoteku

Na ovaj nain pojednostavljuje se

i olakava rad sa datotekama koje ine tekstualni podaci. Da bi interpretiranje

sk
o

sadraja tekstualne datoteke bilo uvek ispravno treba izbegavati, na primer,


pravljenje tekstualnih datoteka koja na kraju poslednjeg reda nemaju oznaku
kraja reda, izbegavati razmake u linijama nakon oznake za kraj reda, izbegavati da tekstualne datoteke sadre karaktere koji nisu vidljivi karakteri, oznake

ro
n

kraja reda i tabulatora i slino.

Drugi nain pristupa datotekama prilagoen je datotekama iji sadraj ne


predstavlja tekst i u kojima se mogu nai bajtovi svih vrednosti od 0 do 255

jpg

ili

kt

(na primer,

zip

datoteke). Za obradu ovakvih datoteka, jezik C nudi

binarni mod rada sa datotekama.

U ovom sluaju nema nikakve konverzije

le

i interpretiranja karaktera prilikom upisa i itanja i svaki bajt koji postoji u


datoteci se ita doslovno.

Razlika izmeu tekstualnih i binarnih datoteka jo je otrija u jezicima koji

podravaju Unicode, jer se u tom sluaju vie bajtova ita i konvertuje u jedan
karakter.

12.3.2

Pristupanje datoteci

Da bi se pristupilo datoteci, bilo za itanje, bilo za pisanje, potrebno je


izvriti odreenu vrstu povezivanja datoteke i programa.
biblioteka funkcija

fopen:

Za ovo se koristi

FILE* fopen(const char* filename, const char* mode);

288

12. Ulaz i izlaz programa

Funkcija

fopen dobija nisku koja sadri ime datoteke (na primer, datoteka.txt)

i uz pomo usluga operativnog sistema (koje nee na ovom mestu biti detaljnije opisane) vraa pokaziva na strukturu (najee dinamiki alociranu)
koja predstavlja sponu izmeu lokalne datoteke i programa i koja sadri informacije o datoteci koje e biti koriene prilikom svakog pristupa datoteci. Ove
informacije mogu da ukljue adresu poetka bafera (prihvatnik, eng. buffer)
kroz koji se vri komunikacija sa datotekom, tekuu poziciju u okviru bafera,

(2
01
5)

informaciju o tome da li se dolo do kraja datoteke, da li je dolo do greke i


slino. Programer ne mora i ne bi trebalo da direktno koristi ove informacije,

FILE i da ga prosleuju svim


FILE je ime tipa, a ne ime
typedef (videti poglavlje 6.7.5).

ve je dovoljno da uva pokaziva na strukturu

funkcijama koje treba da pristupaju datoteci. Ime


strukture; ovo ime je uvedeno korienjem
Prvi argument funkcije

fopen

je niska karaktera koja sadri ime datoteke.

Drugi argument je niska karaktera koja predstavlja nain (mod) otvaranja daukljuuju itanje (read,

"r"),

pisanje (write,

Dozvoljeni modovi

je

toteke i koja ukazuje na to kako e se datoteka koristiti.

"w")

i dopisivanje (append,

"a").

an

Ako se datoteka koja ne postoji na sistemu otvara za pisanje ili dopisivanje,


onda se ona kreira (ukoliko je to mogue). U sluaju da se postojea datoteka
otvara za pisanje, njen stari sadraj se brie, dok se u sluaju otvaranja za

dopisivanje stari sadraj zadrava, a novi sadraj upisuje nakon njega. Ukoliko

iz

se pokuava itanje datoteke koja ne postoji dobija se greka. Takoe, greka


se javlja i u sluaju da se pokuava pristup datoteci za koju program nema
odgovarajue dozvole.

U sluaju greke funkcija

fopen

vraa

NULL.

Modovi

ukazuju da e rad sa datotekom podrazumevati i itanje i pisanje

sk
o

r+, w+ i a+

(ili dopisivanje). U sluaju da se eli otvaranje binarne datoteke, na mod se


dopisuje

"b"

(na primer,

rb, wb, a+b,

. . . ).

ro
n

Kada se C program pokrene, operativni sistem otvara tri toka podataka


(standardni ulaz, stadnardni izlaz i standardni izlaz za greke), kao da su datoteke i obezbeuje pokazivae kojima im se moe pristupati. Ti pokazivai se

kt

nazivaju:

le

FILE* stdin;
FILE* stdout;
FILE* stderr;
Funkcija

int fclose(FILE *fp)


prekida vezu izmeu programa i datoteke koju je funkcija
Pozivom funkcije

fclose

fopen

ostvarila.

prazne se baferi koji privremeno uvaju sadraj da-

toteka ime se obezbeuje da sadraj zaista bude upisan na disk.


kreirana struktura

FILE nije vie potrebna i uklanja se iz memorije.

Takoe,

S obzirom

na to da veina operativnih sistema ograniava broj datoteka koje mogu biti


istovremeno otvorene, dobra je praksa zatvarati datoteke im prestanu da budu

289

12. Ulaz i izlaz programa

potrebne. U sluaju da program normalno zavri svaka otvorena datoteka se


automatski zatvara.

12.3.3

Ulaz i izlaz pojedinanih karaktera

Nakon to se otvori datoteka, iz nje se ita ili se u nju pie sadraj.

To

Funkcija

FILE

getc

(2
01
5)

mogu biti i pojedinani karakteri.


vraa naredni karakter iz datoteke odreene prosleenim

pokazivaem ili

EOF

u sluaju kraja datoteke ili greke.

int getc(FILE *fp)


Slino, funkcija

FILE

putc upisuje dati karakter u datoteku odreenu prosleenim


EOF u sluaju greke. Iako su

pokazivaem i vraa upisani karakter ili

je

greke prilikom izlaza retke, one se nekada javljaju (na primer, ako se prepuni

int putc(int c, FILE *fp);

getchar i putchar, getc i putc mogu biti definisani kao makroi,

Slino kao i

an

hard disk), pa bi trebalo vriti i ovakve provere.

ulazna.txt u datoteku izlazna.txt

iz

a ne funkcije.

Naredni primer kopira sadraj datoteke

itajui i piui pritom pojedinane karaktere.

Naglasimo da je ovo veoma

Program 12.3.

sk
o

neefikasan nain kopiranja datoteka.

ro
n

#include <stdio.h>

le

kt

/* filecopy: copy file ifp to file ofp */


void filecopy(FILE *ifp, FILE *ofp)
{
int c;
while ((c = getc(ifp)) != EOF)
putc(c, ofp);
}
int main()
{
FILE *ulaz, *izlaz;
ulaz = fopen("ulazna.txt","r");
if(ulaz == NULL)
return -1;
izlaz = fopen("izlazna.txt","w");

290

12. Ulaz i izlaz programa

if(izlaz == NULL)
return -1;
filecopy(ulaz,izlaz);

Funkcija

(2
01
5)

fclose(ulaz);
fclose(izlaz);
return 0;
ungetc:

int ungetc (int c, FILE *fp);

vraa karakter u datoteku i vraa identifikator pozicije datoteke tako da

je

naredni poziv operacije itanja nad ovom datotekom vrati upravo vraeni karakter. Ovaj karakter moe, ali ne mora biti jednak poslednjem proitanom karak-

an

teru datoteke. Iako ova funkcije utie na naredne operacije itanja datoteke,
ona ne menja fiziki sadraj same datoteke (naime vraeni karakteri se najee
smetaju u memorijski bafer odakle se dalje itaju, a ne u datoteku na disku).

ungetc vraa EOF ukoliko je dolo do greke, a vraeni karakter inae.

Funkcija

iz

Naredni primer ita karaktere iz datoteke dok su u pitanju cifre i pri tom
gradi dekadni ceo broj. Poto poslednji karakter koji je proitan nije cifra, on

sk
o

se (uslovno reeno) vraa u tok kako ne bi bio izostavljen prilikom narednih


itanja.

#include <stdio.h>

le

kt

ro
n

int readint(FILE* fp) {


int val = 0, c;
while (isdigit(c = getc(fp)))
val = 10*val + (c - 0);
ungetc(c, fp);
}

12.3.4

Provera greaka i kraja datoteke

Funkcija

feof vraa vrednost tano (ne-nula) ukoliko se dolo do kraja date

datoteke.

int feof(FILE *fp)


Funkcija

ferror

vraa vrednost tano (ne-nule) ukoliko se dolo do greke

u radu sa datotekom.

291

12. Ulaz i izlaz programa

int ferror(FILE *fp)

12.3.5

Linijski ulaz i izlaz

Standardna biblioteka definie i funkcije za rad sa tekstualnim datotekama


Funkcija

fgets

(2
01
5)

liniju po liniju.

ita jednu liniju iz datoteke.

char *fgets(char *line, int maxline, FILE *fp)

fgets ita sledeu liniju iz datoteke (ukljuujui oznaku kraja


fp i rezultat smeta u nisku line. Moe da bude proitano
najvie maxline-1 karaktera. Rezultujua niska zavrava se karakterom \0.
U normalnom toku izvravanja, funkcija fgets vraa pokaziva na poetak
linije, a u sluaju kraja datoteke ili greke vraa NULL.
Funkcija fputs ispisuje nisku (koja ne mora da sadri oznaku kraja reda)
Funkcija

an

je

reda) iz datoteke

u datoteku:

EOF

u sluaju da doe do greke, a neki nenegativan broj inae.

Za razliku od funkcija

puts

fgets i fputs,

funkcija

gets

brie zavrni

\n,

ga dodaje.

sk
o

funkcija

iz

Ona vraa

int fputs(const char *line, FILE *fp)

Implementacija bibliotekih funkcija nije znaajno razliita od implementacije


ostalih funkcija, to je ilustrovano implementacijama funkcija

fgets i fputs,

ro
n

u obliku doslovno preuzetom iz jedne realne implementacije C biblioteke:

le

kt

/* fgets: get at most n chars from iop */


char *fgets(char *s, int n, FILE *iop)
{
register int c;
register char *cs;

cs = s;
while (--n > 0 && (c = getc(iop)) != EOF)
if ((*cs++ = c) == \n)
break;
*cs = \0;
return (c == EOF && cs == s) ? NULL : s;

/* fputs: put string s on file iop */


int fputs(char *s, FILE *iop)
{

292

12. Ulaz i izlaz programa

register int c;
while (c = *s++)
putc(c, iop);
return ferror(iop) ? EOF : 0;

Korienjem funkcije

fgets jednostavno je napraviti funkciju koja ita liniju

(2
01
5)

po liniju sa standardnog ulaza, vraajui duinu proitane linije, odnosno nulu


kada liniju nije mogue proitati:

Formatirani ulaz i izlaz

iz

12.3.6

an

je

/* getline: read a line, return length */


int getline(char *line, int max)
{
if (fgets(line, max, stdin) == NULL)
return 0;
else
return strlen(line);
}

Za formatirani ulaz i izlaz mogu se koristiti funkcije

scanf i printf,

sk
o

One su identine funkcijama

fscanf

fprintf.
FILE

osim to je prvi argument

pokaziva koji ukazuje na datoteku iz koje se ita, odnosno u koju se pie.


Format niska je u ovom sluaju drugi argument.

kt

ro
n

int fscanf(FILE *fp, const char *format, ...)


int fprintf(FILE *fp, const char *format, ...)

Rad sa binarnim datotekama

le

12.3.7

Standardna biblioteka nudi funkcije za direktno itanje i pisanje bajtova

u binarne datoteke. Progameru su na raspolaganju i funkcije za pozicioniranje u okviru datoteka, pa se binarne datoteke mogu koristiti i kao neke vrste
memorije sa slobodnim pristupom.

fread se koristi za itanje niza slogova iz binarne


fwrite za pisanje niza slogova u binarnu datoteku.

Funkcija
funkcija

size_t fread(void *ptr, size_t size,


size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size,
size_t nmemb, FILE *stream);

datoteke, a

293

12. Ulaz i izlaz programa

Za ove funkcije, prvi argument je adresa na koju se smetaju proitani slogovi


iz datoteke, odnosno u kojoj su smeteni slogovi koji e biti upisani u datoteku. Drugi argument predstavlja veliina jednog sloga, trei broj slogova, a
etvrti pokaziva povezan datoteke. Funkcije vraaju broj uspeno proitanih,
odnosno upisanih slogova.
Funkcija

fseek

slui za pozicioniranje na mesto u datoteci sa koga e biti

proitan ili na koje e biti upisan sledei podatak.

Funkcija

ftell

vraa

(2
01
5)

trenutnu poziciju u datoteci (u obliku pomeraja od poetka izraenog u broju


bajtova). Iako primena ovih funkcija nije striktno ograniena na binarne datoteke, one se najee koriste sa binarnim datotekama.

int fseek (FILE * stream, long int offset, int origin);


long int ftell (FILE * stream);

je

Prvi argument obe funkcije je pokaziva na datoteku. Funkcija

fseek kao drugi

argument dobija pomeraj izraen u broju bajtova, dok su za trei argument


na poetak datoteke,
na tekuu poziciju i

SEEK_SET koja oznaava da se pomeraj rauna u


SEEK_CUR koji oznaava da se pomeraj rauna u
SEEK_END koji oznaava da se pomeraj rauna u

an

dozvoljene vrednosti

odnosu

na kraj datoteke.

odnosu
odnosu

iz

Sledei primer ilustruje primenu ovih funkcija.

Program 12.4.

sk
o

#include <stdio.h>

kt

ro
n

int main() {
struct S {
int broj;
int kvadrat;
} s;

le

FILE* f;
int i;

if ((f = fopen("junk", "r+b")) == NULL) {


fprintf(stderr, "Greska prilikom otvaranja datoteke");
return 1;
}
for (i = 1; i <= 5; i++) {
s.broj = i; s.kvadrat = i*i;
fwrite(&s, sizeof(struct S), 1, f);
}
printf("Upisano je %ld bajtova\n", ftell(f));

294

12. Ulaz i izlaz programa

for (i = 5; i > 0; i--) {


fseek(f, (i-1)*sizeof(struct S), SEEK_SET);
fread(&s, sizeof(struct S), 1, f);
printf("%3d %3d\n", s.broj, s.kvadrat);
}

(2
01
5)

fclose(f);

12.4 Argumenti komandne linije programa

Jedan nain da se odreeni podaci proslede programu je i da se navedu


u komandnoj liniji prilikom njegovog pokretanja.

Argumenti koji su tako

(koji se obino naziva

argc,

main.

je

navedeni prenose se programu kao argumenti funkcije

Prvi argument

od engleskog argument count ) je broj argume-

pokretanja programa.

an

nata komandne linije (ukljuujui i sm naziv programa) navedenih prilikom


Drugi argument (koji se obino naziva

argv,

od en-

gleskog argument vector ) je niz niski karaktera koje sadre argumente svaka
Ako je

argc

tano 1, onda nisu navedeni dodatni argumenti nakon

iz

argv[0].

niska direktno odgovara jednom argumentu. Nazivu programa odgovara niska

argv[0] je ime programa, argv[1] do argv[argc-1]


argv[argc] sadri vrednost NULL.
Identifikatori argc i argv su proizvoljni i funkcija main moe biti deklarisana i
imena programa. Dakle,

na sledei nain:

sk
o

su tekstovi argumenata programa, a element

ro
n

int main (int br_argumenata, char* argumenti[]);


Naredni jednostavan program tampa broj argumenata kao i sadraj vektora
argumenata.

kt

Program 12.5.

le

#include <stdio.h>
int main(int argc, char* argv[]) {
int i;
printf("argc = %d\n", argc);

/* Nulti argument uvek je ime programa (na primer, a.out) */


for (i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
return 0;

Ukoliko se program prevede sa gcc -o echoargs echoargs.c


./echoargs -U zdravo svima "dobar dan", ispisae

i pozove sa

295

12. Ulaz i izlaz programa

./echoargs
-U
zdravo
svima
dobar dan

(2
01
5)

argc = 5
argv[0] =
argv[1] =
argv[2] =
argv[3] =
argv[4] =

Jedna od moguih upotreba argumenata komandne linije je da se programu


navedu razliite opcije.

Obiaj je da se opcije kodiraju pojedinanim karak-

-. Pri tome, esto je predvieno da se iza


- moe navesti vie karaktera koji odreuju opcije. Na primer,

terima i da se navode iza karaktera


jednog simbola
pozivom:

programu se zadaju opcije

a, b, c, d e i f

134 i zdravo.

je

./program -a -bcd 134 -ef zdravo


i argumenti

an

Naredni program ispisuje sve opcije pronaene u komandnoj liniji:

Program 12.6.

iz

#include <stdio.h>

le

kt

ro
n

sk
o

int main(int argc, char* argv[]) {


/* Za svaki argument komande linije, pocevsi od argv[1]
(preskace se ime programa) */
int i;
for (i = 1; i < argc; i++) {
/* Ukoliko i-ti argument pocinje crticom */
if (argv[i][0] == -) {
/* Ispisuju se sva njegova slova od pozicije 1 */
int j;
for (j = 1; argv[i][j] != \0; j++)
printf("Prisutna je opcija : %c\n", argv[i][j]);
}
}
return 0;
}
Krae, ali dosta kompleksnije reenje se intenzivno zasniva na pokazivakoj

aritmetici i prioritetu operatora.

Program 12.7.
#include <stdio.h>
int main(int argc, char* argv[]) {
char c;

296

12. Ulaz i izlaz programa

(2
01
5)

/* Dok jos ima argumenata i dok je na poziciji 0 crtica */


while(--argc>0 && (*++argv)[0]==-)
/* Dok se ne dodje do kraja tekuce niske */
while (c=*++argv[0])
printf("Prisutna je opcija : %c\n",c);
return 0;

Pitanja i zadaci za vebu


Pitanje 12.1.
ta je to

stderr?

Pitanje 12.2.

U kojoj datoteci zaglavlja se nalazi deklaracija funkcije

printf?

U kojoj datoteci zaglavlja se nalazi deklaracija funkcije

an

Pitanje 12.3.

je

Navesti njen prototip. Koju vrednost vraa ova funkcija?

scanf?

Navesti njen prototip. Koju vrednost vraa ova funkcija?


ta, u format niski koja je argument funkcije

Pitanje 12.4.

printf, specifikuje

primer:

iz

opcioni broj koji se navodi iza opcione take za argument koji je niska (na

printf("%.2s", "zdravo");)?

ta specifikuje opcioni broj koji se navodi iza opcione take za argument koji

Pitanje 12.5.

printf("%.2f", 3.2453);)?

sk
o

realan broj (na primer:

printf("#%6.*f#", 2, 3.14159);?
printf("%6.1f",1/7);?

ta je rezultat poziva

ro
n

ta je rezultat poziva

Pitanje 12.6.

Navesti prototip funkcije iz standardne biblioteke koja omoguava

formatirani ispis u nisku.

Navesti primer korienja.

O emu treba voditi

kt

rauna prilikom pozivanja ove funkcije?

Pitanje 12.7.

Na to jednostavniji nain u nisku

le

upisati vrednosti

1/7 i 2/7

n (deklarisanu sa char n[8];)

sa po pet cifara iza decimalnog zareza i razdvojene

razmakom.

Pitanje 12.8.

Koju vrednost vraa

Pitanje 12.9.

Navesti prototip funkcije

Kakva je razlika izmeu funkcija


funkcija

puts i fputs?

Pitanje 12.10.
Pitanje 12.11.

sscanf("1 2","%i%i%i", &a, &b, &c);


gets

gets. Navesti prototip funkcije puts.


i fgets? Kakva je razlika izmeu

U emu se razlikuju tekstualne i binarne datoteke?


Navesti prototip funkcije

fopen.

funkcija ukoliko se datoteka ne moe otvoriti?

Koju vrednost vraa ova

297

12. Ulaz i izlaz programa

Pitanje 12.12.

Navesti prototip standardne biblioteke funkcije za zatvaranje

datoteke. Koju vrednost ona vraa? Navesti bar dva razloga zbog kojih je preporuljivo zatvoriti datoteku im se zavri njeno korienje.

Pitanje 12.13.

Moe se desiti da nakon prekida rada programa u toku njegovog

izvravanja, datoteka u koju su u okviru prorama upisani neki podaci funkcijom


ipak bude prazna. Zato se to moe desiti?

Pitanje 12.14.

Navesti prototip funkcije kojom se proverava da li dostignut

(2
01
5)

fprintf

p?

kraj datoteke sa datotekim pokazivaem

Pitanje 12.15.

Ukratko opisati funkcije za odreivanje mesta u datoteci.

Pitanje 12.16.

emu slue funkcije

fseek i fsetpos?

tekstualne i binarne datoteke?

Pitanje 12.17.

Da li one isto rade za

ta moe biti vrednost argumenta offset u pozivu


fseek (int fseek(FILE *stream, long offset, int origin)) za

je

an

lnu datoteku?

Pitanje 12.18.

Navesti prototip funkcije

Pitanje 12.19.

Kako se, u okviru funkcije

main

sa argumentima.

main,

moe ispisati ime programa

iz

koji se izvrava?

Zadatak 12.1.

funkcije

tekstua-

Napisati funkciju

main

koja izraunava i ispisuje zbir svih

sk
o

argumenata navedenih u komandnoj liniji (pretpostaviti da e svi argumenti


biti celi brojevi koji se mogu zapisati u okviru tipa

Zadatak 12.2.

int).

Napisati program koji iz datoteke, ije se ime zadaje kao prvi

a za-

ro
n

argument komandne linije, ita prvo dimenziju kvadratne matrice

tim elemente matrice (pretpostavljamo da se u datoteci nalaze brojevi pravilno


rasporee
. ni, odnosno da za dato , sledi elemenata matrice). Matricu
dinamiki alocirati. Nakon toga, na standardni izlaz ispisati redni broj kolone

kt

koja ima najvei zbir elemenata. Na primer, za datoteka sa sadrajem:

le

3
1 2 3
7 3 4
5 3 1

0 (jer je
2 + 3 + 3 = 8, u

program treba da ispie redni broj

1 + 7 + 5 = 13,

Zadatak 12.3.

u prvoj

Data je datoteka

suma elemenata u nultoj koloni


drugoj

apsolventi.txt.

3 + 4 + 1 = 8).

U svakom redu datoteke

nalaze se podaci o apsolventu: ime (ne vee od 20 karaktera), prezime (ne vee
od 20 karaktera), broj preostalih ispita. Datoteka je dobro formatirana i broj
redova datoteke nije poznat. Potrebno je uitati podatke iz datoteke, odrediti
prosean broj zaostalih ispita i potom ispisati imena i prezimena studenta koji
imaju vei broj zaostalih ispita od prosenog u datoteku ije ime je zadato kao
argument komadne linije. NAPOMENA: koristiti strukturu

298

12. Ulaz i izlaz programa

typedef struct {
char ime[20];
char prezime[20];
unsigned br_ispita;
} APSOLVENT;

Zadatak 12.4.

Napisati funkciju

unsigned btoi(char s[], unsigned char b);

koja odreuje vrednost zapisa datog neoznaenog broja


pisati zatim i funkciju

(2
01
5)

u datoj osnovi

void itob(unsigned n, unsigned char b, char s[]);


n zapisuje u datoj osnovi b i smeta rezultat

koja datu vrednost

b.

Na-

u nisku

s.

Napisati zatim program koji ita liniju po liniju datoteke koja se zadaje kao

je

prvi argument komandne linije i obrauje ih sve dok ne naie na praznu liniju.
Svaka linija sadri jedan dekadni, oktalni ili heksadekadni broj (zapisan kako

an

se zapisuju konstante u programskom jeziku C). Program za svaki uneti broj


u datoteku koja se zadaje kao drugi argument komandne linije ispisuje njegov

le

kt

ro
n

sk
o

iz

binarni zapis. Pretpostaviti da e svi uneti brojevi biti u opsegu tipa

unsigned
.

(2
01
5)

Dodatak A

le

kt

ro
n

sk
o

iz

an

je

Tabela prioriteta operatora

299

300

A. Tabela prioriteta operatora

Opis

Asocijativnost

poziv funkcije

sleva na desno

indeksni pristup elementu niza


pristup lanu strukture/unije
pristup lanu strukture/unije preko pokazivaa
postfiksni inkrement/dekrement

logika negacija/bitski komplement


eksplicitna konverzija tipa (cast)
dereferenciranje
referenciranje (adresa)
veliina u bajtovima
sabiranje i oduzimanje

an

bitsko pomeranje ulevo i udesno


relacije manje, manje jednako
relacije vee, vee jednako

iz

bitska konjunkcija

relacija jednako, razliito

sleva na desno

je

mnoenje, deljenje, ostatak

sleva na desno
sleva na desno
sleva na desno
sleva na desno

bitska ekskluzivna disjunkcija

sleva na desno

bitska disjunkcija

sleva na desno

logika konjunkcija

sleva na desno

logika disjunkcija

sleva na desno

ternarni uslovni

zdesna na levo

dodele

zdesna na levo

kt

le
E

zdesna na levo

unarni plus/minus

(2
01
5)

prefiksni inkrement/dekrement

ro
n

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

sk
o

Operator

spajanje izraza u jedan

sleva na desno

(2
01
5)

Dodatak B

je

Reenja zadataka

an

Softver savremenih raunara

Reenje zadatka 1.4:

Reenje se zasniva na algoritmu opisanom u primeru 3.3.

le

kt

ro
n

sk
o

cx privremeno uva ostale potrebne vrednosti.


200 uva rezultujua vrednost .
mov [200], 0
mov ax, 0
mov bx, 1
petlja:
cmp ax, bx
je uvecanje
mov cx, [100]
cmp cx, ax
je kraj
add ax, 1
jmp petlja
uvecanje:
mov cx, [200]
add cx, 1
mov [200], cx
add bx, cx
add bx, cx
jmp petlja
kraj:

Na raspolaganju

ax uva vrednost 1 , bx vrednost 2 , dok registar

iz

imamo samo 3 registra. Neka

301

Neka se na memorijskoj lokaciji

302

B. Reenja zadataka

Reprezentacija podataka u raunarima


Reenje zadatka 2.1:
(a) 185

(b) 964

(c) 476

(2
01
5)

Reenje zadatka 2.2:


(11111110)2 , (376)8 , ( )16 ,

Reenje zadatka 2.3:

Prevoenjem svake etvorke binarnih cifara zasebno, dobija se

(48 5566293)16 .

Prevoenjem svake heksadekadne cifre zasebno dobija se

je

(1010 0011 1011 1111 0100 0110 0001 1100 1000 1001 1011 1110 0010 0011 1101 0111)2

an

Reenje zadatka 2.4:

(a) rgb(53, 167, 220) (b) #FFFF00 (c) Svaki par heksadekadnih cifara je isti

iz

(npr. #262626 ili #A0A0A0).

Reenje zadatka 2.5:


4

sk
o

0 (00 . . . 00), a najvei 2 1 (11 . . . 11). Dakle, (a) od 0 do


2 1 = 15, (b) od 0 do 28 1 = 255, (c) od 0 do 216 1 = 65535 = 64 , (d)
24
od 0 do 2
1 = 16 777 216 = 16 , (e) 232 1 = 4 294 967 296 = 4.
Najmanji broj je

(a)

ro
n

Reenje zadatka 2.6:


00001100,

(b)

01111011,

(c)

11111111,

(d) ne moe da se zapie

kt

Reenje zadatka 2.7:

21 (10 . . . 00),

a najvei je

21 1 (011 . . . 11).

Dakle,

le

Najmanji broj je

(a) od -8 do 7, (b) od -128 do 127, (c) -32768 do 32767, (d) od -8388608 do

8388607 i (e) od -2147483648 do 2147483647.

Reenje zadatka 2.8:

(a)

00001100,

(b)

10000101,

(c)

00000000,

(d)

11101110,

(e)

10000000

(f ) ne

moe da se zapie

Reenje zadatka 2.9:


5 se zapisuje
100111.

Broj
kao

kao

000101,

broj

kao

111011,

zbir kao

000000,

a proizvod

303

B. Reenja zadataka

Reenje zadatka 2.10:


(a)

38,

(b)

83,

(c)

128,

(d)

1,

(e)

127,

(f )

Reenje zadatka 2.11:


razliitih karaktera. Dakle, najmanji

(2
01
5)

bitova mogue je kodirati ukupno 2


broj bitova je 5.

Sa

Reenje zadatka 2.12:


46 41 4b 55 4c 54 45 54, DISKRETNE

je

Reenje zadatka 2.13:

Heksadekadno: 22 50 72 6f 67 72 61 6d 69 72 61 6e 6a 65 20 31 22,

an

Binarno: 00100010 01010000 01110010 01101111 01100111 01110010 01100001


01001101 01101001 01110010 01100001 01101110 01101010 01100101 00100000

00110001 00100010

Oktalno: 042 120 162 157 147 162 141 115 151 162 141 156 152 145 040 061

iz

042

Dekadno: 34 80 114 111 103 114 97 109 105 114 97 110 106 101 32 49 34

sk
o

Reenje zadatka 2.14:

Windows-1250

ISO-8859-5

ISO-8859-2

Unicode (UCS-2)

11

11

22

12

informatika

11

11

11

11

22

11

ro
n

ASCII
raunarstvo

UTF-8

Reenje zadatka 2.15:

kt

UCS-2 : 006b 0072 0075 017e 0069 0107 UTF-8 : 6b 72 75 c5be 69 c487

le

Izraunljivost

Reenje zadatka 3.1:

Predloeni algoritam se zasniva na sledeoj osobini:

= + (1 + . . . + 1) + . . . + (1 + . . . + 1)

Odgovarajui

urm program podrazumeva sledeu poetnu konfiguraciju:


3 . . .
... ...

304

B. Reenja zadataka

i sledeu radnu konfiguraciju:

dobija redom vrednosti

redom vrednosti
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.

0, 1, . . . , .
(4)
(1, 10, 100)
(2, 10, 14)
(1, 3)
(4)
(4, 2, 12)
(5)
(5)
(3)
(5, 1, 5)
(1, 1, 8)
(3, 1)
(1, 1, 100)
(1)

...
...
0, 1, . . . , ,

= 0,
= 0?
:=
:= + 1
= ?
:= 0
:= + 1
:= + 1

1
0 1

0 1

le

kt

:=

:= + 1
=

ro
n

=0

:= 0

:= + 1
:= + 1

Reenje zadatka 3.5:

dobija

onda kraj

iz

sk
o
=0

=0
ako je

:= 0

a za svaku od ovih vrednosti

(2
01
5)

je

an

gde

305

B. Reenja zadataka

Predloeni algoritam se zasniva na sledeoj osobini:

= =+
Odgovarajui

urm program podrazumeva sledeu poetnu konfiguraciju:


3 . . .
... ...

i sledeu radnu konfiguraciju:

...
...

(2
01
5)

:= 0

je

:= 0

:= + 1

>

:= + 1
:= + 1

iz

ro
n

sk
o

1.

2.

kt

3.

le

4.

5.

6.
7.
8.
9.
10.
11.

(3)
(4)
(1, 3, 11)
(2, 3, 7)
(3)
(1, 1, 3)
(3)
(4)
(3, 1, 11)
(1, 1, 7)
(4, 1)

Jezik C - uvod
Reenje zadatka 5.2.1:

an

=0
=0
= ?
= ?
:= + 1
:= + 1
:= + 1
= ?
1

306

B. Reenja zadataka

int main() {
double r;
printf("Unesi poluprecnik kruga: ");
scanf("%lf", &r);
assert(r > 0);
printf("Obim kruga je: %lf\n", 2*r*M_PI);
printf("Povrsina kruga je: %lf\n", r*r*M_PI);
return 0;
}

je

Reenje zadatka 5.2.2:

(2
01
5)

#include <stdio.h>
#include <math.h>
#include <assert.h>

an

#include <stdio.h>
#include <math.h>

sk
o

iz

int main() {
/* Koordinate tacaka A, B, C */
double xa, ya, xb, yb, xc, yc;
/* Duzine stranica BC, AC, AB */
double a, b, c;
/* Poluobim i povrsina trougla ABC */
double s, P;

le

kt

ro
n

printf("Unesi koordinate tacke A: \n");


scanf("%lf%lf", &xa, &ya);
printf("Unesi koordinate tacke B: \n");
scanf("%lf%lf", &xb, &yb);
printf("Unesi koordinate tacke C: \n");
scanf("%lf%lf", &xc, &yc);

/* Izracunavaju se duzine stranice trougla ABC


njegova povrsina Heronovim obrascem */
a = sqrt((xb - xc)*(xb - xc) + (yb - yc)*(yb b = sqrt((xa - xc)*(xa - xc) + (ya - yc)*(ya c = sqrt((xa - xb)*(xa - xb) + (ya - yb)*(ya s = (a + b + c) / 2;
P = sqrt(s*(s - a)*(s - b)*(s - c));
printf("Povrsina trougla je: %lf\n", P);

return 0;

i
yc));
yc));
yb));

307

B. Reenja zadataka

Reenje zadatka 5.2.3:

int main() {
/* Duzine stranica trougla */
double a, b, c;
/* Velicine uglova trougla */
double alpha, beta, gamma;

an

je

printf("Unesi duzinu stranice a: ");


scanf("%lf", &a); assert(a > 0);
printf("Unesi duzinu stranice b: ");
scanf("%lf", &b); assert(b > 0);
printf("Unesi ugao gama (u stepenima): ");
scanf("%lf", &gamma);

(2
01
5)

#include <stdio.h>
#include <math.h>
#include <assert.h>

sk
o

iz

/* Kosinusnom teoremom izracunavamo duzinu trece stranice i


preostala dva ugla. Pri tom se vrsi konverzija stepena
u radijane i obratno. */
c = sqrt(a*a + b*b - 2*a*b*cos(gamma*M_PI/180.0));

ro
n

alpha = acos((b*b + c*c - a*a) / (2*b*c)) / M_PI * 180.0;


beta = acos((a*a + c*c - b*b) / (2*a*c)) / M_PI * 180.0;

return 0;

le

kt

printf("Duzina stranice c je: %lf\n", c);


printf("Velicina ugla alfa (u stepenima) je: %lf\n", alpha);
printf("Velicina ugla beta (u stepenima) je: %lf\n", beta);

Reenje zadatka 5.2.4:

#include <stdio.h>
int main() {
double kmh;
printf("Unesi brzinu u km/h: ");
scanf("%lf", &kmh);
printf("Brzina u ms/s je: %lf\n", kmh * 1000.0 / 3600.0);
return 0;
}

308

B. Reenja zadataka

Reenje zadatka 5.2.5:


#include <stdio.h>
#include <assert.h>

je

printf("Unesi pocetnu brzinu (u m/s): ");


scanf("%lf", &v0);
printf("Unesi ubrzanje (u m/s^2): ");
scanf("%lf", &a);
printf("Unesi vreme: ");
scanf("%lf", &t); assert(t >= 0);

(2
01
5)

int main() {
/* Pocetna brzina u m/s, ubrzanje u m/s^2 i vreme u s*/
double v0, a, t;

ro
n

#include <stdio.h>

sk
o

Reenje zadatka 5.2.6:

iz

an

printf("Trenutna brzina (u m/s) je : %lf\n", v0+a*t);


printf("Predjeni put (u m) je : %lf\n", v0*t+a*t*t/2);
return 0;

le

kt

int main() {
double a1, a2, a3, a4, a5, a6, a7, a8, a9;
scanf("%lf%lf%lf", &a1, &a2, &a3);
scanf("%lf%lf%lf", &a4, &a5, &a6);
scanf("%lf%lf%lf", &a7, &a8, &a9);
/* Determinantu ra\v cunamo primenom Sarusovog pravila:
a1 a2 a3 a1 a2
a4 a5 a6 a4 a5
a7 a8 a9 a7 a8
- glavne dijagonale pozitivno, sporedne negativno
*/
printf("%lf\n", a1*a5*a9 + a2*a6*a7 + a3*a4*a8
- a3*a5*a7 - a1*a6*a8 - a2*a4*a9);
return 0;
}

Reenje zadatka 5.2.7:

309

B. Reenja zadataka

#include <stdio.h>

je

(2
01
5)

int main() {
int a1, a2, a3; /* brojevi */
int m; /* maksimum brojeva */
printf("Unesi tri broja: ");
scanf("%d %d %d", &a1, &a2, &a3);
m = a1;
if (a2 > m)
m = a2;
if (a3 > m)
m = a3;
printf("Maksimum je: %d\n", m);
return 0;
}

an

Reenje zadatka 5.2.8:

iz

ro
n

sk
o

int main() {
int a, b, i;
scanf("%d%d", &a, &b);
for (i = a; i <= b; i++)
printf("%d\n", i*i*i);
return 0;
}

#include <stdio.h>

kt

Jezik C - izrazi

le

Reenje zadatka 6.4.1:

#include <stdio.h>
int main() {
int h, m, s, h1, m1, s1;
scanf("%d:%d:%d", &h, &m, &s);
if (h < 0 || h > 23) {
printf("Neispravno unet sat\n");
return 1;
}
if (m < 0 || m > 59) {
printf("Neispravno unet minut\n");
return 2;

310

B. Reenja zadataka

}
if (s < 0 || s > 59) {
printf("Neispravno unet sekund\n");
return 3;
}
= 60 = 59 = 23 (s1 ==
s1 = 0;
m1++;

s;
m;
h;
60) {

(2
01
5)

s1
m1
h1
if

#include <stdio.h>

an

sk
o

Reenje zadatka 6.4.2:

iz

printf("%d:%d:%d\n", h1, m1, s1);


return 0;

je

}
if (m1 == 60) {
m1 = 0;
h1++;
}

le

kt

ro
n

int main() {
double x, y, z;
scanf("%lf%lf%lf", &x, &y, &z);
if (x > 0 && y > 0 && z > 0 &&
x + y > z && x + z > y && y + z > x)
printf("Trougao postoji\n");
else
printf("Trougao ne postoji\n");
return 0;
}

Reenje zadatka 6.4.3:


#include <stdio.h>
int main() {
/* Broj cija se suma cifara racuna */
int n;
/* Cifre broja*/

311

B. Reenja zadataka

int c0, c1, c2, c3;

c0
c1
c2
c3

n % 10;
(n / 10) % 10;
(n / 100) % 10;
(n / 1000) % 10;

je

printf("Suma cifara je: %d\n", c0 + c1 + c2 + c3);


return 0;

an

=
=
=
=

(2
01
5)

printf("Unesi cetvorocifreni broj: ");


scanf("%d", &n);
if (n < 1000 || n >= 10000) {
printf("Broj nije cetvorocifren\n");
return 1;
}

Reenje zadatka 6.4.4:

iz

#include <stdio.h>

le

kt

ro
n

sk
o

int main() {
unsigned n, c0, c1; /* broj, poslednja i pretposlednja cifra */
printf("Unesi broj: ");
scanf("%d", &n);
c0 = n % 10;
c1 = (n / 10) % 10;
printf("Zamenjene poslednje dve cifre: %u\n",
(n / 100)*100 + c0*10 + c1);
return 0;
}

Reenje zadatka 6.4.5:

#include <stdio.h>
int main() {
/*
(0, 0) -> 1
(0, 1) -> 2
(2, 0) -> 4
(0, 3) -> 7
...
*/

(1, 0) -> 3
(1, 1) -> 5 (0, 2) -> 6
(1, 2) -> 8 (2, 1) -> 9 (3, 0) -> 10

312

unsigned x, y; /* koordinate */
unsigned z;
/* pomocna promenljiva */
unsigned n;
/* redni broj u cik-cak nabrajanju */
printf("Unesi x i y koordinatu: ");
scanf("%d%d", &x, &y);
z = x + y;
if (z % 2)
n = z*(z + 1)/2 + x + 1;
else
n = z*(z + 1)/2 + y + 1;
printf("Redni broj u cik-cak nabrajanju je: %u\n", n);
return 0;

(2
01
5)

B. Reenja zadataka

je

Reenje zadatka 6.4.6:

an

#include <stdio.h>

kt

ro
n

sk
o

iz

int main() {
double A, B;
printf("Unesi koeficijente A i B jednacine A*X + B = 0: ");
scanf("%lf%lf", &A, &B);
if (A != 0)
printf("Jednacina ima jedinstveno resenje: %lf\n", -B/A);
else if (B == 0)
printf("Svaki realan broj zadovoljava jednacinu\n");
else
printf("Jednacina nema resenja\n");
return 0;
}

le

Reenje zadatka 6.4.7:

#include <stdio.h>
int main() {
double a1, b1, c1, a2, b2, c2; /* koeficijenti sistema */
double Dx, Dy, D; /* determinante */
scanf("%lf%lf%lf", &a1, &b1, &c1);
scanf("%lf%lf%lf", &a2, &b2, &c2);
/* Sistem resavamo primenom Kramerovog pravila */
/* Determinanta sistema:
a1 b1
a2 b2
*/

313

B. Reenja zadataka

Reenje zadatka 6.4.8:

an

return 0;

iz

je

(2
01
5)

D = a1*b2 - b1*a2;
/* Determinanta promenljive x:
c1 b1
c2 b2
*/
Dx = c1*b2 - b1*c2;
/* Determinanta promenljive y:
a1 c1
a2 c2
*/
Dy = a1*c2 - c1*a2;
if (D != 0)
printf("x = %lf\ny = %lf\n", Dx / D, Dy / D);
else if (Dx == 0 && Dy == 0)
printf("Sistem ima beskonacno mnogo resenja\n");
else
printf("Sistem nema resenja\n");

sk
o

#include <stdio.h>
#include <math.h>
#include <assert.h>

le

kt

ro
n

int main() {
float a, b, c; /* koeficijenti */
float D;
/* diskriminanta */
printf("Unesi koeficijente a, b, c"
" kvadratne jednacine ax^2 + bx + c = 0: ");
scanf("%f%f%f", &a, &b, &c);
assert(a != 0);
D = b*b - 4*a*c;
if (D > 0) {
float sqrtD = sqrt(D);
printf("Realna resenja su: %f i %f\n",
(-b + sqrtD) / (2*a), (-b - sqrtD) / (2*a));
} else if (D == 0) {
printf("Jedinstveno realno resenje je: %f\n",
-b/(2*a));
} else {
printf("Jednacina nema realnih resenja\n");
}
return 0;
}

314

B. Reenja zadataka

Reenje zadatka 6.4.9:


#include <stdio.h>

je

(2
01
5)

int main() {
unsigned n; /* broj koji se ispituje */
unsigned d; /* kandidat za delioca */
scanf("%u", &n);
for (d = 1; d <= n; d++)
if (n % d == 0)
printf("%u\n", d);
return 0;
}

an

Reenje zadatka 6.4.10:

iz

#include <stdio.h>
#include <ctype.h>

ro
n

sk
o

int main() {
int c;
while ((c = getchar()) != . && c != , && c != EOF)
putchar(toupper(c));
}

Jezik C - nizovi

le

kt

Reenje zadatka 6.6.1:

#include <stdio.h>
#define MAX 1000
int main() {
int a[MAX];
int n, i, max, zbir;
scanf("%d", &n);
if (n >= MAX) {
printf("Previse elemenata\n");
return 1;
}
/* Ucitavanje niza */

315

B. Reenja zadataka

for (i = 0; i < n; i++)


scanf("%d", &a[i]);

(2
01
5)

/* Ispisivanje niza unatrag */


for (i = n - 1; i >= 0; i--)
printf("%d ", a[i]);
printf("\n");

return 0;

iz

an

/* Odredjivanje i ispis maksimuma */


max = a[0];
for (i = 1; i < n; i++)
if (a[i] > max)
max = a[i];
printf("max = %d\n", max);

ro
n

sk
o

Reenje zadatka 6.6.2:


#include <stdio.h>
int main() {
int b[10], i;

le

kt

for (i = 0; i < 10; i++)


b[i] = 0;

while ((c = getchar()) != .)


if (0<=c && c<=9)
b[c - 0]++;

for (i = 0; i < 10; i++)


printf("%d ", b[i]);
}

je

/* Odredjivanje i ispis zbira */


zbir = 0;
for (i = 0; i < n; i++)
zbir += a[i];
printf("zbir = %d\n", zbir);

return 0;

Reenje zadatka 6.6.3:

316

B. Reenja zadataka

#include <stdio.h>
#include <assert.h>

(2
01
5)

/* Pretprocesorska direktiva kojom se proverava da li je godina


prestupna. Godina je prestupna ako je deljiva sa 4, a ne i sa 100
ili je deljiva sa 400. */
#define prestupna(g) (((g)%4 == 0 && (g)%100 != 0) || ((g)%400 == 0))

ro
n

sk
o

iz

an

je

int main() {
int d, m, g, b, M;
/* Broj dana po mesecima. Niz je napravljen tako da se broj dana za
mesec m moze ocitati sa br_dana[m].
*/
int br_dana[] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
printf("Unesi datum u formatu d/m/g: ");
assert(scanf("%d/%d/%d", &d, &m, &g) == 3);
/* Provera ispravnosti datuma */
if (g < 0) {
printf("Pogresna godina\n");
return 1;
}
if (m < 1 || m > 12) {
printf("Pogresan mesec\n");
return 1;
}
if (d < 1 || d > (m == 2 && prestupna(g) ? 29 : br_dana[m])) {
printf("Pogresan dan\n");
return 1;
}

le

kt

b = 0;
/* Broj dana u prethodnim mesecima */
for (M = 1; M < m; M++)
b += br_dana[M];
/* Broj dana u tekucem mesecu */
b += d;
/* Eventualno dodati i 29. 2. */
if (prestupna(g) && m > 2)
b++;
printf("%d\n", b);

return 0;

Reenje zadatka 6.6.4:


#include <stdio.h>

317

B. Reenja zadataka

#include <ctype.h>

je
an

iz

return 0;

sk
o

/* Ispisujemo tekuci red */


for (k = 0; k <= n; k++)
printf("%d ", a[k]);
printf("\n");

(2
01
5)

int main() {
int a[100], n, k, m;
/* Ucitavamo broj redova trougla */
scanf("%d", &m);
for (n = 0; n < m; n++) {
/* Azuriramo tekuci red trougla */
/* (n n) = 1 */
a[n] = 1;
for (k = n-1; k > 0; k--)
/* (n k) = (n-1 k) + (n-1 k-1) */
a[k] = a[k] + a[k-1];
/* (n 0) = 1 */
/* a[0] = 1; -- ovo vec vazi */

Reenje zadatka 6.6.5:

ro
n

#include <stdio.h>
#include <assert.h>

le

kt

int main() {
int n, A[10][10], i, j, s;
/* ucitavamo matricu */
scanf("%d", &n); assert(0 < n && n <= 10);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &A[i][j]);
/* sumiramo elemente glavne dijagonale */
s = 0;
for (i = 0; i < n; i++)
s += A[i][i];
printf("Suma elemenata glavne dijagonale je: %d\n", s);
/* sumiramo elemente iznad sporedne dijagonale */
s = 0;
for (i = 0; i < n; i++)

318

B. Reenja zadataka

for (j = 0; i + j + 1 < n; j++)


s += A[i][j];
printf("Suma elemenata iznad sporedne dijagonale je: %d\n", s);
}

return 0;

(2
01
5)

Reenje zadatka 6.6.6:


#include <stdio.h>
#include <assert.h>

ro
n

sk
o

iz

an

je

int main() {
int n, A[100][100], i, j, dt;
/* ucitavamo matricu */
scanf("%d", &n); assert(0 < n && n <= 100);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &A[i][j]);
/* proveravamo da li je matrica donjetrougaona */
dt = 1;
for (i = 0; i < n && dt; i++)
for (j = i+1; j < n && dt; j++)
if (A[i][j] != 0)
dt = 0;
printf("Matrica %s donjetrougaona\n", dt ? "je" : "nije");
return 0;
}

kt

Jezik C - korisniki definisani tipovi

le

Reenje zadatka 6.7.1:

#include <stdio.h>
#include <math.h>
/* Struktura za reprezentovanje kompleksnog broja */
typedef struct complex {
double Re, Im;
} COMPLEX;
int main() {
/* Najveci broj */
COMPLEX max_z;

319

B. Reenja zadataka

sk
o

Reenje zadatka 6.7.2:

iz

an

je

int i;
for (i = 0; i < 10; i++) {
/* Tekuci broj */
COMPLEX z;
/* Moduo tekuceg broja */
double z_m;
/* Ucitavanje */
scanf("%lf%lf", &z.Re, &z.Im);
/* Racunanje modula */
z_m = sqrt(z.Re*z.Re + z.Im*z.Im);
/* Azuriranje najveceg */
if (z_m > max_m) {
max_z = z;
max_m = z_m;
}
}
printf("%lf + i*%lf\n", max_z.Re, max_z.Im);
return 0;

(2
01
5)

/* Najveci moduo */
double max_m = 0.0;

ro
n

#include <stdio.h>
#include <assert.h>

le

kt

int main() {
enum dani {PON = 1, UTO, SRE, CET, PET, SUB, NED};
int dan;
scanf("%d", &dan);
assert(1 <= dan && dan <= 7);
if (dan == SUB || dan == NED)
printf("Vikend\n");
else
printf("Radni dan\n");
return 0;
}

Jezik C - naredbe
Reenje zadatka 7.1:
#include <stdio.h>

320

B. Reenja zadataka

(2
01
5)

int main() {
int n, i;
printf("Unesi gornju granicu: ");
scanf("%d", &n);
for (i = 1; i < n; i += 2)
printf("%d ", i);
printf("\n");
return 0;
}

#include <stdio.h>
#include <math.h>

ro
n

sk
o

iz

an

int main() {
int N = 100;
double l = 0.0, d = 2*M_PI;
double h = (d - l) / (N - 1);
double x;
printf(" x
sin(x)\n");
for (x = l; x <= d; x += h)
printf("%4.2lf %7.4lf\n", x, sin(x));
return 0;
}

je

Reenje zadatka 7.2:

Reenje zadatka 7.3:

kt

#include <stdio.h>

le

int main() {
double x, s;
unsigned n, i;
printf("Unesi broj x: ");
scanf("%lf", &x);
printf("Unesi izlozilac n: ");
scanf("%d", &n);
for (s = 1.0, i = 0; i < n; i++)
s *= x;
printf("x^n = %lf\n", s);
return 0;
}

321

B. Reenja zadataka

Reenje zadatka 7.4:


#include <stdio.h>

(2
01
5)

#define N 4
int main() {
int i, j;
/* Deo (a): */

printf("--------------\n");

sk
o

iz

/* Deo (b): */
for (i = 0; i < N; i++) {
for (j = 0; j < N - i; j++)
putchar(*);
putchar(\n);
}

an

je

for (i = 0; i < N; i++) {


for (j = 0; j < N; j++)
putchar(*);
putchar(\n);
}

ro
n

printf("--------------\n");

le

kt

/* Deo (c): */
for (i = 0; i < N; i++) {
for (j = 0; j < i + 1; j++)
putchar(*);
putchar(\n);
}

printf("--------------\n");
/* Deo (d): */
for (i = 0; i < N; i++) {
for (j = 0; j < i; j++)
putchar( );
for (j = 0; j < N - i; j++)
putchar(*);
putchar(\n);
}
printf("--------------\n");

322

B. Reenja zadataka

(2
01
5)

/* Deo (e): */
for (i = 0; i < N; i++) {
for (j = 0; j < N - i - 1; j++)
putchar( );
for (j = 0; j < i + 1; j++)
putchar(*);
putchar(\n);
}

printf("--------------\n");

an

iz

/* Deo (f): */
for (i = 0; i < N; i++) {
for (j = 0; j < i; j++)
putchar( );
for (j = 0; j < N - i - 1; j++) {
putchar(*); putchar( );
}
putchar(*);
putchar(\n);
}

je

printf("--------------\n");

le

kt

ro
n

sk
o

/* Deo (g): */
for (i = 0; i < N; i++) {
for (j = 0; j < N - i - 1; j++)
putchar( );
for (j = 0; j < i; j++) {
putchar(*); putchar( );
}
putchar(*);
putchar(\n);
}

return 0;

Reenje zadatka 7.5:


#include <stdio.h>
/* Delioci se dodaju u parovima: ako je n deljiv sa d, deljiv je i
sa n/d. Pretraga se vrsi do korena iz n.
Ako je n potpun kvadrat, koren se sabira samo jednom.
Napomena: za jako velike vrednosti n, d*d moze da prekoraci.

323

B. Reenja zadataka

an

je

Reenje zadatka 7.6:

(2
01
5)

*/
int main() {
unsigned n; /* broj koji se ispituje */
unsigned s; /* suma delioca */
unsigned d; /* kandidat za delioca */
scanf("%u", &n);
for (s = 0, d = 1; d*d < n; d++)
if (n % d == 0)
s += d + n / d;
if (d * d == n)
s += d;
printf("Suma: %u\n", s);
return 0;
}

#include <stdio.h>
#include <assert.h>

le

kt

ro
n

sk
o

iz

/* Teorema: Ako broj ima pravog delioca koji je veci od korena iz n,


onda ima delioca koji je manji od korena iz n.
Dokaz: Ako je d <= sqrt(n) delilac broja n, onda je n/d >= sqrt(n)
takodje delilac.
Zato je dovoljno proveravati delioce samo od 2 do sqrt(n).
Uslov d <= sqrt(n) menjamo sa d*d <= n, da bismo izbegli rad sa
realnim brojevima (za jako velike vrednosti n, ovo moze da dovede do
prekoracenja)
*/
int main() {
unsigned n, d;
int prost;
scanf("%d", &n);
assert(n > 1); /* Brojevi <= 1 nisu ni prosti ni slozeni */
for (prost = 1, d = 2; prost && d*d <= n; d++)
if (n % d == 0)
prost = 0;
printf("Broj je %s\n", prost ? "prost" : "slozen");
return 0;
}

Reenje zadatka 7.7:


#include <stdio.h>

324

B. Reenja zadataka

int main() {
unsigned n, d;
/* Ucitavamo broj */
scanf("%u", &n);

sk
o

iz

an

je

(2
01
5)

/* Prvi kandidat za prost cinioc je 2 */


d = 2;
/* Broj n delimo sa jednim po jednim njegovim ciniocem. Postupak se
zavrsava kada trenutni broj postane prost */
while (d*d <= n) {
/* Broj je deljiv sa d - dakle, d je prost cinioc. Zaista, ako d
ne bi bio prost, bio bi deljiv sa nekim svojim ciniocem d koji
je manji od njega. Time bi i n bio deljiv sa d. No, kada se d
uvecavalo (a moralo je biti uvecano da bi se stiglo do d) n
nije bio deljiv njime, sto je kontradikcija. */
if (n % d == 0) {
printf("%u\n", d);
n /= d;
} else
/* Broj nije deljiv sa d, pa prelazimo na narednog kandidata */
d++;
}
/* poslednji preostali cinilac */
if (n > 1)
printf("%u\n", n);
return 0;

ro
n

Reenje zadatka 7.8:

le

kt

#include <stdio.h>
#include <limits.h>
#include <math.h>

int main() {
int a; /* broj koji se unosi */
int n = 0; /* broj unetih brojeva */
int s = 0; /* zbir unetih brojeva */
int p = 1; /* proizvod unetih brojeva */
int min = INT_MAX; /* minimum unetih brojeva */
int max = INT_MIN; /* maksimum unetih brojeva */
double sr = 0; /* zbir reciprocnih vrednosti */
while (1) {
scanf("%d", &a);
if (a == 0) break;
n++;
s += a;

325

B. Reenja zadataka

p *= a;
if (a < min) min = a;
if (a > max) max = a;
sr += 1.0/a;

#include <stdio.h>

sk
o

Reenje zadatka 7.9:

an

return 0;

iz

je

(2
01
5)

}
if (n == 0) {
printf("Nije unet nijedan broj\n");
return 1;
}
printf("broj: %d\n", n);
printf("zbir: %d\n", s);
printf("proizvod: %d\n", p);
printf("minimum: %d\n", min);
printf("maksimum: %d\n", max);
printf("aritmeticka sredina: %f\n", (double)s / (double)n);
printf("geometrijska sredina: %f\n", pow(p, 1.0/n));
printf("harmonijska sredina: %f\n", n / sr);

ro
n

int main() {
int ts = 0; /* Tekuca serija */
int ns = 0; /* Najduza serija */
int pb, tb; /* Prethodni i tekuci broj */

le

kt

scanf("%d", &pb);
if (pb != 0) {
ts = ns = 1;
while(1) {
scanf("%d", &tb);
if (tb == 0) break; /* Prekidamo kada je uneta 0 */
/* Da li je tekuci broj jednak prethodnom? */
if (tb == pb)
/* Ako jeste, nastavlja se tekuca serija */
ts++;
else
/* Inace, krenula je nova serija */
ts = 1;
/* Azuriranje najduze serije */
if (ts > ns)

326

B. Reenja zadataka

ns = ts;
/* Azuriranje prethodnog broja */
pb = tb;

(2
01
5)

}
}
/* Ispis rezultata */
printf("%d\n", ns);
return 0;

Reenje zadatka 7.10:

je

#include <stdio.h>

iz

an

int main() {
/* Izracunava se ceo deo korena unetog broja x. Trazi se interval
oblika [n^2, (n+1)^2] = [N1, N2] tako da mu x pripada i tada je n
ceo deo korena iz x.
*/
unsigned x;
unsigned N1, N2, n;

sk
o

/* Ucitava se broj x */
scanf("%d", &x);

le

kt

ro
n

/* Krece se od intervala [0, 1] */


n = 0; N1 = 0; N2 = 1;
while (x != N1) {
N1++;
if (N1 == N2) {
/* Prelazi se na sledeci interval */
unsigned l;
/* Uvecava se malo n */
n++;
/* N2 je potrebno uvecati za 2*n+1 */
N2++;
l = 0;
do {
l++;
N2 += 2;
} while (l != n);
}
}
/* Ispis rezultata */
printf("%d\n", n);

327

B. Reenja zadataka

Reenje zadatka 7.11:

#include <stdio.h>

sk
o

Reenje zadatka 7.12:

iz

je

an

#define EPS 0.0001


int main() {
double xp, x, a;
printf("Unesite broj: ");
scanf("%lf", &a);
x = 1.0;
do {
xp = x;
x = xp - (xp * xp - a) / (2.0 * xp);
printf("%lf\n", x);
} while (fabs(x - xp) >= EPS);
printf("%lf\n", x);
return 0;
}

(2
01
5)

#include <stdio.h>
#include <math.h>

le

kt

ro
n

int main() {
unsigned fpp = 1, fp = 1, k;
scanf("%d", &k);
if (k == 0) return 0;
printf("%d\n", fpp);
if (k == 1) return 0;
printf("%d\n", fp);
k -= 2;
while (k > 0) {
unsigned f = fpp + fp;
printf("%d\n", f);
fpp = fp; fp = f;
k--;
}
return 0;
}

Reenje zadatka 7.13:

328

B. Reenja zadataka

#include <stdio.h>

(2
01
5)

int main() {
unsigned n;
printf("Unesi broj: ");
scanf("%u", &n);
do {
/* Poslednja cifra broja */
printf("%u\n", n % 10);
/* Brisemo poslednju cifru broja */
n /= 10;
} while (n > 0);
return 0;
}

je

#include <stdio.h>

ro
n

sk
o

iz

an

int main() {
unsigned n, suma = 0;
printf("Unesi broj: ");
scanf("%u", &n);
do {
suma += n % 10;
n /= 10;
} while (n > 0);
printf("Suma cifara broja je: %u\n", suma);
return 0;
}

kt

Reenje zadatka 7.14:


#include <stdio.h>

le

int main() {
unsigned n1, n2, tmp;
scanf("%d", &n1);
scanf("%d", &n2);
/* Da bi se izvrsilo nadovezivanje, n1 se mnozi sa 10^k,
gde je k broj cifara broja n2 i zatim se dodaje n2 */
/* posto ce nam n2 kasnije trebati, kopiramo ga u pomocnu promenljivu */
tmp = n2;
/* Dok ima cifara broja tmp */
while (tmp > 0) {
/* Mnozimo n1 sa 10 */
n1 *= 10;

329

B. Reenja zadataka

/* Uklanjamo poslednju cifru broja tmp */


tmp /= 10;

(2
01
5)

}
/* Uvecavamo n1 za n2 */
n1 += n2;
printf("%d\n", n1);
return 0;

Reenje zadatka 7.15:


#include <stdio.h>

ro
n

sk
o

iz

an

je

int main() {
unsigned n;
/* polazni broj */
unsigned o = 0; /* obrnuti broj */
scanf("%d", &n);
do {
/* poslednja cifra broja n se uklanja iz broja n i
dodaje na kraj broja o */
o = 10*o + n % 10;
n /= 10;
} while (n > 0);
printf("%d\n", o);
return 0;
}

Reenje zadatka 7.16:

kt

#include <stdio.h>

le

int main() {
/* Broj koji se obradjuje */
unsigned n;
/* Rezultat i 10^k gde je k broj cifara rezultata (ovaj stepen je
potreban zbog dodavanja cifara na pocetak rezutlata) */
unsigned r = 0, s = 1;
/* Ucitavamo broj */
scanf("%u", &n);
while (n > 0) {
/* Uklanjamo mu poslednju cifru */
unsigned c = n % 10;
n /= 10;
if (c % 2 == 0) {
/* Ako je parna, dodajemo je kao prvu cifru rezultata */

330

B. Reenja zadataka

r = c * s + r;
s *= 10;

(2
01
5)

}
}
/* Ispis rezultata */
printf("%u\n", r);
return 0;

Reenje zadatka 7.17:

an

je

#include <stdio.h>
int main() {
unsigned n, s = 1;
unsigned char p, c;
scanf("%u%hhu%hhu", &n, &p, &c);

iz

/* s = 10^p */
while (p > 0) {
s *= 10;
p--;
}

ro
n

sk
o

/* Broj se razdvaja na prvih p cifara (n/s) i poslednjih p cifara


(n%s). Prve cifre se pomeraju za jedno mesto ulevo (n/s)*s*10,
umece se cifra (c*s) i dodaju poslednje cifre (n%s). */
printf("%d\n", (n/s)*s*10 + c*s + n%s);
return 0;

le

kt

Reenje zadatka 7.18:

/* Razmena prve i poslednje cifre */


#include <stdio.h>
int main() {
unsigned n, a, tmp, s, poc, sred, kraj;
scanf("%u", &n);
/* Jednocifreni brojevi se posebno obradjuju */
if (n < 10) {
printf("%u\n", n);
return 0;
}

331

B. Reenja zadataka

(2
01
5)

/* Odredjuje se s = 10^k gde je k+1 broj cifara broja n. Koristi se


pomocna promenljiva tmp kako bi se ocuvala vrednost n.
*/
tmp = n; s = 1;
while (tmp >= 10) {
s *= 10;
tmp /= 10;
}

an

/* Gradi se i stampa rezultat */


printf("%u\n", s*kraj + 10 * sred + poc);

je

/* Prva cifra */
poc = n / s;
/* Cifre izmedju prve i poslednje */
sred = (n % s) / 10;
/* Poslednja cifra */
kraj = n % 10;

return 0;

sk
o

/* Rotiranje ulevo */
#include <stdio.h>

iz

ro
n

int main() {
unsigned n, tmp, s;
scanf("%u", &n);

le

kt

/* Odredjuje se s = 10^k gde je k+1 broj cifara broja n. Koristi se


pomocna promenljiva tmp kako bi se ocuvala vrednost n.
*/
tmp = n; s = 1;
while (tmp >= 10) {
s *= 10;
tmp /= 10;
}
/* Gradi se i ispisuje rezultat tako sto se poslednja cifra broja n
stavlja ispred ostalih cifara broja n. */
printf("%u\n", s * (n % 10) + n / 10);

return 0;

/* Rotiranje udesno */
#include <stdio.h>

332

B. Reenja zadataka

int main() {
unsigned n, tmp, s;
scanf("%u", &n);

(2
01
5)

/* Odredjuje se s = 10^k gde je k+1 broj cifara broja n. Koristi se


pomocna promenljiva tmp kako bi se ocuvala vrednost n.
*/
tmp = n; s = 1;
while (tmp >= 10) {
s *= 10;
tmp /= 10;
}

return 0;

an

je

/* Gradi se i ispisuje rezultat tako sto se prva cifra broja n


stavlja iza ostalih cifara broja n. */
printf("%u\n", n % s * 10 + n / s);

iz

ro
n

int main() {
int d, m, g, dm;

sk
o

#include <stdio.h>
#include <assert.h>

Reenje zadatka 7.19:

kt

/* Ucitavamo datum i proveravamo da je ispravno ucitan */


assert(scanf("%d/%d/%d", &d, &m, &g) == 3);

le

/* Vrsimo analizu meseca */


switch(m) {
/* Meseci sa 31 danom */
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
dm = 31;
break;
/* Meseci sa 30 dana */
case 4: case 6: case 9: case 11:
dm = 30;
break;
/* Februar */
case 2:
/* Proverava se da li je godina prestupna */
dm = (g % 4 == 0 && g % 100 != 0 || g % 400 == 0) ? 29 : 28;
break;
default:

333

printf("Pogresan mesec\n");
return 1;

je

(2
01
5)

/* Provera dana */
if (d < 1 || d > dm) {
printf("Pogresan dan\n");
return 1;
}
/* Provera godine */
if (g < 0) {
printf("Pogresna godina\n");
return 1;
}
printf("Uneti datum je korektan\n");
return 0;

an

B. Reenja zadataka

iz

#include <stdio.h>
#define BROJ_PREDMETA 12

Reenje zadatka 7.20:

sk
o

int main() {
/* Nabrojivi tip */
enum Uspeh {NEDOVOLJAN, DOVOLJAN, DOBAR, VRLO_DOBAR, ODLICAN, GRESKA};

ro
n

/* Broj jedinica i prosecna ocena ucenika */


int broj_jedinica;
float prosek;

le

kt

/* Uspeh ucenika - odredjuje se automatski na osnovu


prosecne ocene i broja jedinica */
enum Uspeh uspeh;

/* Unos podataka */
printf("Unesi broj jedinica: ");
scanf("%d", &broj_jedinica);
printf("Unesi prosek: ");
scanf("%f", &prosek);
/* Odredjivanje uspeha */
if (broj_jedinica > BROJ_PREDMETA || prosek < 2.0 || prosek > 5.0)
uspeh = GRESKA;
else if (broj_jedinica > 0)
uspeh = NEDOVOLJAN;
else if (prosek < 2.5)

334

B. Reenja zadataka

= DOVOLJAN;
(prosek < 3.5)
= DOBAR;
(prosek < 4.5)
= VRLO_DOBAR;
= ODLICAN;

return 0;

kt

ro
n

sk
o

iz

an

je

/* Prijavljivanje rezultata */
switch(uspeh) {
case NEDOVOLJAN:
printf("Nedovoljan uspeh\n");
break;
case DOVOLJAN:
printf("Dovoljan uspeh\n");
break;
case DOBAR:
printf("Dobar uspeh\n");
break;
case VRLO_DOBAR:
printf("Vrlo dobar uspeh\n");
break;
case ODLICAN:
printf("Odlican uspeh. Cestitamo!\n");
break;
case GRESKA:
printf("Deluje da su podaci neispravni\n");
break;
}

(2
01
5)

uspeh
else if
uspeh
else if
uspeh
else
uspeh

le

Reenje zadatka 7.21:

#include <stdio.h>
#include <limits.h>
int main() {
int x; /* tekuci broj */
int m; /* najmanji prethodno unet broj */
int n; /* broj unetih brojeva */
int s; /* suma unetih brojeva */
/* Prvi uneti broj mora biti specificno obradjen jer nema
prethodnih brojeva kako bi se odredio njihov minimum. Po uslovu

B. Reenja zadataka

zadatka, uvek ga ispisujemo.


*/
scanf("%d", &x);
printf("manji od minimuma: %d\n", x);
m = x;
/* Za sredinu prethodnih se uzima da je 0.0 */
if (x > 0.0)
printf("Veci od proseka prethodnih: %d\n", x);
/* Azuriramo prosek prethodnih */
s = x; n = 1;

(2
01
5)

335

return 0;

sk
o

iz

an

je

/* Obradjujemo ostale brojeve dok se ne pojavi 0 */


while (x != 0) {
scanf("%d", &x);
if (x < m) {
printf("Manji od minimuma: %d\n", x);
/* Azuriramo vrednost minimuma */
m = x;
}
if (x > s / n)
printf("Veci od proseka prethodnih: %d\n", x);
/* Azuriramo prosek prethodnih */
s += x; n++;
}

ro
n

Reenje zadatka 7.22:

kt

#include <stdio.h>

le

int main() {
unsigned a[1000], n, i, j;

scanf("%d", &n);
/* Gradimo niz sve do pozicije n */
a[0] = 0;
for (i = 1; i < n; i = j)
/* Kopiramo prefiks uvecavajuci elemente za 1, vodeci racuna da ne
predjemo granicu */
for (j = i; j < i+i && j < n; j++)
a[j] = a[j - i] + 1;
/* Stampamo niz */
for (i = 0; i < n; i++)

336

B. Reenja zadataka

printf("%d ", a[i]);


printf("\n");
}

return 0;

(2
01
5)

Reenje zadatka 7.23:


#include <stdio.h>
#include <assert.h>

an

je

int main() {
int a[100], b[100]; /* Ulazni nizovi */
int na, nb; /* Njihov broj elemenata */
int p[100], u[200], r[100]; /* Presek, unija, razlika */
int np, nu, nr; /* Njihov broj elemenata */
int i, j, k; /* Pomocne promenljive */

sk
o

iz

/* Ucitavamo niz a proveravajuci da se uneti elementi ne ponavljaju */


printf("Unesi broj elemenata niza a: ");
scanf("%d", &na);
for (i = 0; i < na; i++) {
scanf("%d", &a[i]);
for (j = 0; j < i; j++)
assert(a[i] != a[j]);
}

le

kt

ro
n

/* Ucitavamo niz b proveravajuci da se uneti elementi ne ponavljaju */


printf("Unesi broj elemenata niza b: ");
scanf("%d", &nb);
for (i = 0; i < nb; i++) {
scanf("%d", &b[i]);
for (j = 0; j < i; j++)
assert(b[i] != b[j]);
}
/* ------------------------------------------------------- */
/* presek - u niz p kopiramo sve elemente niza a koji se javljaju u
nizu b */
np = 0;
for (i = 0; i < na; i++) {
for (j = 0; j < nb; j++) {
/* Ako je element a[i] pronadjen u nizu b dodajemo ga u presek p
i prekidamo pretragu */
if (a[i] == b[j]) {
p[np++] = a[i];
break;

337

B. Reenja zadataka

(2
01
5)

}
/* Ispisujemo elemente preseka */
printf("Presek: ");
for (i = 0; i < np; i++)
printf("%d ", p[i]);
printf("\n");

kt

ro
n

sk
o

iz

an

je

/* ------------------------------------------------------- */
/* unija - u niz u kopiramo sve elemente niza a i za njima sve
elemente niza b koji se ne javljaju u a */
/* Kopiramo niz a u niz u */
nu = 0;
for (i = 0; i < na; i++)
u[nu++] = a[i];
for (i = 0; i < nb; i++) {
/* Trazimo b[i] u nizu a */
for (j = 0; j < na; j++)
if (b[i] == a[j])
break;
/* Ako je petlja stigla do kraja, znaci da niz a ne sadrzi b[i] pa
ga dodajemo u uniju u */
if (j == na)
u[nu++] = b[i];
}
/* Ispisujemo elemente unije */
printf("Unija: ");
for (i = 0; i < nu; i++)
printf("%d ", u[i]);
printf("\n");

le

/* ------------------------------------------------------- */
/* razlika - u niz r kopiramo sve elemente niza a koji se ne
javljaju u nizu b */
nr = 0;
for (i = 0; i < na; i++) {
/* Trazimo a[i] u nizu b */
for (j = 0; j < nb; j++)
if (a[i] == b[j])
break;
/* Ako je petlja stigla do kraja, znaci da niz b ne sadrzi a[i] pa
ga dodajemo u razliku r */
if (j == nb)
r[nr++] = a[i];
}
/* Ispisujemo elemente razlike */

338

B. Reenja zadataka

printf("Razlika: ");
for (i = 0; i < nr; i++)
printf("%d ", r[i]);
printf("\n");
return 0;

Reenje zadatka 7.24:


#include <stdio.h>
#include <string.h>

an

je

int main() {
/* Rec koja se proverava */
char s[] = "anavolimilovana";
/* Bulovska promenljiva koja cuva rezultat */
int palindrom = 1;

(2
01
5)

sk
o

iz

/* Obilazimo nisku paralelno sa dva kraja sve dok se pozicije ne


mimoidju ili dok ne naidjemo na prvu razliku */
int i, j;
for (i = 0, j = strlen(s) - 1; i < j && palindrom; i++, j--)
if (s[i] != s[j])
palindrom = 0;

ro
n

kt

le

/* Ispisujemo rezultat */
if (palindrom)
printf("Rec %s je palindrom\n", s);
else
printf("Rec %s nije palindrom\n", s);

Reenje zadatka 7.25:

#include <stdio.h>
#include <string.h>
int main() {
/* Niska koja se obrce */
char s[] = "Zdravo";
/* Nisku obilazimo paralelno sa dva kraja sve dok se pozicije ne
susretnu, razmenjujuci karaktere */
int i, j;

339

B. Reenja zadataka

for (i = 0, j = strlen(s)-1; i<j; i++, j--) {


int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}

(2
01
5)

/* Ispisujemo obrnutu nisku */


printf("%s\n", s);

Reenje zadatka 7.26:

je

#include <stdio.h>
#include <assert.h>

an

#define MAX 100

ro
n

iz

sk
o

/* Ucitavanje matrice */
scanf("%u", &n);
assert(n < MAX);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &m[i][j]);

int main() {
unsigned n, i, j, k;
int m[MAX][MAX];

le

kt

/* Ispisujemo dijagonale - na svakoj je i+j konstantno */


for (k = 0; k <= 2*n-2; k++) {
for (i = 0; i <= k; i++)
if (i < n && k-i < n)
printf("%d ", m[i][k-i]);
putchar(\n);
}

return 0;

Reenje zadatka 7.27:


#include <stdio.h>
#include <assert.h>
#define MAX 100

340

B. Reenja zadataka

int main() {
unsigned m, n, i, j;
int a[MAX][MAX];

(2
01
5)

/* Ucitavamo matricu */
scanf("%d%d", &m, &n);
assert(m < MAX && n < MAX);
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
scanf("%d", &a[i][j]);

iz

an

je

/* Proveravamo sva polja */


for (i = 0; i < m; i++)
for (j = 0; j < n; j++) {
/* Odredjujemo zbir susednih elemenata polja (i, j) */
int k, l;
int s = 0;
for (k = -1; k <= 1; k++)
for (l = -1; l <= 1; l++) {
if (k == 0 && l == 0)
continue;
if (0 <= i+k && i+k < m && 0 <= j+l && j+l < n)
s += a[i+k][j+l];
}

sk
o

return 0;

kt

ro
n

/* Proveravamo da li je zbir jednak vrednosti na polju (i, j) */


if (s == a[i][j])
printf("%u %u: %d\n", i, j, a[i][j]);

le

Jezik C - funkcije

Reenje zadatka 8.1:

#include <stdio.h>
int prost(unsigned n) {
unsigned d;
if (n <= 1) return 0; /* najmanji prost broj je 2 */
/* Proveravaju se delioci do korena i prekida se ako se
pronadje delioc (moze da prekoraci za jako veliko n) */
for (d = 2; d * d <= n; d++)
if (n % d == 0)

341

return 0;
/* Ako delioc nije pronadjen, broj je prost */
return 1;

int main() {
/* Ucitava se broj i proverava da li je prost */
unsigned n;
scanf("%u", &n);
printf(prost(n) ? "Prost\n" : "Nije prost\n");
}

Reenje zadatka 8.2:

an

je

#include <stdio.h>
#include <math.h>

(2
01
5)

B. Reenja zadataka

iz

double rastojanje(double x1, double y1, double x2, double y2) {


double dx = x2 - x1, dy = y2 - y1;
return sqrt(dx*dx + dy*dy);
}

le

kt

ro
n

sk
o

int main() {
double xa, ya, xb, yb, xc, yc;
scanf("%lf%lf", &xa, &ya);
scanf("%lf%lf", &xb, &yb);
scanf("%lf%lf", &xc, &yc);
double a = rastojanje(xb, yb, xc, yc);
double b = rastojanje(xa, ya, xc, yc);
double c = rastojanje(xa, ya, xb, yb);
double s = (a + b + c) / 2.0;
double P = sqrt(s * (s - a) * (s - b) * (s - c));
printf("%lf\n", P);
return 0;
}

Reenje zadatka 8.3:

#include <stdio.h>
unsigned suma_delilaca(unsigned n) {
unsigned s = 1, d;
for (d = 2; d*d < n; d++)
if (n % d == 0)
s += d + n / d;

342

B. Reenja zadataka

if (d * d == n)
s += d;
return s;

(2
01
5)

int savrsen(unsigned n) {
return n == suma_delilaca(n);
}

je

int main() {
unsigned n;
for (n = 1; n <= 10000; n++)
if (savrsen(n))
printf("%u\n", n);
return 0;
}

sk
o

/* Struktura razlomak */
struct razlomak {
int brojilac, imenilac;
};

iz

#include <stdio.h>
#include <assert.h>

an

Reenje zadatka 8.4:

le

kt

ro
n

/* a/b < c/d je ekvivalentno sa


a*d < c*b ako je a*d > 0, tj. sa
a*d > c*b ako je a*d < 0 */
int poredi_razlomke(struct razlomak a, struct razlomak b) {
assert(a.imenilac != 0 && b.imenilac != 0);
if(a.imenilac*b.imenilac>0) {
if(a.brojilac*b.imenilac > a.imenilac*b.brojilac)
return 1;
else if(a.brojilac*b.imenilac == a.imenilac*b.brojilac)
return 0;
else
return -1;
} else {
if(a.brojilac*b.imenilac < a.imenilac*b.brojilac)
return 1;
else if(a.brojilac*b.imenilac == a.imenilac*b.brojilac)
return 0;
else
return -1;
}

343

B. Reenja zadataka

(2
01
5)

/* Ucitavaju se dva razlomka i porede se */


int main() {
struct razlomak a, b;
scanf("%d%d", &a.brojilac, &a.imenilac); assert(a.imenilac != 0);
scanf("%d%d", &b.brojilac, &b.imenilac); assert(b.imenilac != 0);
printf("%d\n", poredi_razlomke(a, b));
}

Reenje zadatka 8.5:

an

iz

int sadrzi(int a[], int n, int x) {


int i;
for (i = 0; i < n; i++)
if (a[i] == x)
return 1;
return 0;
}

je

#include <stdio.h>

ro
n

sk
o

int prva_poz(int a[], int n, int x) {


int i;
for (i = 0; i < n; i++)
if (a[i] == x)
return i;
return -1;
}

le

kt

int poslednja_poz(int a[], int n, int x) {


int i;
for (i = n - 1; i >= 0; i--)
if (a[i] == x)
return i;
return -1;
}
int suma(int a[], int n) {
int i;
int s = 0;
for (i = 0; i < n; i++)
s += a[i];
return s;
}
double prosek(int a[], int n) {

344

B. Reenja zadataka

int i;
int s = 0;
for (i = 0; i < n; i++)
s += a[i];
return (double)s / (double)n;

je

sk
o

iz

an

/* Pretpostavlja se da je niz neprazan */


int max_poz(int a[], int n) {
int i, mp;
mp = 0;
for (i = 1; i < n; i++)
if (a[i] > a[mp])
mp = i;
return mp;
}

(2
01
5)

/* Pretpostavlja se da je niz neprazan */


int min(int a[], int n) {
int i, m;
m = a[0];
for (i = 1; i < n; i++)
if (a[i] < m)
m = a[i];
return m;
}

kt

ro
n

int sortiran(int a[], int n) {


int i;
for (i = 0; i + 1 < n; i++)
if (a[i] > a[i+1])
return 0;
return 1;
}

le

int main() {
int a[] = {3, 2, 5, 4, 1, 3, 8, 7, 5, 6};
int n = sizeof(a) / sizeof(int);
printf("Sadrzi: %d\n", sadrzi(a, n, 3));
printf("Prva pozicija: %d\n", prva_poz(a, n, 3));
printf("Poslednja pozicija: %d\n", poslednja_poz(a, n, 3));
printf("Suma: %d\n", suma(a, n));
printf("Prosek: %lf\n", prosek(a, n));
printf("Minimum: %d\n", min(a, n));
printf("Pozicija maksimuma: %d\n", max_poz(a, n));
printf("Sortiran: %d\n", sortiran(a, n));
return 0;
}

345

B. Reenja zadataka

Reenje zadatka 8.6:


#include <stdio.h>

iz

an

/* Ne cuva se redosled elemenata niza. */


int izbaci_prvi_2(int a[], int n) {
int i;
a[0] = a[n - 1];
return n - 1;
}

je

/* Cuva se redosled elemenata niza */


int izbaci_prvi_1(int a[], int n) {
int i;
for (i = 0; i + 1 < n; i++)
a[i] = a[i + 1];
return n - 1;
}

(2
01
5)

int izbaci_poslednji(int a[], int n) {


return n - 1;
}

kt

ro
n

sk
o

/* Cuva se redosled elemenata niza. */


int izbaci_kti(int a[], int n, int k) {
int i;
for (i = k; i + 1 < n; i++)
a[i] = a[i + 1];
return n - 1;
}

le

/* Izbacivanje prvog se moze svesti na izbacivanje k-tog. */


int izbaci_prvi_3(int a[], int n) {
return izbaci_kti(a, n, 0);
}
/* Pretpostavlja se da ima dovoljno prostora za ubacivanje. */
int ubaci_na_kraj(int a[], int n, int x) {
a[n] = x;
return n + 1;
}
/* Pretpostavlja se da ima dovljno prostora za ubacivanje.
Cuva se redosled elemenata niza. */
int ubaci_na_pocetak_1(int a[], int n, int x) {
int i;
for (i = n; i > 0; i--)

346

B. Reenja zadataka

a[i] = a[i-1];
a[0] = x;
return n + 1;

(2
01
5)

/* Pretpostavlja se da ima dovljno prostora za ubacivanje.


Ne cuva se redosled elemenata niza. */
int ubaci_na_pocetak_2(int a[], int n, int x) {
int i;
a[n] = a[0];
a[0] = x;
return n + 1;
}

iz

an

je

/* Pretpostavlja se da ima dovljno prostora za ubacivanje.


Cuva se redosled elemenata niza. */
int ubaci_na_poz_k(int a[], int n, int k, int x) {
int i;
for (i = n; i > k; i--)
a[i] = a[i-1];
a[k] = x;
return n + 1;
}

sk
o

/* Ubacivanje na pocetak se moze svesti na ubacivanje na poziciju k. */


int ubaci_na_pocetak_3(int a[], int n, int x) {
return ubaci_na_poz_k(a, n, 0, x);
}

le

kt

ro
n

int izbaci_sve(int a[], int n, int x) {


int i, j;
for (j = 0, i = 0; i < n; i++)
if (a[i] != x)
a[j++] = a[i];
return j;
}

void ispisi(int a[], int n) {


int i;
for (i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
int main() {
int a[10] = {1, 2, 3};
int n = 3;
n = ubaci_na_pocetak_1(a, n, 0);
ispisi(a, n);

347

n = izbaci_poslednji(a, n);
ispisi(a, n);
n = ubaci_na_poz_k(a, n, 2, 4);
ispisi(a, n);
n = ubaci_na_kraj(a, n, 1);
ispisi(a, n);
n = izbaci_sve(a, n, 1);
ispisi(a, n);
return 0;

(2
01
5)

B. Reenja zadataka

Reenje zadatka 8.7:

je

#include <stdio.h>

d
iz

sk
o

void ispisi(int a[], int n) {


int i;
for (i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}

an

/* Napomena: odredjen broj funkcija u ovom zadatku se moze


implementirati i efikasnije, medjutim, uz prilicno komplikovaniji
kod. */

le

kt

ro
n

int najduza_serija_jednakih(int a[], int n) {


int i;
/* Duzina tekuce serije je 0 ili 1 u zavisnosti od toga da li je niz
prazan ili nije */
int ts = n != 0;
/* Najduza serija je tekuca serija */
int ns = ts;
for (i = 1; i < n; i++) {
/* Ako je element jednak prethodnom */
if (a[i] == a[i-1])
/* Nastavlja se tekuca serija */
ts++;
else
/* Inace, zapocinjemo novu seriju */
ts = 1;
/* Azuriramo vrednost najduze serije */
if (ts > ns)
ns = ts;
}
/* Vracamo duzinu najduze serije */
return ns;

348

B. Reenja zadataka

an

je

(2
01
5)

/* Ova funkcija se od prethodne razlikuje samo po uslovu poredjenja


dva susedna elementa niza. Kasnije ce biti prikazano kako se to
poredjenje moze parametrizovati. */
int najduza_serija_neopadajucih(int a[], int n) {
int i;
int ts = n != 0;
int ns = ts;
for (i = 1; i < n; i++) {
if (a[i] >= a[i-1])
ts++;
else
ts = 1;
if (ts > ns)
ns = ts;
}
return ns;
}

le

kt

ro
n

sk
o

iz

int podniz_uzastopnih(int a[], int n, int b[], int m) {


int i, j;
/* Za svako i takvo da od pozicije i do kraja niza a ima bar onoliko
elemenata koliko i u nizu b*/
for (i = 0; i + m - 1 < n; i++) {
/* Proveravamo da li se niz b nalazi u nizu a pocevsi od
pozicije i */
for (j = 0; j < m; j++)
if (a[i + j] != b[j])
break;
/* Nismo naisli na razliku, dakle, ceo niz b se nalazi u nizu a
pocevsi od pozicije i */
if (j == m)
return 1;
}
/* Nismo pronasli b unutar a (inace bi funkcija bila prekinuta sa
return 1) */
return 0;
}
int podniz(int a[], int n, int b[], int m) {
int i, j;
/* Prolazimo kroz nisku a, trazeci slova niske b. */
for (i = 0, j = 0; i < n && j < m; i++)
/* Kada pronadjemo tekuce slovo niske b, prelazimo na sledece */
if (a[i] == b[j])
j++;
/* Ako smo iscrpli sve karaktere niske b, onda jeste podniz, inace
nije */

349

B. Reenja zadataka

return j == m;

je

(2
01
5)

void rotiraj_desno(int a[], int n, int k) {


int i, j;
/* k puta rotiramo za po jednu poziciju */
for (j = 0; j < k; j++) {
/* Upamtimo poslednji */
int tmp = a[n-1];
/* Sve elemente pomerimo za jedno mesto na desno */
for (i = n-1; i > 0; i--)
a[i] = a[i-1];
/* Raniji poslednji stavimo na pocetak */
a[0] = tmp;
}
}

ro
n

sk
o

iz

an

void rotiraj_levo(int a[], int n, int k) {


int i, j;
/* k puta rotiramo za po jednu poziciju */
for (j = 0; j < k; j++) {
/* upamtimo prvi */
int tmp = a[0];
/* Sve elemente pomerimo za jedno mesto u levo */
for (i = 0; i + 1 < n; i++)
a[i] = a[i+1];
/* Raniji prvi postavimo na kraj */
a[n - 1] = tmp;
}
}

le

kt

int izbaci_duplikate(int a[], int n) {


int i, j, k;
/* za svaki element niza a */
for (i = 0; i < n; i++) {
/* izbacujemo element a[i] iz ostatka niza a tako sto se elementi
a[j] razliciti od a[i] prepisuju u niz a (ali na poziciju k
koja moze biti i manja od j). */
for (k = i + 1, j = i + 1; j < n; j++)
if (a[j] != a[i])
a[k++] = a[j];
n = k;
}
return n;
}
/* Pretpostavlja se da u niz c moze da se smesti bar n + m elemenata */
int spoji(int a[], int n, int b[], int m, int c[]) {
int i, j, k;

350

/* Tekuca pozicija u prvom, drugom nizu i u rezultatu */


i = 0, j = 0, k = 0;
/* Dok postoje elementi i u jednom i u drugom nizu */
while (i < n && j < m)
/* U rezultat prepisujemo manji element */
c[k++] = a[i] < b[j] ? a[i++] : b[j++];
/* Ono sto je preostalo u nizovima prepisujemo u rezultat (jedna od
naredne dve petlje je uvek prazna) */
while (i < n)
c[k++] = a[i++];
while (j < m)
c[k++] = b[j++];
return k;

(2
01
5)

B. Reenja zadataka

sk
o

iz

an

je

void obrni(int a[], int n) {


int i, j;
/* Prolazimo niz paralelno sa dva kraja dok se pozicije ne
mimoidju */
for (i = 0, j = n-1; i < j; i++, j--) {
/* Vrsimo razmenu elemenata */
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}

le

kt

ro
n

/* Testiramo napisane funkcije */


int main() {
int a[] = {3, 4, 8, 8, 9, 12}, b[] = {10, 9, 7, 7, 7, 6, 5, 5, 2},
c[] = {4, 8, 8, 9}, d[] = {3, 4, 9, 12}, e[20];
int na = sizeof(a)/sizeof(int), nb = sizeof(b)/sizeof(int),
nc = sizeof(c)/sizeof(int), nd = sizeof(d)/sizeof(int), ne;
printf("%d\n", najduza_serija_jednakih(b, nb));
printf("%d\n", najduza_serija_neopadajucih(b, nb));
printf("%d\n", najduza_serija_neopadajucih(a, na));
printf("%d\n", podniz_uzastopnih(a, na, c, nc));
printf("%d\n", podniz_uzastopnih(a, na, d, nd));
printf("%d\n", podniz(a, na, c, nc));
printf("%d\n", podniz(a, na, d, nd));
printf("%d\n", podniz(b, nb, d, nd));
obrni(b, nb);
ne = spoji(a, na, b, nb, e);
ne = izbaci_duplikate(e, ne);
ispisi(e, ne);
rotiraj_levo(e, ne, 2);
ispisi(e, ne);
rotiraj_desno(e, ne, 5);
ispisi(e, ne);

351

B. Reenja zadataka

return 0;

Reenje zadatka 8.8:

(2
01
5)

#include <stdio.h>

je

/* Funkcija radi slicno funkciji strcmp iz string.h */


int poredi(char s1[], char s2[]) {
/* Petlja tece sve dok ne naidjemo na prvi razliciti karakter */
int i;
for (i = 0; s[i]==t[i]; i++)
if (s[i] == \0) /* Naisli smo na kraj obe niske,
a nismo nasli razliku */
return 0;

an

d
iz

/* s[i] i t[i] su prvi karakteri u kojima se niske razlikuju.


Na osnovu njihovog odnosa, odredjuje se odnos stringova */
return s[i] - t[i];

sk
o

int main() {
printf("%d\n", poredi("zdravo", "svima"));
return 0;
}

ro
n

Reenje zadatka 8.9:

kt

#include <stdio.h>

le

/* Proverava da li se niska sub javlja kao podniz niske str (redosled


je bitan, ali karakteri ne moraju da se javljaju uzastopno.
Funkcija vraca 1 ako jeste, a 0 ako nije podniz. */
int podniz(char str[], char sub[]) {
int i, j = 0;
/* Trazimo svako slovo iz niske sub */
for (i = 0; sub[i] != \0; i++)
/* Petlja traje dok ne nadjeno trazeno slovo */
while (str[j] != sub[i]) {
/* Ako smo usput stigli do kraja niske str, a nismo
nasli trazeno slovo, onda nije podniz. */
if (str[j] == \0)
return 0;
j++;
}

352

B. Reenja zadataka

/* Svako slovo iz sub smo pronasli, onda jeste pondiz */


return 1;

iz

an

je

(2
01
5)

/* Proverava da li niska str sadrzi nisku sub kao podnisku (karakteri


moraju da se jave uzastopno). Funkcija radi isto slicno kao
bibliotecka funkcija strstr, ali vraca poziciju na kojoj sub
pocinje, odnosno -1 ukoliko ga nema. Postoje efikasniji algoritmi
za re\v savanje ovog problema, od naivnog algoritma koji je ovde
naveden. */
int podniska(char str[], char sub[]) {
int i, j;
/* Proveravamo da li sub pocinje na svakoj poziciji i */
for (i = 0; str[i] != \0; i++)
/* Poredimo sub sa str pocevsi od pozicije i
sve dok ne naidjemo na razliku */
for (j = 0; str[i+j] == sub[j]; j++)
/* Nismo naisli na razliku a ispitali smo
sve karaktere niske sub */
if (sub[j+1]==\0)
return i;
/* Nije nadjeno */
return -1;
}

ro
n

sk
o

int main() {
printf("%d\n", podniz("banana", "ann"));
printf("%d\n", podniska("banana", "anan"));
return 0;
}

kt

Reenje zadatka 8.10:

le

#include <stdio.h>

/* Dve niske su permutacija jedna druge akko imaju podjednak broj


pojavljivanja svih karaktera. Pretpostavljamo da niske sadrze samo
ASCII karaktere. */
int permutacija(char s[], char t[]) {
/* Broj pojavljivanja svakog od 128 ASCII karaktera u niskama s i t */
int ns[128], nt[128], i;
/* Inicijalizujemo brojace na 0 */
for (i = 0; i < 128; i++)
ns[i] = nt[i] = 0;
/* Brojimo karaktere niske s */
for (i = 0; s[i]; i++)
ns[s[i]]++;

353

B. Reenja zadataka

/* Brojimo karaktere niske t */


for (i = 0; t[i]; i++)
nt[t[i]]++;

(2
01
5)

/* Poredimo brojeve za svaki od 128 ASCII karaktera */


for (i = 0; i < 128; i++)
if (ns[i] != nt[i])
return 0;
/* Nismo naisli na razliku - dakle svi karakteri se javljaju isti
broj puta */
return 1;

iz

Reenje zadatka 8.11:

an

je

/* Provera funkcije */
int main() {
char s[] = "tom marvolo riddle ", t[] = "i am lord voldemort";
printf("%d\n", permutacija(s, t));
return 0;
}

sk
o

#include <stdio.h>
#include <assert.h>

le

kt

ro
n

int zbir_vrste(int m[10][10], int n, int i) {


int j;
int zbir = 0;
assert(n < 10 && i < 10);
for (j = 0; j < n; j++)
zbir += m[i][j];
return zbir;
}

int zbir_kolone(int m[10][10], int n, int j) {


int i;
int zbir = 0;
assert(n < 10 && j < 10);
for (i = 0; i < n; i++)
zbir += m[i][j];
return zbir;
}
int zbir_glavne_dijagonale(int m[10][10], int n) {
int i;
int zbir = 0;

354

B. Reenja zadataka

assert(n < 10);


for (i = 0; i < n; i++)
zbir += m[i][i];
return zbir;

iz

je

an

int ucitaj(int m[10][10]) {


int i, j, n;
scanf("%d", &n); assert(1 <= n && n < 10);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &m[i][j]);
return n;
}

(2
01
5)

int zbir_sporedne_dijagonale(int m[10][10], int n) {


int i;
int zbir = 0;
assert(n < 10);
for (i = 0; i < n; i++)
zbir += m[i][n-i-1];
return zbir;
}

le

kt

ro
n

sk
o

int magicni(int m[10][10], int n) {


int i, j, zbir;
zbir = zbir_vrste(m, n, 0);
for (i = 1; i < n; i++)
if (zbir_vrste(m, n, i) != zbir)
return 0;
for (j = 0; j < n; j++)
if (zbir_kolone(m, n, j) != zbir)
return 0;
if (zbir_glavne_dijagonale(m, n) != zbir)
return 0;
if (zbir_sporedne_dijagonale(m, n) != zbir)
return 0;
return 1;
}
int main() {
int n, m[10][10];
n = ucitaj(m);
printf("%d\n", magicni(m, n));
return 0;
}

355

B. Reenja zadataka

Reenje zadatka 8.12:


#include <stdio.h>
#include <assert.h>

(2
01
5)

#define MAX 100


typedef struct {
float a[MAX][MAX];
unsigned m, n;
} MATRICA;

sk
o

iz

an

je

/* Efikasnije bi bilo prenositi matricu kao argument,


preko pokazivaca, ali to jos nije uvedeno. */
MATRICA ucitaj() {
MATRICA m;
unsigned i, j;
scanf("%u%u", &m.m, &m.n);
assert(m.n < MAX);
for (i = 0; i < m.m; i++)
for (j = 0; j < m.n; j++)
scanf("%f", &m.a[i][j]);
return m;
}

le

kt

ro
n

MATRICA saberi(MATRICA m1, MATRICA m2) {


MATRICA m;
unsigned i, j;
assert(m1.m == m2.m && m1.n == m2.n);
m.m = m1.m; m.n = m1.n;
for (i = 0; i < m.n; i++)
for (j = 0; j < m.n; j++)
m.a[i][j] = m1.a[i][j] + m2.a[i][j];
return m;
}
MATRICA pomnozi(MATRICA m1, MATRICA m2) {
MATRICA m;
unsigned i, j, k;
assert(m2.m == m1.n);
m.m = m1.m; m.n = m2.n;
for (i = 0; i < m.m; i++)
for (j = 0; j < m.n; j++) {
m.a[i][j] = 0;
for (k = 0; k < m1.n; k++)
m.a[i][j] += m1.a[i][k]*m2.a[k][j];
}

356

B. Reenja zadataka

return m;

je
an

sk
o

iz

int main() {
MATRICA m1, m2, m;
m1 = ucitaj(); m2 = ucitaj();
if (m1.m == m2.m && m1.n == m2.n) {
m = saberi(m1, m2);
ispisi(m);
}
if (m1.n = m2.m) {
m = pomnozi(m1, m2);
ispisi(m);
}
return 0;
}

(2
01
5)

void ispisi(MATRICA m) {
unsigned i, j;
for (i = 0; i < m.m; i++) {
for (j = 0; j < m.n; j++)
printf("%g ", m.a[i][j]);
putchar(\n);
}
}

ro
n

Reenje zadatka 8.13:


#include <stdio.h>
#include <assert.h>

kt

#define MAX 100

le

/* Veliki broj je predstavljen nizom od n cifara. Cifre se zapisuju


"naopako" kako bi se cifra uz 10^i nalazila na poziciji i */
typedef struct {
unsigned char c[MAX];
unsigned n;
} BROJ;
BROJ ucitaj() {
BROJ rez;
rez.n = 0;
int c, i, j;
while(isdigit(c = getchar())) {
rez.c[rez.n++] = c - 0;
assert(rez.n <= MAX);

B. Reenja zadataka

}
/* Obrcemo zapis */
for (i = 0, j = rez.n-1; i < j; i++, j--) {
unsigned char tmp = rez.c[i];
rez.c[i] = rez.c[j];
rez.c[j] = tmp;
}
return rez;

void ispisi(BROJ b) {
int i;
for (i = b.n-1; i >= 0; i--)
putchar(0 + b.c[i]);
}

(2
01
5)

357

le

kt

ro
n

sk
o

iz

an

je

BROJ saberi(BROJ a, BROJ b) {


BROJ rez;
unsigned i;
/* Prenos */
unsigned char p = 0;
for (i = 0; i < a.n || i < b.n; i++) {
/* Cifra prvog broja ili 0 ako su sve cifre iscrpljene */
unsigned char c1 = i < a.n ? a.c[i] : 0;
/* Cifra drugog broja ili 0 ako su sve cifre iscrpljene */
unsigned char c2 = i < b.n ? b.c[i] : 0;
/* Zbir cifara + prenos sa prethodne pozicije*/
unsigned char c = c1 + c2 + p;
/* Nova cifra */
rez.c[i] = c % 10;
/* Prenos na sledecu poziciju */
p = c / 10;
}
/* Broj cifara rezultata */
rez.n = i;
/* Ako postoji prenos, treba dodati jos jednu cifru */
if (p > 0) {
assert(rez.n < MAX);
rez.c[rez.n] = p;
rez.n++;
}
return rez;
}
BROJ pomnozi(BROJ a, BROJ b) {
BROJ rez; /* rezultat */
unsigned i, j;
unsigned char p; /* prenos */

B. Reenja zadataka

/* Maksimalni broj cifara rezultata */


rez.n = a.n + b.n;
assert(rez.n <= MAX);
/* Inicijalizujemo sve cifre rezultata */
for (i = 0; i < rez.n; i++)
rez.c[i] = 0;
/* Mnozimo brojeve ne vrseci nikakav prenos */
for (i = 0; i < a.n; i++)
for (j = 0; j < b.n; j++)
rez.c[i+j] += a.c[i]*b.c[j];

(2
01
5)

358

iz

an

je

/* Normalizujemo rezultat */
p = 0;
for (i = 0; i < rez.n; i++) {
unsigned char c = rez.c[i] + p;
rez.c[i] = c % 10;
p = c / 10;
}
/* Ako je prva cifra 0, smanjujemo broj cifara */
if (rez.c[rez.n-1] == 0)
rez.n--;
return rez;

kt

ro
n

sk
o

int main() {
BROJ a = ucitaj(), b = ucitaj(), c;
c = saberi(a, b);
ispisi(c);
putchar(\n);
c = pomnozi(a, b);
ispisi(c);
putchar(\n);
}

le

Jezik C - pokazivai

Reenje zadatka 10.2.1:

#include <stdio.h>
#include <assert.h>
/* Funkcija vraca 3 vrednosti preko pokazivaca */
void od_ponoci(unsigned n, unsigned* h, unsigned *m, unsigned *s) {
*h = n / 3600;
n %= 3600;
*m = n / 60;

359

B. Reenja zadataka

n %= 60;
*s = n;

(2
01
5)

int main() {
unsigned n, h, m, s;
scanf("%d", &n); assert(n < 60*60*24);
od_ponoci(n, &h, &m, &s);
printf("%d:%d:%d\n", h, m, s);
return 0;
}

Reenje zadatka 10.8.1:

je

#include <stdio.h>

d
iz

sk
o

int pozitivan(int x) {
return x > 0;
}

an

int paran(int x) {
return x % 2 == 0;
}

le

kt

ro
n

/* Kriterijum se prosledjuje u obliku pokazivaca na funkciju */


int najduza_serija(int a[], int n, int (*f) (int)) {
int i;
/* Duzina tekuce serije je 0 ili 1 u zavisnosti od toga da li je niz
prazan ili nije */
int ts = 0;
/* Najduza serija je tekuca serija */
int ns = ts;
for (i = 0; i < n; i++) {
/* Ako element zadovoljava kriterijum */
if ((*f)(a[i]))
/* Nastavlja se tekuca serija */
ts++;
else
/* Inace, prekidamo seriju */
ts = 0;
/* Azuriramo vrednost najduze serije */
if (ts > ns)
ns = ts;
}
/* Vracamo duzinu najduze serije */
return ns;
}

360

B. Reenja zadataka

(2
01
5)

/* Testiramo napisane funkcije */


int main() {
int a[] = {1, 2, 4, -6, 5, 3, -3, 2, 5, 7, 9, 11},
n = sizeof(a)/sizeof(int);
printf("%d %d\n", najduza_serija(a, n, &paran),
najduza_serija(a, n, &pozitivan));
}

Reenje zadatka 10.5.1:

an
d

size_t my_strlen(const char* s) {


const char* t;
for (t = s; *t; t++)
;
return t - s;
}

je

#include <stdio.h>

sk
o

iz

size_t my_strcpy(char* dest, const char* src) {


while(*dest++ = *src++)
;
}

ro
n

int my_strcmp(char* s, char *t) {


while (*s && *s == *t)
s++, t++;
return *s - *t;
}

le

kt

void my_strrev(char* s) {
char *t = s;
/* Dovodimo s ispred terminalne nule */
while(*s)
s++;
s--;
/* Obrcemo karaktere */
for (; t < s; t++, s--) {
char tmp = *s; *s = *t; *t = tmp;
}
}
const char* my_strchr(char x, const char* s) {
while(*s) {
if (*s == x) return s;
s++;

361

B. Reenja zadataka

}
return NULL;

for ( ; *str; str++) {


const char *s, *t;
for (s = str, t = sub; *s && (*s == *t); s++, t++)
if (*t == \0)
return str;

}
return NULL;

je

(2
01
5)

const char* my_strstr(const char* str, const char* sub) {


if (str == NULL || sub == NULL)
return NULL;

ro
n

sk
o

iz

an

int main() {
char s[] = "abc", t[] = "def", r[4];
printf("%lu %lu\n", my_strlen(s), my_strlen(t));
my_strcpy(r, s);
printf("%s\n", r);
my_strrev(s);
printf("%s\n", s);
printf("%d\n", my_strcmp(s, t));
printf("%c\n", *my_strchr(x, "abcxyz"));
printf("%s\n", my_strstr("abcdefghi", "def"));
return 0;
}

kt

Reenje zadatka 10.9.1:

le

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main() {
unsigned n, i, min;
int *a, x;
/* Ucitavamo niz */
scanf("%u", &n);
assert(n > 0);
a = malloc(n*sizeof(int)); /* Dinamicka alokacija */
assert(a != NULL);
for (i = 0; i < n; i++)

362

B. Reenja zadataka

scanf("%d", &a[i]);

/* Trazimo element niza a najblizi broju x */


min = 0;
for (i = 1; i < n; i++)
if (abs(a[i] - x) < abs(a[min] - x))
min = i;
/* Ispisujemo rezultat */
printf("a[%d] = %d\n", min, a[min]);

je
an

/* Oslobadjamo niz */
free(a);
return 0;

(2
01
5)

/* Ucitavamo broj koji se trazi */


scanf("%d", &x);

#define KORAK 32

sk
o

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

iz

Reenje zadatka 10.9.2:

ro
n

int main() {
unsigned n = 0, aloc = 0, i, m, nm;
int *a = NULL;

le

kt

/* Ucitavamo niz, dinamicki ga realocirajuci */


do {
if (aloc <= n) {
int* a_novo;
aloc += KORAK;
a_novo = realloc(a, aloc*sizeof(int));
assert(a_novo);
a = a_novo;
}
scanf("%d", &a[n]);
} while(a[n++] != 0);
/* Trazenje najcesceg elementa - ovaj algoritam je neefikasan, ali
se jednostavno implementira */
/* Broj pojavljivanja najcesceg elementa */
nm = 0;

363

B. Reenja zadataka

(2
01
5)

for (i = 0; i < n; i++) {


/* Brojimo koliko puta se javlja element a[i] */
int ni = 0, j;
for (j = 0; j < n; j++)
if (a[i] == a[j])
ni++;
/* Ako se javlja cesce od do tada najcesceg, azuriramo broj
pojavljivanja najcesceg elementa i vrednost najcesceg */
if (ni > nm) {
nm = ni;
m = a[i];
}
}

je

/* Ispisujemo najcesci element i njegov broj pojavljivanja */


printf("%d - %d\n", m, nm);

return 0;

sk
o

Reenje zadatka 10.9.3:

iz

an

/* Oslobadjamo niz */
free(a);

ro
n

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main() {
int n, i, j, lx, ux, ly, uy, **A;

le

kt

/* Ucitavamo dimenziju matrice */


scanf("%d", &n);

/* Dinamicki alociramo prostor */


A = malloc(n*sizeof(int*));
assert(A);
for (i = 0; i < n; i++) {
A[i] = malloc(n*sizeof(int));
assert(A[i]);
}
/* Ucitavamo elemente matrice */
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &A[i][j]);

364

B. Reenja zadataka

(2
01
5)

/* Spiralno ispisujemo raspon [lx, ux] * [ly, uy] */


lx = 0; ux = n-1; ly = 0; uy = n-1;
while (lx <= ux && ly <= uy) {
for (i = lx; i <= ux; i++)
printf("%d ", A[i][ly]);
for (j = ly+1; j <= uy; j++)
printf("%d ", A[ux][j]);
for (i = ux-1; i >= lx; i--)
printf("%d ", A[i][uy]);
for (j = uy-1; j >= ly+1; j--)
printf("%d ", A[lx][j]);
lx++; ux--; ly++; uy--;
}

an
sk
o

Reenje zadatka 10.9.4:

return 0;

iz

je

/* Oslobadjamo matricu */
for (i = 0; i < n; i++)
free(A[i]);
free(A);

ro
n

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

le

kt

int skalarni_proizvod(int *a, int *b, int n) {


int suma = 0, i;
for (i = 0; i < n; i++)
suma += a[i]*b[i];
return suma;
}

int ortonormirana(int** A, int n) {


int i, j;
for (i = 0; i < n; i++) {
if (skalarni_proizvod(A[i], A[i], n) != 1)
return 0;
for (j = i+1; j < n; j++)
if (skalarni_proizvod(A[i], A[j], n) != 0)
return 0;
}
return 1;
}

365

B. Reenja zadataka

int main() {
int n, i, j, **A;
/* Ucitavamo dimenziju matrice */
scanf("%d", &n);

(2
01
5)

/* Dinamicki alociramo prostor */


A = malloc(n*sizeof(int*));
assert(A);
for (i = 0; i < n; i++) {
A[i] = malloc(n*sizeof(int));
assert(A[i]);
}

an

je

/* Ucitavamo elemente matrice */


for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", &A[i][j]);

return 0;

iz

ro
n

sk
o

/* Oslobadjamo matricu */
for (i = 0; i < n; i++)
free(A[i]);
free(A);

/* Ispitujemo da li je matrica ortonormirana */


printf("%d\n", ortonormirana(A, n));

kt

Jezik C - ulaz/izlaz

le

Reenje zadatka 12.1:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
int zbir = 0;
for (i = 0; i < argc; i++)
zbir += atoi(argv[i]);
printf("%d\n", zbir);
return 0;
}

366

B. Reenja zadataka

Reenje zadatka 12.2:

(2
01
5)

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
/* Racuna se zbir kolone j matrice A dimenzije n */
int zbir_kolone(int** A, unsigned n, unsigned j) {
int i, zbir = 0;
for (i = 0; i < n; i++)
zbir += A[i][j];
return zbir;
}

an

je

int main(int argc, char* argv[]) {


unsigned n, i, j, max_j;
int **A, max;
FILE* dat;

sk
o

iz

if (argc < 2) {
fprintf(stderr, "Greska: nedostaje ime ulazne datoteke\n");
return -1;
}

kt

ro
n

dat = fopen(argv[1], "r");


if (dat == NULL) {
fprintf(stderr,
"Greska: ucitavanje datoteke %s nije uspelo\n",
argv[1]);
return -1;
}

le

/* Ucitavamo dimenziju matrice */


assert(fscanf(dat, "%u", &n) == 1);
assert(n >= 1);
/* Dinamicki alociramo prostor */
A = malloc(n*sizeof(int*));
assert(A);
for (i = 0; i < n; i++) {
A[i] = malloc(n*sizeof(int));
assert(A[i]);
}
/* Ucitavamo matricu */
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)

367

B. Reenja zadataka

/* Odredjujemo maksimum */
max_j = 0; max = zbir_kolone(A, n, 0);
for (j = 1; j < n; j++) {
int m = zbir_kolone(A, n, j);
if (m > max) {
max_j = j;
max = m;
}
}
/* Prijavljujemo rezultat */
printf("Kolona: %u Zbir: %d\n", max_j, max);

an

je

/* Oslobadjamo matricu */
for (i = 0; i < n; i++)
free(A[i]);
free(A);

iz

/* Zatvaramo datoteku */
fclose(dat);
return 0;

sk
o

(2
01
5)

assert(fscanf(dat, "%d", &A[i][j]) == 1);

ro
n

Reenje zadatka 12.3:

kt

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

le

#define KORAK 64

typedef struct {
char ime[20];
char prezime[20];
unsigned br_ispita;
} APSOLVENT;
int main() {
FILE* dat;
APSOLVENT* apsolventi = NULL, apsolvent;
unsigned aloc = 0, n = 0, i, zbir;
float prosek;
dat = fopen("apsolventi.txt", "r");

368

B. Reenja zadataka

if (dat == NULL) {
fprintf(stderr,
"Greska pri otvaranju datoteke apsolventi.txt\n");
return 1;
}

an

je

(2
01
5)

/* Ucitavanje apsolvenata uz dinamicku realokaciju niza */


while(fscanf(dat, "%s%s%d",
apsolvent.ime, apsolvent.prezime, &apsolvent.br_ispita)
== 3) {
if (n >= aloc) {
aloc += KORAK;
APSOLVENT* tmp = realloc(apsolventi, aloc*sizeof(APSOLVENT));
assert(tmp);
apsolventi = tmp;
}
apsolventi[n++] = apsolvent;
}

/* Zatvaramo datoteku */
fclose(dat);

sk
o

iz

/* Izracunavanje prosecnog broja ispita */


zbir = 0;
for (i = 0; i < n; i++)
zbir += apsolventi[i].br_ispita;
prosek = (float)zbir / n;

kt

ro
n

/* Ispisujemo apsolvente sa natprosecnim brojem ispita */


for (i = 0; i < n; i++)
if (apsolventi[i].br_ispita > prosek)
printf("%s %s: %d\n", apsolventi[i].ime,
apsolventi[i].prezime,
apsolventi[i].br_ispita);

le

/* Oslobadjamo memoriju */
free(apsolventi);

return 0;

Reenje zadatka 12.4:


#include <stdio.h>
#include <ctype.h>
#include <assert.h>

369

B. Reenja zadataka

/* Maksimalan broj cifara u zapisu */


#define MAX_DIGITS 100

je

(2
01
5)

/* Vrednost cifre predstavljene ASCII karakterom.


Npr. 0->0, ..., 9->9,
a->10, ..., f -> 15,
A -> 10, ..., F -> 15,
Za karakter koji nije alfanumericki vraca -1 */
signed char vrednost_cifre(unsigned char c) {
if (isdigit(c)) /* Cifre */
return c-0;
if (isalpha(c) && islower(c)) /* Mala slova */
return c-a + 10;
if (isalpha(c) && isupper(c)) /* Velika slova */
return c-A + 10;
return -1;
}

ro
n

sk
o

iz

an

/* Cita zapis niske s kao broja u osnovi b. Citanje se vrsi dok se


javljaju validne cifre u osnovi b. Koristi se Hornerova shema. */
unsigned btoi(char s[], unsigned char b) {
unsigned rez = 0, i;
for (i = 0; s[i]; i++) {
signed char c = vrednost_cifre(s[i]);
/* Karakter ne predstavlja validnu cifru u osnovi b */
if (c == -1 || c >= b) break;
rez = rez * b;
rez += c;
}
return rez;
}

le

kt

/* Odredjuje zapis cifre c kao ASCII karakter */


unsigned char zapis_cifre(unsigned c) {
assert(c <= 36);
if (0 <= c && c <= 9)
return 0 + c;
else if (10 <= c && c <= 36)
return a + c;
}
/* Zapisuje broj n u osnovi b.
Funkcija pretpostavlja da niska s sadrzi dovoljno karaktera za
zapis. */
void itob(unsigned n, unsigned char b, char s[]) {
/* Formira se niz cifara */
unsigned i = 0, j;
do {
s[i++] = zapis_cifre(n % b);

370

n /= b;
} while (n > 0);
s[i] = \0;
/* Obrce se niz cifara */
for (j = 0, --i; j < i; j++, i--) {
char tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}

(2
01
5)

B. Reenja zadataka

an

je

int main(int argc, char* argv[]) {


/* Broj u osnovi b koji se ucitava (niska cifara i vrednost) */
char s[MAX_DIGITS];
unsigned n;
/* Preveden broj u osnovu 2 */
char bs[MAX_DIGITS];
/* Datoteke iz kojih se ucitava i u koje se upisuje */
FILE *ulaz, *izlaz;

le

kt

ro
n

sk
o

iz

/* Otvaranje datoteka */
if (argc < 3) {
fprintf(stderr, "Upotreba: %s <ulaz> <izlaz>\n", argv[0]);
return 1;
}
ulaz = fopen(argv[1], "r");
if (ulaz == NULL) {
fprintf(stderr, "Greska prilikom otvaranja %s\n", argv[1]);
return 1;
}
izlaz = fopen(argv[2], "w");
if (izlaz == NULL) {
fprintf(stderr, "Greska prilikom otvaranja %s\n", argv[2]);
return 1;
}

/* Citanje i obrada brojeva */


while (fgets(s, MAX_DIGITS, ulaz) != NULL) {
char *t = s;
/* Ako je uneta prazna linija, prekida se postupak */
if (*t == \0 || *t == \n)
break;
if (*t == 0) {
t++;
if (*t == x || *t == X) {
/* Heksadekadni broj pocinje sa 0x ili 0X */
t++;
n = btoi(t, 16);
printf("%u\n", n);

iz

an

/* Zatvaramo datoteke */
fclose(ulaz);
fclose(izlaz);
return 0;

le

kt

ro
n

sk
o

itob(n, 2, bs);
fputs(bs, izlaz); fputc(\n, izlaz);
} else {
/* Oktalni broj pocinje sa 0 */
n = btoi(t, 8);
printf("%u\n", n);
itob(n, 2, bs);
fputs(bs, izlaz); fputc(\n, izlaz);
}
} else {
/* Dekadni broj */
n = btoi(t, 10);
printf("%u\n", n);
itob(n, 2, bs);
fputs(bs, izlaz); fputc(\n, izlaz);
}

je

B. Reenja zadataka

(2
01
5)

371

le

E
ro
n

kt
sk
o
d

iz
an
je

(2
01
5)

372
B. Reenja zadataka

(2
01
5)

Indeks
abakus, 12

an

ABC (raunar), 15
algoritam, 61

analitika maina, 13
API, 35, 269
argument funkcije, 86

iz

analogni zapis, 39

294

sk
o

argumenti komandne linije programa,


asembler, 29

getc, 289
getchar, 278
gets, 279
isalnum, 274
isalpha, 107, 274
isdigit, 107
isdigit, 274
islower, 274
isupper, 274
malloc, 258, 272
matematika (sin, cos, log2,
exp, . . . ), 275
printf, 93, 280
putc, 289
putchar, 278
rand, 272
realloc, 260, 272
scanf, 95, 283
sprintf, 285
sqrt, 96, 275
srand, 272
sscanf, 286
strcat, 269
strchr, 269
strcmp, 269
strcpy, 136, 248, 269
strlen, 135, 247, 269
strstr, 269
system, 272
tolower, 107, 274
toupper, 107, 274

je

32-bitni i 64-bitni sistem, 105, 219

ro
n

automatska promenljiva, 200


bajt, 11, 104

biblioteka funkcija

le

kt

assert, 276
calloc, 258, 272
exit, 272
fclose, 288
feof, 290
ferror, 290
fgets, 291
fopen, 287
fprintf, 292
fputs, 279, 291
fread, 292
free, 259, 272
fscanf, 292
fseek, 293
ftell, 293
fwrite, 292

373

374

B. Reenja zadataka

ungetc,

290

Fon Nojmanova arhitektura rau-

biblioteka programskog jezika, 35

nara, 16

bit, 11, 12, 44, 104

font, 48

blok, 97, 152, 198

format niska, 95, 105107, 280, 283

blok dijagram, 62

fragmentisanje memorije, 264

brojevni sistem, 40

funkcija, 85, 167


argument, 170

heksadekadni, 41, 44, 109

definicija, 168, 169

oktalni, 41, 109

deklaracija, 94, 168, 169

main,

buena kartica, 13, 14

(2
01
5)

binarni, 11, 38, 40, 44

93, 167, 190, 294

parametar, 170
C (programski jezik), 18

poziv, 168

ANSI/ISO C, 92

prenos argumenata, 171, 223

C11, 92

prenos argumenata po adresi,

C99, 92

je

239

curenje memorije, 262

prenos argumenata po vrednosti,

an

171

er-Tjuringova teza, 63

prenos niza, 174, 242


prototip, vidi funkcija (deklaracija)

datoteka, 286
tekstualna, 287

iz

binarna, 287
datoteka zaglavlja, 94, 186, 194, 269

ro
n

sk
o

<assert.h>, 276
<ctype.h>, 106, 274
<math.h>, 96, 275
<stdio.h>, 94, 277
<stdlib.h>, 258, 272
<string.h>, 269

debager, 190

kt

definicija, 169, 204


naelna, 204

le

stvarna, 204

deklaracija, 101, 133, 169, 204

deljenje vremena, 18
diferencijska maina, 13

sa promenljivim brojem argumenata, 179

void,

171

funkcionalna dekompozicija programa,


192
generacije raunara, 16
generisanje i optimizacija koda, 187
glif, 48
globalna promenljiva, 103, 169, 199,
201
greka u programu, 94
izvravanje, 210, 230, 235, 262
kompilacija, 209
povezivanje, 209
pretprocesiranje, 209

digitalni zapis, 38, 39

halting problem, 72

dinamika alokacija memorije, 258

hard disk, 26

doseg identifikatora, 83, 103, 192,

hardver, 11, 16, 22

198
EDVAC raunar, 16
elektromehanike maine, 13

hip, vidi segment memorije (hip)


Holeritova maina, 13
Hornerova ema, 42

ENIAC (raunar), 15

identifikator, 102, 169

enigma maina, 15

IEEE 754 standard, 47, 107, 127

375

B. Reenja zadataka

integrisano kolo, 17

celobrojna promocija, 129

integrisano razvojno okruenje, 189

democija, 127

interpretator, 78, 87

eksplicitna, 126

izraunljiva funkcija, 63

implicitna, 126, 241

izraz, 85, 101, 112

promocija, 126

izvorna datoteka, 192

uobiajena aritmetika, 129

izvorni program, 78, 87, 94, 185,

kvalifikator

auto, 193, 200


const, 103, 171, 174, 235
extern, 193, 205
long, 104
long long, 104
register, 193
short, 104
signed, 104, 106
static, 193, 200, 202, 205, 207
unsigned, 104, 106

(2
01
5)

192
izvrni program, 79, 87, 94, 185,
218
jedinica prevoenja, 186, 192, 194,
203
jeziki procesor, vidi programski pre-

je

vodilac

kardinalnost, 69
kastovanje, vidi konverzija tipova (eksplicitna)

ASCII, 49, 106

iz

leksema, 81, 186

kodiranje karaktera, 48

leksika analiza, 186


leksiki analizator, 81, 87

sk
o

ISO-8859, 51

l-vrednost, 114, 115, 134, 241


Lajbnicova maina, 12

klizni lenjir, 12

ISO-10646, 52

an

karakter, 48

leksika programskog jezika, 80


lenjo izraunavanje, 118, 122
linker, vidi poveziva

UCS-2, 54

lokalna funkcija, 199

ro
n

kdna strana, 48
Unicode, 52
UTF-8, 54

lokalna promenljiva, 103, 169, 171,


199, 200

windows-125x/ANSI, 51

kt

YUSCII, 50

magistrala, 23
magnetni dobo, 17

komentar, 94

make (program), 189

kompilacija, 186

makro, vidi pretprocesorska direk-

le

Kolos (raunar), 15

odvojena, 189

tiva

define

kompilator, 78, 87, 186

Manesterska Beba (raunar), 17

konflikt identifikatora, 200

Mark I (raunar)

konstanta, 101, 109


celobrojna, 109

harvardski, 14
manesterski, 17

karakterska, 110

matina ploa, 23

u pokretnom zarezu, 110

matrica, vidi niz (dvodimenzioni)

konstanti izraz, 111

memorija

kontroler, 23

glavna, 16, 2325

konverzija tipova, 84, 110, 114, 115,

ke, 25

126, 173

RAM, 24, 26

376

B. Reenja zadataka

ROM, 25

arnost, 112

spoljanja, 16, 24, 26

asocijativnost, 113

mikroip, 17

bitovski, 119

mikroprocesor, 19

dekrementiranje, 115

mini raunari, 18

dereferenciranja, 234, 244

model boja, 55

inkrementiranje, 115
logiki, 117

RGB, 55

postfiksni, 112, 115

(2
01
5)

CMYK, 56

prefiksni, 112, 115


naredba, 85

prioritet, 113

break, 155, 159


continue, 160
do-while, 99, 158
for, 98, 157
goto, 151
if, 97, 152

referenciranja, 234, 244


relacijski, 104, 107, 117

sizeof,

je

uslovni, 122
zarez, 122

174

nazubljivanje koda, 94
neodluiv problem, 71

parametar funkcije, 86

prenos po adresi, 86

sk
o

prenos po vrednosti, 86

Paskalina, 12

iz

naredba dodele, 85, 113

niska, 134

an

izraza, 151

return, 94, 168,


switch, 155
while, 98, 156

123, 134, 142, 241

sloene dodele, 121

pokaziva, 233
na funkciju, 254

pokazivai i nizovi, 241

doslovna niska, 246

pokazivaka aritmetika, 241, 244

zavrna nula, 135

polje bitova, 145

ro
n

niz, 132

poluprovodniki elementi, 17
potprogram, 85

dvodimenzioni, 137, 250

povezanost identifikatora, 192, 203

indeks, 133, 241

poveziva, 187

inicijalizacija, 133, 135

povezivanje, 186, 187

kt

deklaracija, 133

niz pokazivaa, 250

le

prenos u funkciju, 174


viedimenzioni, 137

NULL,

235

dinamiko, 188, 218


statiko, 188
pragmatika programskog jezika, 83
prebrojiv skup, 69
prekoraenje, 105

objektni modul, 187

prekoraenje bafera, 264

objektno-orijentisano programiranje,

prelazak u novi red, 50

79

pretprocesiranje, 186, 193

odbirak, 39, 57

pretprocesor, 186, 193

operativni sistem, 34, 218

pretprocesorska direktiva, 193

operator, 101, 112

->,

253

adresni, 234
aritmetiki, 104, 107, 114

define, 98, 194


if-elif-endif, 197
ifdef/ifndef, 197
include, 94, 193

377

B. Reenja zadataka

undef,

sempl, vidi odbirak

196

preusmeravanje (redirekcija) ulaza


i izlaza, 277

sintaksa programskog jezika, 80, 81


sintaksika analiza, 186

procesor, 16, 22, 23

sintaksiki analizator, 82, 87

procesorska instrukcija, 29

sintaksiko stablo, 81

programiranje, 11

sloenost izraunavanja, 73

programska paradigma, 80

softver, 11, 16, 34

programski jezik

(2
01
5)

aplikativni, 34

asemblerski, 28

sistemski, 34, 91

mainski, 27, 28, 33, 87

standardna biblioteka programskog

mainski zavisan, 26

jezika, 86, 93, 188, 269

vii, 17, 27, 79, 87

standardni izlaz, 93, 277

programski prevodilac, 78, 87, 94


gcc, 94, 96, 187189, 210, 220
promenljiva, 83, 101

standardni izlaz za greke, 208, 277


standardni ulaz, 95, 277

je

statika promenljiva, 201, 202


stek, vidi segment memorije (stek)

inicijalizacija, 99, 102

string, vidi niska

an

deklaracija, 95, 101, 102


propratni efekat, 114, 115

struktura, 140

punilac, 190
raunar, 11
elektromehaniki, 14
elektronski, 14

iz

definicija, 141

78

sk
o

fon Nojmanove arhitekture, 16,

inicijalizacija, 142
prenos u funkciju, 177

strukturno programiranje, 79, 85


terminal, 18
tip podataka, 83, 101, 104

rantajm biblioteka, 35, 86, 218

bool, 108
char, 106
double, 96, 107
float, 107
int, 93, 104

rasterska grafika, 55

korisniki definisan, 140

rekurzija, 178, 225

logiki, 108

lini, 19

ro
n

sa skladitenim programom, 16
raunarstvo i informatika, 11

kt

oblasti, 21

le

rezolucija, 56

sakuplja otpada, 86

long double, 107


nabrojivi (enum), 140,

segment memorije, 220

pokazivaki, 233

hip, 258, 265

polje bitova, 145

segment kda, 220


segment podataka, 221
stek, 221
sekvenciona taka, 116
semantika analiza, 187

size_t,

123

struktura (struct), 140

typedef, 147
unija (union),
void*, 235

140, 144

semantiki analizator, 87

Tjuringova maina, 62

semantika programskog jezika, 80,

tok, 277

82

146

opseg, 105

token, 81

378

B. Reenja zadataka

tranzistor, 17
ulazno-izlazni ureaji, 16, 23, 26
unija, 144
Unix (operativni sistem), 18, 91
upozorenje prevodioca, 95, 210

(2
01
5)

UR maina, 62, 64
vakuumska cev, 17
vektorska grafika, 55
Z3 (raunar), 14
zapis
fiksni zarez, 47
neoznaeni brojevi, 41

je

oznaena apsolutna vrednost, 45

an

oznaeni brojevi, 45
pokretni zarez, 47, 107
potpuni komplement, 45

realni brojevi, 46

iz

slika, 55
tekst, 48

akardov razboj, 13

sk
o

zvuk, 56

le

kt

ro
n

ivotni vek promenljive, 83, 192, 200