Professional Documents
Culture Documents
p1 PDF
p1 PDF
le
kt
ro
n
sk
o
iz
d
an
je
(2
01
5)
E
le
kt
ro
n
sk
o
iz
d
an
je
(2
01
5)
Filip Mari Predrag Janii
5)
01
(2
PROGRAMIRANJE 1
je
Osnove programiranja kroz programski jezik C
an
d
iz
o
sk
n
ro
kt
le
E
Beograd
2015.
Autori:
dr Filip Mari, docent na Matematikom fakultetu u Beogradu
dr Predrag Janii, redovni profesor na Matematikom fakultetu u Beogradu
PROGRAMIRANJE 1
5)
Za izdavaa: prof. dr Zoran Raki, dekan
Recenzenti:
01
dr Gordana Pavlovi-Laeti, redovni profesor na Matematikom fakultetu u
Beogradu
(2
dr Miodrag ivkovi, redovni profesor na Matematikom fakultetu u Beogradu
dr Dragan Uroevi, nauni savetnik na Matematikom institutu SANU
je
an
d
iz
o
sk
n
ro
kt
ISBN 978-86-7589-100-0
le
E
01
(2
je
Sadraj 5
an
I Osnovni pojmovi raunarstva i programiranja 10
d
3 Algoritmi i izraunljivost 61
le
5
4.4 Pragmatika programskih jezika . . . . . . . . . . . . . . . . . . 83
II Jezik C 90
5 Osnovno o programskom jeziku C 91
5.1 Standardizacija jezika . . . . . . . . . . . . . . . . . . . . . . . 91
5.2 Prvi programi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5)
6 Predstavljanje podataka i operacije nad njima 101
01
6.1 Promenljive i deklaracije . . . . . . . . . . . . . . . . . . . . . . 101
6.2 Osnovni tipovi podataka . . . . . . . . . . . . . . . . . . . . . . 104
6.3 Konstante i konstantni izrazi . . . . . . . . . . . . . . . . . . . 109
(2
6.4 Operatori i izrazi . . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.5 Konverzije tipova . . . . . . . . . . . . . . . . . . . . . . . . . . 126
6.6 Nizovi i niske . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
je
6.7 Korisniki definisani tipovi . . . . . . . . . . . . . . . . . . . . . 140
an
7 Naredbe i kontrola toka 151
7.1 Naredba izraza . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
d
8 Funkcije 168
o
sk
5)
11.2 Zaglavlje stdlib.h . . . . . . . . . . . . . . . . . . . . . . . . . 272
11.3 Zaglavlje ctype.h . . . . . . . . . . . . . . . . . . . . . . . . . 274
01
11.4 Zaglavlje math.h . . . . . . . . . . . . . . . . . . . . . . . . . . 275
11.5 Zaglavlje assert.h . . . . . . . . . . . . . . . . . . . . . . . . . 276
(2
12 Ulaz i izlaz programa 277
12.1 Standardni tokovi . . . . . . . . . . . . . . . . . . . . . . . . . . 277
je
12.2 Ulaz iz niske i izlaz u nisku . . . . . . . . . . . . . . . . . . . . 285
12.3 Ulaz iz datoteka i izlaz u datoteke . . . . . . . . . . . . . . . . 286
an
12.4 Argumenti komandne linije programa . . . . . . . . . . . . . . 294
Indeks 373
o
sk
n
ro
kt
le
E
7
5)
Predgovor
01
(2
Ova knjiga pisana je kao udbenik za predmet Programiranje 1 na smeru
je
Informatika Matematikog fakulteta u Beogradu. U ovom predmetu i u ovoj
knjizi, centralno mesto ima programski jezik C, ali predmet i knjiga nisu samo
an
kurs ovog jezika, ve pokuavaju da dju ire osnove programiranja, ilustrovane
kroz jedan konkretan jezik.
d
lovima koji se u okviru tog predmeta ne predaju ili se predaju u vrlo ogranie-
nom obimu. Zahvaljujui tome, ova knjiga i njen nastavak (Programiranje 2
o
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 peri-
odu 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
8
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-
cenzentima Gordani Pavlovi-Laeti, Miodragu ivkoviu i Draganu Uroe-
5)
viu. Na brojnim sugestijama i ispravkama zahvalni smo i nastavnicima Matem-
atikog fakulteta Mileni Vujoevi-Janii, Nenadu Mitiu i Mladenu Nikoliu,
01
kao i studentima Nikoli Premevskom, Mladenu Canoviu, Nemanji Mioviu,
Vojislavu Grujiu, Stefanu oreviu, Petru Vukmiroviu, Bobanu Piskuliu,
(2
Jani Proti, Ljubici Peleksi, Ivanu Baleviu, Danielu Doi, Milou Samardiji,
Stefanu Saviu, Petru Kovrliji i Tomislavu Milovanoviu.
Ova knjiga dostupna je (besplatno) u elektronskom obliku preko internet
je
strana autora. Sadraj tampanog i elektronskog izdanja je identian. Be-
splatna dostupnost elektronskog oblika knjige odraava stav autora o otvorenim
an
sadrajima kdu programa i sadraju knjiga.
d
iz
Autori
o
sk
9
5)
01
(2
Deo I
10
Glava 1
5)
Raunarstvo i raunarski sistemi
01
(2
je
Raunarstvo i informatika predstavljaju jednu od najatraktivnijih i naj-
vanijih oblasti dananjice. ivot u savremenom drutvu ne moe se zamis-
an
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
d
i jedinica tj. binarnih cifara, tj. bitova (engl. bit, od binary digit ). Koristei
sk
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 izrauna-
vanja koja vri raunar. Raunarstvo je danas veoma iroka i dobro utemeljena
nauna disciplina sa mnotvom podoblasti.
5)
Programiranje u savremenom smislu postalo je praktino mogue tek kra-
jem Drugog svetskog rata, ali je njegova istorija znatno starija. Prvi pre-
cizni postupci i sprave za reavanje matematikih problema postojali su jo
01
u vreme antikih civilizacija. Na primer, kao pomo pri izvoenju osnovnih
matematikih operacija koriene su raunaljke zvane abakus . U IX veku per-
3 precizno je opisao postupke raunanja u indo-
(2
sijski matematiar Al Horezmi
arapskom dekadnom brojevnom sistemu (koji i danas predstavlja najkorieniji
brojevni sistem). U XIII veku Leonardo Fibonai
4 doneo je ovaj nain zapi-
je
sivanja brojeva iz Azije u Evropu i to je bio jedan od kljunih preduslova za
razvoj matematike i tehnikih disciplina tokom renesanse. Otkrie logaritma
an
omoguilo je svoenje mnoenja na sabiranje, dodatno olakano raznovrsnim
5
analognih spravama (npr. klizni lenjir iber ) . Prve mehanike sprave koje
su mogle da potpuno automatski izvode aritmetike operacije i pomau u rea-
d
5)
funkcija (i eliminie este ljudske greke u tom poslu) u cilju izrade to pre-
ciznijih logaritamskih tablica. Ime je dobila zbog toga to je koristila tzv. metod
01
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
10 . Ubrzo nakon to je rad na prvom projektu utihnuo bez
(2
nikada zavrena
rezultata, Bebid je zapoeo rad na novoj maini nazvanoj analitika maina .
Osnovna razlika u odnosu na sve prethodne maine, koje su imale svoje speci-
je
fine namene, bila je u tome to je analitika maina zamiljena kao raun-
ska maina opte namene koja moe da se programira (programima zapisanim
an
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-
d
mlin (engl. mill) i skladite (engl. store), koji po svojoj funkcionalnosti sasvim
odgovaraju procesoru i memoriji dananjih raunara. Ada Bajron
11 zajedno
sa Bebidem napisala je prve programe za analitiku mainu i, da je maina
o
zove brojeva (takozvane Bernulijeve brojeve). Zbog ovoga se ona smatra prvim
programerom u istoriji (i njoj u ast jedan programski jezik nosi ime Ada ).
n
Herman Holerit
stanovnitva u SAD. Naime, obrada rezultata popisa iz 1880. godine trajala
je vie od 7 godina, a zbog naglog porasta broja stanovnika procenjeno je
5)
01
(2
Slika 1.2: akardov razboj. Bebidova diferencijska maina.
je
da bi obrada rezultata iz 1890. godine trajala vie od 10 godina, to je bilo
an
neprihvatljivo mnogo. Holerit je sproveo ideju da se podaci prilikom popisa za-
pisuju na mainski itljivom medijumu (na buenim karticama), a da se kasnije
obrauju njegovom mainom. Koristei ovaj pristup obrada rezultata popisa
d
raunarom
14 . Cuzeove maine tokom Drugog svetskog rata naile su samo na
ograniene primene. Cuzeova kompanija proizvela je oko 250 razliitih tipova
n
instrukcije sa buene papirne trake, imala je preko 760000 delova, duinu 17m,
visinu 2.4m i masu 4.5t. Mark I mogao je da pohrani u memoriji (korienjem
le
sekundi.
5)
01
(2
je
Slika 1.3: Holeritova maina. Harvard Mark I. ENIAC (proces reprogrami-
ranja).
an
16 i Beri 17 .
d
gramabilna.
sk
30m i masu 30t. 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.
5)
kablove u okviru kompleksnog sistema ENIAC i tako ga instruisali da izvrava
novi zadatak.
01
Potpuna konceptualna promena dola je kasnih 1940-ih, sa pojavom rauna-
ra koji programe na osnovu kojih rade uvaju u memoriji zajedno sa podacima
(2
raunara sa skladitenim programima (engl. stored program computers) . U
okviru ovih raunara, postoji jasna podela na hardver i softver. Iako ideje
za ovaj koncept datiraju jo od arlsa Bebida i njegove analitike maine i
je
nastavljaju se kroz radove Tjuringa, Cuzea, Ekerta, Moklija, za rodonaelnika
ovakve arhitekture raunara smatra se Don fon Nojman
21 . Fon Nojman se u
an
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
d
kojoj se programi mogu uitavati isto kao i podaci koji se obrauju. Rau-
iz
nara EDVAC bio prvi opis fon Nojmanove arhitekture, pre 1951. godine - kada
sk
soru zadaje koju akciju ili operaciju da izvri). I podaci i programi se zapisuju
obino kao binarni sadraj i nema nikakve sutinske razlike izmeu zapisa pro-
grama 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-
turi.
5)
Slika 1.4: Osnovni gradivni elementi korieni u etiri generacije raunara:
01
vakuumska cev, tranzistor, integrisano kolo i mikroprocesor
(2
I generacija raunara (od kraja 1930-ih do kraja 1950-ih) koristila je vaku-
umske cevi kao logika kola i magnetne doboe (a delom i magnetne trake) za
je
memoriju. Za programiranje su korieni mainski jezik i asembler a glavne
primene su bile vojne i naune. Raunari su uglavnom bili unikatni (tj. za
an
veinu nije postojala serijska proizvodnja). Prvi realizovani raunari fon No-
jmanove arhitekture bili su Manesterska Beba (engl. Manchester Baby)
eksperimentalna maina, razvijena 1949. na Univerzitetu u Manesteru, na
d
II generacija raunara
ro
dine, tek sredinom pedesetih poinje da se koristi umesto vakuumskih cevi kao
osnovna elektronska komponenta u okviru raunara. Tranzistori su izgraeni
od tzv. poluprovodnikih elemenata (obino silicijuma ili germanijuma). U
le
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-
dine.
5)
01
Slika 1.5: Integrisana kola dovela su do minijaturizacije i kompleksni iani
spojevi su mogli biti realizovani na izuzetno maloj povrini.
(2
Nova tehnologija omoguila je poslovnu primenu raunara u mnogim oblas-
je
tima. U ovoj eri dominirali su mejnfrejm (engl. mainframe)mejnfrejm raunari
raunari koji su bili izrazito moni za to doba, ija se brzina merila milionima
an
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
d
ovo vreme uvedeni su prvi standardi za jezike vieg nivoa (npr. ANSI FOR-
TRAN). Korieni su razliiti operativni sistemi, uglavnom razvijeni u okviru
kompanije IBM. Sa udelom od 90%, kompanija IBM je imala apsolutnu domi-
n
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).
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.
19 1. Raunarstvo i raunarski sistemi
5)
Slika 1.6: Mejnfrejm raunar: IBM 7094. Mini raunar: DEC PDP 7
01
U kompaniji Intel 1971. godine napravljen je prvi mikroprocesor Intel 4004
(2
celokupna centralna procesorska jedinica bila je smetena na jednom ipu. Iako
prvobitno namenjena za ugradnju u kalkulatore, ova tehnologija omoguila je
razvoj brzih a malih raunara pogodnih za linu tj. kunu upotrebu.
je
asopis Popular electronics nudio je 1975. godine itaocima mogunost
naruivanja delova za sklapanje mikroraunara MITS Altair 8800 zasnovanog
an
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
d
raunarske opreme.
Kuni raunari koristili su se sve vie uglavnom od strane entuzijasta
za jednostavnije obrade podataka, uenje programiranja i igranje rau-
kt
5)
01
(2
je
Slika 1.7: Prvi mikroprocesor: Intel 4004. Naslovna strana asopisa Popular
electronics sa Altair 8800. Commodore 64. IBM PC 5150.
an
raunara koji nisu proizvedeni u okviru kompanije IBM, ali koji su kompat-
d
tritu (pre svega u SAD) je serija raunara Macintosh kompanije Apple. Mac-
intosh, koji se pojavio 1984., je prvi komercijalni kuni raunar sa grafikim
le
5)
01
(2
je
Slika 1.8: Stoni raunar. Prenosni raunar: IBM ThinkPad. Tablet: Apple
Ipad 2. Pametni telefon: Samsung Galaxy S2.
an
su i prenosni (engl. notebook ili laptop) raunari. U najnovije vreme, javlja
d
5)
Prevoenje programskih jezika (efikasno prevoenje viih programskih
jezika, obino na mainski jezik);
01
Operativni sistemi (sistemi za upravljanje raunarom i programima);
(2
Mreno raunarstvo (algoritmi i protokoli za komunikaciju izmeu rau-
nara);
je
Primene (dizajn i razvoj softvera za svakodnevnu upotrebu);
an
Istraivanje podataka (pronalaenje relevantnih informacija u velikim sku-
povima podataka);
d
rija), 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 znaa-
jnija je podela na osnovu koje raunar ine:
5)
Sve nabrojane komponente meusobno su povezane i podaci se tokom rada
01
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
(2
podataka. Svi periferijski ureaji se sa memorijom, procesorom i magistralama
povezuju hardverskim sklopovima koji se nazivaju kontroleri . Matina ploa
(engl. motherboard) je tampana ploa na koju se prikljuuju procesor, mem-
je
orijski ipovi i svi periferijski ureaji. Na njoj se nalaze ipovi magistrale, a
danas i mnogi kontroleri periferijskih ureaja. Osnovu hardvera savremenih
an
raunara, dakle, ine sledee komponente:
d
CPU
Kontrolna Aritmetiko
registri
magistrala
5)
01
Ulazni Izlazni
Memorija
ureaji ureaji
(2
Slika 1.9: Shema raunara fon Nojmanove arhitekture
je
an
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
(GHz)) vei radni takt obino omoguava izvravanje veeg broja operacija
d
u jedinici vremena.
iz
linearno ureeni niz registara (najee bajtova), pri emu svaki registar ima
svoju adresu. Kako se kod ove memorije sadraju moe pristupati u sluajnom
redosledu (bez unapred fiksiranog redosleda), ova memorija se esto naziva
n
pod napajanjem
registri
Ke memorija
RAM
5)
ROM/BIOS
01
nia cena/vei kapacitet
bez napajanja
USB diskovi
(2
hard diskovi
je
CD, DVD, Blu-ray, magnetne trake
an
Slika 1.10: Memorijska hijerarhija
d
iz
orija. Pre pristupa glavnoj memoriji procesor uvek prvo pristupa keu. Ako
traeni podatak tamo postoji, u pitanju je tzv. pogodak kea (engl. cache hit) i
kt
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 mem-
orija koja sadri osnovne programe koji slue za kontrolu odreenih kompone-
nata raunara (na primer, osnovni ulazno-izlazni sistem BIOS). Znatno vei
deo glavne memorije ini RAM privremena promenljiva memorija sa slobod-
nim pristupom. Terminoloki, podela glavne memorije na ROM i RAM nije
26 1. Raunarstvo i raunarski sistemi
5)
Spoljne memorije uvaju podatke trajno, i kada raunar ostane bez elek-
trinog napajanja. Kao centralna spoljna skladita podataka uglavnom se ko-
01
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
(2
drive) koji uvaju podatke korienjem elektronskih tzv. fle memorija (engl.
flash memory). Kao prenosne spoljne memorije koriste se uglavnom USB fle-
memorije (izraene u slinoj tehnologiji kao i SSD) i optiki diskovi (CD, DVD,
je
Blu-ray).
an
Ulazni ureaji. Osnovni ulazni ureaji dananjih raunara su tastature i
mievi. Prenosni raunari imaju ugraenu tastaturu, a umesto mia moe se
d
5)
1.5.1 Primeri opisa izraunavanja
01
Program specifikuje koje operacije treba izvriti da bi se reio neki zadatak.
Principi rada programa mogu se ilustrovati na primeru nekoliko jednostavnih
(2
izraunavanja i instrukcija koje ih opisuju. Ovi opisi izraunavanja dati su u
vidu prirodno-jezikog opisa ali direktno odgovaraju i programima na viim
programskim jezicima.
je
Kao prvi primer, razmotrimo izraunavanje vrednosti 2 + 3 za datu vred-
nost . U programiranju (slino kao i u matematici) podaci se predstavljaju
an
promenljivama. Meutim, promenljive u programiranju (za razliku od matem-
atike) vremenom mogu da menjaju svoju vrednost (tada kaemo da im se
dodeljuje nova vrednost). U programiranju, svakoj promenljivoj pridrueno je
d
y := 2*x + 3
n
unari (tj. njihovi procesori) obino imaju instrukcije za poreenje brojeva, ali
odreivanje vrednosti veeg broja zahteva nekoliko koraka. Pretpostavimo da
le
opisom.
5)
s := 1, i := 0
dok je i < n radi sledee:
01
s := sx, i := i+1
(2
niz koraka.
s := 1, i := 0, poto je i(=0) manje od
n(=2), vre se dalje ope-
je
racije
s := sx = 13 = 3, i := i+1 = 0+1 = 1, poto je i(=1) manje od
an
n(=2), vre se dalje ope-
racije
s := sx = 33 = 9, i := i+1 = 1+1 = 2, poto i(=2) nije manje od
d
operacije.
o
nostavne (na primer, postoje samo instrukcije za sabiranje dva broja, kon-
junkcija bitova, instrukcija skoka i slino) i nije lako kompleksne i apstraktne
le
5)
apred fiksiran, konaan skup instrukcija (engl. instruction set). Svaki program
raunara predstavljen je nizom instrukcija i skladiti se u memoriji raunara.
01
Naravno, raunari se razlikuju (na primer, po tome koliko registara u proce-
soru imaju, koje instrukcije moe da izvri njihova aritmetiko-logika jedinica,
(2
koliko memorije postoji na raunaru, itd). Meutim, da bi se objasnili osnovni
principi rada raunara nije neophodno razmatrati neki konkretan raunar, ve
se moe razmatrati neki hipotetiki raunar. Pretpostavimo da procesor sadri
je
tri registra oznaena sa ax, bx i cx i jo nekoliko izdvojenih bitova (tzv. zas-
tavica). Dalje, pretpostavimo da procesor moe da izvrava naredne aritmetike
an
instrukcije (zapisane ovde u asemblerskom obliku):
u registar ax. Operacija add moe se primeniti na bilo koja dva registra.
Instrukcija mul ax, bx oznaava operaciju mnoenja vrednosti brojeva
o
u registar ax. Operacija mul moe se primeniti na bilo koja dva registra.
Instrukcija cmp ax, bx oznaava operaciju poreenja vrednosti brojeva
n
5)
instrukciju ove vrste.
01
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
(2
se pristupa podacima u odreenom registru), broj u zagradama (to oz-
naava da se pristupa podacima u memoriji i to na adresi odreenoj
brojem u zagradama) ili samo broj (to oznaava da je podatak ba taj
je
navedeni broj). Na primer, instrukcija mov ax bx oznaava da se sadraj
bx prepisuje u registar ax, instrukcija mov ax, [10] oznaava da
an
registra
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 instruk-
d
mov bx, 2
mul ax, bx
kt
mov bx, 3
add ax, bx
le
mov [11], ax
E
10, broj na adresi 11, dok rezultat treba smestiti na adresu 12. Program
(niz instrukcija) kojima moe da se odredi maksimum je sledei:
5)
jmp kraj
vecix:
01
mov[12], ax
kraj:
(2
Nakon prenosa vrednosti oba broja u registre procesora (instrukcijama mov
ax, [10] i mov bx, [11]), vri se njihovo poreenje (instrukcija cmp ax, bx).
je
Ukoliko je broj vei od ili jednak broju prelazi se na mesto oznaeno labe-
lom vecix (instrukcijom jge vecix) i na mesto rezultata upisuje se vrednost
promenljive (instrukcijom mov[12], ax). Ukoliko uslov skoka jge nije is-
an
punjen (ako nije vee ili jednako ), na mesto rezultata upisuje se vrednost
promenljive (instrukcijom mov [12], bx) i bezuslovno se skae na kraj pro-
d
ax, a promenljiva u registru bx. Poto postoji jo samo jedan registar (cx), u
njega e naizmenino biti smetane vrednosti promenljivih i , kao i konstanta
ro
mov ax, 1
mov bx, 0
le
petlja:
E
10: 3 ax: ?
11: 2 bx: ?
12: ? cx: ?
5)
Nakon izvravanja prve dve instrukcije (mov ax, 1 i mov bx, 0), postavlja
01
se vrednost registara ax i bx i prelazi se u sledeu konfiguraciju:
10: 3 ax: 1
(2
11: 2 bx: 0
12: ? cx: ?
je
Sledea instrukcija (mov cx, [11]) kopira vrednost 2 sa adrese 11 u regis-
tar cx:
an
10: 3 ax: 1
11: 2 bx: 0
d
12: ? cx: 2
iz
10: 3 ax: 3
11: 2 bx: 0
ro
12: ? cx: 3
kt
istru bx uveava za 1.
10: 3 ax: 3
E
11: 2 bx: 1
12: ? cx: 1
10: 3 ax: 9
11: 2 bx: 2
12: ? cx: 1
5)
njom instrukcijom (mov [12], ax) konana vrednost iz registra ax kopira u
memoriju na dogovorenu adresu 12, ime se stie u zavrnu konfiguraciju:
01
10: 3 ax: 9
11: 2 bx: 2
(2
12: 9 cx: 1
je
Mainski jezik. Fon Nojmanova arhitektura podrazumeva da se i sam pro-
an
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,
d
add 010
mul 011
o
cmp 100
sk
jge 101
jmp 110
n
registarsko 01
apsolutno 10
ax 00, bx 01,
le
5)
jednu instrukciju i izvrava akciju zadatu tom instrukcijom. Kod realnih proce-
sora, broj instrukcija i naini adresiranja su mnogo bogatiji a prilikom pisanja
01
programa potrebno je uzeti u obzir mnoge aspekte na koje se u navedenim
jednostavnim primerima nije obraala panja. Ipak, mainske i asemblerske
(2
instrukcije stvarnih procesora veoma su sline navedenim hipotetikim instruk-
cijama.
je
1.5.3 Klasifikacija savremenog softvera
an
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
d
funkcionalnost koju mu nudi sloj ispod njega. U skladu sa tim, softver savre-
menih raunara se obino deli na aplikativni i sistemski . Osnovni zadatak
n
5)
orijama itd. Najznaanjni operativni sistemi danas su Microsoft Windows,
sistemi zasnovani na Linux jezgru (na primer, Ubuntu, RedHat, Fedora, Suse)
01
i Mac OS X.
OS upravlja svim resursima raunara (procesorom, memorijom, periferi-
(2
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
direktnu podrku specijalizovanog hardvera namenjenog iskljuivo izvravanju
je
OS. Nekada se hardver i operativni sistem smatraju jedinstvenom celinom i
umesto podele na hardver i softver razmatra se podela na sistem (hardver i
an
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-
d
nije ako programer umesto da mora da kae Neka se zavrti ploa diska, neka
iz
Pitanja za vebu
Pitanje 1.1. Nabrojati osnovne periode u razvoju raunara i navesti njihove
osnovne karakteristike i predstavnike.
5)
Pitanje 1.3. Kojoj spravi koja se koristi u dananjem svetu najvie odgovaraju
Paskalove i Lajbnicove sprave?
01
Pitanje 1.4. Kakva je veza izmeu tkakih razboja i raunara s poetka XIX
(2
veka?
je
zovu i koja od njih je trebalo da bude programabilna? Ko se smatra prvim
programerom?
an
Pitanje 1.6. Na koji nain je Herman Holerit doprineo izvravanju popisa
d
stanovnika u SAD 1890? Kako su bili uvani podaci sa tog popisa? Koja
uvena kompanija je nastala iz kompanije koju je Holerit osnovao?
iz
Pitanje 1.8.
sk
ver a ta softver?
E
Pitanje 1.16.
5)
ta je to tehnoloka konvergencija? ta su to tableti, a ta
pametni telefoni?
01
Pitanje 1.17. Koje su osnovne komponente savremenog raunara? ta je
memorijska hijerarhija? Zato se uvodi ke-memorija? Koje su danas najko-
(2
rienije spoljne memorije?
Pitanje 1.18. U koju grupu jezika spadaju mainski jezici i asemblerski jezici?
Pitanje 1.19.
je
Da li je kd na nekom mainskom jeziku prenosiv sa jednog na
sve druge raunare? Da li asembler zavisi od maine na kojoj se koristi?
an
Pitanje 1.20. Ukoliko je raspoloiv asemblerski kd nekog programa, da li
je mogue jednoznano konstruisati odgovarajui mainski kd? Ukoliko je
d
ako je (x < 0)
ro
y := 3*x;
inace
kt
x := 3*y;
Zadatak 1.3. Na opisanom asemblerskom jeziku opisati izraunavanje:
le
x := x + 2*y + 3;
Zadatak 1.4.
Na opisanom asemblerskom jeziku opisati izraunavanje kojim
se izraunava [ ], pri emu se nalazi na adresi 100, a rezultat smeta na
adresu 200.
5)
Reprezentacija podataka u
01
raunarima
(2
je
an
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
d
ukoliko izmeu dve take postoji napon vii od odreenog praga, onda se smatra
sk
kompakt diska bui rupice kojim je odreen zapis podataka pa polje koje
nije izbueno predstavlja vrednost 0, a ono koje jeste izbuesno predstavlja
vrednost 1. U nastavku e biti pokazano da je azbuka od samo dva simbola
kt
38
39 2. Reprezentacija podataka u raunarima
5)
svojstva medijuma na kome je signal zapisan.
Osnovna prednost analogne tehnologije je da je ona obino veoma jednos-
01
tavna ukoliko se zadovoljimo relativno niskim kvalitetom (jo su drevni narodi
mogli da naprave nekakav zapis zvuka uz pomo jednostavne igle prikaene na
(2
trepereu membranu).
Osnovni problem analogne tehnologije je to je izrazito teko na medijumu
napraviti veran zapis signala koji se zapisuje i izrazito je teko napraviti dva
je
identina zapisa istog signala. Takoe, problem predstavlja i inherentna nestal-
nost medijuma, njegova promenljivost tokom vremena i podlonost spoljanjim
an
uticajima. S obzirom na to da varijacije medijuma direktno dovode do vari-
jacije zapisanog signala, vremenom neizbeno dolazi do pada kvaliteta analogno
zapisanog signala. Obrada analogno zapisanih signala je obino veoma komp-
d
Digitalni zapis.
o
5)
01
0
(2
Slika 2.1: Digitalizacija zvunog signala
je
pis brojeva koji predstavljaju vrednosti boja u takama digitalno zapisane fo-
an
tografije, injenica da papir uti ne bi predstavljala problem dok god se brojevi
mogu razaznati.
Digitalni zapis omoguava kreiranje apsolutno identinih kopija to dalje
d
stavlja problem sve dok se brojevi koji su na njima zapisani mogu razaznati.
Obrada digitalno zapisanih podataka se svodi na matematiku manipulaciju
n
izovanih maina.
Osnovni problem implementacije digitalnog zapisa predstavlja injenica da
je neophodno imati veoma razvijenu tehnologiju da bi se uopte stiglo do iole
kt
5)
prirodna broja je uvek jedan isti prirodni broj, bez obzira na to u kom sistemu
su ova tri broja zapisana.
01
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-
(2
ori samo celi brojevi, dok su ispravnija imena oznaeni celi brojevi (engl. signed
integers) i neoznaeni celi brojevi (engl. unsigned integers), koji podrazumevaju
konaan zapis. Ni svi realni brojevi (sa potencijalno beskonanim decimalnim
je
zapisom) ne mogu biti zapisani u raunaru. Za zapis zapisivih realnih bro-
jeva (koji su uvek racionalni) obino se koristi konvencija zapisa u pokretnom
an
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
d
( 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
:= 0
za svako od 0 do
:= +
ili, malo modifikovano:
5)
:= 0
01
za svako od 1 do
:= +
(2
Za izraunavanje vrednosti nekog ( + 1)-tocifrenog zapisa drugim nave-
(+1)
denim postupkom potrebno je sabiranja i + ( 1) + . . . + 1 =
2
je
mnoenja. Zaista, da bi se izraunalo potrebno je mnoenja, da bi se
1
izraunalo 1 potrebno je 1 mnoenja, itd. Meutim, ovo izrauna-
an
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
izraunavanja primenjen je u sledeem postupku:
d
iz
:= 0
:= 1
o
za svako od 1 do
:=
sk
:= +
n
sheme:
( 1 . . . 1 0 ) = (. . . (( + 1 ) + 2 ) . . . + 1 ) + 0
kt
:= 0
za svako od unazad do 0
:= +
3 2 1 0
9 8 7 6
0 0 10 + 9 = 9 9 10 + 8 = 98 98 10 + 7 = 987 987 10 + 6 = 9876
43 2. Reprezentacija podataka u raunarima
3 2 1 0
3 2 4 5
5)
0 08+3=3 3 8 + 2 = 26 26 8 + 4 = 212 212 8 + 5 = 1701
01
Navedena tabela moe se krae zapisati na sledei nain:
(2
3 2 4 5
0 3 26 212 1701
je
Hornerov postupak je efikasniji u odnosu na poetni postupak, jer je u
svakom koraku dovoljno izvriti samo jedno mnoenje i jedno sabiranje (ukupno
an
+1 sabiranja i +1 mnoenja).
d
poslednja cifra broja i broj koji se dobija uklanjanjem poslednje cifre iz zapisa.
sk
:= 0
dok je razliito od 0
le
:= mod
:= div
E
:= + 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:
0 1 2 3
1701 1701 div 8 = 212 212 div 8 = 26 26 div 8 = 3 3 div 8 = 0
1701 1701 mod 8 = 5 212 mod 8 = 4 26 mod 8 = 2 3 mod 8 = 3
44 2. Reprezentacija podataka u raunarima
1701 212 26 3 0
5 4 2 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
itaju unatrag.
5)
Ovaj algoritam i Hornerov algoritam su meusobno simetrini u smislu da
se svi meurezultati poklapaju.
01
Direktno prevoenje izmeu heksadekadnog i binarnog sistema.
(2
Osnovni razlog korienja heksadekadnog sistema je mogunost jednostavnog
prevoenja brojeva izmeu binarnog i heksadekadnog sistema. Pri tome, hek-
sadekadni sistem omoguava da se binarni sadraj memorije zapie kompakt-
je
nije (uz korienje manjeg broja cifara). Prevoenje se moe izvriti tako to
se grupiu etiri po etiri binarne cifre, krenuvi unazad, i svaka etvorka se
an
zasebno prevede u odgovarajuu heksadekadnu cifru na osnovu sledee tabele:
(1011 0110 0111 1100 0010 1001 1111 0001)2 = (6729 1)16
ro
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
u upotrebi oznaena apsolutna vrednost i potpuni komplement.
5)
Oznaena apsolutna vrednost. Zapis broja se formira tako to se na prvu
poziciju zapisa unapred fiksirane duine , upie znak broja, a na preostalih
01
1 pozicija upie zapis apsolutne vrednosti broja. Poto se za zapis koriste
samo dva simbola (0 i 1), konvencija je da se znak + zapisuje simbolom 0,
a znak simbolom 1. Ovim se postie da pozitivni brojevi imaju identian
(2
+100 = (0 1100100)82 ,
zapis kao da su u pitanju neoznaeni brojevi. Na primer,
8
100 = (1 1100100)2 .
Osnovni problem zapisa u obliku oznaene apsolutne vrednosti je injenica
je
da se osnovne aritmetike operacije teko izvode ukoliko su brojevi zapisani na
an
ovaj nain.
0.
sk
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
binarno dekadno
???????? -100
le
+ 01100100 +100
1 00000000 0
E
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
sledei nain. Ukoliko je poznat zapis broja, 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:
46 2. Reprezentacija podataka u raunarima
01100100 +100
10011011 komplementiranje
+ 1
10011100
Kao to je traeno, zapisi svih pozitivnih brojeva i nule poinju cifrom 0
dok zapisi negativnih brojeva poinju sa 1.
Broj 21 je jedini izuzetak u optem postupku odreivanja zapisa u pot-
punom komplementu. Zapis broja (100 . . . 00)2 je sam sebi komplementaran, a
5)
poto poinje cifrom 1, uzima se da on predstavlja zapis najmanjeg zapisivog
negativnog broja, tj. broja 21 . Zahvaljujui ovoj konvenciji, u zapisu pot-
01
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
(2
komplementu:
broj bita raspon
8 128
od do +127
je
16 od 32768 do +32767
32 od 2147483648 do +2147483647
an
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
d
narima.
sk
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,
E
(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 za-
pisuje 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.
Zapis u pokretnom zarezu podrazumeva oblik . Vrednost je osnova
5)
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
01
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
(2
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-
pisano je standardom IEEE 754 iz 1985. godine, meunarodne asocijacije In-
je
stitut inenjera elektrotehnike i elektronike, IEEE (engl. Institute of Electrical
and Electronics Engineers). Ovaj standard predvia da se odreene kombi-
an
nacije bitova odvoje za zapis tzv. specijalnih vrednosti (beskonanih vrednosti,
greaka u izraunavanju i slino).
Ilustrujmo osnovne principe zapisa realnih brojeva na dekadnom zapisu
d
nenegativnih realnih brojeva (kao to smo rekli, u raunaru se ovakav zapis in-
iz
dela, a odreeni broj cifara za zapis decimala i takav nain zapisa predstavlja
sk
male odvoje dva mesta, onda moemo zapisivati vrednosti 0,00, 0,01, ..., 9,98
ro
i 9,99. Ovim smo dobili bolju preciznost (svaki broj je zapisan sa dve, umesto
sa jednom decimalom), ali smo to platili mnogo uim rasponom brojeva koje
moemo zapisati (umesto irine oko 100, dobili smo raspono irine oko 10). U
kt
raunaru se fiksni zarez esto ostvaruje binarno (odreeni broj bitova kodira
ceo, a odreeni broj bitova kodira razlomljeni deo), pri emu se uvek jedan bit
le
Raspon je prilino irok (od 0, 000001 do 99 000, 0 tj. od oko 106 do oko
5
10 ) 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
brojeva preciznost zapisa je mnogo vea nego kod velikih. Na primer, kod malih
5)
brojeva moemo zapisivati veliki broj decimala, ali nijedan broj izmeu 98 000
i 99 000 nije mogue zapisati (brojevi iz tog raspona bi se morali zaokruiti na
01
neki od ova dva broja). Ovo nije preveliki problem, jer nam obino kod velikih
brojeva preciznost nije toliko bitna koliko kod malih (matematiki gledano,
(2
relativna greka koja nastaje usled zaokruivanja se ne menja puno kroz ceo
raspon). Dve vane komponente koje karakteriu svaki zapis u pokretnom
zarezu su raspon brojeva koji se mogu zapisati (u naem primeru to je bilo od
je
oko 106 do oko 105 ) i on je skoro potpuno odreen irinom eksponentna, kao i
broj dekadnih znaajnih cifara (u naem primer, imamo dve dekadne znaajne
an
cifre) i on je skoro potpuno odreeno irinom mantise.
fotografski elementi ili njihove kombinacije, koji ine sadraj dokumenta. Iako
se tekst obino zamilja kao dvodimenzioni objekat, u raunarima se tekst pred-
n
biti jednoznana. Naime, softver koji prikazuje tekst moe vie karaktera pred-
staviti 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 el-
jeni nain, bez obzira to je ispravno kodiran. Fontovi koji se obino instaliraju
uz operativni sistem sadre glifove za karaktere koji su popisani na takozvanoj
WGL4 listi (Windows Glyph List 4 ) koja sadri uglavnom karaktere koriene
5)
u evropskim jezicima, dok je za ispravan prikaz, na primer, kineskih karaktera,
potrebno instalirati dodatne fontove. Specijalnim karakterima se najee ne
01
pridruuju zasebni grafiki likovi.
(2
Englesko govorno podruje. Tokom razvoja raunarstva, broj karaktera
koje je bilo poeljno kodirati je postajao sve vei. Poto je raunarstvo u ranim
fazama bilo razvijano uglavnom u zemljama engleskog govornog podruja, bilo
je
je potrebno predstaviti sledee karaktere:
an
Mala slova engleskog alfabeta: a, b, ... , z
Velika slova engleskog alfabeta: A, B, ... , Z
d
Cifre 0, 1, ..., 9
iz
zapis karaktera.
ASCII.
le
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 NUL STX SOT ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
1 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
2 ! " # $ % & ' ( ) * + , - . /
3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4 @ A B C D E F G H I J K L M N O
5 P Q R S T U V W X Y Z [ \ ] ^ _
6 ` a b c d e f g h i j k l m n o
7 p q r s t u v w x y z { | } ~ DEL
5)
Slika 2.2: ASCII tablica
01
(2
Cifre 0-9 predstavljene su kdovima (30)16 do (39)16 , tako da se njihov
ASCII zapis jednostavno dobija dodavanjem prefiksa 011 na njihov bina-
rni zapis.
je
Kdovi velikih i malih slova se razlikuju u samo jednom bitu u binarnoj
reprezentaciji. Na primer, se kodira brojem (41)16 odnosno (100 0001)2 ,
an
dok se kodira brojem (61)16 odnosno (110 0001)2 . Ovo omoguava da
se konverzija veliine slova u oba smera moe vriti efikasno.
d
I.B1.002, JUS I.B1.003) kao deo standarda ISO 646, tako to su kdovi koji
imaju slobodno korienje (a koji u ASCII tabeli uobiajeno kodiraju zagrade
le
@ (40)16 (60)16
[ (5)16 { (7)16
\ (5)16 | (7)16
] (5)16 } (7)16
^ (5)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.
5)
standardizacija ovako kreiranih kdnih strana i to od strane ISO (International
Standard Organization) i od strane znaajnih korporacija, pre svega kompanije
01
Microsoft.
ISO je definisao familiju 8-bitnih kdnih strana koje nose zajedniku oznaku
(2
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
kontrolnim karakterima):
je
ISO-8859-1 Latin 1 veina zapadno-evropskih jezika
ISO-8859-2 Latin 2 centralno i istono-evropski jezici
an
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
d
0 1 2 3 4 5 6 7 8 9 A B C D E F
8
le
9
A NBSP SHY
E
B
C
D
E
F
0 1 2 3 4 5 6 7 8 9 A B C D E F
8
9
A NBSP SHY
B
C
D
E
F
5)
Slika 2.4: ISO-8859-2 tablica
01
0 1 2 3 4 5 6 7 8 9 A B C D E F
(2
8
9
A
B
je
C
D
an
E
F
d
iz
0 1 2 3 4 5 6 7 8 9 A B C D E F
o
8
sk
9
A NBSP SHY
B
n
C
D
ro
E
F
kt
irilicu i latinicu. Takoe, za azijske jezike nije dovoljno 256 mesta za zapis
svih karaktera. 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 standard-
izaciju 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 proizvod-
njom 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 1 2 3 4 5 6 7 8 9 A B C D E F
8
9
A
B
C
D
E
F
5)
01
Slika 2.7: Windows-1251 tablica
(2
tera koristi se kao osnovni viejezini skup karaktera, dok je preostali prostor
ostavljen kao proirenje za drevne jezike, naunu notaciju i slino.
Unicode je za cilj imao da bude:
je
Univerzalan (UNIversal) sadri sve savremene jezike sa pismom;
an
jedinstven (UNIque) bez dupliranja karaktera - kodiraju se pisma, a
ne jezici;
d
menom se shvatilo da dva bajta nee biti dovoljno za zapis svih karaktera
koji se koriste na planeti, pa je odlueno da se skup karaktera proiri i Uni-
n
je osnovna viejezina ravan (engl. basic multilingual plane) koja sadri veinu
danas korienih karaktera (ukljuujui i CJK Chinese, Japanese, Korean
kt
viejezikoj ravni:
54 2. Reprezentacija podataka u raunarima
5)
...
2000-2FFF specijalni karakteri
01
3000-3FFF CJK (Chinese-Japanese-Korean) simboli
...
(2
Unicode standard u sutini predstavlja veliku tabelu koja svakom karakteru
dodeljuje broj. Standardi koji opisuju kako se niske karaktera prevode u nizove
bajtova se definiu dodatno.
UCS-2.
je
ISO definie UCS-2 standard koji svaki Unicode karakter osnovne
an
viejezike ravni jednostavno zapisuje sa odgovarajua dva bajta.
UTF-8.
d
sledeih pravila:
ro
kt
5)
proirivanje osnovne namene raunara je posledica iroke raspoloivosti velike
koliine multimedijalnih informacija (slika, zvuka, filmova, . . . ) koje su za-
01
pisane u digitalnom formatu. Sve ovo je posledica tehnolokog napretka koji
je omoguio jednostavno i jeftino digitalizovanje signala, skladitenje velike
(2
koliine digitalno zapisanih informacija, kao i njihov brz prenos i obradu.
je
Slike se u raunaru zapisuju koristei vektorski zapis, rasterski zapis ili kom-
an
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-
d
koje raunari generiu esto koriste vektorsku grafiku. Vektorski zapisane slike
esto zauzimaju manje prostora, dozvoljavaju uveavanje (engl. zooming) bez
gubitaka na kvalitetu prikaza i mogu se lake preureivati, s obzirom na to
o
uklanjati.
n
ro
kt
le
E
5)
U RGB modelu boja, kombinovanjem crvene (R), zelene (G) i plave (B)
komponente svetlosti reprezentuju se ostale boje. Tako se, na primer, kombi-
01
novanjem crvene i zelene boje reprezentuje uta boja. Bela boja se reprezentuje
maksimalnim vrednosti sve tri osnovne komponente, dok se crna boja reprezen-
(2
tuje minimalnim vrednostima osnovnih komponenti. U ovom modelu, zapis
boje ini informacija o intenzitetu crvene, plave i zelene komponente. RGB
model boja se koristi kod ureaja koji boje prikazuju kombinovanjem svetlosti
je
(monitori, projektori, . . . ). Ukoliko se za informaciju o svakoj komponenti ko-
risti po jedan bajt, ukupan broj bajtova za zapis informacije o boji je 3, te je
an
mogue koristiti 224 = 16777216 razliitih boja. Ovaj model se esto naziva i
TrueColor model boja.
Za razliku od aditivnog RGB modela boja, kod kojeg se bela boja dobija
d
tivni CMY (Cyan-Magenta-Yellow) model boje kod kojeg se boje dobijaju kom-
binovanjem obojenih pigmenata na belom papiru. Kako se potpuno crna teko
dobija meanjem drugih pigmenata, a i kako je njena upotreba obino daleko
o
U ovom modelu, svaka boja se reprezentuje Hue (H) komponentom (koja pred-
ro
tricom piksela, pri emu se za svaki piksel uva informacija o njegovoj boji.
E
Zvuni talas predstavlja oscilaciju pritiska koja se prenosi kroz vazduh ili
neki drugi medijum (tenost, vrsto telo). Digitalizacija zvuka se vri meren-
jem i zapisivanjem vazdunog pritiska u kratkim vremenskim intervalima. Os-
novni parametri koji opisuju zvuni signal su njegova amplituda (koja odgovara
glasnoi) i frekvencija (koja odgovara visini). Poto ljudsko uho obino uje
raspon frekvencija od 20Hz do 20KHz, dovoljno je koristiti frekvenciju odabi-
5)
ranja 40KHz, tj. dovoljno je izvriti odabiranje oko 40 000 puta u sekundi.
Na primer, AudioCD standard koji se koristi prilikom snimanja obinih audio
01
kompakt diskova, propisuje frekvenciju odabiranja 44.1KHz. Za postizanje jo
veeg kvaliteta, neki standardi (miniDV, DVD, digital TV) propisuju odabi-
ranje na frekvenciji 48KHz. Ukoliko se snima ili prenosi samo ljudski govor
(2
(na primer, u mobilnoj telefoniji), frekvencije odabiranja mogu biti i znatno
manje. Drugi vaan parametar digitalizacije je broj bita kojim se zapisuje svaki
pojedinani odbirak. Najee se koristi 2 bajta po odbirku (16 bita), ime se
je
dobija mogunost zapisa 216 = 65536 razliitih nivoa amplitude.
Da bi se dobio prostorni oseaj zvuka, primenjuje se tehnika viekanalnog
an
snimanja zvuka. U ovom sluaju, svaki kanal se nezavisno snima posebnim
mikrofonom i reprodukuje na posebnom zvuniku. Stereo zvuk podrazumeva
d
Pitanja i zadaci
le
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
karaktere.
5)
Pitanje 2.9. Nabrojati bar tri kdne sheme u kojima moe da se zapie re
raunarstvo.
01
Pitanje 2.10. Koliko bitova koristi ASCII tabela karaktera, koliko YUSCII
tabela, koliko ISO-8859-1, a koliko osnovna UNICODE ravan? Koliko razliitih
(2
karaktera ima u ovim tabelama?
Pitanje 2.11. Koja kodiranja teksta je mogue koristiti ukoliko se u okviru is-
je
tog dokumenta eli zapisivanje teksta koji sadri jedan pasus na srpskom (pisan
latinicom), jedan pasus na nemakom i jedan pasus na ruskom (pisan irili-
an
com)?
Pitanje 2.13. Prilikom prikazivanja filma, neki program prikazuje titlove tipa
iz
Zadatak 2.1.
sk
ro
Zadatak 2.2. Zapisati dekadni broj 254 u osnovama 2, 8 i 16.
kt
1010101101001000111101010101011001101011101010101110001010010011.
Zapisati ovaj broj u heksadekadnom sistemu.
E
Zadatak 2.7.
5)
U registru se zapisuju brojevi u potpunom komplementu. Koji
raspon brojeva moe da se zapie ukoliko je irina registra:
01
(a) 4 bita (b) 8 bita (c) 16 bita (d) 24 bita (e) 32 bita
(2
mentu irine 8 bita:
(a) 12 (b) 123 (c) 0 (d) 18 (e) 128 (f ) 200
je
6 bita. Odrediti, takoe u potpunom komplementu duine 6 bita, zapis zbira i
an
proizvoda ova dva broja.
brojeva?
sk
45.
Zadatak 2.13.
le
Zadatak 2.17. Uz pomo omiljenog editora teksta (ili nekog naprednijeg, uko-
liko editor nema traene mogunosti) kreirati datoteku koja sadri listu imena
10 vaih najomiljenijih filmova (pisano latinicom uz ispravno korienje dijakri-
5)
tika). Datoteka treba da bude kodirana kodiranjem:
(a) Windows-1250 (b) ISO-8859-2 (c) Unicode (UCS-2) (d) UTF-8
01
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
(2
ishod (uz pomo odgovarajuih tabela koje prikazuju kdne rasporede).
je
editora teksta ili nekog od specijalizovanih alata (na primer, iconv) rekodirati
ovu datoteku u ISO-8859-2. Eksperimentisati i sa drugim kodiranjima.
an
Zadatak 2.19. Korienjem nekog naprednijeg grafikog programa (na primer,
GIMP ili Adobe Photoshop) videti kako se boja #B58A34 predstavlja u CMY i
d
HSB modelima.
iz
o
sk
n
ro
kt
le
E
Glava 3
5)
Algoritmi i izraunljivost
01
(2
je
Neformalno govorei, algoritam
1 je precizan opis postupka za reavanje
nekog problema u konanom broju koraka. Algoritmi postoje u svim ljud-
an
skim delatnostima. U matematici, na primer, postoje algoritmi za sabiranje
i za mnoenje prirodnih brojeva. U raunarstvu, postoje algoritmi za odrei-
d
jveeg zajednikog delioca dva broja), pa i pre toga. Ipak, sve do poetka
ro
(engl. Muhammad ibn Musa al-Khwarizmi). On je 825. godine napisao knjigu, u meuvre-
menu 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 problem, poznat pod imenom Entscheidungsproblem, postavio je David Hilbert
1928. 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, manip-
ulisanjem 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
5)
formalizama, tj. nekoliko raznorodnih sistema izraunavanja. Najznaajniji
meu njima su:
01
Tjuringove maine (Tjuring),
3 i Klini4 ),
(2
rekurzivne funkcije (Gedel
-raun 5
(er ),
je
Markovljevi algoritmi (Markov ),
7
an
maine sa beskonano mnogo registara (engl. Unlimited Register Ma-
chines urm)8 .
d
veliki broj operacija (koje, sa teorijskog stanovita, nisu neophodne jer se mogu
definisati preko malog broja osnovnih operacija).
Blok dijagrami (kae se i algoritamske eme, dijagrami toka, tj. tokovnici )
kt
mogu se smatrati poluformalnim nainom opisa algoritama. Oni nee biti raz-
matrani u teorijskom kontekstu ali e biti korieni u reenjima nekih zadataka,
le
ovu mainu i tako da izvri sva izraunavanja koja moe da izvri Tjuringova
5)
Zbog toga se, umesto pojmova poput, na primer, Tjuring-izraunljiva ili urm-
izraunljiva funkcija (i slinih) moe koristiti samo termin izraunljiva funkcija.
01
Svi navedeni formalizmi za izraunavanje, podrazumevaju u nekom smislu,
pojednostavljeno reeno, beskonau raspoloivu memoriju. Zbog toga savre-
(2
meni raunari (koji raspolau konanom memorijom) opremljeni savremenim
programskim jezicima nisu Tjuring potpuni, u strogom smislu. S druge starne,
svako izraunavanje koje se moe opisati na nekom modernom programskom
je
jeziku, moe se opisati i kao program za Tjuringovu mainu ili neki drugi ek-
vivalentan formalizam.
an
3.2 er-Tjuringova teza
d
er-Tjuringova teza:
kt
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 ekvi-
valentne, kao i da do sada nije pronaen nijedan primer intuitivno, efektivno
izvodivog postupka koji nije mogue formalizovati u okviru nabrojanih formal-
nih sistema izraunavanja.
3.3 ur maine
U daljem tekstu, pojam izraunljivosti bie uveden i izuavan na bazi ur
maina ( 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
ogranien (mali) skup instrukcija, programe i memoriju.
Kao i drugi formalizmi izraunavanja, ur maine su apstrakcije sine koje
5)
formalizuju pojam algoritma, predstavljajui matematiku idealizaciju rau-
nara. ur maine su dizajnirane tako da koriste samo mali broj operacija.
01
Oigledno je da nije neophodno da formalizam za izraunavanje kao osnovnu
operaciju ima, na primer, stepenovanje prirodnih brojeva, jer se ono moe
(2
svesti na mnoenje. Slino, nije neophodno da formalizam za izraunavanje
kao primitivnu operaciju ima mnoenje prirodnih brojeva, jer se ono moe
svesti na sabiranje. ak ni sabiranje nije neophodno, jer se moe svesti na
je
operaciju pronalaenja sledbenika (uveavanja za vrednost 1). Zaista, defini-
cija prirodnih brojeva podrazumeva postojanje nule i operacije sledbenika
10 i
an
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
d
prostor za uvanje podataka, tj. kao memorija maine. Registri trake oznaeni
iz
slici:
sk
1 2 3 ...
1 2 3 ...
n
(kada se doe do kraja programa ili kada se naie na skok na instrukciju koja
ne postoji u numerisanom nizu instrukcija).
Poetnu konfiguraciju ini niz prirodnih brojeva 1 , 2 , . . . koji su upisani
u registre 1 , 2 , . . .. Ako je funkcija koju treba izraunati (1 , 2 , . . . , ),
onda se podrazumeva da su vrednosti 1 , 2 , . . . , redom smetene u prvih
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
() nulainstrukcija 0 (tj. := 0)
() instrukcija sledbenik + 1 (tj. := + 1)
(, ) instrukcija prenosa (tj. := )
(, , ) instrukcija skoka ako je = , idi na -tu;
inae idi na sledeu instrukciju
5)
01
registara.
12 Podrazumeva se i da, na kraju rada programa, rezultat treba da
(2
bude smeten u prvi registar.
Ako urm program za poetnu konfiguraciju 1 , 2 , . . . , ne staje sa
radom, onda piemo (1 , 2 , . . . , ) . Inae, ako program staje sa radom i u
prvom registru je, kao rezultat, vrednost , onda piemo (1 , 2 , . . . , ) .
je
Kaemo da urm program izraunava funkciju : N N ako za svaku
an
-torku argumenata 1 , 2 , . . . , za koju je funkcija definisana i vai (1 ,
2 , . . ., ) = istovremeno vai i (1 , 2 , . . . , ) . Funkcija je urm-
izraunljiva ako postoji urm program koji je izraunava.
d
+ = + 1 + 1 + ... + 1
n
Odgovarajui
1 2 3 . . .
kt
... ...
i sledeu konfiguraciju u toku rada programa:
le
1 2 3 ...
+ ...
E
gde je {0, 1, . . . , }.
Algoritam se moe zapisati u vidu dijagrama toka i u vidu urm programa
kao u nastavku:
12 Neki opisi 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
=
:= + 1
5)
:= + 1
01
1. (3)
(2
2. (3, 2, 100)
3. (1)
4. (3)
je
5. (1, 1, 2)
13 .
an
Prekid rada programa je realizovan skokom na nepostojeu instrukciju 100
Bezuslovni skok je realizovan naredbom oblika (1, 1, . . .) poreenje registra
sa samim sobom uvek garantuje jednakost te se skok vri uvek.
d
{
0 , ako
(, ) =
1 , inae
o
1 2 3 ...
n
...
ro
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
I u programima koji slede, uniformnosti radi, za prekid programa e se takoe koristiti skok
na instrukciju 100.
E
67 3. Algoritmi i izraunljivost
:= 0
=
> 0 1
=
5)
1 1
:= + 1
01
(2
1. (3) =0
2. (1, 3, 6) = ?
3. (2, 3, 8) = ?
je
4. (3) := + 1
5. (1, 1, 2)
an
6. (1) 0 1
7. (1, 1, 100) kraj
8. (1)
d
9. (1) 1 1
iz
() = [ ]
sk
= [ ] 2 < ( + 1)2
ro
1 2 . . .
... ...
le
1 = 2 2 = ( + 1)2 ...
Osnovna ideja algoritma je uveavanje broja za 1 i odgovarajuih vrednosti
1 i 2 , sve dok se broj
ne nae izmeu njih. Nakon to se 1 i 2 postave
2 2
na vrednosti kvadrata dva uzastopna broja i ( + 1) , broj 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
toga se ceo postupak ponavlja.
68 3. Algoritmi i izraunljivost
:= 0
1 := 0
2 := 1
5)
= 1
01
1
1 := 1 + 1
(2
1 = 2
je
:= + 1
2 := 2 + 1
an
:= 0
d
iz
2 := 2 + 2
:= + 1
o
=
sk
1. (2) := 0
n
2. (3) 1 := 0
ro
3. (4)
4. (4) 2 := 1
kt
5. (1, 3, 17) = 1 ?
6. (3) 1 := 1 + 1
le
7. (3, 4, 9) 1 = 2 ?
E
8. (1, 1, 5)
9. (2) := + 1
10. (4) 2 := 2 + 1
11. (5) := 0
12. (4) 2 := 2 + 1
13. (4) 2 := 2 + 1
14. (5) := + 1
15. (5, 2, 5) = ?
16. (1, 1, 12)
17. (2, 1) 1
69 3. Algoritmi i izraunljivost
5)
2. (1, 1, 1)
01
3.4 Enumeracija urm programa
Kardinalnost. Za dva skupa kae se da imaju istu kardinalnost ako i samo
(2
ako je izmeu njih mogue uspostaviti bijektivno preslikavanje. Za skupove
koji imaju istu kardinalnost kao skup prirodnih brojeva kae se da su prebro-
jivi . Dakle, neki skup je prebrojiv ako i samo ako je njegove elemente mogue
je
poreati u niz (niz odgovara bijekciji sa skupom prirodnih brojeva). Za skupove
an
koji su ili konani ili prebrojivi, kae se da su najvie prebrojivi. Georg Kan-
tor
14 je prvi pokazao da skup realnih brojeva ima veu kardinalnost od skupa
prirodnih brojeva, tj. da skup realnih brojeva nije prebrojiv.
d
Primer 3.5. Skupovi parnih i neparnih brojeva imaju istu kardinalnost jer je
iz
istu kardinalnost kao i skup prirodnih brojeva, iako su njegovi pravi podskupovi
sk
3.1.
E
1 2 3 4 5 6 7
1 1 2 6 7 ...
2 3 5 8
3 4 9
4
5
5)
6
7
01
. .
. .
. .
(2
Enumeracija urm programa.
je
Vano pitanje je koliko ima urm programa i
koliko ima razliitih urm programa (tj. onih koji izraunavaju razliite funkcije).
an
Oigledno je da ih ima beskonano, a naredna tvrenja govore da ih ima pre-
brojivo mnogo.
d
je unija ova etiri prebrojiva skupa, pa je na osnovu leme 3.3 i ovaj skup
prebrojiv.
kt
Dokaz: Skup svih urm programa se moe predstaviti kao unija skupa pro-
grama koji imaju jednu instrukciju, skupa programa koji imaju dve in-
strukcije 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.
pravilo koje svakom urm programu dodeljuje jedinstven prirodan broj i koje
svakom prirodnom broju dodeljuje jedinstven urm program. Zbog toga, za
fiksirano dodeljivanje brojeva programima, moemo da govorimo o prvom, dru-
gom, treem, . . . , stotom urm programu itd.
3.5 Neizraunljivost i neodluivost
5)
Razmotrimo narednih nekoliko problema.
01
nekoliko rei prvog skupa i, nezavisno, nekoliko rei drugog skupa tako
da se dobije ista re. Na primer, za skupove {, , } i {, , },
(2
jedno reenje je = . Za skupove {, } i
{, } reenje ne postoji, jer se nadovezivanjem rei prvog skupa uvek
dobija re ija su poslednja dva slova razliita, dok se nadovezivanjem rei
je
drugog skupa uvek dobija re ija su poslednja dva slova ista. Zadatak je
utvrditi da li postoji opti algoritam koji za proizvoljna dva zadata skupa
an
rei odreuje da li traena nadovezivanja postoje.
15
aksioma.
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 {, } i, nezavisno, nekoliko rei
skupa {, } tako da se dobije ista re.
72 3. Algoritmi i izraunljivost
5)
tavlja 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
01
postupak kojim se za proizvoljni dati program i proizvoljne vrednosti ulaznih
argumenata moe proveriti da li se program zaustavlja ako se pokrene sa tim
(2
argumentima.
Iako se problem ispitivanja zaustavljanja moe razmatrati i za programe
u savremenim programskim jezicima, u nastavku emo razmotriti formulaciju
urm programe:
je
halting problema za
Da li postoji urm program koji na ulazu dobija drugi urm program i neki
an
broj i ispituje da li se program zaustavlja za ulazni parametar ?
Problem prethodne formulacije je injenica da traeni urm program mora
d
nemogue, s obzirom na to da
samo prirodne brojeve. Ipak, ovo se jednostavno razreava zahvaljujui tome
to je svakom urm programu mogue dodeliti jedinstveni prirodan broj
o
na sledei nain:
{
1, ako se program zaustavlja za ulaz
kt
(, ) =
0, inae.
le
argument .
() 0 ako je ()
() ako je ()
5)
() 0 ako je ()
() ako je ()
01
No, ako je jednako upravo , pokazuje se da je definicija ponaanja
programa (tj. programa ) kontradiktorna: program (tj. program
(2
) za ulaznu vrednost vraa 0 ako se ne zaustavlja za , a izvrava
beskonanu petlju ako se zaustavlja za :
je
() 0 ako je ()
an
() ako je ()
1 (tj. funkcija iz u {0, 1}) ima neprebrojivo mnogo, dok programa ima samo
ro
5)
Pitanja i zadaci za vebu
01
Pitanje 3.1. Po kome je termin algoritam dobio ime?
(2
Pitanje 3.2. ta je to algoritam (formalno i neformalno)? Navesti nekoliko
formalizma za opisivanje algoritama. Kakva je veza izmeu formalnog i nefor-
malnog pojma algoritma. ta tvrdi er-Tjuringova teza? Da li se ona moe
je
dokazati?
an
Pitanje 3.3. Da li postoji algoritam koji opisuje neku funkciju iz skupa prirod-
nih brojeva u skup prirodnih brojeva i koji moe da se isprogramira u program-
d
Pitanje 3.5. U emu je kljuna razlika izmeu urm maine i bilo kog stvarnog
sk
raunara?
n
Pitanje 3.8. Da li postoji urm program koji izraunava broj
2? Da li postoji
urm program koji izraunava -tu decimalnu cifru broja
le
2, gde je zadati
prirodan broj?
E
Pitanje 3.10. Koliko ima racionalnih brojeva? Koliko ima kompleksnih bro-
jeva? Koliko ima razliitih programa za Tjuringovu mainu? Koliko ima ra-
zliitih 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 ele-
menata ima unija konano mnogo prebrojivih skupova? Koliko elemenata ima
unija prebrojivo mnogo prebrojivih skupova?
75 3. Algoritmi i izraunljivost
5)
pridruiti jedinstven
01
broj (razliit za svaki program)? Da li se svakom realnom broju moe pridruiti
jedinstven urm program (razliit za svaki broj)?
(2
Pitanje 3.15. Kako se naziva problem ispitivanja zaustavljanja programa?
Kako glasi halting problem? Da li je on odluiv ili nije? Ko je to dokazao?
je
Pitanje 3.16. 1. Da li postoji algoritam koji za drugi zadati urm program
an
utvruje da li se zaustavlja ili ne?
3. Da li je mogue napisati
proverava da li radi beskonano?
4. Da li je mogue napisati
sk
(0) = 0?
6. Da li je mogue napisati urm program koji za drugi zadati urm program
kt
Pitanje 3.17.
le
Zadatak
3.1. Napisati urm program koji izraunava funkciju (, ) = .
5)
{
/3 , ako 3|
() =
, inae
01
Zadatak 3.7. urm program koji izraunava funkciju () = !.
Napisati
(2
Zadatak 3.8. Napisati urm program koji izraunava funkciju () = 2
[ ]
3 .
Zadatak 3.9. Napisati urm program koji broj 1331 smeta u prvi registar.
je
Zadatak 3.10. Napisati urm program koji izraunava funkciju () = 1000.
an
Zadatak 3.11. Napisati urm program koji izraunava funkciju (, ) = 2 +
.
d
(, ), odnosno:
{
, ako
(, ) =
o
, inae
urm
sk
{
1 , ako |
(, ) =
kt
0 , inae
{ [ ]
, ako = 0
E
(, ) =
, inae
5)
3 , ako 2|
(, , ) =
+1 , inae
01
Zadatak 3.21. Napisati urm program koji izraunava funkciju
{
1, ako je + >
(2
(, , ) =
2, inae
je
an
d
iz
o
sk
n
ro
kt
le
E
Glava 4
5)
Vii programski jezici
01
(2
je
Razvoj programskih jezika, u bliskoj je vezi sa razvojem raunara tj. sa
razvojem hardvera. Programiranje u dananjem smislu nastalo je sa pojavom
an
raunara fon Nojmanovog tipa iji se rad kontrolie programima koji su smeteni
u memoriji, zajedno sa podacima nad kojim operiu. Na prvim raunarima
d
78
79 4. Vii programski jezici
5)
4.1 Kratki pregled istorije programskih jezika
01
Prvim viim programskim jezikom najee se smatra jezik FORTRAN,
(2
nastao u periodu 1953-1957 godine. Njegov glavni autor je Don Bakus , koji
1
je implementirao i prvi interpretator i prvi kompilator za ovaj jezik. Ime FOR-
TRAN dolazi od The IBM Mathematical FORmula TRANslating System, to
je
ukazuje na to da je osnovna motivacija bila da se u okviru nauno-tehnikih pri-
mena omogui unoenje matematikih formula, dok je sistem taj koji bi unete
an
matematike formule prevodio u niz instrukcija koje raunar moe da izvrava.
Neposredno nakon pojave Fortrana, Don Mekarti
2 je dizajnirao programski
jezik LISP (LISt Processing ), zasnovan na -raunu. LISP je uveo funkcionalno
d
ih godina (period kada zbog loe prakse programiranja softver nije mogao da
dostigne mogunosti hardvera), nastala je praksa strukturnog programiranja
kt
5)
Pojavom veba postaju znaajni skript jezici, kao to su PHP, JavaScript,
Python, Ruby itd.
01
4.2 Klasifikacije programskih jezika
(2
Po nainu programiranja, programski jezici se klasifikuju u programske
paradigme.
je
Najkorieniji programski jezici danas spadaju u grupu imperativnih pro-
gramskih jezika. Kako u ovu grupu spada i programski jezik C (ali i program-
an
ski 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-
d
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
jezika. Na primer, leksika jezika ur maina razlikuje rezervisane rei ( , , ,
5)
) i brojevne konstante. Razmotrimo naredni fragment kda u jeziku C:
01
if (a < 3)
x1 = 3+4*a;
(2
U ovom kdu, razlikuju se sledee lekseme (rei) i njima pridrueni tokeni
(kategorije).
if
je
kljuna re
( zagrada
a
an
identifikator
< operator
3 celobrojni literal
d
) zagrada
x1
iz
identifikator
= operator
3 celobrojni literal
o
+ operator
sk
4 celobrojni literal
* operator
a
n
celobrojni literal
; interpunkcija
ro
< =
3 1 +
3 *
5)
4
01
Dakle, taj fragment kda predstavlja if-then naredbu (iskaz) kojoj je uslov
dat izrazom poreenja vrednosti promenljive a i konstante 3, a telo predstavlja
naredba dodele promenljivoj x vrednosti izraza koji predstavlja zbir konstante
(2
3 i proizvoda konstante 4 i vrednosti promenljive a.
Sintaksom programa obino se bavi deo programskog prevodioca koji se
naziva sintaksiki analizator.
Semantika. je
an
Semantika pridruuje znaenje sintaksiki ispravnim niskama
jezika. Za prirodne jezike, semantika pridruuje ispravnim reenicama neke
specifine objekte, misli i oseanja. Za programske jezike, semantika za dati
d
Bezbojne zelene ideje besno spavaju ili Pera je oenjeni neenja. Slino je
i sa programskim jezicima. Neki aspekti semantike korektnosti programa se
ro
aspekti mogu proveriti tek u fazi izvravanja programa (na primer, da ne dolazi
do deljenja nulom). Na osnovu toga, razlikuje se statika i dinamika semantika.
le
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
3
jezike . U ostalim sluajevima, semantika programskog jezika se opisuje ne-
formalno, opisima zadatim korienjem prirodnog jezika. est je sluaj da neki
5)
4.4 Pragmatika programskih jezika
01
Pragmatika jezika govori o izraajnosti jezika i o odnosu razliitih naina za
iskazivanje istih stvari. Pragmatika prirodnih jezika se odnosi na psiholoke i
(2
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
drugaije u pisanju pesama. Pragmatika programskih jezika ukljuuje pitanja
je
kao to su lakoa programiranja, efikasnost u primenama i metodologija pro-
gramiranja. Pragmatika je kljuni predmet interesovanja onih koji dizajniraju
an
i implementiraju programske jezike, ali i svih koji ih koriste. U pitanja prag-
matike 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
d
skup operacija koje se mogu primeniti nad podacima tog tipa (na primer,
5)
sabiranje, oduzimanje, mnoenje, . . . ),
01
narnog potpunog komplementa irine 8 bita, odakle sledi opseg vrednosti
od -128 do 127).
(2
Naredni fragment C kda obezbeuje da su promenljive x, y i z celobrojnog
tipa (tipa int), a da z nakon izvravanja ovog fragmenta ima vrednost jednaku
promenljivih x i y.
je
zbiru
int x, y;
an
...
int z = x + y;
d
iz
5)
Kontrola toka izvravanja. Osnovi gradivni element imperativnih pro-
01
grama su naredbe . Osnovna naredba je naredba dodele kojom se vrednost neke
promenljive postavlja na vrednost nekog izraza definisanog nad konstantama i
(2
definisanim promenljivim. Na primer, x1 = 3 + 4*a;.
Naredbe se u programu esto niu i izvravaju sekvencijalno, jedna nakon
druge. Meutim, da bi se postigla vea izraajnost, programski jezici uvode
je
specijalne vrste naredbi kojima se vri kontrola toka izvravanja programa
(tzv. kontrolne strukture). Ovim se postie da se u zavisnosti od tekuih
an
vrednosti promenljivih neke naredbe uopte ne izvravaju, neke izvravaju vie
puta i slino. Najee koriene kontrolne strukture su granajue naredbe
(if-then-else), petlje (for, while, do-while, repeat-until) i naredbe skoka
d
(goto). Za naredbu skoka (goto) je pokazano da nije neophodna, tj. svaki pro-
iz
gram 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
o
vrstu petlje (na primer, Ovaj vaan teorijski rezultat ima svoju
punu praktinu primenu i u dananjem, strukturnom, programiranju naredba
sk
5)
Potprogrami imaju i mogunost vraanja vrednosti izraunavanja pozi-
vaocu. Neki jezici (npr. Pascal) sutinski razlikuju funkcije koje izraunavaju
01
(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
(2
promenljive).
je
visne celine. Celine, koje sadre definicije srodnih podataka i funkcija, obino
se nazivaju biblioteke (engl. library) i smetaju se u posebne datoteke. Ovim
an
se postie lake odravanje kompleksnih sistema, kao i mogunost viestruke
upotrebe pojedinih modula u okviru razliitih programa. Celine se obino za-
d
library) koje sadre funkcije esto potrebne programeru (npr. funkciju za izrau-
navanje duine niske karaktera). esto se kd funkcija standardne biblioteke
o
Upravljanje memorijom.
le
vea sloboda, ali i mnogo vea mogunost pravljenja greaka. Sa druge strane,
neki programski jezici imaju za cilj skrivanje svojstava hardvera od program-
era, tite memoriju od direktnog pristupa programera i doputaju korienje
podataka samo u okviru memorije zauzete promenljivim programa.
5)
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
01
programskog jezika generiu kd na mainskom jeziku (koji odgovara polaznom
programu, tj. vri izraunavanje koje je opisano na viem programskom jeziku).
(2
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
jezika.
je
U zavisnosti od toga da li se ceo program analizira i transformie u main-
ski kd pre nego to moe da se izvri, ili se analiza i izvravanje programa
an
obavljaju naizmenino deo po deo programa (na primer, naredba po naredba),
jeziki procesori se dele u dve grupe: kompilatore i interpretatore.
d
5)
tora. Naime, kd sa vieg programskog jezika se prvo kompilira u neki precizno
definisan meujezik niskog nivoa (ovo je obino jezik neke apstraktne virtuelne
01
maine), a zatim se vri interpretacija ovog meujezika i njegovo izvravanje
na konkretnom raunaru. Ovaj pristup primenjen je kod programskog jezika
(2
Java, kod .Net jezika (C#, VB), itd.
C?
iz
objektno-orijentisano programiranje?
Pitanje 4.5. Navesti primer leksiki ispravnog, ali sintaksiki neispravnog dela
E
5)
memoriji iz programa? ta su sakupljai otpada?
01
nosti, a koje su mane korienja kompilatora u odnosu na korienje interpre-
tatora?
(2
Pitanje 4.12. Ako se koristi kompilator, da li je za izvravanje programa ko-
risniku neophodno dostaviti izvorni kd programa? Ako se koristi interpretator,
da li je za izvravanje programa korisniku neophodno dostaviti izvorni kd pro-
je
grama?
an
d
iz
o
sk
n
ro
kt
le
E
E
le
kt
ro
n
sk
o
90
Deo II
iz
d
Jezik C
an
je
(2
01
5)
Glava 5
5)
Osnovno o programskom jeziku C
01
(2
je
Programski jezik C je programski jezik opte namene koji je 1972. godine
razvio Denis Rii
1 u Belovim telefonskim laboratorijama (engl. Bell Telephone
an
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
d
91
92 5. Osnovno o programskom jeziku C
5)
ANSI C i ISO C. Tokom 1980-ih godina, C se proirio na veliki broj het-
01
erogenih platformi i time se javila potreba za zvaninom standardizaci-
jom jezika. Godine 1989. ameriki nacionalni institut za standardizaciju
(ANSI) objavio je standard pod zvaninim nazivom ANSI X3.159-1989
(2
Programming Language C . Ova verzija jezika C se obino jednostavnije
naziva ANSI C ili C89. Godine 1990. Meunarodna organizacija za stan-
je
dardizaciju (ISO) usvojila je ovaj dokument (uz sitnije izmene) pod oz-
nakom ISO/IEC 9899:1990 ime je briga o standardizaciji jezika C prela
an
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
d
C11 (nekada C1X). Godine 2007. zapoet je rad na novom standardu jezika
n
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?
5)
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.
01
Program Zdravo!
(2
Prikaz jezika C bie zapoet programom koji na standardni izlaz ispisuje
poruku Zdravo!. Neki delovi programa e biti objanjeni samo povrno, a u
je
kasnijem tekstu e biti dat njihov detaljni opis.
Program 5.1.
an
#include <stdio.h>
d
int main() {
iz
ali obavezno mora da sadri funkciju koja se zove main i izvravanje programa
ro
naava da ova funkcija, kao rezultat, vraa celobrojnu vrednost (engl. integer),
tj. vrednost tipa int.
Naredbe funkcije main su grupisane izmeu simbola {i} (koji oznaavaju
le
5)
umesto prve linije upisuje celokupan sadraj datoteke stdio.h.
Naredba return 0; prekida izvravanje funkcije main i, kao njen rezultat,
01
vraa vrednost 0. Vrednost funkcije vraa se u okruenje iz kojeg je ona poz-
vana, u ovom sluaju u okruenje iz kojeg je pozvan sm program. Uobiajena
(2
konvencija je da se iz funkcije main vraa vrednost 0 da ukae na to da je
izvravanje proteklo bez problema, a ne-nula vrednost da ukae na problem ili
greku koja se javila tokom izvravanja programa.
je
Tekst naveden izmeu simbola /* i simbola */ predstavlja komentare. Oni
su korisni samo programerima, doprinose itljivosti i razumljivosti samog pro-
an
grama. 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
d
uteno 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-
sikom strukturom nezaobilazna praksa. Naglasimo i da postoje razliiti stilovi
o
sledeem redu). Meutim, obino se smatra da nije bitno koji se stil koristi
dok god se koristi na uniforman nain.
n
Ukoliko se, na primer, koristi GCC prevodilac (to je est sluaj pod opera-
ro
Zdravo!
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. Pro-
gramer, 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
upozorenjima bie u poglavlju 9.2.5.
5)
01
Program koji ispisuje kvadrat unetog celog broja
Prethodni program nije uzimao u obzir nikakve podatke koje bi uneo ko-
(2
risnik, ve je prilikom svakog pokretanja davao isti izlaz. Naredni program
oekuje od korisnika da unese jedan ceo broj i onda ispisuje kvadrat tog broja.
Program 5.2.
#include <stdio.h>
je
an
int main() {
int a;
d
scanf("%i", &a);
printf("Kvadrat unetog broja je: %i", a*a);
return 0;
o
}
sk
(poziv funkcije printf) na standardni izlaz ispisuje tekst Unesite ceo broj:,
a naredba nakon nje (poziv funkcije scanf) omoguava uitavanje vrednosti
kt
%i. Nakon formata, zapisuje se ime promenljive u koju treba upisati proi-
& govori da e promenljiva a biti promenjena u funkciji
E
5)
Program koji izraunava rastojanje izmeu taaka
Sledei primer prikazuje program koji rauna rastojanje izmeu dve take
01
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 double,
(2
programu, umesto promenljivih tipa koriste se promenljive tipa
dok se prilikom uitavanja i ispisa ovakvih vrednost za format koristi niska %lf
umesto niske %i. Dodatno, za raunanje kvadratnog korena koristi se funkcija
sqrt math.h.
je
deklarisana u zaglavlju
Program 5.3.
an
#include <stdio.h>
#include <math.h>
d
iz
int main() {
double x1, y1, x2, y2;
printf("Unesi koordinate prve tacke: ");
o
return 0;
}
kt
teoreme (2 1 )2 + (2 1 )2 . Poto u jeziku C ne postoji operator ste-
penovanja, kvadriranje se sprovodi mnoenjem.
E
Program 5.4.
#include <stdio.h>
int main() {
5)
int a;
printf("Unesi broj: ");
01
scanf("%d", &a);
if (a % 2 == 0)
printf("Broj %d je paran\n", a);
(2
else
printf("Broj %d je neparan\n", a);
return 0;
je
}
an
Ceo broj je paran ako i samo ako je ostatak pri deljenju sa dva jednak nuli.
Ostatak pri deljenju se izraunava operatorom %, dok se poreenje jednakosti
d
vri operatorom ==. Operator ispitanja jednakosti (==) i operator dodele (=) se
if
iz
uslova (takozvana
ukoliko postoji, naredba navedena nakon rei else (takozvana else grana). I
then i else grana mogu da sadre samo jednu naredbu ili vie naredbi.
n
Ukoliko
sadre vie naredbi, onda te naredbe ine blok iji se poetak i kraj moraju
ro
Program 5.5.
E
#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 pro-
menljivih). Petlja se izvrava tako to se prvo izvri inicijalizacija promenljive
i na vrednost 1 (zahvaljujui kdu i=1), u svakom koraku petlje se vrednost
promenljive i uveava za 1 (zahvaljujui kdu i++) i sve to se ponavlja dok
i N i <= N). Pre pre-
5)
vrednost promenljive ne postane (zahvaljujui uslovu
voenja programa vrednost N menja se brojem 100 i to zahvaljujui tzv. pret-
#define N 100 koja se esto koristi za definisanje kon-
01
procesorskoj direktivi
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
(2
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.
Za svaku vrednost promenljive i izmeu 1 i 100 izvrava se telo petlje
je
naredba printf. U okviru format niske se, umesto %d, koristi %3d, ime se
postie da se broj uvek ispisuje u polju irine 3 karaktera. Slino se, korienjem
an
%7.4f, postie da se vrednost korena ispisuje na 4 decimale u polju ukupne
irine 7 karaktera.
d
iz
Naredni program ispisuje prvi prirodni broj za koji je zbir svih prirodnih
o
Program 5.6.
#include <stdio.h>
n
ro
#define N 100
kt
int main() {
int i = 1;
int s = 1;
le
while(s <= N) {
E
i++;
s = s+i;
}
printf("%d\n", i);
return 0;
}
5)
Program 5.7.
#include <stdio.h>
01
#include <ctype.h>
int main() {
(2
int c;
printf("Otkucaj recenicu (zavrsi je znakom .): ");
do {
je
c = getchar();
putchar(toupper(c));
an
} while (c != .);
putchar(\n);
return 0;
d
}
iz
o
nog ulaza (i smeta ga promenljivu c), funkcija toupper koja prevodi mala
u velika slova (a ne menja argument ako nije malo slovo) i funkcija putchar
kt
petlje vri na kraju (za razliku od petlje while u kojoj se uslov proverava na
poetku petlje i telo petlja ne mora da se izvri ni jednom). Telo petlje se
izvrava sve dok je uitani i prepisani karakter c 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.
5)
Zadatak 5.2.1. Napisati program koji za uneti poluprenik izraunava obim
01
i povrinu kruga (za broj koristiti konstantu M_PI iz zaglavlja math.h).
Zadatak 5.2.2. Napisati program koji za unete koordinate temena trougla
(2
izraunava njegov obim i povrinu.
Zadatak 5.2.3. Napisati program koji za unete dve duine stranica trougla
je
i ( > 0, > 0) i ugla izmeu njih ( > 0 je zadat u stepenima) izraunava
duinu tree stranice i veliine dva preostala ugla i . Napomena: koristiti
an
sinusnu i/ili kosinusnu teoremu i funkcije sin() i cos() iz zaglavlja math.h
.
d
varajuu brzinu u .
ravnomerno ubrzano.
nava determinantu:
1 2 3
ro
4 5 6
7 8 9
kt
le
Zadatak 5.2.7. Napisati program koji ispisuje maksimum tri uneta broja.
E
Zadatak 5.2.8. Napisati program koji uitava cele brojeve i i zatim ispisuje
sve kubove brojeva izmeu njih.
Glava 6
5)
Predstavljanje podataka i
01
operacije nad njima
(2
je
an
U ovoj glavi bie opisani naredni pojmovi:
Promenljive i konstante,
d
Operatori,
ro
101
102 6. Predstavljanje podataka i operacije nad njima
5)
da malim slovima poinju imena promenljivih i funkcija, a velikim imena sim-
bolikih konstanti (vidi poglavlja o nabrojivim tipovima 6.7.4 i pretprocesoru
01
9.2.1), vrednosti koje se ne menjaju u toku programa.
Imena promenljivih i funkcija, u principu, treba da oslikavaju njihovo zna-
(2
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-
ljive sadri vie rei, onda se, radi bolje itljivosti, te rei razdvajaju sim-
je
bolom _ (na primer, broj_studenata) ili poetnim velikim slovima (na primer,
brojStudenata) ovo drugo je takozvana kamilja notacija (CamelCase). Pos-
an
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
d
Ukoliko dve promenljive imaju vie od 63 poetna znaka ista, onda se ne garan-
sk
6.1.2 Deklaracije
ro
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 (C99).
3 Deklaracije promenljivih najee su ujedno i definicije. Odnos izmeu 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
5)
/* ovu promenljivu nije moguce menjati */
const double GRAVITY = 9.81;
01
Kvalifikator const mogue je navesti i nakon imena tipa.
(2
double const GRAVITY = 9.81;
Izmeu ova dva naina navoenja kvalifikatora razlike postoje samo kod
je
sloenijih tipova (pre svega pokazivaa) i o tome e biti vie rei u narednim
an
glavama.
Vrednost tipa const T moe biti dodeljena promenljivoj tipa T, ali pro-
menljivoj tipa const T ne moe biti dodeljena vrednost (osim prilikom inici-
d
5)
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
01
koji su, pogodnosti radi, organizovani u sloenije podatke (na primer, cele
brojeve ili brojeve u pokretnom zarezu). Jedan tip karakterie: vrsta podataka
(2
koje opisuje, nain reprezentacije, skup operacija koje se mogu primeniti nad
podacima tog tipa, kao i broj bitova koji se koriste za reprezentaciju (odakle
sledi opseg moguih vrednosti).
koristei potpuni komplement. Nad podacima ovog tipa mogu se koristiti arit-
iz
metike operacije (na primer, +, -, *, /, %), relacije (na primer,<, >=) i druge.
Standardom nije propisano koliko bitova koriste podaci tipa int, ali je pro-
pisano da se koristi najmanje esnaest bita (tj. dva bajta). Veliina tipa int
o
raunarima, podaci tipa int obino zauzimaju 32 ili 64 bita , tj. 4 ili 8 bajtova5 .
Tipu int mogu biti pridrueni kvalifikatori short, long i (od standarda
C99) long long.
n
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
kt
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
le
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.
E
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
kao oznaen i za njegovu reprezentaciju se najee koristi zapis u potpunom
komplementu. Ukoliko uz tip short, int, long ili long long nije naveden ni
kvalifikator signed ni kvalifikator unsigned, podrazumeva se da je vrednost
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
5)
kratki 2B = 16b 2B = 16b
(short int) [-32K, 32K-1] = [0, 64K-1] =
01
15
[-2 , 215 -1] = [0, 216 -1] =
[-32768, 32767] [0, 65535]
(2
dugi 4B = 32b 4B = 32b
(long int) [-2G, 2G-1] = [0, 4G-1] =
31
[-2 , 231 -1] = [0, 232 -1] =
je
[-2147483648,2147483647] [0, 4294967295]
veoma dugi 8B = 64b 8B = 64b
an
63
(long long int) [-2 263 -1] =
, [0, 264 -1] =
18 18 19
od C99 [-9.210 , 9.210 ] [0, 1.8410 ]
d
iz
Program 6.1.
#include <stdio.h>
le
int main() {
E
Program 6.2.
#include <stdio.h>
int main() {
unsigned int a = 2000000000, b = 2000000000;
5)
printf("Zbir brojeva %u i %u je: %u\n", a, b, a + b);
return 0;
01
}
(2
Zbir brojeva 2000000000 i 2000000000 je: 4000000000
operacije i relacije. Podatak tipa char zauzima tano jedan bajt. Standard
char smatra oznaenim
iz
janje vrednosti malih celih brojeva, u jeziku C se ovaj tip obino koristi za
brojeve koji predstavljaju kdove karaktera (otuda i ime char). Standard ne
le
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.
5)
nom zarezu dvostruke tanosti, a tip long double brojeve u pokretnom zarezu
proirene tanosti. Nije propisano koliko ovi tipovi zauzimaju bitova, ali pro-
01
pisano je da double zauzima barem onoliko bajtova koliko i float, a da
long double zauzima barem onoliko bajtova koliko double. Podaci o opsegu
(2
i detaljima ovih (i drugih tipova) za konkretan raunar i C prevodilac sadrani
su u standardnoj datoteci zaglavlja <float.h>.
I nad podacima ovih tipova mogu se koristiti uobiajene aritmetike op-
je
eracije (osim operacije raunanja ostatka pri deljenju %) i relacije.
Brojevi u pokretnom zarezu u savremenim raunarima se najee zapisuju
an
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
d
GCC i funkcija
kao inf, a kao nan.
Najvei broj funkcija iz C standardne biblioteke (pre svega matematike
le
5)
true koja oznaava tano i false koja oznaava netano.
01
Pitanje 6.2.1. ta sve karakterie jedan tip podataka?
(2
Pitanje 6.2.2. Navesti barem jedan tipa u jeziku C za koji je standardom
definisano koliko bajtova zauzima.
Pitanje 6.2.4. Koliko bajtova zauzima podatak tipa signed char? Koja je
d
Pitanje 6.2.5. Koliko bajtova zauzima podatak tipa unsigned char? Koja je
najmanja a koja najvea vrednost koju moe da ima?
o
Pitanje 6.2.6. Koja ogranienja vai za duine u bajtovima tipova short int,
sk
(a) char (b) int (c) short int (d) unsigned long
Pitanje 6.2.11. Koja ogranienja vai za duine u bajtovima tipova float i
double?
Pitanje 6.2.12. U kojoj datoteci zaglavlja se nalaze podaci o opsezima tipova
broja u pokretnom zarezu za konkretnu implementaciju?
109 6. Predstavljanje podataka i operacije nad njima
5)
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
01
se znalo koliko memorijskog prostora treba rezervisati za neke meurezultate
u fazi izvravanja.
(2
6.3.1 Celobrojne konstante
je
Celobrojne konstante navedene u tekstu programa kao to su
su tipa int. Velike celobrojne konstante koje ne mogu biti reprezentovane
an
tipom int, a mogu u tip long su tipa long. Ako ne mogu da budu reprezento-
vane ni tipom long, a mogu tipom unsigned long, onda su tipa unsigned long.
Dakle, taan tip dekadne celobrojne konstante ne moe da se odredi ako se ne
d
ispisuje
sk
2147483647 -2147483648
n
jer se 2147483647 tumai kao konstanta tipa int, dok se 2147483648 tumai
ro
jna konstanta tretira kao da je tipa long, onda se na njenom kraju zapisuje
l ili L. Na primer, 12345l long, 12345 je int, 12345ul
E
5)
zarezu sadre decimalnu taku (na primer,
jedno i drugo. Vrednosti ispred i iza decimalne take mogu biti izostavljene
(ali ne istovremeno). Na primer, ispravne konstante su i .4 ili 5. (ali ne i .).
01
Brojevi su oznaeni i konstante mogu poinjati znakom - ili znakom + (koji
ne proizvodi nikakav efekat). Tip svih ovih konstanti je double, osim ako na
(2
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.
je
6.3.3 Karakterske konstante
an
Iako se tip char 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-
d
char c = a;
char c = 97; /* ekvivalentno prethodnom (na ASCII masinama),
kt
5)
\? question mark
\ single quote
01
\" double quote
\ooo (npr. \012) octal number
\xhh \x12)
(2
(npr. hexadecimal number
Karakterska konstanta \0 predstavlja karakter ija je vrednost nula. Ovaj
karakter ima specijalnu ulogu u programskom jeziku C jer se koristi za ozna-
je
avanje kraja niske karaktera (o emu e vie biti rei u nastavku). Iako je
numerika vrednost ovog karaktera ba 0, esto se u programima pie \0
an
umesto 0 da bi se istakla karakterska priroda ovog izraza.
Poto se karakterske konstante identifikuju sa njihovim numerikim vred-
nostima, one predstavljaju podatke tipa int i mogu ravnopravno da uestvuju
d
Konstantni izraz je izraz koji sadri samo konstante (na primer, 4 + 3*5).
ro
Pitanje 6.3.5. Koja je razlika izmeu konstanti 123 i 0123, a koja izmeu
konstanti 3.4 i 3.4f?
Pitanje 6.3.6. Kojeg su tipa i koje brojeve predstavljaju sledee konstante?
(a)1234 (b) . (c) 6423ul (d) 12.3e-2 (e) 3.74e+2f (f ) 0x47 (g) 0543
(h) 3u (i) 0
Pitanje 6.3.7. Kolika je vrednost konstantnog izraza 0x20 + 020 + 2 - 0
?
5)
Pitanje 6.3.8. Ako se na sistemu koristi ASCII tabela karaktera, ta ispisuje
01
sledei C kd:
(2
printf("%c %d %d %c", c1, c1, c2, c2);
je
Izrazi se u programskom jeziku C grade od konstanti i promenjivih pri-
an
menom irokog spektra operatora. Osim od konstanti i promenljivih, elemen-
tarni izrazi se mogu dobiti i kao rezultat poziva funkcija, operacija pristupa
d
menjuju. Unarni operatori deluju samo na jedan operand i mogu biti prefiksni
kada se navode pre operanda i postfiksni kada se navode nakon svog operanda.
n
Binarni operatori imaju dva operanda i obino su infiksni tj. navode se izmeu
ro
5)
1. Unarni operatori imaju vei prioritet u odnosu na binarne.
01
unarne operatore.
(2
prioritet u odnosu na logike operatore.
je
Druga vana konvencija je asocijativnost operatora koja definie kojim re-
dosledom e se izraunavati dva ista operatora ili operatora istog prioriteta
an
kada se nau uzastopno u istom, nezagraenom izrazu. Obino se razlikuju
leva asocijativnost, kada se izraz izraunava sleva na desno i desna asocija-
d
tivnost, kada se izraz izraunava zdesna na levo. Neki jezici razlikuju i neaso-
cijativnost, kada je zabranjeno da se isti operator dva puta uzastopno ponovi
iz
7
ali dolazi do prekoraenja . Ovakvo ponaanje je posledica injenice da je u
ro
broj_studenata = 80;
broj_grupa = 2;
5)
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
01
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).
(2
Promena vrednosti objekta na levoj strani je propratni (boni, sporedni) efekat
(engl. side effect) do kojeg dolazi prilikom izraunavanja vrednosti izraza. Na
primer, izvravanje naredbe broj_studenata = 80; svodi se na izraunavanje
je
izrazabroj_studenata = 80. Tip promenljive broj_studenata je istovre-
meno i tip ovog izraza, vrednost je jednaka 80, a prilikom ovog izraunavanja
an
menja se vrednost promenljive broj_studenata. Ovakvo ponaanje moe se
iskoristiti i za viestruko dodeljivanje. Na primer, nakon sledee naredbe, sve
x, y i z 0:
d
x = y = z = 0;
o
sk
operatori:
ro
/
le
+ unarni operator.
5)
Prefiksni unarni operatori + i - imaju desnu asocijativnost i vii prioritet
od svih binarnih operatora. Operatori *, / i % imaju isti prioritet, vii od
01
prioriteta binarnih operatora + i -. Svi navedeni binarni operatori imaju levu
asocijativnost.
(2
Inkrementiranje i dekrementiranje. Inkrementiranje generalno znai po-
stepeno uveavanje ili uveavanje za neku konkretnu vrednost. U programi-
je
ranju se pod inkrementiranjem obino podrazumeva uveavanje za 1, a pod
dekrementiranjem umanjivanje za 1. U jeziku C, operator inkrementiranja
an
(uveavanja za 1) zapisuje se sa ++, a operator dekrementiranja (umanjivanja
za 1) zapisuje se sa --:
d
mogu se upotrebiti u prefiksnom (na primer, ++n) ili postfiksnom obliku (na
ro
primer,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
kt
5, onda
x = n++;
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
ispisuje
a = 4, b = 4, x = 3, y = 4
5)
01
Ukoliko ne postoji iri kontekst, tj. ako inkrementiranje ini itavu naredbu,
vrednost izraza se i ne koristi i onda nema razlike izmeu naredbe n++; i ++n;.
Na primer,
(2
int a = 3, b = 3;
a++; ++b;
printf("a = %d, b = %d\n", a, b);
je
an
prethodni kd ispisuje
a = 4, b = 4
d
iz
izmeu svake dve susedne promenljive koje se deklariu (mesto oznaenom sim-
sk
kd
ispisuje
a = 5, x = 3, y = 4,
b = 5, z = 6
5)
likovana i stoga se ne savetuje korienje sloenijih izraza sa ovim operatorima,
koji se oslanjaju na fine detalje semantike.
01
6.4.4 Relacijski i logiki operatori
(2
Relacijski operatori. Nad celim brojevima i brojevima u pokretnom zarezu
mogu se koristiti sledei binarni relacijski operatori:
je
== jednako;
an
!= razliito.
> vee;
d
< manje;
ima vrednost 0, a zatim izraz 0 < 5 ima vrednost 1. Kako u ovakvim slua-
E
5)
! logika negacija ne;
01
&& logika konjunkcija i;
(2
Operator && ima vii prioritet u odnosu na operator ||, a oba su levo
asocijativna. Binarni logiki operatori imaju nii prioritet u odnosu na binarne
je
relacijske i logike operatore. Operator !, kao unarni operator, ima vii prioritet
u odnosu na bilo koji binarni operator i desno je asocijativan. Na primer,
an
vrednost izraza 5 && 4.3 jednaka je 1;
d
izmeu 3 i 5;
izraz a > b || b > c && b > d ekvivalentan je izrazu
kt
izrazom proverava se
da li je godinag prestupna.
E
5)
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-
01
nost prvog operanda jednaka 0, onda se izraunava i vrednost drugog operanda.
Na primer, nakon
(2
1<2 || a++_
je
2<1 || a++
an
se menja (uveava za 1) vrednost promenljive a.
d
sk
bitovska negacija;
| bitovska disjunkcija;
ro
5)
| bitovsko ili primenom ovog operatora vri se (obina) disjunkcija po-
jedinanih bitova dva navedena argumenta. Za brojeve iz tekueg primera,
01
vrednost izraza x1 | x2 je 01011111, tj. 95, tj. 0x5F.
bitovsko ekskluzivno ili primenom ovog operatora vri se ekskluzivna
(2
disjunkcija pojedinanih bitova dva argumenta. Za brojeve iz tekueg
primera, vrednost izraza x1 ^ x2 je 00011101, tj. 29, tj. 0x1D.
jedinini komplement
je
primenom ovog operatora vri se komplemen-
tiranje (invertovanje) svakog bita argumenta. Na primer, vrednost izraza
an
~x1 u tekuem primeru je 10110101, tj. B5, tj. 181.
levo pomeranje (iftovanje) primenom ovog operatora bitovi prvog
d
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
5)
Dodela koja ukljuuje aritmetiki operator i = i + 2; moe se zapisati
krae i kao i += 2;. Slino, naredba x = x * (y+1); ima isto dejstvo kao i
01
x *= y+1;. Za veinu binarnih operatora postoje odgovarajui sloeni opera-
tori dodele:
(2
+=, -=, *=, /=, %=, &=, |=, =, =
Operatori dodele imaju nii prioritet od svih ostalih operatora i desnu aso-
je
cijativnost.
an
Izraunavanje vrednosti izraza
Program 6.3.
E
#include <stdio.h>
int main() {
unsigned char c = 254;
c = 255
c = 0
5)
01
6.4.7 Operator uslova
?:
(2
Ternarni operator uslova se koristi u sledeem optem obliku:
je
Prioritet ovog operatora je nii u odnosu na sve binarne operatore osim
dodela i operatora ,.
an
Izraz izraz1 se izraunava prvi. Ako on ima ne-nula vrednost (tj. ako ima
istinitosnu vrednost tano), onda se izraunava vrednost izraza izraz2 i to je
d
m = (a > b) ? a : b
o
m = (a < 0) ? -a : a
n
ro
izvravanja kda
n = 0;
le
x = (2 > 3) ? n++ : 9;
E
Binarni operator zarez (,) je operator kao i svaki drugi (najnieg je pri-
oriteta 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
x = 3, y = 5; /* ekivalentno bi bilo i x = 3; y = 5; */
5)
Treba razlikovati operator , od zareza koji razdvajaju promenljive prilikom
deklaracije i poziva funkcije (koji nisu operatori). esta greka u korienju
01
ovog operatora je pri pokuaju pristupa viedimenzionom nizu (vie o nizovima
reeno je u poglavlju 6.6.4). Na primer A[1, 2] potpuno je ekvivalentno sa
A[2], A dvodimenzioni. Ispravan nain pristupa
(2
to je pogreno ako je niz
elementu na poziciji (1, 2) je A[1][2].
je
6.4.9 Operator sizeof
an
Veliinu u bajtovima koju zauzima neki tip ili neka promenljiva mogue
je odrediti korienjem operatora sizeof. Tako, sizeof(int) predstavlja
veliinu tipa int i na tridesetidvobitnim sistemima vrednost ovog izraza je
d
najee 4.
iz
Vrednost koju vraa operator sizeof ima tip size_t. Ovo je neoznaen
celobrojni tip, koji obino slui za reprezentovanje veliine objekata u memoriji.
Tip size_t ne mora nuno da bude jednak tipu unsigned int (standard C99
o
Pitanje 6.4.1.
ro
operatore.
Pitanje 6.4.4. Navesti neki operator jezika C koji ima levu i neki operator
E
Pitanje 6.4.8. Da li dodele spadaju u grupu nisko ili visoko prioritetnih op-
eratora?
124 6. Predstavljanje podataka i operacije nad njima
5)
Pitanje 6.4.11. Postaviti zagrade u naredne izraze u skladu sa podrazumevanim
01
prioritetom i u skladu sa podrazumevanom asocijativnou operatora (na primer,
3+4*5+7 (3+(4*5))+7).
(a) a = b = 4 (b) a = 3 == 5 (c) c = 3 == 5 + 7 <= 4
(2
(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
je
Pitanje 6.4.12. Koja je vrednost narednih izraza:
(a) 3 / 4 (b) 3.0 / 4 (c) 14 % 3 (d) 3 >= 7
an
(e) 3 && 7 (f ) 3 || 0 (g) a = 4 (h) (3 < 4) ? 1 : 2
(k) 3 < 5 < 5 (i) 3 < 7 < 5 (j) 6%3 || (6/3 + 5)
(j) 3 < 5 ? 6 + 2 : 8 + 3
d
iz
nost:
sk
(a) 2++ (b) a++ (c) 2** (d) a** (e) 2>>2 (f ) a>>2 (g) a &&= 0 (e) a ||= -7
Pitanje 6.4.15. Koje vrednosti imaju relevantne promenljive nakon navedenih
n
naredbi:
ro
4. int a = 1, b = 1, x, y;
x = a++; y = ++b;
int a = 3, b = 0, c, d;
c = a % 2 || b++;
d = a % 3 || b++;
printf("%d %d %d %d", a, b, c, d);
Pitanje 6.4.18.
5)
1. Napisati izraz koji je taan ako je godina g prestupna.
01
3. Napisati izraz ija je vrednost jednaka apsolutnoj vrednosti broja a.
4. Napisati izraz koji je, na ASCII sistemu, taan ako je karakter c malo
(2
slovo.
je
6. Napisati izraz ija je vrednost jednaka vrednosti implikacije p q.
7. Napisati izraz koji ako je c malo slovo ima vrednost odgovarajueg velikog
an
slova, a inae ima vrednost c.
Zadatak 6.4.1. Napisati program koji za zadati sat, minut i sekund izraunava
d
Zadatak 6.4.2. Napisati program koji za uneta tri pozitivna broja u pokretnom
o
Zadatak 6.4.3. Napisati program koji izraunava zbir cifara unetog etvoro-
n
cifrenog broja.
ro
Zadatak 6.4.4. Napisati program koji razmenjuje poslednje dve cifre unetog
prirodnog broja. Na primer, za uneti broj 1234 program treba da ispie 1243.
kt
Napisati program koji ciklino u levo rotira poslednje tri cifre unetog prirodnog
broja. Na primer, za uneti broj 12345 program treba da ispie 12453.
le
Zadatak 6.4.5. Napisati program koji za uneti par prirodnih brojeva izrau-
E
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.9. Napisati program koji ispisuje sve delioce unetog neoznaenog
celog broja (na primer, za unos 24 treeni delioci su 1, 2, 3, 4, 6, 8, 12i
24).
Zadatak 6.4.10.
5)
Napisati program koji uitava karaktere sa standardnog ulaza
sve dok se ne unese taka (karakter .), zarez (karakter ,) ili kraj datoteke (EOF)
01
i prepisuje ih na standardni izlaz menjajui svako malo slovo velikim. (Napom-
ena: za uitavanje karaktera koristiti funkciju getchar, a za ispis funkciju
putchar)
(2
6.5 Konverzije tipova
je
Konverzija tipova predstavlja pretvaranje vrednosti jednog tipa u vred-
nost drugog tipa. Jezik C je veoma fleksibilan po pitanju konverzije tipova
an
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 ).
d
grama, konverzije mogu dovesti i do gubitka podataka ili njihove loe inter-
pretacije. Jezik C je statiki tipiziran, pa, iako se prilikom konverzija konver-
o
tuju vrednosti izraza, promenljive sve vreme ostaju da budu onog tipa koji im
sk
je pridruen deklaracijom.
n
float f = 16777217;
printf("%f\n", f);
16777216.00000
jer vrednost 16777217.0 ne moe da se zapie u okviru tipa float ako on koristi
5)
etiri bajta i IEEE 754 zapis. Naime, tada tip float za zapis mantise koristi
tri bajta, tj. dvadeset etiri binarne cifre i moe da reprezentuje sve pozitivne
01
celobrojne vrednosti do 224 ali samo neke vee od 224 . Broj 16777217 jednak
24
je 2 +1 i binarno se zapisuje kao 1000000000000000000000001, pa prilikom
float
(2
konverzije u (duine etiri bajta) dolazi do gubitka informacija.
Drugi oblik konverzije predstavlja konverzija vrednosti vieg tipa u vrednost
nieg tipa (na primer, long u short, double u int). Ovaj oblik konverzije
je
ponekad se naziva democija (ili nazadovanje ). Prilikom ovog oblika konverzije,
mogue je da doe do gubitka informacije (u sluaju da se polazna vrednost
an
ne moe predstaviti u okviru novog tipa). U takvim sluajevima, kompilator
obino izdaje upozorenje, ali ipak vri konverziju.
d
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
E
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
Navedeni primer
jednaka desnoj strani (u ovom sluaju 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
tom prilikom takoe dolazi do implicitne konverzije. S obzirom na to da stan-
dard 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
5)
programi izvravali identino na svim raunarima.
Sve brojevne vrednosti (i cele i u pokretnom zarezu) prevode se u istinitosne
01
vrednosti tako to se 0 prevodi u 0, a sve ne-nula vrednosti se prevode u 1.
(2
6.5.2 Eksplicitne konverzije
Operator eksplicitne konverzije tipa ili operator kastovanja (engl. type cast
je
operator) se navodi tako to se ime rezultujueg tipa navodi u malim zagradama
ispred izraza koji se konvertuje:
an
(tip)izraz
d
int a = 13, b = 4;
ro
printf("%d\t", a/b);
printf("%f\n", (double)a/(double)b);
kt
3 3.250000
le
Prilikom prvog poziva funkcije printf upotrebljen je format %d, zbog toga
E
int a;
double b = (a = 3.5);
5)
double konstante 3.5 u vrednost 3 tipa int, a zatim se, prilikom dodele pro-
menljivoj b, vri konverzija te vrednosti u double vrednost 3.0.
01
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-
(2
verzije (engl. usual arithmetic conversions ). Ove konverziju se, na primer,
primenjuju prilikom primene aritmetikih (+, -, *, /) i relacijskih binarnih
operatora (<, >, <=, >=, ==, !=), prilikom primene uslovnog operatora ?:.
je
Aritmetiki operatori se ne primenjuju na male tipove tj. na podatke tipa
char short
an
i (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 int. Ovo se naziva
d
c3 = 4;
sk
cresult = c1 * c2 / c3;
n
moe predstaviti u okviru tipa char i rezultat ne bi bio korektan (tj. ne bi bila
dobijena vrednost (100 3)/4).
le
pravila konverzije:
1. Ako je bar jedan od operanada tipa long double, onda se drugi konver-
tuje u long double;
2. inae, ako je jedan od operanada tipa double, onda se drugi konvertuje
u double;
12 Celobrojna 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 in-
strukcije 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
5)
U sluaju korienja neoznaenih operanada (tj. meanja oznaenih i neo-
01
znaenih operanada), pravila konverzije su neto komplikovanija:
(2
1. Ako je neoznaeni operand iri
vertuje u neoznaeni iri tip;
2. inae, ako je tip oznaenog operanda takav da moe da predstavi sve vred-
je
nosti neoznaenog tipa, tada se neoznaeni tip prevodi u iri, oznaeni.
Zaista, u ovom primeru porede se vrednosti tipa signed long i unsigned int.
Poto signed long moe da predstavi sve vrednosti tipa unsigned int, vri
signed long i vri se poreenje. S druge strane,
o
vai da je
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
n
13 Preciznije, standard uvodi pojam konverzionog ranga (koji raste od char ka long long)
i u ovoj situaciji se razmatra konverzioni rang.
131 6. Predstavljanje podataka i operacije nad njima
5)
double u long, (d) long u int?
Pitanje 6.5.3.
01
Navesti pravila koja se primenjuju prilikom primene aritmetikih
operatora.
(2
Pitanje 6.5.4. 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
je
unsigned char c = 255, d = 1; signed char e = c;
char f = c + d; int g = c + d;?
an
Pitanje 6.5.5. Ako aritmetiki operator ima dva argumenta, a nijedan od njih
nije ni tipa long double, ni tipa double, ni tipa float, u koji tip se implicitno
d
Pitanje 6.5.6.
1. Koju vrednost ima promenljiva x tipa float nakon naredbe
o
x = (x = 3/2);?
sk
2. Ako promenljiva c ima tip char, koji tip e ona imati nakon dodele
c = 1.5 * c;?
n
x tipa float
ro
5)
6.6.1 Primer korienja nizova
01
nog ulaza, a zatim ih ispisuje u obratnom poretku. Bez nizova, neophodno je
koristiti deset promenljivih. Da se u zadatku trailo ispisivanje unatrag 1000
(2
brojeva, program bi bio izrazito mukotrpan za pisanje i nepregledan.
Program 6.4.
je
#include <stdio.h> an
int main() {
int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9;
scanf("%d%d%d%d%d%d%d%d%d%d",
d
&b0, &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &b9);
iz
printf("%d %d %d %d %d %d %d %d %d %d",
b9, b8, b7, b6, b5, b4, b3, b2, b1, b0);
}
o
sk
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
n
ro
Program 6.5.
#include <stdio.h>
le
E
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
tip ime_niza[dimenzija];
int a[10];
5)
uvodi niz a od 10 celih brojeva. Prvi element niza ima indeks 0, pa su elementi
01
niza:
a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]
(2
Indeksi niza su obino nenegativni celi brojevi (mada je u nekim prilikama kada
se nizovi koriste u kombinaciji sa pokazivaima doputeno koristiti i negativne
je
indekse, o emu e vie biti rei u poglavlju 10.3).
an
Prilikom deklaracije moe se izvriti i inicijalizacija:
int a[5] = { 1, 2, 3, 4, 5 };
d
1 2 3 4 5
o
sk
int x;
char a[100+10];
kt
int b[];
float c[x];
le
E
14 Standardi nakon C99 uvode pojam niza promenljive duine (engl. variable length array,
VLA). U tom svetlu, deklaracija niza c bila bi ispravna. Ipak, u ovoj knjizi, VLA nee biti
razmatrani.
134 6. Predstavljanje podataka i operacije nad njima
int b[] = { 1, 2, 3 };
1 2 3
5)
bajtovima. Ukoliko dimenzija niza nije zadata eksplicitno ve je implicitno
odreena inicijalizacijom, broj elemenata moe se izraunati na sledei nain:
01
sizeof(ime niza)/sizeof(tip elementa niza)
(2
Kada se pristupa elementu niza, indeks moe da bude proizvoljan izraz
celobrojne vrednosti, na primer:
a[2*2+1]
je
a[i+2]
an
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
d
van opsega deklarisanog niza (na primer, mogue je koristiti element a[13], pa
ak element a[-1] u prethodnom primeru). Ovo najee dovodi do fatalnih
greaka prilikom izvravanja programa. S druge strane, ovakva (jednostavna)
o
6.6.3 Niske
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
5)
char s1[] = {Z, d, r, a, v, o};
char s2[] = {Z, d, r, a, v, o, \0};
01
char s3[] = "Zdravo";
s1
(2
Nakon navedenih deklaracija, sadraj niza jednak je:
0 1 2 3 4 5
Z d r a v o
je
a sadraj nizova s2 i s3 jednak je:
0 1 2 3 4 5 6
an
Z d r a v o \0
Niz s1 sadri 6 karaktera (i zauzima 6 bajtova). Deklaracije za s2 i s3
d
je ekvivaletno sa
kt
printf("Zdravo, svima");
le
16 Neki 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. P-
niske).
136 6. Predstavljanje podataka i operacije nad njima
int i = 0;
while (s[i] != \0)
i++;
5)
...
01
ili oblika:
(2
...
je
vrednost netano), poreenje u prethodnoj petlji moe da se izostavi:
an
for (i = 0; s[i]; i++)
...
d
...
sk
velika da primi nisku koja se dodeljuje. Ako to nije ispunjeno, vri se promena
sadraja memorijskih lokacija koje su van dimenzija niza to moe dovesti do
kt
int i = 0;
E
int i;
for (i = 0; dest[i] = src[i]; i++)
; /* prazno telo petlje */
137 6. Predstavljanje podataka i operacije nad njima
tip ime_niza[dimenzija_1]...[dimenzija_2];
5)
su elementi nizovi. Zato se elementima dvodimenzionog niza pristupa sa:
ime_niza[vrsta][kolona]
01
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
(2
6.4).
Elementi se u memoriji smetaju po vrstama pa se, kada se elementima
je
pristupa u redosledu po kojem su smeteni u memoriji, najbre menja poslednji
indeks. Niz se moe inicijalizovati navoenjem liste inicijalizatora u vitiastim
an
zagradama; poto su elementi opet nizovi, svaki od njih se opet navodi u okviru
vitiastih zagrada (mada je unutranje vitiaste zagrade mogue i izostaviti).
Razmotrimo, kao primer, jedan dvodimenzioni niz:
d
char a[2][3] = {
iz
{1, 2, 3},
{4, 5, 6}
o
};
sk
char a[][3] = {
{1, 2, 3},
kt
{4, 5, 6}
};
le
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}
};
5)
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:
01
broj dana za mesec
(2
char bd = broj_dana[prestupna][mesec];
je
Vrednost logikog izraza je uvek nula (netano) ili jedan (tano), pa se
vrednost prestupna moe koristiti kao indeks pri pristupanju nizu.
an
Pitanja i zadaci za vebu
d
Pitanje 6.6.2. Navesti primer inicijalizacije niza tipa char tako da mu sadraj
o
Pitanje 6.6.3. Ukoliko je niz a deklarisan kao float a[10];, koja je vrednost
n
izraza sizeof(a)?
ro
ziju?
Pitanje 6.6.6.
E
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
5)
3 4 .
5 6
01
Zadatak 6.6.1. Napisati program koji unosi prirodan broj ( < 1000), a
zatim i elemenata niza celih brojeva, nakon ega:
(2
1. ispisuje unete brojeve unatrag;
je
an
Zadatak 6.6.2.
d
svake od cifara (broj pojavljivanja smestiti u niz od 10 elemenata).
Zadatak 6.6.3. Napisati program koji za uneti datum u obliku (dan, mesec,
o
datuma. U obzir uzeti i prestupne godine. Koristiti niz koji sadri broj dana
za svaki mesec i uporediti sa reenjem zadatka bez korienja nizova.
n
Zadatak 6.6.4.
()
Paskalov trougao sadri binomne koeficijente . Napisati
ro
1
1 1
le
1 2 1
1 3 3 1
E
1 4 6 4 1
1 5 10 10 5 1
() ( )
(primetite da su ivice trougla 1 tj. da vai 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 + ).
Zadatak 6.6.5. Napisati program koji sa standardnog ulaza unosi prvo dimen-
ziju matrice ( < 10) pa zatim elemente matrice. Na primer,
140 6. Predstavljanje podataka i operacije nad njima
4
1 2 3 4
5 6 7 8
9 1 2 3
4 5 6 7
Program izraunava i ispisuje sumu elemenata glavne dijagonale i sumu ele-
menata iznad sporedne dijagonale matrice. Suma elemenata glavne dijagonale
5)
matrice navedene u primeru je 1 + 6 + 2 + 7 = 16, a iznad sporedne dijagonale
je 1 + 2 + 3 + 5 + 6 + 9 = 26
01
Zadatak 6.6.6. Napisati program koji sa standardnog ulaza unosi prvo dimen-
ziju matrice ( < 100) pa zatim elemente matrice i zatim proverava da li je
(2
matrica donje-trougaona. Matrica je donje-trougaona ako se u gornjem trouglu
(iznad glavne dijagonale, ne ukljuujui je) nalaze sve nule. Na primer:
je
1 0 0 0
5 6 0 0
an
9 1 2 0
4 5 6 7
d
iz
nain se povezane vrednosti (ne nuno istog tipa) tretiraju kao jedna celina
i za razliku od nizova gde se pristup pojedinanim vrednostima vri na os-
kt
6.7.1 Strukture
Osnovni tipovi jezika C esto nisu dovoljni za pogodno opisivanje svih po-
dataka 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 odra-
vanje. 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
5)
definisati na sledei nain:
struct razlomak {
01
int brojilac;
int imenilac;
(2
};
je
strukture, a zatim, izmeu vitiastih zagrada, opis njenih lanova (ili polja).
an
Imena lanova strukture se ne mogu koristiti kao samostalne promenljive, one
postoje samo kao deo sloenijeg objekta. Prethodnom definicijom strukture
uveden je samo novi tip pod imenom struct razlomak, ali ne i promenljive
d
tog tipa.
iz
struct student {
o
char ime[50];
sk
float prosek;
};
n
ro
Strukture mogu biti ugnjedene, tj. lanovi struktura mogu biti druge struk-
ture. Na primer:
kt
struct dvojni_razlomak {
struct razlomak gore;
le
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, na primer:
struct razlomak a, b, c;
142 6. Predstavljanje podataka i operacije nad njima
struct razlomak a = { 1, 2 };
5)
Redosled navoenja inicijalizatora odgovara redosledu navoenja lanova
strukture. Dakle, navedenom deklaracijom je uveden razlomak a iji je brojilac
01
1, a imenilac 2.
Definisanje strukture i deklarisanje i inicijalizacija promenljivih moe se
;
(2
uraditi istovremeno (otuda i neuobiajeni simbol nakon zatvorene vitiaste
zagrade prilikom definisanja strukture):
struct razlomak {
je
int brojilac;
int imenilac;
an
} a = {1, 2}, b, c;
d
a.imenilac
o
na sledei nain:
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
mesec koja sadri broj dana i ime:
5)
struct opis_meseca {
char ime[10];
01
int broj_dana;
};
(2
i koristiti niz ovakvih struktura:
13 je
an
(deklarisan je niz duine da bi se meseci mogli referisati po svojim rednim
brojevima, pri emu se poetni element niza ne koristi).
Mogua je i deklaracija sa inicijalizacijom (u kojoj nije neophodno navoenje
d
{ "januar",31 },
{ "februar",28 },
sk
{ "mart",31 },
...
n
{ "decembar",31 }
ro
};
kt
"",0,
"januar",31,
E
"februar",28,
"mart",31,
...
"decembar",31
};
sizeof(meseci)/sizeof(struct opis_meseca)
6.7.2 Unije
5)
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
01
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
(2
najveeg polja. Osnovna svrha unija je uteda memorije.
Skoro sva sintaksika pravila koja se odnose na strukutre se prenose i na
unije (jedina razlika je da se umesto kljune rei struct koristi kljuna re
je
union).
an
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).
Oba polja unije nee se moi koristiti istovremeno.
d
union vreme {
iz
int obicno;
float precizno;
};
o
sk
union vreme a;
ro
a.obicno = 17;
kt
Unije se esto koriste i kao lanovi struktura. Neka se, na primer, u pro-
gramu uvaju i obrauju informacije o studetima i zaposlenima na nekom fakul-
le
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
int main() {
5)
struct akademac pera = {"Pera Peric", "0101970810001", z};
pera.dodatno.plata = 56789.5;
01
printf("%f\n", pera.dodatno.plata);
(2
strcpy(ana.dodatno.indeks, "12/123");
printf("%s\n", ana.dodatno.indeks);
}
je
pera.dodatno.indeks bi naruio podatak o koefici-
an
Pokuaj promene polja
jentu plate, dok bi pokuaj promene polja ana.dodatno.koeficijent naruio
podatak o broju indeksa.
d
(engl. bit fields). Naime, najmanji celobrojni tip podataka je char koji za-
uzima jedan bajt, a za predstavljanje neke vrste podataka dovoljan je manji
le
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 : 1;
unsigned char boja : 3;
146 6. Predstavljanje podataka i operacije nad njima
5)
zauzimala bi 3 bajta.
Polje bitova se nadalje koristi kao obina struktura. Na primer:
...
01
#define ZELENA 02
...
(2
#define PUN 00
je
op.popunjen = 0;
op.boja = ZELENA;
an
op.vrsta_okvira = PUN;
d
iz
U nekim sluajevima korisno je definisati tip podataka koji ima mali skup
o
enum znak_karte {
n
KARO,
ro
PIK,
HERC,
TREF
kt
};
le
programa. Pri tome, obino nije vano koje su konkretne vrednosti pridruene
imenima KARO, PIK, HERC, TREF, ve je dovoljno znati da su one sigurno me-
usobno razliite i celobrojne. U navedenom primeru, KARO ima vrednost 0,
PIK vrednost 1, HERC vrednost 2 i TREF vrednost 3. Mogue je i eksplicitno
navoenje celobrojnih vrednosti. Na primer:
enum znak_karte {
KARO = 1,
PIK = 2,
HERC = 4,
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
moe postii i pretprocesorskom direktivom #define (videti poglavlje 9.2.1),
enum).
5)
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.
01
Slino kao i kod struktura i unija, uz definiciju tipa mogue je odmah deklar-
isati i promenljive. Promenljive se mogu i naknadno definisati (uz obavezno
ponovno korienje kljune rei enum). Na primer,
(2
enum znak_karte znak;
je
Nabrojivi tipovi mogu uestvovati u izgradnji drugih sloenih tipova.
struct karta {
an
unsigned char broj;
enum znak_karte znak;
d
enum return_type {
OK,
FileError,
kt
MemoryError,
TimeOut
le
};
E
6.7.5 Typedef
U jeziku C mogue je kreirati nova imena postojeih tipova koristei kljunu
re typedef. Na primer, deklaracija
uvodi ime Length kao sinonim za tip int. Ime tipa Length se onda moe
koristiti u deklaracijama, eksplicitnim konverzijama i slino, na isti nain kao
to se koristi ime int:
Length len, maxlen;
5)
Obino se novouvedena imena tipova piu velikim poetnim slovima da bi se
istakla.
01
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-
(2
rama da bi se izbeglo pisanje kljune rei struct pri svakom korienju imenu
strukturnog tipa. Na primer:
je
struct point {
int x, y;
an
};
typedef struct point Point;
d
Point a, b;
iz
meno. Na primer:
sk
} Point;
ro
Point a, b;
kt
uvodi ime PFI, za tip pokaziva na funkciju koja prima dva char * argumenta
i vraa int (vie rei o pokazivaima na funkcije e biti u glavi 10) i koje se
moe koristiti na primer kao:
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 typedef deklaracije. Jedan od
primera je korienje typedef za imenovanje celobrojnog tipa, i zatim odabir
short, int i long u zavisnosti od maine. Druga svrha upotrebe typedef
je poboljanje itljivosti programa tip sa imenom Point se jednostavnije
5)
razumeti nego dugo ime strukture.
01
Pitanja i zadaci za vebu
(2
Pitanje 6.7.1. Definisati strukturu complex koja ima dva lana tipa double.
Pitanje 6.7.2. Definisati strukturu student kojom se predstavljaju podaci o
studentu (ime, prezime, JMBG, prosena ocena).
Pitanje 6.7.3.
je
Da li je nad vrednostima koje su istog tipa strukture dozvoljeno
an
koristiti operator dodele i koje je njegovo dejstvo?
datum.
struct tacka {
sk
int a, b;
char naziv[5];
n
}
ro
Pitanje 6.7.7. Na koji nain se postojeem tipu t moe dodeliti novo ime
NoviTip?
Pitanje 6.7.8. Uvesti novo ime real za tip double.
Pitanje 6.7.9. Definisati novi tip novitip koji odgovara strukturi koji ima
jedan lan tipa int i jedan lan tipa float.
Zadatak 6.7.1. 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
nabrojivi tip podataka).
5)
01
(2
je
an
d
iz
o
sk
n
ro
kt
le
E
Glava 7
5)
Naredbe i kontrola toka
01
(2
je
Osnovni elementi kojima se opisuju izraunavanja u programima su naredbe.
Naredbe za kontrolu toka omoguavaju razliite naine izvravanja programa,
an
u zavisnosti od vrednosti promenljivih. 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
d
i tekih za odravanje a, dodatno, svaki program koji koristi naredbu goto moe
iz
naredbe za kontrolu toka radi bolje itljivosti kda. Iako mogu da postoje opte
sk
programera.
ro
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
f (pri emu se, ako je ima, povratna vrednost funkcije zanemaruje).
Zanimljiva je i prazna naredba koja se obeleava samo znakom ; (na primer,
telo for petlje moe sadrati samo praznu naredbu).
5)
U nekim sluajevima potrebno je vie razliitih naredbi tretirati kao jednu
01
jedinstvenu naredbu. Vitiaste zagrade {i} se koriste da grupiu naredbe u
sloene naredbe tj. blokove i takvi blokovi se mogu koristiti na svim mestima
(2
gde se mogu koristiti i pojedinane naredbe. Iza zatvorene vitiaste zagrade
ne pie se znak ;. Vitiaste zagrade koje okruuju vie naredbi neke petlje su
jedan primer njihove upotrebe, ali one se, za grupisanje naredbi, koriste i u
je
drugim kontekstima. Doputeno je i da blok sadri samo jednu naredbu, ali
tada nema potrebe koristiti blok (izuzetak je definicija funkcije koja ne moe da
an
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
d
pravilima dosega (o emu e vie rei biti u poglavlju 9.2.2). Nakon deklaracija,
navode se naredbe (elementarne ili sloene, tj. novi blokovi). Postoje razliite
o
if (izraz)
E
naredba1
else
naredba2
je taan (tj. da je uslov ispunjen) ako ima ne-nula vrednost, a inae se smatra
da je netaan. Na primer, nakon naredbe
if (5 > 7)
a = 1;
else
a = 2;
5)
promenljiva a e imati vrednost 2, a nakon naredbe
if (7)
01
a = 1;
else
(2
a = 2;
je
Kako se ispituje istinitosna vrednost izraza koji je naveden kao uslov, ponekad
je mogue taj uslov zapisati krae. Na primer, if (n != 0) je ekvivalentno sa
an
if (n).
Dodela je operator, pa je naredni C kd je sintaksiki ispravan, ali verovatno
d
a = 3;
if (a = 0)
printf("a je nula\n");
o
else
sk
(a ne da ispita da li je
je vrednost izraza a = 0 nula, to se smatra netanim. Zamena operatora ==
operatorom = u naredbi if je esta greka.
kt
nove naredbe uslova, tj. moe biti vie ugnjedenih if naredbi. Ukoliko vi-
else se odnosi na poslednji
E
if (izraz1)
if (izraz2)
naredba1
else
naredba2
154 7. Naredbe i kontrola toka
if (izraz1) {
if (izraz2)
naredba1
} else
naredba2
5)
7.3.2 Konstrukcija else-if
01
Za viestruke odluke esto se koristi konstrukcija sledeeg oblika:
(2
if (izraz1)
naredba1
else if (izraz2)
je
naredba2
else if (izraz3)
an
naredba3
else
naredba4
d
iz
if (a > 0)
printf("A je veci od nule\n");
ro
else if (a < 0)
printf("A je manji od nule\n");
kt
else /* if (a == 0) */
printf("A je nula\n");
le
E
Naredna naredba
if (a > b)
x = a;
else
x = b;
155 7. Naredbe i kontrola toka
x = (a > b) ? a : b;
switch
5)
7.3.4 Naredba
01
switch (izraz) {
case konstantan_izraz1: naredbe1
(2
case konstantan_izraz2: naredbe2
...
default: naredbe_n
je
}
an
Naredbe koje treba izvriti oznaene su sluajevima (engl. case) za razliite
mogue pojedinane vrednosti zadatog izraza izraz. Svakom sluaju pridruen
izraz
d
sve dok se ne naie na kraj ili naredbu break. Na sluaj default se prelazi
izraz default je
sk
nije naveden kao poslednji, ako vrednost izraza izraz nije navedena ni uz jedan
drugi sluaj, prelazi se na izvravanje naredbi od naredbe pridruene sluaju
default.
le
int main() {
int n;
5)
scanf("%i",&n);
01
switch (n % 3) {
case 1:
(2
case 2:
printf("Uneti broj nije deljiv sa 3");
break;
je
default: printf("Uneti broj je deljiv sa 3");
}
an
return 0;
}
d
bie ispisan tekstUneti 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
o
7.4 Petlje
ro
grupa naredbi) izvrava vie puta (sve dok je neki logiki uslov ispunjen).
le
while(izraz)
naredba
U petlji while ispituje se vrednost izraza izraz i ako ona ima istinitosnu
vrednost tano (tj. ako je vrednost izraza razliita od nule), izvrava se naredba
(to je ili pojedinana naredba ili blok naredbi). Zatim se uslov izraz iznova
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++;
5)
while (1)
i++;
01
for
(2
7.4.2 Petlja
je
for (izraz1; izraz2; izraz3)
naredba
an
Komponente izraz1, izraz2 i izraz3 su izrazi. Obino su izraz1 i izraz3
izrazi dodele ili inkrementiranja, a izraz2 je relacijski izraz. Izraz izraz1 se
d
avanja petlje. Petlja se izvrava sve dok uslov (izraz izraz2) ima ne-nula
vrednost (tj. sve dok mu je istinitosna vrednost tano), a korak (izraz izraz3)
n
dakle, oblika: inicijalizacija, uslov, telo, korak, uslov, telo, korak, . . . , uslov,
telo, korak, uslov, pri emu je uslov ispunjen svaki, osim poslednji put. Dakle,
gore navedena opta forma petlje for ekvivalentna je konstrukciji koja koristi
kt
petlju while:
izraz1;
le
while (izraz2) {
E
naredba
izraz3;
}
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
beskonano (ako u bloku naredbi koji ovde nije naveden nema neke naredbe
break return):
5)
koja prekida izvravanje, na primer, ili
for (;;)
01
...
(2
Ako je potrebno da neki od izraza objedini vie
izraza, moe se koristiti operator ,.
for (i = 0, j = 10; i < j; i++, j--)
je
printf("i=%d, j=%d\t", i, j);
an
Prethodni kd ispisuje
i=0, j=10 i=1, j=9 i=2, j=8 i=3, j=7 i=4, j=6
d
iz
Program 7.2.
sk
#include<stdio.h>
n
int main() {
ro
int i, j, n=3;
for(i = 1; i <= n; i++) {
kt
}
E
return 0;
}
1 * 1 = 1 1 * 2 = 2 1 * 3 = 3
2 * 1 = 2 2 * 2 = 4 2 * 3 = 6
3 * 1 = 3 3 * 2 = 6 3 * 3 = 9
159 7. Naredbe i kontrola toka
do {
naredbe
} while(izraz)
5)
i onda se izraunava uslov (izraz izraz). Ako je on taan, telo se izvrava
ponovo i to se nastavlja sve dok izraz izraz nema vrednost nula (tj. sve dok
01
njegova istinitosna vrednost ne postane netano).
Za razliku od petlje while, naredbe u bloku ove petlje se uvek izvravaju
(2
barem jednom.
Naredni program ispisuje cifre koje se koriste u zapisu unetog neoznaenog
broja, zdesna na levo.
je
Program 7.3.
an
#include <stdio.h>
int main() {
unsigned n;
d
scanf("%u", &n);
do {
printf("%u ", n % 10);
o
n /= 10;
sk
}
ro
4 3 2 1
while, do-while
le
5)
otea njegovu analizu (na primer, analizu ispravnosti ili analizu sloenosti).
U nekim situacijama, korienje naredbe break moe da pobolja itljivost,
ali kd koji koristi naredbu break uvek se moe napisati i bez nje. U datom
01
primeru, odgovarajui alternativni kd je, na primer:
(2
...
continue
je
Naredbom se prelazi na sledeu iteraciju u petlji. Na primer,
}
iz
...
kt
ispisuje
0 0 0 1 0 2 1 0 1 1 2 0
161 7. Naredbe i kontrola toka
if (!x)
x += 2;
x *= 2;
0, 5?
5)
ako je pre navedenog kda imala vrednost a koju ako je imala vrednost
01
int x = 0;
if (x > 3);
(2
x++;
Pitanje 7.3. Navesti primer naredbe u kojoj se javlja if-else vieznanost.
je
Pitanje 7.4. Kako se, u okviru naredbe switch, oznaava sluaj koji pokriva
an
sve sluajeve koji nisu ve pokriveni?
Pitanje 7.5. Ako su promenljive i i j tipa int odrediti njihovu vrednost nakon
d
naredbi:
iz
i=2; j=5;
switch(j/i)
{
o
case 1: i++;
sk
break;
case 2: i += ++j;
n
default: j += ++i;
ro
}
Pitanje 7.6. Ako su promenljive i i j tipa int odrediti njihovu vrednost nakon
kt
naredbi:
switch (j%3) {
E
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
if (i % 3 == 0)
j--;
else {
i+=2; j++;
}
printf("%d %d\n", i, j);
}
5)
Pitanje 7.8. ta se ispisuje prilikom izvravanja narednog kda?
01
for (j = 0; j < 5; j++) {
if ((i + j) % 3 == 0) break;
(2
printf("%d %d\n", i, j);
}
Pitanje 7.9.
je
ta se ispisuje prilikom izvravanja narednog kda?
Pitanje 7.11. Ukoliko se u naredbi for (e1; e2; e3) ... izostavi izraz e2,
ro
Pitanje 7.12.
kt
povezani ti podizrazi?
Pitanje 7.13. Izraziti sledei kd (i) petljom while i (ii) petljom for
E
do {
naredbe
} while(izraz)
Pitanje 7.14. Izraziti sledei kd (i) petljom while i (ii) petljom do-while
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 break:
while(A) {
if(B) break;
C;
}
5)
Pitanje 7.17. Transformisati naredni kd tako da ne sadri continue:
01
for(;A;) {
if(B) continue;
(2
C;
}
je
Pitanje 7.18. Transformisati naredni kd i zapisati ga u obliku while petlje
tako da ne sadri break:
an
1. for(i = 1;;i++) if (i++ == 3) break; else printf("%d", i);
for(i = 1;;) if (++i == 3) break; else printf("%d", i);
d
2.
Zadatak 7.1. Napisati program koji ispisuje sve neparne brojeve manje od
unetog neoznaenog celog broja n.
Zadatak 7.2. Napisati program koji izraunava i ispisuje vrednost funkcije
sin() u 100 taaka intervala [0, 2] na jednakim rastojanjima.
Zadatak 7.3. Napisati program koji uitava realan broj i neoznaeni ceo
broj i izraunava .
Zadatak 7.4. Napisati programe koji ispisuje naredne dijagrame, pri emu se
dimenzija n unosi. Svi primeri su za = 4:
164 7. Naredbe i kontrola toka
Zadatak 7.5. Napisati program koji odreuje sumu svih delilaca broja (koristiti
injenicu da se delioci javljaju u paru).
5)
Zadatak 7.6. Napisati program koji odreuje da li je uneti neoznaeni ceo broj
01
prost.
Zadatak 7.7. Napisati program koji ispisuje sve proste inioce unetog neoz-
(2
naenog celog broja (na primer, za unos 24 traeni prosti inioci su 2, 2, 2,
3).
Zadatak 7.8.
je
Napisati program koji uitava cele brojeve sve dok se ne unese
0, a onda ispisuje:
an
1. broj unetih brojeva;
1 +...+
6. aritmetiku sredinu unetih brojeva ( );
sk
7. geometrijsku sredinu unetih brojeva (
1 . . . );
n
8. harmonijsku sredinu unetih brojeva ( 1 );
1 +...+ 1
ro
kt
Zadatak 7.9. Napisati program koji uitava cele brojeve sve dok se ne unese
0 i izraunava duinu najdue serije uzastopnih jednakih brojeva.
le
2
0 = 1, +1 =
2
tei ka
, napisati program koji (bez korienja funkcije sqrt) procenjuje
vrednost . Iterativni postupak zaustaviti kada je |+1 | < 0.0001.
165 7. Naredbe i kontrola toka
Zadatak 7.13.
5)
Napisati program koji ispisuje sve cifre unetog neoznaenog
celog broja n, poevi od cifre jedinica. Napisati i program koji izraunava
sumu cifara unetog neoznaenog celog broja n.
01
Zadatak 7.14. Napisati program koji nadovezuje dva uneta neoznaena cela
123 i 456 program ispisuje 123456).
(2
broja (na primer, za unos Ako je jedan od
brojeva 0, rezultat treba da bude jednak drugom broju. Pretpostaviti da rezultat
staje u opseg tipa unsigned.
je
Zadatak 7.15. Napisati program koji izraunava broj dobijen obrtanjem cifara
unetog celog broja (na primer, za unos 1234 program ispisuje broj 4321).
an
Zadatak 7.16. Napisati program koji izbacuje sve neparne cifre iz zapisa un-
d
etog neoznaenog celog broja (na primer, za uneti broj 123456 program ispisuje
246).
iz
Zadatak 7.17. Napisati program koji umee datu cifru na datu poziciju
neoznaenog celog broja (pozicije se broje od 0 sa desna). Na primer, za unos
o
= 5, = 2, = 1234, program ispisuje 12534.
sk
Zadatak 7.18.
n
naenog celog broja (na primer, za unos 1234 program ispisuje 4231).
2. Napisati program koji ciklino pomera cifre unetog neoznaenog celog
kt
Zadatak 7.19. Napisati program koji za zadati dan, mesec i godinu ispituje da
li je uneti datum korektan (uzeti u obzir i prestupne godine). Koristiti switch
naredbu.
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:
5)
Zadatak 7.22. Napisati program koji ispisuje prvih (najvie 100000) ele-
menata niza koji se dobija tako to se kree od 0, a zatim prethodni niz ponovi
01
pri emu se svaki broj uvea za 1, tj. 0112122312232334...
Zadatak 7.23. Sa standardnog ulaza se unose dva niza brojeva (svaki sadri
(2
najvie 100 elemenata). Napisati program koji odreuje njihov presek, uniju i
razliku (redosled prikaza elemenata nije bitan, i u ulaznim nizovima se elementi
ne ponavljaju).
je
Zadatak 7.24. Napisati program koji proverava da li je data niska palindrom
an
(ita se isto sleva i zdesna, na primer, anavolimilovana). Prilagoditi program
tako da se razmaci zanemaruju i ne pravi se razlika izmeu malih i velikih slova
(na primer, Ana voli Milovana je palindrom).
d
Zadatak 7.25. Napisati program koji obre i ispisuje datu nisku.
iz
Zadatak 7.26. Napisati program koji sa standardnog ulaza unosi prvo dimenz-
o
iju matrice ( < 100) pa zatim elemente matrice i zatim ispisuje sve dijagonale
matrice paralelne sa sporednom dijagonalom. Na primer, unos:
sk
3 1 2 3 4 5 6 7 8 9
opisuje matricu
n
ro
1 2 3
4 5 6
7 8 9
kt
1
2 4
E
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
toga ispisuje indekse ( i ) onih elemenata matrice koji su jednaki zbiru svih
svojih susednih elemenata (pod susednim elementima podrazumevamo okolnih
8 polja matrice ako postoje). Na primer, za matricu:
167 7. Naredbe i kontrola toka
1 1 2 1 3
0 8 1 9 0
1 1 1 0 0
0 3 0 2 2
polja na pozicijama [1][1], [3][1], i [3][4] zadovoljavaju traeni uslov.
5)
01
(2
je
an
d
iz
o
sk
n
ro
kt
le
E
Glava 8
5)
Funkcije
01
(2
je
Svaki C program sainjen je od funkcija. Funkcija main mora da postoji
i, pojednostavljeno reeno, izvravanje programa uvek poinje izvravanjem
an
1
ove funkcije . Iz funkcije main (ali i drugih) pozivaju se druge funkcije, bilo
biblioteke (poput funkcije printf), bilo korisniki definisane (kakve e biti
2
d
navanje, neka obrada koja predstavlja celinu za sebe i koristi se vie puta u
programu. Tako se dobija ne samo krai i jednostavniji kd, ve i kvalitetniji
o
movi koji su u okviru ovog primera samo ukratko objanjeni bie detaljnije
objanjeni u nastavku teksta.
le
Program 8.1.
E
#include <stdio.h>
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 main, kao i da se odreeni
delovi programa izvravaju i nakon njenog zavretka.
2 Iz funkcija programa moe se pozivati i funkcija main, ali to obino nema mnogo smisla
i generalno se ne preporuuje.
168
169 8. Funkcije
int kvadrat(int n) {
return n*n;
}
int kvadrat(int n); deklarie funkciju kvadrat koja e biti defin-
5)
Linija
3
isana kasnije u kdu . Iz deklaracije se vidi da funkcija kvadrat ima jedan
parametar tipa int i vraa rezultat tipa int. U funkciji main, u okviru poziva
01
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
(2
moe ravnopravno dalje uestvovati u irim izrazima) iji je tip povratni tip
funkcije, a vrednost povratna vrednost funkcije. Na mestu poziva, tok izvra-
vanja programa prelazi na poetak funkcije koja je pozvana, a kada se zavri
je
izvravanje funkcije tok izvravanja programa vraa se na mesto poziva. Defini-
cija funkcije kvadrat je jednostavna: ona kao rezultat, korienjem naredbe
an
return vraa kvadrat celobrojne vrednosti n ija se vrednost postavlja na os-
novu vrednosti koja je prosleena prilikom poziva.
stepen izraunava celobrojni stepen realne
d
Program 8.2.
o
#include <stdio.h>
sk
int main() {
kt
unsigned i;
for(i = 0; i < max; i++)
printf("%d %f %f\n", i, stepen(2.0f,i), stepen(3.0f,i));
le
return 0;
E
return s;
}
Primetimo da je promenljiva i deklarisana u funkciji main, druga promenljiva
i deklarisana je u funkciji stepen, a promenljiva max deklarisana je van svih
funkcija. Promenljive deklarisana u funkcijama nazivamo obino lokalne pro-
menljive i njih je mogue koristiti samo u okviru funkcije u kojoj su definisane,
dok promenljive deklarisana van svih funkcija nazivamo obino globalne pro-
5)
menljive i one su zajednike za vie funkcija. O ovoj temi bie vie rei u
poglavlju 9.2.2.
01
8.2 Deklaracija i definicija funkcije
(2
Deklaracija (ili prototip ) funkcije ima sledei opti oblik:
tip ime_funkcije(niz_deklaracija_parametara);
naredbe
iz
a definicija
int kvadrat(int n) {
le
return n*n;
}
E
int kvadrat(int);
5)
cije funkcije moe da utvrdi sve relevantne tipove). Meutim, kada postoji
vie funkcija u programu i kada postoje njihove meuzavisnosti, moe biti
01
veoma teko (i to nepotrebno teko) poreati njihove definicije na nain koji
omoguava prevoenje (sa proverom tipova argumenata). Zato je uobiajena
(2
praksa da se na poetku programa navode prototipovi funkcija, ime poredak
njihovih definicija postaje irelevantan.
Ukoliko se ni definicija ni deklaracije funkcije ne navedu pre prvog poziva
int
je
te funkcije, prevodilac pretpostavlja da funkcija vraa vrednost tipa i ne
vri nikakvu provera ispravnosti argumenata u pozivima funkcije. Ovakvo pon-
an
aanje 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.
d
jeno, ali postojanje dve deklaracije funkcije istog imena, a razliitih lista param-
etara dovodi do greke tokom prevoenja. Postojanje dve definicije funkcije
n
istog imena u jednom programu dovodi do greke tokom prevoenja ili povezi-
vanja (ak i ako su liste parametara razliite).
ro
izbegavati i zaglavlja bi uvek trebalo eksplicitno ukljuiti (tj. pre svakog poziva
funkcije trebalo bi osigurati da kompilator poznaje njen prototip).
5)
znaenje i ulogu u programu. Pre imena svakog parametra neophodno je navesti
njegov tip. Ukoliko funkcija nema parametara, onda se izmeu zagrada ne
01
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
(2
da li je ona zaista pozvana bez argumenata.
Promenljive koje su deklarisane kao parametri funkcije lokalne su za tu
funkciju i njih ne mogu da koriste druge funkcije. tavie, bilo koja druga
je
funkcija moe da koristi isto ime za neki svoj parametar ili za neku svoju
lokalnu promenljivu.
an
Kvalifikatorom const 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
d
Funkcija main moe biti bez parametara ili moe imati dva parametra un-
apred odreenog tipa (videti poglavlje 12.4).
Prilikom poziva funkcije, vri se prenos argumenata, to e biti opisano u
o
narednom poglavlju.
sk
koja se koristi kao argument funkcije kopira kada pone izvravanje funkcije i
E
Program 8.3.
173 8. Funkcije
#include <stdio.h>
5)
int main() {
int x = 3, y = 5;
01
swap(x, y);
printf("x = %d, y = %d\n", x, y);
(2
}
je
pozvana iz neke druge funkcije sa swap(x, y), onda e vrednosti promenljivih
xiy ostati nepromenjene nakon ovog poziva.
an
x = 3, y = 5
d
Program 8.4.
o
#include <stdio.h>
sk
void f(int a) {
n
a = 3;
printf("f: a = %d\n", a);
ro
}
kt
int main() {
int a = 5;
le
f(a);
printf("main: a = %d\n", a);
E
f: a = 3
main: a = 5
5)
Prilikom poziva funkcije, ukoliko je poznata njena deklaracija, vri se implic-
itna konverzija tipova argumenata u tipove parametara (ako se oni razlikuju).
01
Slino, prilikom vraanja vrednosti funkcije (putem return naredbe) vri se
konverzija vrednosti koja se vraa u tip povratne vrednosti funkcije.
(2
U sledeem primeru, prilikom poziva funkcije f vri se konverzija double
vrednosti u celobrojnu vrednost i program ispisuje 3:
Program 8.5.
#include <stdio.h>
je
an
void f(int a) {
printf("%d\n", a);
d
}
iz
int main() {
f(3.5);
o
}
sk
5)
biti nedefinisana vrednost (to je obino pogreno). Ako funkcija ne treba da
vraa rezultat, onda se kao tip povratne vrednosti navodi specijalan tip void
01
i tada naredba return nema argumenata (tj. navodi se return;). tavie, u
tom sluaju nije ni neophodno navoditi naredbu return iza poslednje naredbe
(2
u funkciji.
Funkcija koja je pozvala neku drugu funkciju moe da ignorie, tj. da ne
koristi vrednost koju je ova vratila.
const
je
Kvalifikator moe se primeniti i na tip povratne vrednosti funkcije.
To nema mnogo smisla, osim u kombinaciji sa pokazivaima (videti glavu 10)
an
i retko se koristi.
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
d
kao argument navesti ime niza. Tokom kompilacije, imenu niza pridruena je
informacija o adresi poetka niza, o tipu elemenata niza i o broju elemenata
n
niza. Kada se ime niza navede kao argument funkcije, onda do te funkcije
ro
(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
imenu niza niti o broju elemenata niza). Poto funkcija koja je pozvana dobija
kt
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:
5)
tip ime_funkcije(tip ime_niza[bv][bk]);
01
tip ime_funkcije(tip ime_niza[][bk]);
(2
Naredni primer ilustruje injenicu da se u funkciju ne prenosi ceo niz. Uko-
liko se program pokrene na maini na kojoj su tip int i adresni tip reprezento-
vani sa 4 bajta) program ispisuje, u okviru funkcije main, broj 20 (5 elemenata
4
tipa int ija je veliina 4 bajta) i, u okviru funkcije f, broj 4 (veliina adrese
je
koja je preneta u funkciju). Dakle, funkcija f nema informaciju o broju eleme-
nata niza a.
an
Program 8.6.
d
#include <stdio.h>
iz
}
sk
int main() {
n
f(a);
return 0;
kt
}
le
main: 20
f: 4
E
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.
Program 8.7.
#include <stdio.h>
void ucitaj_broj(int a) {
5)
printf("Ucitaj broj: ");
scanf("%d", &a);
01
}
(2
void ucitaj_niz(int a[], int n) {
int i;
printf("Ucitaj niz: ");
je
for (i = 0; i < n; i++)
scanf("%d", &a[i]);
an
}
int main() {
d
int x = 0;
iz
Unesi broj: 5
Unesi niz: 1 2 3
kt
x = 0
y = 1, 2, 3
le
Prenos niski u funkciju se vri kao i prenos bilo kog drugog niza. Jedina
E
razlika je to nije neophodno funkciji prosleivati duinu niske, jer se ona moe
odrediti i u samoj funkciji zahvaljujui postojanju terminalne nule.
5 Na primer,
funkcija strchr stanadardne biblioteke proverava da li data niska sadri dati
karakter. U nastavku je navedena jedna njena mogua implementacija, zas-
novana na takozvanoj linearnoj pretrazi niza. Ova implementacija pronalazi
prvu poziciju karaktera 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
return -1;
}
5)
U nekim sluajevima elimo da spreimo da funkcija izmeni niz (ili nisku)
01
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 strchr. Kljuna re const
(2
mogla bi se navesti i uz parametar c, ali to bi (kako se karakter prenosi po
vrednosti) znailo samo da ovaj parametar ne moe da se menja unutar tela
funkcije.
Pored toga, funkcije kao tip povratne vrednosti mogu imati tip strukture.
Prenos argumenta se i u ovom sluaju vri po vrednosti.
iz
return rezultat;
ro
}
kt
5)
r.brojilac /= n; r.imenilac /= n;
}
01
Naime, nakon poziva
(2
struct razlomak r = {2, 4};
skrati(r);
je
razlomak r ostaje jednak 2/4 (u funkciji se menja kopija originalne strukture
nastala prilikom prenosa po vrednosti).
an
8.9 Rekurzija
d
if (n == 0)
return 1;
n
else
return x*stepen(x, n-1);
ro
}
kt
5)
#include <stdio.h>
#include <stdarg.h>
01
int sumof(int n_args, ...) {
int i;
(2
int sum;
va_list args;
va_start(args, n_args);
je
sum = 0;
for (i = 1; i <= n_args; i++)
an
sum += va_arg(args, int);
va_end(args);
d
return sum;
}
iz
int main() {
o
return 0;
}
n
ro
Pitanje 8.3. Koliko najmanje parametara moe da ima funkcija? Kako izgleda
deklaracija funkcije koja nema parametara? Koja je razlika izmeu deklaracija
void f(void); i void f();?
Pitanje 8.4. ta se navodi kao tip povratne vrednosti za funkciju koja ne
vraa rezultat? Da li takva funkcija mora da sadri naredbu return? Da li
takva funkcija moe da sadri naredbu return? ta se navodi kao argument
return naredbe?
int f(int x) {
x = x+2;
return x+4;
}
int main() {
5)
int x = 1, y = 2;
x = f(x+y);
01
printf("%d\n", x);
}
(2
Pitanje 8.7. ta ispisuje sledei program?
je
n = 3 * k++;
}
an
int main() {
int n = 4, k = 5;
d
f(n, k);
iz
void f(int x) {
x += (++x) + (x++);
n
}
ro
int main() {
int x = 2;
kt
f(x); f(x);
printf("%d\n", x);
}
le
Pitanje 8.9.
E
5)
int main() {
int i;
01
int a[] = {1, 2, 3, 4};
f(a);
for(i = 0; i < sizeof(a)/sizeof(int); i++)
(2
printf("%d ", a[i]);
}
je
Pitanje 8.11. Koja funkcija standardne biblioteke se koristi za izraunavanje
duine niske i u kojoj datoteci zaglavlja je ona deklarisana?
an
Pitanje 8.12. emu je jednako sizeof("abc"), a emu strlen("abc")?
d
Pitanje 8.14. Navesti liniju kda koja obezbeuje da se prilikom poziva void
funkcije f celobrojni argument 2 implicitno prevede u double vrednost.
o
int main() {
sk
f(2);
return 0;
n
}
ro
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.
E
Zadatak 8.3. Za prirodan broj se kae da je savren ako je jednak zbiru svih
svojih pravih delioca (koji ukljuuju broj 1, ali ne i sam taj broj). Ispisati sve
savrene brojeve manje od 10000.
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.
2. pronalazi indeks prve pozicije na kojoj se u nizu nalazi dati broj (-1 ako
niz ne sadri broj).
5)
3. pronalazi indeks poslednje pozicije na kojoj se u nizu nalazi dati broj (-1
ako niz ne sadri broj).
01
4. izraunava zbir svih elemenata datog niza brojeva;
(2
jeva;
je
7. odreuje poziciju najveeg elementa u nizu brojeva (u sluaju vie pojavlji-
vanja najveeg elementa, vratiti najmanju poziciju);
an
8. proverava da li je dati niz brojeva ureen neopadajue.
d
Zadatak 8.6.
iz
Napomena: funkcija kao argument prima niz i broj njegovih trenutno popun-
jenih elemenata, a vraa broj popunjenih elemenata nakon izvoenja zahtevane
E
operacije.
5)
9. spaja dva niza brojeva koji su sortirani neopadajui u trei niz brojeva
koji je sortiran neopadajui.
01
Zadatak 8.8. Napisati funkciju koja poredi dve niske leksikografski (kao u
(2
reniku, u skladu sa kdnim rasporedom sistema). Funkcija vraa negativan
rezultat ukoliko prva niska leksikografski prethodi drugoj, nulu u sluaju da su
niske jednake i pozitivan rezultat ukoliko druga niska leksikografski prethodi
je
prvoj.
an
Zadatak 8.9. Napisati funkciju koja za dve niske proverava da li je:
pozicijama u drugoj).
iz
permutacija druge (niska je permutacija druge ako se od nje dobija samo pre-
metanjem njegovih karaktera - bez ikakvog brisanja ili dodavanja karaktera).
"abc" "cba" "aab"i
kt
koji sa standardnog ulaza uitava prirodni broj ( < 10) i zatim elemente
kvadratne matrice, proverava da li je ona magini kvadrat i ispisuje odgovara-
juu poruku na standardni izlaz. Koristiti pomone funkcije za izraunavanje
zbira elemenata vrsta, kolona i dijagonala matrice.
Primer, matrica:
7 12 1 14
2 13 8 11
16 3 10 5
9 6 15 4
je magini kvadrat.
185 8. Funkcije
5)
4. Napisati funkciju koja mnoi dve matrice odgovarajuih dimenzija.
01
Zadatak 8.13.
(2
Napisati funkcije koji vre unos, ispis, sabiranje i mnoenje
velikih prirodnih brojeva (za koje nije dovoljna veliina tipa unsigned long).
Cifre velikog broja smetati u niz i pretpostaviti da brojevi nemaju vie od1000
je
cifara.
an
d
iz
o
sk
n
ro
kt
le
E
Glava 9
5)
Organizacija izvornog i izvrnog
01
programa
(2
je
an
U prethodnim glavama ve je naglaeno da se izvorni program pie najee
na viim programskim jezicima i predstavlja sredstvo komunikacije izmeu pro-
d
tavni, imali su svega nekoliko funkcija i nije bilo potrebno previe obraati
panju na pomenuta pravila. Meutim, sa uslonjavanjem programa, poto-
kt
vanje kodeksa postaje kljuno jer u protivnom pisanje i odravanje kda postaje
1
veoma komplikovano . Takoe, postoje pravila za organizovanje kda izvrnog
programa koja omoguavaju njegovo efikasno izvravanje na odreenom rau-
le
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 pro-
gram 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-
javljivanje greaka tokom prevoenja i izvravanja programa znatno olakavaju
5)
proces programiranja i esto ukazuju i na sutinske propuste koji naruavaju
ispravnost programa.
01
9.1 Od izvornog do izvrnog programa
(2
Iako proces prevoenja jednostavnih programa poetnicima izgleda kao
jedan, nedeljiv proces, on se sastoji od vie faza i podfaza (a od kojih se svaka
je
i sama sastoji od vie koraka). U sluaju jezika C, ti koraci su obino pretpro-
cesiranje (engl. preprocessing), kompilacija (engl. compilation) i povezivanje
an
(engl. linking). Tokom svih faza prevoenja, moe biti otkrivena i prijavljena
greka u programu. U izvetajima o grekama obino se ne navodi eksplicitno
u kojoj fazi je greka detektovana (mada se ta informacija moe rekonstruisati
d
5)
Kompilacijom se od svake jedinice prevoenja gradi zasebni objektni modul
01
2
(engl. object module) . Objektni moduli sadre programe (mainski kd funkcija)
i podatke (memorijski prostor rezervisan za promenljive). Iako su u mainskom
(2
obliku, objektni moduli se ne mogu izvravati.
Na primer, rezultat rada GCC kompilatora moe se dobiti navoenjem op-
cije -c (na primer, gcc -c program.c). Ovim se dobija datoteka program.o
je
objektni modul koji je na Linux sistemu u ELF formatu (engl. Executable
and Linkable Format), formatu u kome je i izvrna datoteka, pri emu objek-
an
tni 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.
Mnoge dodatne opcije utiu na rezultat kompilacije. Na primer, ukoliko se
d
od jednog ili vie objektnih modula koji su nastali ili kompilacijom izvornog
kda programa ili su objektni moduli koji sadre mainski kd i podatke stan-
3
n
dardne ili neke nestandardne biblioteke . Program koji vri povezivanje zove
se poveziva , linker (engl. linker) ili ureiva veza.
ro
2 Objektni moduli na sistemu Linux najee imaju ekstenziju .o, a na sistemu Windows
.obj.
3 Biblioteke na sistemu Linux najee imaju ekstenziju .a (jer su arhive koje sadre
nekoliko .o datoteka), dok na sistemu Windows najee imaju ekstenziju .lib.
189 9. Organizacija izvornog i izvrnog programa
5)
lioteke.
Najei primer korienja unapred pripremljenog mainskog kda sa prate-
01
im datotekama zaglavlja je korienje standardne biblioteke (pregled sadraja
standardne biblioteke bie dat u glavi 11). Kd standardne biblioteke je obino
(2
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-
dardne biblioteke su datoteke zaglavlja koje sadre samo potrebne deklaracije
je
(na primer, deklaracija funkcije printf moe se pronai u zaglavlju <stdio.h>).
Pored statikog povezivanja , koje se vri nakon kompilacije, postoji i di-
an
namiko povezivanje , koje se vri tokom izvravanja programa (zapravo na nje-
govom poetku). Naime, statiko povezivanje u izvrnu datoteku umee main-
ski kd svih bibliotekih funkcija. Da bi se smanjila veliina izvrnih datoteka,
d
(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-
liotekih funkcija je da se nove verzije biblioteka (esto sa ispravljenim sitnijim
kt
4 Ekstenzija ovih datoteka u sistemu Linux je obino .so (shared object), dok je u sistemu
Windows .dll.
190 9. Organizacija izvornog i izvrnog programa
5)
Odvojena kompilacija i povezivanje. Korak kompilacije i korak povezi-
vanja mogue je razdvojiti tj. mogue je prvo prevesti datoteku sa izvornim
01
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
(2
da se koristi GCC, to se postie sa:
gcc -c program.c
je
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 objek-
tni modul u datoteci program.o. Drugi poziv vri povezivanje tog objektnog
d
gcc -c program1.c
gcc -c program2.c
kt
uli koji se ne menjaju ne prevode iznova svaki put kada je potrebno napraviti
E
5)
program: program1.o program2.o biblio.o
01
gcc -o program program1.o program2.o biblio.o
(2
gcc -c program1.c
Program make ima jo mnogo opcija ali one nee ovde biti opisivane.
n
izvravanja programa.
Izvrni programi smeteni su u datotekama na disku i pre pokretanja uita-
vaju se u glavnu memoriju. Za ovo je zaduen program koji se naziva punilac
kt
ili louder (engl. loader) koji je obino integrisan u operativni sistem. Njegov
zadatak je da proveri da li korisnik ima pravo da izvri program, da prenese
le
5)
Pitanja i zadaci za vebu
01
Pitanje 9.1.1. Navesti i objasniti osnovne faze na putu od izvornog do izvrnog
programa.
(2
Pitanje 9.1.2. U kom obliku se isporuuje standardna C biblioteka?
Pitanje 9.1.3. Kako se korienjem GCC prevodioca moe izvriti samo faza
je
pretprocesiranja kda i prikazati rezultat? Kako se moe izvriti samo faza
kompilacije, bez povezivanja objektnih modula?
an
Pitanje 9.1.4. ta su jedinice prevoenja? ta su datoteke zaglavlja? U kojoj
fazi se od vie datoteka grade jedinice prevoenja?
d
Pitanje 9.1.5.
iz
Pitanje 9.1.6.
sk
Pitanje 9.1.7.
ro
5)
pisanje, razumevanje i odravanje programa, za jezik C (kao i za svaki drugi
vii programski jezik), programeru su na raspolaganju mnoga sredstva koja
01
omoguavaju da program bude krai, pregledniji, da se efikasnije kompilira, da
se bre izvrava itd.
(2
Osnovni koraci u organizovanju sloenijih programa obino su podela slo-
enih zadataka na jednostavnije poslove i njihovo izdvajanje u zasebne funkcije
(tzv. funkcionalna dekompozicija ), definisanje odgovarajuih tipova podataka
je
i organizovanje podataka definisanjem odgovarajuih promenljivih. Funkcije u
programu trebalo bi da budu to nezavisnije i to slabije meusobno uslovljene
an
(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
d
brojeva i funkcije za izvoenje operacija nad tim tipom ima smisla grupisati u
zaseban modul za rad sa kompleksnim brojevima). Mnogi moduli mogu biti
korieni u razliitim programima i tada se obino grade kao biblioteke.
o
tupna 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 izvra-
vanje programa omoguava da se preko njih vri komunikacija izmeu razliitih
funkcija modula. Povezanost identifikatora (engl. linkage) u vezi je sa deljen-
jem podataka izmeu razliitih jedinica prevoenja i daje mogunost korienja
zajednikih promenljivih i funkcija u razliitim jedinicama prevoenja (mod-
ulima), 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 kval-
ifikatora 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.
9.2.1 Pretprocesor
5)
Kada se od izvornog programa napisanog na jeziku C proizvodi program
na mainskom jeziku (izvrni program), pre samog prevodioca poziva se C
01
pretprocesor. Pretprocesiranje, dakle, predstavlja samo pripremnu fazu, pre
kompilacije. Sutinski, pretprocesor vri samo jednostavne operacije nad tek-
(2
stualnim sadrajem programa i ne koristi nikakvo znanje o jeziku C. Pretpro-
cesor ne analizira znaenje naredbi napisanih u jeziku C ve samo pretpro-
cesorske direktive (engl. preprocessing directive) (one se ne smatraju delom
je
jezika C) na osnovu kojih vri odreene transformacije teksta izvornog pro-
grama. Neke od operacija pretprocesora su zamena komentara belinama ili
an
spajanje linija razdvojenih u izvornom programu simbolom \. Dve najee
koriene pretprocesorske direktive su #include (za ukljuivanje sadraja neke
druge datoteke) i #define koja zamenjuje neki tekst, makro, drugim tekstom.
d
koju se nadovezuje kasnija faza leksike analize, koja se vri tokom kompilacije.
sk
datoteke koje se onda ukljuuju gde god je potrebno. Takve datoteke zovu se
datoteke zaglavlja (engl. header files). Osnovni primer datoteka zaglavlja su za-
glavlja 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:
#include "ime_datoteke"
5)
i linija oblika
#include <ime_datoteke>
01
zamenjuju se sadrajem datoteke ime_datoteke. U prvom sluaju, datoteka
(2
koja se ukljuuje trai se u okviru posebnog skupa direktorijuma include path
(koja se veini kompilatora zadaje korienjem opcije -I) i koja obino po-
drazumevano sadri direktorijum u kojem se nalazi datoteka u koju se vri
je
ukljuivanje. Ukoliko je ime, kao u drugom sluaju, navedeno izmeu znakova
< i >, datoteka se trai u sistemskom include direktorijumu u kojem se nalaze
an
standardne datoteke zaglavlja, ija lokacija zavisi od sistema i od C prevodioca
koji se koristi.
d
direktive #include.
Poto, zahvaljujui #include direktivi, do kompilatora stie program koji
o
Makro zamene
kt
#define MAX_LEN 80
5)
reda koji se nastavlja. Direktive zamene mogu da koriste direktive koje im
prethode.
01
Zamene se ne vre u konstantnim niskama niti u okviru drugih simbolikih
6 #define MAX_LEN 80 nee uticati
imen a . Na primer, gore navedena direktiva
(2
na naredbu printf( "MAX_LEN is 80"); niti na simboliko ime MAX_LEN_VAL.
Mogue je defisati i pravila zamene sa argumentima od kojih zavisi tekst
zamene. Na primer, sledea definicija
je
#define max(A, B) ((A) > (B) ? (A) : (B))
an
max(A, B) koji zavisi od argumenata. Ukoliko je u nas-
definie tekst zamene za
tavku datoteke, u nekoj naredbi navedeno max(2, 3), to e, pre prevoenja,
d
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)
iz
6 Zato je neophodno da pretprocesor tokom svog rada izvri jednostavniju leksiku analizu.
197 9. Organizacija izvornog i izvrnog programa
5)
menljivamaa i b se, zahvaljujui ovom makrou, mogu razmeniti vrednosti sa
swap(int, a, b).
01
Ukoliko se u direktivi #define, u novom tekstu, ispred imena parametra
navede simbol #, kombinacija e biti zamenjena vrednou parametra nave-
(2
denog izmeu dvostrukih navodnika. Ovo moe da se kombinuje sa nadovezi-
vanjem niski. Na primer, naredni makro moe da poslui za otkrivanje greaka:
je
an
Tako e tekst:
dprint(x/y);
d
Poto se niske automatski nadovezuju, efekat ove naredbe je isti kao efekat
sk
naredbe:
##. Na primer,
niz_##ime[brojac_##ime++] = element
E
Poziv
dodaj_u_niz(a, 3);
niz_a[brojac_a++] = 3;
#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 neoeki-
vanog rada programa. Argument makroa u zamenjenoj verziji moe biti nave-
den vie puta to moe da utie na izvravanje programa, a izostavljanje zagrada
5)
u tekstu zamene moe da utie na redosled izraunavanja operacija. S druge
strane, kod poziva makroa nema prenosa argumenata te se oni izvravaju bre
01
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
(2
na korienje makroa. Sve u svemu, makro zamene sa argumentima mogu imaju
i dobre i loe strane i treba ih koristiti oprezno.
Mnoge standardne funkcije za ulaz i izlaz iz standardne C biblioteke mogu
je
biti, alternativno, implementirane i kao makroi (na primer, getchar koji koristi
funkciju getc, printf koji koristi funkciju fprintf, itd.).
an
Uslovno prevoenje
d
prevode) sve linije programa do direktive #endif ili do direktive #else ili do
#elif koja ima znaenje kao else-if. U okviru argumenta direktive
direktive
n
#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
ro
Program 9.1.
le
#define SRPSKI
#include <stdio.h>
E
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 ispi-
sivao bi tekst na engleskom jeziku.
7 Ovo grananje se sutinski razlikuje od
grananja zasnovanog na C naredbi if. Naime, u navedenom primeru prevodi
se samo jedna od dve verzije programa i dobijeni izvrni program nema nikakvu
informaciju o drugoj verziji. Za razliku od toga, kada se koristi grananje koje
5)
koristi C jezik (a ne pretprocesor), program sadri kd za sve mogue grane.
01
9.2.2 Doseg identifikatora
(2
nom definiu u funkcijama (ili ak nekim uim blokovima) i upotreba promen-
ljive je uglavnom ograniena na funkciju (ili blok) u kojoj je deklarisana. Ovim
se smanjuje zavisnost izmeu funkcija i ponaanje funkcije odreeno je samo
je
njenim ulaznim parametrima, a ne nekim globalnim stanjem programa. Time
se omoguava i da se analiza rada programa zasniva na analizi pojedinanih
an
funkcija, nezavisnoj od konteksta celog programa. Ipak, u nekim sluajevima
prihvatljivo je da funkcije meusobno komuniciraju korienjem zajednikih
d
jekat (na primer, promenljivu ili funkciju). Svaki identifikator ima neki doseg.
sk
vrste dosega:
ro
doseg nivoa datoteke (engl. file level scope) koji podrazumeva da ime vai
od take uvoenja do kraja datoteke;
kt
doseg nivoa bloka (engl. block level scope) koji podrazumeva da ime vai
le
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 pod-
razumeva 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.
Najznaajni nivoi dosega su doseg nivoa datoteke i doseg nivoa bloka. Iden-
tifikatori koji imaju doseg nivoa datoteke najee se nazivaju spoljanji ili glob-
alni , dok se identifikatori koji imaju ostale nivoe dosega (najee doseg nivoa
bloka) nazivaju unutranji ili lokalni .
8 Na osnovu diskusije sa poetka ovog
poglavlja, jasno je da je poeljno koristiti identifikatore promenljivih lokalnog
dosega kada god je to mogue. S druge strane, funkcije su obino globalne. Ima-
jui u vidu podelu na globalne i lokalne objekte, C program se esto definie
kao skup globalnih objekata (promenljivih, funkcija, tipova podataka itd.).
5)
U ranim verzijama jezika C nije bilo mogue definisati funkciju u okviru
definicije druge funkcije, tj. funkciju sa dosegom nivoa bloka, pa nije bilo
01
lokalnih funkcija , dok je od standarda C99 i takva mogunost predviena.
Doseg globalnih funkcija je doseg nivoa datoteke i protee se od mesta deklaracije
(2
pa do kraja datoteke. U nastavku su dati primeri razliitih dosega:
int a;
/* a je globalna promenljiva - doseg nivoa datoteke */
/* d je lokalna promenljiva -
doseg nivoa bloka (tela funkcije f) */
o
sk
/* e je lokalna promenljiva -
doseg nivoa bloka (tela petlje) */
le
...
}
E
kraj:
/* labela kraj - doseg nivoa 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
5)
for (i = 0; i < 4; i++) {
int a = 5;
01
printf("%d ", a);
}
}
(2
5 5 5 5
je
Ovim je omogueno da prilikom uvoenja novih imena programer ne mora
an
da brine da li je takvo ime ve upotrebljeno u irem kontekstu.
d
statiki (engl. static) ivotni vek koji znai da je objekat dostupan tokom
celog izvravanja programa;
ro
deklaracije do kraja bloka i nije ih mogue koristiti van bloka u kojem su deklar-
isane. 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
promenljive automatski ivotni vek podrazumeva. Poetna vrednost lokalnih
5)
automatskih promenljivih nije odreena i zavisi od ranijeg sadraja memorijske
lokacije koja je pridruena promenljivoj, pa se smatra nasuminom.
01
Automatske promenljive postoje samo tokom izvravanja funkcije u kojoj
su deklarisane i prostor za njih je rezervisan u stek okviru te funkcije (videti
(2
poglavlje 9.3.3). Ne postoji veza izmeu promenljive jednog imena u razliitim
aktivnim instancama jedne funkcije (jer svaka instanca funkcije ima svoj stek
okvir i u njemu prostor za promenljivu tog imena). Dakle, ukoliko se u jednu
je
funkciju ue rekurzivno, kreira se prostor za novu promenljivu, potpuno neza-
visan od prostora za prethodnu promenljivu istog imena.
an
Formalni parametri funkcija, tj. promenljive koje prihvataju argumente
funkcije imaju isti status kao i lokalne automatske promenljive.
Na lokalne automatske promenljive i parametre funkcija mogue je primeniti
d
kda veoma dobro mogu da odrede koje promenljive ima smisla uvati u reg-
sk
datoteke. ivotni vek ovih promenljivih uvek je statiki, tj. prostor za ove
promenljive rezervisan je tokom celog izvravanja programa: prostor za njih
le
5)
tim, zbog globalnog dosega tu promenljivu bilo bi mogue koristiti (i promeniti)
i iz drugih funkcija, to je nepoeljno. Zato je poeljna mogunost definisanja
01
promenljivih koje bi bile statikog ivotnog veka (da bi uvale vrednost tokom
itavog izvravanja programa), ali lokalnog dosega (da bi se mogle koristiti i
(2
menjati samo u jednoj funkciji).
U deklaraciji lokalne promenljive moe se primeniti kvalifikator static i
u tom sluaju ona ima statiki ivotni vek kreira se na poetku izvrava-
je
nja programa i oslobaa prilikom zavretka rada programa. Tako modifiko-
vana promenljiva ne uva se u stek okviru svoje funkcije, ve u segmentu po-
an
dataka (videti poglavlje 9.3.3). Ukoliko se vrednost statike lokalne promenljive
promeni tokom izvravanja funkcije, ta vrednost ostaje sauvana i za sledei
poziv te funkcije. Ukoliko inicijalna vrednost statike promenljive nije nave-
d
Program 9.2.
ro
#include <stdio.h>
kt
void f() {
int a = 0;
le
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;
}
Kada se prevede i pokrene, prethodni program ispisuje:
f: 0 f: 0 g: 0 g: 1
5)
01
9.2.4 Povezanost identifikatora i kvalifikatori static i extern
(2
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.
Meutim, kada se program sastoji od vie jedinica prevoenja, doseg nije do-
je
voljan i potrebna je malo finija kontrola. Poeljno je da postoji mogunost
definisanja: (i) objekata (promenljivih ili funkcija) koji se mogu koristiti samo
an
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
d
jedinicama prevoenja.
iz
5)
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
01
je u fazi povezivanja potrebno da bi sva korienja nekog identifikatora u pro-
gramu mogla da budu razreena. Na primer, definicija funkcije f implementira
(2
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
da u objektnom kodu generisanom na osnovu te jedinice prevoenja treba da
je
bude rezervisana memorija za jedan podatak tipa int, da taj podatak treba da
bude incijalno postavljen na vrednost 3 i da se sva korienja te promenljive au
an
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
date samo deklaracije, a ne i definicije, faza kompilacije proi e uspeno, ali
d
prati inicijalizacija, ona se uvek ujedno smatra i definicijom. Ali, ako je globalna
promenljiva uvedena bez inicijalizacije (npr. ako postoji globalna deklaracija
n
int a;), nije jasno da li je u pitanju deklaracija ili definicija. Takav kod se
ro
nema, onda se naelna definicija smatra definicijom (uz inicijalnu vrednost 0),
tj. ponaanje je isto kao da pored naelne definicije postoji stvarna definicija
le
5)
... }
} int g2() {
01
static int i, j;
...
}
(2
Spoljanja povezanost i kvalifikator extern
je
Spoljanja povezanost identifikatora omoguava da se isti objekat koristi u
an
vie jedinica prevoenja. Sve deklaracije identifikatora sa spoljanjom poveza-
nou u skupu jedinica prevoenja odreuju jedan isti objekat (tj. sve pojave
d
objekta. Tako se jedan identifikator koristi za isti objekat u okviru vie jedinica
prevoenja.
extern
o
inicijalizaciju promenljivih niti telo funkcije (to ima smisla samo prilikom
ro
5)
cija) promenljive i da je ta promenljiva definisana na nekom drugom mestu
(tj. da promenljiva ima spoljanju povezanost). Ovom, donekle neobinom kon-
01
strukcijom, postie se da globalna promenljiva (sa spoljanjom povezanou)
u nekoj drugoj jedinici prevoenja, u tekuoj jedinici prevoenja ima samo
(2
lokalni doseg.
Razmotrimo naredni primer koji sadri dve jedinice prevoenja.
Program 9.3.
#include <stdio.h> #include <stdio.h>
je
an
int a; extern int a;
int b = 3; void f();
d
int g() {
iz
}
sk
int main() {
n
a = 1;
ro
/* b = 2; */
g();
return 0;
kt
}
le
b=3
E
a=0
5)
da se misli na promenljivu b definisanu u prvoj jedinici prevoenja. U funkciji
main postavlja se vrednost promenljive a na 1. Pokuaj postavljanja vrednosti
01
promenljive b (pod komentarom) ne bi uspeo jer identifikator b nije u dosegu
funkcije main.
(2
Unutranja povezanost i kvalifikator static
je
Globalni objekat ima unutranju povezanost ako se kvalifikuje kvalifika-
torom static.10 Unutranja povezanost povezuje sva pojavljivanja istog iden-
an
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
d
mora postojati tano jedna definicija u toj jedinici prevoenja. S druge strane,
static
iz
dinice prevoenja.
Osnovna uloga unutranje povezanosti obino je u tome da neki deo kda
ro
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
5)
g(); /* f() */
int g() { return 0;
01
f(); }
}
(2
Program ispisuje
je
f: a=3, b=5
an
U prvoj jedinici prevoenja promenljiva a i funkcija f imaju unutranju
povezanost (dok promenljiva b i funkcija g imaju spoljanju povezanost (o ko-
d
malim izmenama:
Program 9.5.
#include<stdio.h>
int main() {
int a = 9;
if (a == 9)
printf("9");
5)
return 0;
}
01
(2
Pretprocesiranje. Na primer, ukoliko je, umesto pretprocesorske direktive
#include, u programu navedeno #Include, bie prijavljena greka (jer ne pos-
toji direktiva #Include):
je
primer.c:1:2: error: invalid preprocessing directive #Include
an
Kompilacija
d
iz
if (a == 9) ...,
ro
5)
procesu prevoenja bivaju otkrivene u fazi leksike, sintaksike ili semantike
analize, ili u fazi linkovanja. Dakle, tokom generisanja i optimizacije meukda,
01
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
(2
otklanjaju.
Ukoliko prevodilac naie na greku ili greke u izvornom kdu, to prijavljuje
(navodi vrstu greke, liniju i kolonu programa u kojoj je greka) i ne generie
je
izvrni program. Izvrni program se, naravno, ne generie ni u sluaju ako je
an
greka otkrivena u fazi povezivanja. Programer tada treba da otkloni detekto-
vane greke i ponovi proces prevoenja.
Pored prijave greaka, kompilator moe da izda i upozorenja (engl. warn-
d
5)
voenja, 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
01
bila drugaija). Biblioteka prua definiciju tipa za reprezentovanje razlomaka
(RAZLOMAK), funkcije za kreiranje razlomka na osnovu brojioca i imenioca, za
(2
skraivanje razlomka i za sabiranje razlomaka. Primena ovih funkcija moe
dovesti do dva (u ovom primeru) ishoda: da je operacija izvrena uspeno i
da se prilikom primene operacije javlja neispravan razlomak (onaj kojem je
je
imenilac 0). Ovim ishodima odgovaraju lanovi OK i IMENILAC_0 nabrojivog
tipa RAZLOMAK_GRESKA. Kako im nisu eksplicitno pridruene vrednosti ovim
an
imenima e implicitno biti pridruene vrednosti 0 i 1. Tekstualni opis moguih
ishoda uva se u nizu razlomak_poruka. Ishod rada funkcije bie uvan u
globalnoj promenljivoj razlomak_greska.
d
#ifndef __RAZLOMAK_H_
o
#define __RAZLOMAK_H_
sk
unsigned imenilac;
ro
} RAZLOMAK;
kt
#endif
5)
bi se spreilo viestruko ukljuivanje, svaka datoteka zaglavlja u tom sluaju
treba da ima sledei opti oblik:
01
#ifndef IME
#define IME
(2
...
je
#endif
an
gde je tekst IME karakteristian za tu datoteku (na primer njeno ime obo-
gaeno nekim specijalnim simbolima). Prilikom prvog ukljuivajna ove da-
d
toteke, definie se simboliko ime IME i zbog toga naredna ukljuivanja (iz iste
iz
#include "razlomak.h"
sk
char* razlomak_poruka[] = {
n
};
kt
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;
}
5)
if (im == 0) {
razlomak_greska = IMENILAC_0; return NULA;
01
}
return skrati_razlomak(rez);
}
(2
RAZLOMAK saberi_razlomke(RAZLOMAK r1, RAZLOMAK r2) {
if (r1.imenilac == 0 || r2.imenilac == 0) {
je
razlomak_greska = IMENILAC_0; return NULA;
}
an
return napravi_razlomak(
r1.brojilac*r2.imenilac + r1.imenilac*r2.brojilac,
d
r1.imenilac*r2.imenilac);
}
iz
ovaj korak nije uvek neophodan (ukoliko se pre svakog poziva funkcije javlja
sk
int main() {
unsigned a, b;
RAZLOMAK r1, r2, r;
5)
return 1;
}
01
scanf("%u%u", &a, &b);
r2 = napravi_razlomak(a, b);
(2
if (razlomak_greska != OK) {
printf("%s\n", razlomak_poruka[razlomak_greska]);
return 1;
je
}
an
r = saberi_razlomke(r1, r2);
if (razlomak_greska != OK)
d
printf("%s\n", razlomak_poruka[razlomak_greska]);
iz
}
sk
5)
Pitanje 9.2.4. Kako se od neke take u programu ponitava dejstvo pretpro-
01
cesorske direktive
#define x(y) y*y+y?
Pitanje 9.2.5.
(2
Kako se moe proveriti da li je neko simboliko ime definisano
u trenutnoj jedinici prevoenja?
Pitanje 9.2.6. Objasniti razliku izmeu makroa i funkcija. U kojoj fazi se vri
je
razreavanje poziva makroa, a u kojoj poziva funkcija? Objasniti ta znai da
an
kod makroa nema prenosa argumenata, a kod funkcija ima.
1. #include <stdio.h>
n
3. #include <stdio.h>
E
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 kvadrat za kvadriranje koji pri definiciji
5)
definiciji #define kvadrat(x) ((x)*(x)) daje ispravan rezultat.
dvostruko
01
2. Navesti primer poziva makroa za koji pri definiciji
(2
daje ispravan rezultat.
je
1. izraunavanje ostatka pri deljenju prvog argumenta drugim,
jeziku C, koja faza prethodi kompilaciji, a koja sledi nakon faze kompilacije?
Pitanje 9.2.17. Koji sve nivoi dosega identifikatora postoje u jeziku C? Koja
su dva najee koriena? Kog nivoa je doseg lokalnih, a kog nivoa doseg
globalnih promenljivih?
Pitanje 9.2.23.
5)
Da li je naredna deklaracija ispravna i koliko bajtova je njome
alocirano:
01
1. int a[] = {1, 2, 3};
2. extern int a[];
(2
3. extern int a[] = {1, 2, 3};
Pitanje 9.2.24. Koje vrste ivotnog veka postoje u jeziku C? Koji ivotni vek
je
imaju lokalne promenljive (ako na njih nije primenjen kvalifikator static)?
Koji ivotni vek imaju globalne promenljive?
an
Pitanje 9.2.25. Ukoliko je za neku lokalnu promenljivu naveden kvalifikator
static, ta e biti sa njenom vrednou nakon kraja izvravanja funkcije u
d
kojoj je deklarisana?
iz
int i = 2;
n
int i;
for(i=0; i<3; i++)
le
printf("%d", f()+g());
}
E
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. Ukoliko je na globalnu promenljivu primenjen kvalifikator
static, kakva joj je povezanost, ta je njen doseg i koliki joj je ivotni vek?
219 9. Organizacija izvornog i izvrnog programa
5)
liotekom, vre se potrebne inicijalizacije i onda izvravanje moe da pone. U
fazi izvravanja mogue je da doe do greaka koje nije bilo mogue detektovati
01
u fazi prevoenja i povezivanja.
Izvrni program generisan za jedan operativni sistem moe se izvravati
(2
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
sistem, ali ima arhitekturu koja ne odgovara generisanoj aplikaciji (na primer,
je
64-bitna aplikacija ne moe da se izvrava na 32-bitnom sistemu).
an
9.3.1 Izvrno okruenje operativni sistem i rantajm biblioteka
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
biblioteke (engl. runtime library). Funkcije rantajm biblioteke obino su reali-
o
zovane kao niz zahteva operativnom sistemu (najee zahteva koji se odnose
sk
5)
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. Isto se
01
deava i sa tipovima: svi tipovi koji se pojavljuju u programu bie svedeni
na osnovne tipove neposredno podrane od strane procesora obino samo
(2
na cele brojeve i brojeve u pokretnom zarezu. Dakle, u izvornom programu,
promenljivama je pridruen tip, ali u izvrnom programu nema eksplicitnih
informacija o tipovima. Sve informacije o tipovima se razreavaju u fazi pre-
je
voenja i u mainskom kdu se koriste instrukcije za konkretne vrste oper-
anada. Na primer, u izvornom programu, operator + se moe primenjivati nad
an
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-
d
izvravati.
11 Faktori koje treba uzeti u obzir su hardver, ali i operativni sistem
raunara na kojem e se program izvravati. Centralni hardver je danas obino
ili 32-bitni ili 64-bitni tj. obino registri procesora, magistrale i podaci tipa int
o
razumeva softver koji koristi 32-bitni adresni prostor tj. moe da adresira 232
ro
11 Sistem 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 oper-
ativnim sistemom.
221 9. Organizacija izvornog i izvrnog programa
5)
pointer 32 64 64 64
01
Za precizno specifikovanje broja bitova mogu se koristiti tipovi iz zaglavlja
<stdint.h>.
(2
Kada se koristi kompilator GCC, podrazumevani broj bitova odgovara sis-
temu na kojem se vri prevoenje. Ovo se moe promeniti opcijama -m32 i -m64
kojima se moe zadati da se generisani kd aplikacije bude 32-bitni ili 64-bitni
je
(bez obzira da li se prevoenje vri na 32-bitnom ili 64-bitnom sistemu).
an
9.3.3 Organizacija memorije
odnosi se, ako to nije drugaije naglaeno, na irok spektar platformi, pa su,
zbog toga, nainjena i neka pojednostavljivanja.
Kada se izvrni program uita u radnu memoriju raunara, biva mu dodel-
o
ro
U nastavku e biti opisana prva tri, dok e o hip segmentu biti vie rei u
poglavlju 10.9, posveenom dinamikoj alokaciji memorije.
E
Segment kda
Fon Nojmanova arhitektura raunara predvia da se u memoriji uvaju po-
daci 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
Segment podataka
5)
U segmentu podataka uvaju se odreene vrste promenljivih koje su zajed-
01
nike za ceo program (one koje imaju statiki ivotni vek, najee globalne
promenljive), kao i konstantni podaci (najee konstantne niske). Ukoliko
(2
se istovremeno izvrava vie instanci istog programa, svaka instanca ima svoj
zaseban segment podataka. Na primer, u programu
Program 9.7.
#include <stdio.h>
je
an
int a;
int main() {
int b;
d
static double c;
iz
printf("Zdravo\n");
return 0;
}
o
sk
Stek segment
le
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
E
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;
meurezultate izraunavanja;
223 9. Organizacija izvornog i izvrnog programa
5)
funkcija treba da se izvri i taj stek okvir se oslobaa (preciznije, smatra se
nepostojeim) onda kada se zavri izvravanje funkcije.
01
Ako izvravanje programa poinje izvravanjem funkcije main, prvi stek
okvir se kreira za ovu funkciju. Ako funkcija main poziva neku funkciju f,
na vrhu steka, iznad stek okvira funkcije main, kreira se novi stek okvir za
(2
ovu funkciju (ilustrovano na slici 9.1). Ukoliko funkcija f poziva neku treu
funkciju, onda e za nju biti kreiran stek okvir na novom vrhu steka. Kada
se zavri izvravanje funkcije f, onda se vrh steka vraa na prethodno stanje i
je
prostor koji je zauzimao stek okvir za f se smatra slobodnim (iako on nee biti
an
zaista obrisan).
d
iz
Vrh steka
o
f(),
sk
njeni argumenti,
Vrh steka lokalne promenljive, Vrh steka
...
n
12 Ime stack je zajedniko ime za strukture podataka koje su okarakterisane ovim nainom
pristupa.
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 odgo-
varajue opcije.
5)
Opisana organizacija steka omoguava jednostavan mehanizam meusobnog
01
pozivanja funkcija, kao i rekurzivnih poziva.
(2
Ilustrujmo prenos argume-
nata u funkciju na sledeem jednostavnom primeru.
Program 9.8.
int f(int a[], int n) {
je
an
int i, s = 0;
for (i = 0; i < n; i++)
s += ++a[i];
d
return s;
iz
int main() {
o
int s;
s = f(a, sizeof(a)/sizeof(int));
n
return 0;
}
kt
Na poetku izvravanja funkcije main na steku se nalazi samo jedan stek okvir
sledeeg oblika
13 :
E
f: 134: ...
130: 0 <- s
5)
126: ? <- i
122: 3 <- n
01
118: 100 <- a
main: 114: ...
(2
112: ? <- s
108: 3
104: 2
je
100: 1 <- a
Nakon izvravanja koraka petlje, stanje steka je sledee.
an
f: 134: ... f: 134: ...
130: 2 <- s 130: 5 <- s
d
108: 3 108: 3
104: 2 104: 3
100: 2 <- a 100: 2 <- a
n
ro
f: 134: ...
130: 9 <- s
kt
126: 2 <- i
122: 3 <- n
le
112: ? <- s
108: 4
104: 3
100: 2 <- a
f: 134: ...
130: 9 <- s
126: 3 <- i
122: 3 <- n
118: 100 <- a
i tada je potrebno vratiti vrednost s pozivaocu (u ovom sluaju funkciji main).
Ovo se najee postie tako to se vrednost promenljive s upie u registar ax
(preciznije, eax ili rax), odakle je main preuzima i naredbom dodele upisuje u
5)
svoju promenljivu s. Kada funkcija f zavri svoje izvravanje, stanje steka je:
01
112: 9 <- s
108: 4
(2
104: 3
100: 2 <- a
Nakon toga dolazi do poziva funkcije printf. Na stek okvir funkcije main
je
postavlja se njen stek okvir i prosleuju se argumenti. Prvi argument je adresa
konstantne niske (koja se nalazi negde u segmentu podataka), a ostali su kopije
an
etiri navedene vrednosti iz funkcije main. Nakon ispisa, uklanja se stek okvir
funkcije printf, a zatim i funkcije main, poto se dolo do njenog kraja.
d
Implementacija rekurzije.
iz
Program 9.9.
sk
#include <stdio.h>
n
int faktorijel(int n) {
ro
if (n <= 0)
return 1;
kt
else
return n*faktorijel(n-1);
le
}
E
int main() {
int n;
while(scanf("%d",&n) == 1)
printf("%d! = %d\n", n, faktorijel(n));
return 0;
}
14 Vrednost faktorijela se, naravno, moe izraunati i iterativno, bez korienja rekurzije.
227 9. Organizacija izvornog i izvrnog programa
5)
U ovom poglavlju emo pokuati da proces kompilacije i povezivanja ogolimo
do krajnjih granica tako to emo pokazati kako je mogue videti mainski
01
kd tj. sadraj objektnih modula i izvrnog programa nastalih kompilacijom
sledeeg jednostavnog programa
15 . Detalji ovog primera svakako u velikoj meri
(2
prevazilaze osnove programiranja u programskom jeziku C, ali zainteresovanom
itaocu mogu da poslue da prilino demistifikuje proces prevoenja i izvra-
vanja C programa.
je
Program 9.10.
an
#include <stdio.h>
int n = 10, sum;
d
int main() {
iz
int i;
for (i = 0; i < n; i++)
sum += i;
o
return 0;
}
n
ro
5)
sum se nalazi u zoni neinicijalizovanih podataka (na ta ukazuje klasa C i sekcija
*COM*) naime, u ranijim razmatranjima smatrali smo da se neinicijalizovani
01
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
(2
(esto se ovaj segment naziva .bss segment). S obzirom na to da ovaj segment
podrazumevano treba da bude ispunjen nulama, za razliku od inicijalizovanih
podataka koji moraju biti upisani u izvrnu datoteku, kod neinicijalizovanih po-
je
dataka, umesto da se nule upisuju u izvrnu datoteku, u njoj se samo naglaava
njegova veliina. Prilikom uitavanja programa u glavnu memoriju, pre pozi-
an
vanja funkcije main vri se inicijalizacija ovog segmenta na nulu. Primetimo
i da ime lokalne automatske promenljive i uopte nije vidljivo u objektnom
modulu (to se i moglo oekivati, jer je ova promenljiva bez povezanosti).
d
objdump -d program.o.
00000000 <main>:
o
0: 55 push ebp
sk
1: 89 e5 mov ebp,esp
3: 83 e4 f0 and esp,0xfffffff0
6: 83 ec 20 sub esp,0x20
n
10: 00
11: eb 16 jmp 29 <main+0x29>
13: 8b 15 00 00 00 00 mov edx,DWORD PTR ds:0x0
kt
5)
tome, na mesto poziva funkcije printf u mainskom kdu generisan je poziv
44: call 45 <main+0x45> koji nije ispravan i nema smisla jer ukazuje up-
ravo na adresu argumenta tog poziva (koji je na 44). Zadatak linkera je da
01
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
(2
nikakvo smisleno znaenje dok se u obzir ne uzme tabela relokacije i dok se sve
navedene stavke ne razree (to je zadatak linkera).
je
OFFSET TYPE VALUE
00000015 R_386_32 sum
an
00000020 R_386_32 sum
0000002a R_386_32 n
00000035 R_386_32 sum
d
promenljive koja se koristi na mestu u maniskom kdu (za koju je, kao
to smo opisali, trenutno pretpostavljeno da se nalazi na adresi 0 u segmentu
podataka, to ne mora biti sluaj u konanom kdu), adresu promenljive sum
le
segmenta
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).
Iako nije od presudnog znaaja za programiranje u C-u, analiza prethodnog
kda moe biti zanimljiva i pokazuje kako se pojednostavljeno opisani meha-
nizmi 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 esp sadri uvek adresu vrha steka, dok reg-
istar ebp 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
promenljiva i nalazi na steku i to odmah iznad sauvane vrednosti poetka
prvobitnog stek okvira (to je adresa esp+0x1c nakon pomeranja vrha steka).
Naredba u liniji 9 je inicijalizacija petlje na vrednost 0. Nakon nje, skae se
5)
na proveru uslova u liniji 29. Prvo se kopira vrednost promenljive n u registar
eax, a zatim se vri poreenje vrednosti promenljive i (smetene u steku na
01
adresi esp+0x1c) sa registrom eax. i manje od n, vri se povratak
Ukoliko je
na telo petlje (instrukcije od linije 13 do 23) i korak (instrukcija 24). Telo
(2
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 pro-
je
menljive sum. Korak uveava vrednost promenljive i (na adresi esp+0x1c) za
jedan. Po zavretku petlje, kada uslov petlje vie nije ispunjen prelazi se na
an
poziv funkcije 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
obratnom poretku vrednost promenljive sum koja se kopira preko registra x),
d
i zatim adresa format niske (iako je u trenutnom kdu za obe adrese upisana
iz
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
izvrni kd jer bi on tako bio ogroman. Umesto da se te rutine ugrauju u
5)
izvrni kd programa, one ine tzv. rantajm biblioteku i pozivaju se dinamiki,
tek u fazi izvravanja (videti poglavlje 9.3.1).
01
Pretpostavimo da je prethodno opisani objektni modul povezan na sledei
nain: gcc -o program program.o, dajui izvrni program program. Ako se
(2
on pregleda (npr. komandom nm), moe da se vidi da postoji znatno vie imeno-
vanih simbola (npr. _start, printf@@GLIBC_2.0 itd.). Ako se pogleda main-
ski kd funkcije main (npr. komandom objdump), moe da se vidi da su sporne
je
adrese uspeno razreene. Meutim, na mestu poziva funkcije printf poziva se
funkcija printf@plt, a ona poziva nedefinisanu funkciju printf@@GLIBC_2.0.
an
Naime, ova funkcija implementirana je u rantajm biblioteci i njena adresa bie
povezana dinamiki, na poetku izvravanja programa.
d
iz
vanja. Te greke mogu biti posledica greke programera koji nije predvideo
ro
neku moguu situaciju a mogu biti i greke koje zavise od okruenja u kojem
se program izvrava.
Jedna od najeih greaka u fazi izvravanja je nedozvoljeni pristup mem-
kt
oriji. Ona se, na primer, javlja ako se pokua pristup memoriji koja nije dodel-
jena programu ili ako se pokua izmena memorije koja je dodeljena programu,
le
ali samo za itanje (engl. read only). Operativni sistem detektuje ovakve
situacije i signalizira, to najee prouzrokuje prekid programa uz poruku
E
Segmentation fault
5)
toru programa jer je prevideo da moe doi do deljenja nulom i nije u programu
predvideo akciju koja to spreava.
01
U fazi izvravanja moe doi i do greaka u komunikaciji sa periferijama (na
primer, pokuaj itanja iz nepostojee datoteke na disku) itd.
(2
Pitanja i zadaci za vebu
Pitanje 9.3.1.
je
Opisati ukratko memorijske segmente koji se dodeljuju svakom
programu koji se izvrava. ta se, tokom izvravanja programa, uva: u stek
an
segmentu, u hip segmentu, u segmentu podataka?
Pitanje 9.3.4. Navesti barem tri vrste podataka koje se uvaju u svakom stek
sk
okviru.
Pitanje 9.3.6. Ukoliko se na steku poziva istovremeno nae vie instanci neke
f, f?
kt
Pitanje 9.3.12. Za svaku promenljivu u narednom kdu rei koji joj je nivo
5)
dosega, kakav joj je ivotni vek u kom memorijskom segmentu je smetena i
kakva joj je inicijalna vrednost.
01
int a;
int f() {
(2
double b; static float c;
}
je
an
d
iz
o
sk
n
ro
kt
le
E
Glava 10
5)
Pokazivai i dinamika alokacija
01
memorije
(2
je
an
U jeziku C, pokazivai imaju veoma znaajnu ulogu i teko je napisati iole
kompleksniji program bez upotrebe pokazivaa. Dodatne mogunosti u radu
d
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 int zapisuje se int *. Slino
vai i za druge tipove. 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, p1, p2 i p3 su pokazi-
vai koji ukazuju na int dok je p4 tipa int:
int *p1;
int* p2;
5)
int* p3, p4;
01
Pokazivaka promenljiva moe da sadri adrese promenljivih ili elemenata
niza
2 i za to se koristi operator &. Unarni operator &, operator referenciranja ili
adresni operator vraa adresu svog operanda. On moe biti primenjen samo na
(2
promenljive i elemente niza, a ne i na izraze ili konstante. Na primer, ukoliko
je naredni kd deo neke funkcije
je
int a=10, *p;
p = &a;
an
onda se prilikom izvravanja te funkcije, za promenljive a i p rezervie prostor
a 10, a u prostor za p
d
*p = 5;
kt
5)
pokazatelj da je u pitanju specijalna pokazivaka vrednost.
Pokazivai se mogu eksplicitno (pa ak i implicitno) konvertovati iz jednog
01
u drugi pokazivaki tip. Na primer int a; char* p = (char*)&a; ili ak
int a; char* p = &a;, pri emu prevoenjem drugog kda dobijamo upo-
(2
zorenje. Meutim, prilikom konverzije pokazivaa vri se samo prosta do-
dela adrese, bez ikakve konverzije podataka na koje pokaziva ukazuje, to
esto moe dovesti do neeljenih efekata, te stoga ovakve konverzije pokazivaa
je
neemo esto koristiti. Konverzije izmeu pokazivaa na podatke i pokazivaa
na funkcije (o kojima e vie biti rei u poglavlju 10.8) nisu doputene (dovode
an
do nedefinisanog ponaanja programa).
U nekim sluajevima, poeljno je imati mogunost opteg pokazivaa,
tj. pokazivaa koji moe da ukazuje na promenljive razliitih tipova. Za to
d
mogue odrediti tip takvog izraza kao ni broj bajtova u memoriji koji pred-
sk
mogue vriti aritmetike operacije (o kojima e vie rei biti u poglavlju 10.4).
const. Tako const int* p
I na pokazivae se moe primeniti kljuna re
oznaava pokaziva na konstantnu promenljivu tipa int, int *const p oz-
kt
naava konstantni pokaziva na promenljivu tipa int, dok const int *const p
oznaava konstantni pokaziva na konstantnu promenljivu tipa int. U prvom
le
dok u treem sluaju nije mogue menjati ni jedno ni drugo. Trik koji po-
mae 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. Ukoliko se
vrednost pokazivaa p dodeli pokazivau q, nee na adresu na koju ukazuje
q biti iskopiran sadraj na koji ukazuje p, nego e samo promenljiva q dobiti
vrednost promenljive p i obe e ukazivati na prostor na koji je pre toga ukazivao
237 10. Pokazivai i dinamika alokacija memorije
5)
originalni pokaziva sadraj originalni pokaziva sadraj
01
(2
kopija pokazivaa novi pokaziva kopija sadraja
je
an
Slika 10.1: Ilustracija plitkog i dubokog kopiranja
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
(ovo je u vezi sa nainom na koji savremeni procesori preuzimaju podatke iz
o
ravnanje dodatno moe da otea konverzije pokazivaa (npr. tip char zauzima
uvek jedan bajt i char* moe da ukae na bilo koju adresu, pa njegova ek-
n
splicitna konverzija u tip int* moe dovesti do problema na sistemu gde se, na
int int* moraju biti
ro
5)
float f = 3.5f;
printf("%x\n", *( ( unsigned* )&f ));
01
Pravi nain da se ovaj zadatak rei je korienje unije, koja vri alijasovanje
promenljivih, ali na standardom doputeni nain jer kompilator prilikom or-
(2
ganizovanja unije vodi rauna o pitanjima koja mogu naruiti ispravnost rada
programa (na primer, vodi se rauna o poravnanju elemenata unije).
je
union { float x; unsigned y } u;
u.x = 3.5f;
an
printf("%x", u.y);
I sledei primer ilustruje pravila striktnog alijasovanja.
d
int a;
iz
*p = 1.234;
sk
g(a);
}
n
Pitanje 10.1.2. Koliko bajtova zauzima podatak tipa unsigned char? Koliko
bajtova zauzima podatak tipa unsigned char*?
Pitanje 10.1.3. Ako je veliina koju zauzima element nekog tipa t 8 bajtova,
koliko onda bajtova zauzima pokaziva na vrednost tipa t: (a) 4; (b) 8; (c) 16;
(d) zavisi od sistema?
5)
zauzima 4 bajta, koliko bajtova na istom sistemu zauzima promenljiva tipa
unsigned char *?
01
Pitanje 10.1.5. Na ta se moe primeniti operator referenciranja? Na ta se
moe primeniti operator dereferenciranja? Kako se oznaavaju ovi operatori?
(2
ta je njihovo dejstvo? Kakav im je prioritet?
je
umesto vrednosti p moe pisati i &(*p)?
an
Pitanje 10.1.7. Kako se oznaava generiki pokazivaki tip? Za ta se on
koristi? Da li se pokaziva ovog tipa moe referencirati? Zato?
d
Pitanje 10.1.8. Ako je promenjliva tipa int*, da li joj se moe dodeliti celo-
iz
int tmp = a;
a = b;
b = tmp;
}
5)
*pa = *pb;
*pb = tmp;
01
}
Zbog drugaijeg tipa argumenata, funkcija swap vie ne moe biti pozvana
(2
na isti nain kao ranije swap(x, y). Njeni argumenti nisu tipaint, ve su
pokazivakog tipa 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
je
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
an
vrednosti, kao i uvek. Funkcija se izvrava koristei samo kopije pokazivaa,
ali zahvaljujui njima ona zaista pristupa promenljivama xiy i razmenjuje im
d
ostatak pri deljenju dva cela broja (ne koristei pritom operatore / i %):
Program 10.1.
n
#include <stdio.h>
ro
*po -= b;
}
}
int main() {
unsigned k, o;
deljenje(14, 3, &k, &o);
printf("%d %d\n", k, o);
return 0;
}
241 10. Pokazivai i dinamika alokacija memorije
1. int a = 1, b = 2;
5)
void f(int* p) {
p = &b;
}
01
int main() {
int *p = &a
(2
f(p);
printf("%d\n", *p);
}
2. #include<stdio.h>
je
an
void f(int* p) { p++; p += 2; p--; p = p + 1; }
int main() {
d
Pitanje 10.2.4. Napisati funkciju f sa povratnim tipom void koja ima samo
ro
Zadatak 10.2.1. Napisati funkciju koja za uneti broj sekundi (0 < 86400)
E
proteklih od prethodne ponoi izraunava trenutno vreme tj. broj sati, minuta i
sekundi.
5)
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
01
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
(2
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
je
tzv. pokazivaka aritmetika o kojoj e biti rei u narednom poglavlju). Naravno,
kao i obino, nema provere granica niza, pa je dozvoljeno pisati (tj. prolazi
an
fazu prevoenja) i a[100], *(a+100), a[-100], *(a-100), iako je veliina niza
samo 10. U fazi izvravanja, pristupanje ovim lokacijama moe da promeni
vrednost podataka koji se nalaze na tim lokacijama ili da dovede do prekida
d
jao na adresi p (bez obzira to p nije niz nego pokaziva). Na primer, ako bi
na sistemu na kojem je sizeof(int) jednako 4 pokaziva p ukazivao na adresu
n
100 na kojoj poinje niz celih brojeva, tada bi p[3] bio ceo broj koji se nalazi
poevi adrese 112. Isti broj bio bi dobijen i izrazom
ro
smeten u memoriji
*(p+3) u kome se koristi pokazivaka aritmetika.
Dakle, bez obzira da li je x pokaziva ili niz, x[n] isto je to i *(x+n),
kt
tj. x+n isto je to i &x[n]. Ovako tesna veza pokazivaa i nizova daje puno
prednosti (na primer, iako funkcije ne primaju niz ve samo pokaziva na prvi
le
int a[10];
int *b;
a[3] = 5; b[3] = 8;
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 a ima vrednost adrese poetnog elementa i tip
int [10] koji se, po potrebi, moe konvertovati u int *. Izraz &a ima istu
vrednost (tj. sadri istu adresu) kao i a, ali drugaiji tip tip int (*)[10]
to je tip pokazivaa na niz od 10 elemenata koji su tipa int. Taj tip ima u
narednom primeru promenljiva c:
5)
int a[10];
01
int *b[10];
int (*c)[10];
(2
U navedenom primeru, promenljiva a je niz od 10 elemenata tipa char i zauz-
ima 10 bajtova. Promenljiva b je niz 10 pokazivaa na char i zauzima prostor
c je (jedan) pokaziva na
je
potreban za smetanje 10 pokazivaa. Promenljiva
niz od 10 elemenata tipa char i zauzima onoliko prostora koliko i bilo koji drugi
pokaziva. Vrednost se promenljivoj c moe pridruiti, na primer, naredbom
an
c=&a;. Tada je (*c)[0] isto to i a[0]. Ukoliko je promenljiva c deklar-
isana, na primer, sa char (*c)[5];, u dodeli c=&a; e biti izvrena implicitna
d
se prenosi samo pokaziva koji ukazuje na poetak niza. Funkcija koja prihvata
sk
takav argument za njegov tip moe da ima char a[] ili char *a. Ovim se u
funkciju kao argument prenosi (kao i uvek po vrednosti) samo adresa poetka
n
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
E
nema informaciju o tome koliko elemenata niza ima nakon prosleene adrese.
5)
kako se moe dobiti adresa drugog elementa niza?
01
tipa int*. Da li je naredba a = p; ispravna? Da li je naredba p = a; ispravna?
Koja je vrednost izraza sizeof(p) nakon naredbe p = a;, ako int* zauzima
(2
etiri bajta?
je
*(a+3) ispravan izraz? Da li mu je vrednost ista kao i vrednost a[3], a[10],
*a[3] ili *a[10]?
an
Pitanje 10.3.8. ta ispisuje naredni kd:
d
printf("%d\n", a);
Pitanje 10.3.9. Ako je kao argument funkcije navedeno ime niza, ta se sve
prenosi u funkciju: (i) adresa poetka niza; (ii) elementi niza; (iii) podatak o
n
adresu 100, na sistemu na kojem int zauzima 4 bajta, vrednost p+3 e biti
adresa 100 + 3 4 = 112. Analogno vai za druge tipove.
Od pokazivaa je mogue oduzimati cele brojeve (na primer, p-n), pri emu
je znaenje ovih izraza analogno znaenju u sluaju sabiranja. Na pokazivae
je mogue primenjivati prefiksne i postfiksne operatore ++ i --, sa slinom
semantikom. Dva pokazivaa je mogue oduzimati. I u tom sluaju se ne
vri prosto oduzimanje dve adrese, ve se razmatra veliina tipa pokazivaa, sa
kojom se razlika deli. Dva pokazivaa nije mogue sabirati.
5)
Pored dereferenciranja, dodavanja i oduzimanja celih brojeva, i oduzimanja
pokazivaa, nad pokazivaima se (samo ako su istog tipa) mogu primenjivati i
01
relacijski operatori (na primer, p1 < p2, p1 == p2, . . . ). Tako je, na primer,
p1 < p2 tano akko p1 ukazuje na raniji element (u smislu linearno ureene
(2
memorije) niza od pokazivaa p2.
Unarni operatori &i* imaju vii prioritet nego binarni aritmetiki opera-
tori. Zato je znaenje izraza *p+1 zbir sadraja lokacije na koju ukazuje pi
je
vrednosti 1 (a ne sadraj na adresi p+1). Unarni operatori &, *, i prefiksni ++
se primenjuju zdesna nalevo, pa naredba ++*p; inkrementira sadraj lokacije
an
na koju ukazuje p. Postfiksni operator ++, kao i svi unarni operatori koji se
primenjuju sleva na desno, imaju vii prioritet od unarnih operatora koji se pri-
menjuju zdesna nalevo, pa *p++ vraa sadraj na lokaciji p, dok se kao boni
d
efekat p inkrementira.
iz
Program 10.2.
o
sk
#include <stdio.h>
int main() {
n
/* Inicijalizacija pokazivaca -
le
/* Pokazivacka aritmetika */
p1++; --p2; p3 += 2; /* a++ nije dozvoljeno */
printf("%d %d %d %lu\n", *p1, *p2, *p3, p3 - p1);
8 5 3
8 5 3
5)
7 3 4
7 6 1 6
01
6 5 6
(2
Pitanja i zadaci za vebu
je
Pitanje 10.4.1. Ako je p tipa int*, ta je efekat naredbe *p += 5; a ta
efekat naredbe p += 5;?
an
Pitanje 10.4.2. Ako su promenljive p i q tipa double *, za koliko e se ra-
zlikovati vrednosti p i q nakon komande p = q+n (pri emu je n celobrojna
d
promenljiva)?
iz
n tipa int)?
Pitanje 10.4.6. Ako su p1, p2 pokazivai istog tipa, da li postoji razlika izmeu
le
Pitanje 10.4.8.
247 10. Pokazivai i dinamika alokacija memorije
5)
Pitanje 10.4.9.
01
1. Kog je tipa x, a kog tipa y nakon deklaracije int *x, *y;? Da li su
dozvoljene operacije x+y i x-y?
(2
2. Kog je tipa a, a kog tipa b nakon deklaracije int* a, b;? Da li su
dozvoljene operacije a+b i a-b?
je
Pitanje 10.4.10. Da li nakon int n[] = {1, 2, 3, 4, 5}; int* p = n;,
n, vrednost pokazivaa p, ili ni jedno ni
an
sledee naredbe menjaju sadraj niza
drugo ili oba: (a) *(p++); (b) (*p)++; (c) *p++;?
d
(\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);),
n
5)
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
01
pokaziva koji je prosleen kao argument:
(2
size_t n;
for (n = 0; *s != \0; s++)
n++;
je
return n;
}
an
Jo jedna verzija ove funkcije koristi mogunost oduzimanja pokazivaa
d
s++;
sk
return s - t;
}
n
ro
char *p;.
E
Slino, naredna dodela nije doputena, jer nizove nije mogue dodeljivati.
5)
char t[5];
...
01
t = s;
s dodeli niski t
(2
Dakle, kao to je i ranije reeno, ispravan nain da se niska
nije dodela, ve poziv funkcije strcpy, iju emo jednu moguu implementaciju
opisati.
je
char s[] = "abcd";
char t[5];
an
...
strcpy(t, s);
d
iz
s++;
t++;
}
kt
}
le
Konano, poreenje sa nulom moe biti izostavljeno jer svaka ne-nula vred-
nost ima istinitosnu vrednost tano:
}
U navedenoj implementaciji funkcije strcpy kvalifikatorom const obezbeeno
je da se sadraj lokacija na koje ukazuje t nee menjati (u protivnom dolazi do
greke u fazi prevoenja.
5)
U kom segmentu memorije se tokom izvravanja programa
uvaju: konstantne niske?
01
Pitanje 10.5.2. Nakon koda
void f() {
(2
char* a = "Zdravo";
char b[] = "Zdravo";
...
je
}
an
u kom segmentu memorije je smetena promenljiva a? u kom je segmentu ono
na ta pokazuje promenljiva a? U kom segmentu su smeteni elementi niza b?
aib a, p?
d
int i;
o
char *dan(int n) {
static char *ime[] = {
"neispravna vrednost", "ponedeljak", "utorak", "sreda",
kt
5)
ment
vai i za viedimenzione nizove. Ime niza tipa T a[d1][d2]...[dn] se konver-
tuje u pokaziva na n-1-dimenzioni niz, tj. u pokaziva tipa T (*)[d2]...[dn].
01
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,
(2
deklaraciju dvodimenzionog niza:
int a[10][20];
je
Svaki od izraza a[0], a[1], a[2], ... oznaava niz od 20 elemenata tipa int,
int [20] (koji se, po potrebi, implicitno konvertuje u tip int*).
an
te ima tip
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,
d
na niz od 20 elemenata, tj. int (*)[20]. Izrazi a i a[0] imaju istu vrednost
(adresu poetnog elementa dvodimenzionalnog niza), ali razliite tipove: prvi
o
ima tip int (*)[20], a drugi tip int*. Ovi tipovi ponaaju se u skladu sa
sk
int a[10][20];
kt
int *b[10];
i
a je pravi dvodimenzioni niz: 200 lokacija za podatak tipa int je rezervisano
E
ovi pokazivai mogu biti razliite duine. Tako, svaki element niza b 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):
char meseci[][10] = {
5)
"Greska", "Januar", "Februar", "Mart", "April",
"Maj", "Jun", "Jul", "Avgust", "Septembar",
01
"Oktobar", "Novembar", "Decembar"};
(2
Poto meseci imaju imena razliite duine, bolje reenje je napraviti niz
pokazivaa na karaktere i inicijalizovati ga da pokazuje na konstantne niske
smetene u segmentu podataka (primetimo da nije potrebno navesti broj ele-
je
menata niza poto je izvrena inicijalizacija):
char *meseci[] = {
an
"Greska", "Januar", "Februar", "Mart", "April",
"Maj", "Jun", "Jul", "Avgust", "Septembar",
d
Slika 10.2 ilustruje slian primer memoriju koja odgovara nizovima aib
deklarisanim u okviru neke funkcije:
o
Pitanje 10.6.1.
kt
Segment podataka
a b c d 0
e f 0
g h i 0
5)
01
Stek segment
(2
[0] [1] [2]
a a b c d 0 e f 0 ? ? g h i 0 ?
[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]
je
an
Slika 10.2: Niz pokazivaa i dvodimenzioni niz u memoriji
d
Pitanje 10.6.6.
iz
Pitanje 10.6.7.
sk
Pitanje 10.6.8. Koliko bajtova zauzima i u kom delu memorije niz koji je u
char* a[10];
le
void f() {
char* a = "Zdravo";
5)
char b[] = "Zdravo";
...
01
}
U kom segmentu memorije se nalazi promenljiva a? U kom segmentu memorije
(2
je ono na ta pokazuje promenljiva a? U kom segmentu memorije je ono na
ta pokazuje promenljiva b?
Pitanje 10.6.14. Koliko bajtova e na steku biti rezervisano za niz
je
char *s[] = { "jedan", "dva", "tri" }; koji je lokalna promenljiva?
an
10.7 Pokazivai i strukture
d
nalaze. Neka su a i b promenljive istog tipa strukture koja ima lan pokazi-
vakog tipa p. Dodelom a=b; bie iskopirane vrednosti svih lanova strukture
kt
istu adresu (na onu na koju je ukazivao Iako se takvo plitko kopranje
koristi (pre svega zbog utede memorije), ono je est uzrok greaka i pokazi-
E
pa->imenilac*pb->brojilac;
pc->imenilac = pa->imenilac*pb->imenilac;
}
5)
jama, vraati kao rezultat funkcija i ne mogu se dodeljivati promenljivima.
Ipak, ove operacije je mogue posredno izvriti ukoliko se koriste pokazivai na
01
funkcije. Razmotrimo naredni ilustrativni primer.
Program 10.3.
(2
#include <stdio.h>
je
int i;
for (i = 0; i < n; i++)
an
b[i] = a[i] + 1;
}
d
int i;
for (i = 0; i < n; i++)
o
b[i] = a[i] * 2;
sk
int i;
ro
}
le
#define N 8
int main() {
int a[N] = {1, 2, 3, 4, 5, 6, 7, 8}, b[N];
return 0;
}
Sve funkcije u prethodnom programu kopiraju elemente niza a u niz b,
prethodno ih transformiui na neki nain. Mogue je izdvojiti ovaj zajedniki
5)
postupak u zasebnu funkciju koja bi bila parametrizovana operacijom transfor-
macije koja se primenjuje na elemente niza a:
01
#include <stdio.h>
(2
int i;
for (i = 0; i < n; i++)
b[i] = (*f)(a[i]);
}
je
an
int inc1(int x) { return x + 1; }
int mul2(int x) { return 2 * x; }
d
}
ro
#define N 8
int main() {
kt
return 0;
}
5)
promenljiva a oznaava funkciju koja vraa rezultat tipa*double, a prima
01
argumente tipa double i int, dok promenljiva b oznaava pokaziva na funkciju
koja vraa rezultat tipa double, a prima argumente tipa double i int.
(2
Najee koriene operacije sa pokazivaima na funkcije su, naravno, ref-
erenciranje (&) i dereferenciranje (*).
5
Mogue je kreirati i nizove pokazivaa na funkcije. Ovi nizovi se mogu i
je
incijalizovati (na uobiajeni nain). U primeru
ment tipa int. Funkcije ije se adrese nalaze u nizu se mogu direktno i pozvati.
Na primer, naredni kd ispisuje vrednost 4:
iz
printf("%d", (*a[0])(3));
o
sk
ima pokaziva na funkciju koja je povratnog tipa char i ima (samo jedan)
argument tipa float.
kt
5)
Kog je tipa a1, a kog a2?
01
Pitanje 10.8.7. Kog je tipa x deklarisano sa:
1. double (*x[3])(int);
(2
2. int (*x) (double);
3. int *x (double);
4. double* (*x) (float*);
je
an
5. int (*f) (float*);
d
Zadatak 10.8.1. Napisati funkciju koja u nizu odreuje najduu seriju el-
iz
5)
void *malloc(size_t n);
01
Ona alocira blok memorije (tj. niz uzastopnih bajtova) veliine n bajtova i
vraa adresu alociranog bloka u vidu generikog pokazivaa (tipa void*). U
(2
sluaju da zahtev za memorijom nije mogue ispuniti (na primer, zahteva se
vie memorije nego to je na raspolaganju), ova funkcija vraa NULL. Memorija
na koju funkcija malloc vrati pokaziva nije inicijalizovana i njen sadraj je,
je
u principu, nedefinisan (tj. zavisi od podataka koji su ranije bili uvani u tom
delu memorije).
an
Funkcija 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,
d
5)
U gore navedenom primeru, nakon uspene alokacije, u nastavku programa
se p moe koristiti kao (statiki alociran) niz celih brojeva. Napomenimo da
n*sizeof(int) moe dovesti do prekoraenja za veoma velike
01
raunanje izraza
vrednosti n (ukoliko je prekoraenje problem, savetuje se upotreba funkcije
calloc).
(2
U trenutku kada dinamiki alociran blok memorije vie nije potreban, poeljno
je osloboditi ga. To se postie funkcijom free:
void free(void* p);
je
an
free(p) oslobaa memoriju na koju ukazuje pokaziva p (a ne mem-
Poziv
orijski prostor koji sadri sm pokaziva p), pri emu je neophodno da p
pokazuje na blok memorije koji je alociran pozivom funkcije malloc ili calloc.
d
Ukoliko neki dinamiki alociran blok nije osloboen ranije, on e biti osloboen
prilikom zavretka rada programa, zajedno sa svom drugom memorijom koja je
n
itno oslobaanje sve dinamiki alocirane memorije pre kraja rada programa, a
poeljno im taj prostor nije potreban.
Upotrebu ovih funkcija ilustruje naredni primer u kojem se unosi i obrnuto
kt
ispisuje niz iji broj elemenata nije unapred poznat (niti je poznato njegovo
gornje ogranienje), ve se unosi sa ulaza tokom izvravanja programa.
le
Program 10.4.
E
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, i, *a;
5)
free(a);
01
return 0;
}
(2
U nekim sluajevima potrebno je promeniti veliinu ve alociranog bloka
memorije. To se postie korienjem funkcije realloc, iji je prototip:
je
an
Parametar memblock je pokaziva na prethodno alocirani blok memorije, a
parametar size je nova veliina u bajtovima. Funkcija realloc vraa pokazi-
va tipa void* na realociran blok memorije, a NULL u sluaju da zahtev ne moe
d
Upotreba funkcije
jeve i smeta ih u memoriju, sve dok se ne unese-1 za kraj. S obzirom na to da
se broj elemenata ne zna unapred, a ne zna se ni gornje ogranienje, neophodno
kt
Program 10.5.
#include <stdio.h>
#include <stdlib.h>
do {
printf("Unesi ceo broj (-1 za kraj): ");
scanf("%d", &i);
5)
if (duzina == alocirano) {
alocirano += KORAK;
01
a = realloc(a, alocirano*sizeof(int));
if (a == NULL) return 1;
}
(2
a[duzina++] = i;
} while (i != -1);
je
/* Ispis elemenata */
printf("Uneto je %d brojeva. Alocirano je %d bajtova\n",
an
duzina, alocirano*sizeof(int));
printf("Brojevi su : ");
for (i = 0; i<duzina; i++)
d
/* Oslobadjanje memorije */
free(a);
o
sk
return 0;
}
n
if (duzina == alocirano) {
kt
new_a = malloc(alocirano*sizeof(int));
/* Kopira se sadrzaj starog niza u novi */
E
a = realloc(a, alocirano*sizeof(int));
5)
10.9.2 Greke u radu sa dinamikom memorijom
01
esto je i uzrok problema. Neki od najeih problema opisani su u nastavku.
(2
Curenje memorije. Jedna od najopasnijih greaka u radu sa dinamiki
alociranom memorijom je tzv. curenje memorije (engl. memory leak). Curenje
memorije je situacija kada se u tekuem stanju programa izgubi informacija o
je
lokaciji dinamiki alociranog, a neosloboenog bloka memorije. U tom sluaju,
program vie nema mogunost da oslobodi taj blok memorije i on biva zauvek
an
(zapravo do kraja izvravanja programa) izgubljen (rezervisan za korienje
od strane programa koji vie nema naina da mu pristupi). Curenje memorije
d
char* p;
p = (char*) malloc(1000);
....
o
p = (char*) malloc(5000);
sk
Inicijalno je 1000 bajtova dinamiki alocirano i adresa poetka ovog bloka mem-
n
rano 5000 bajtova i adresa poetka tog bloka memorije je opet smetena u
promenljivu p. Meutim, poto originalnih 1000 bajtova nije osloboeno ko-
rienjem funkcije free, a adresa poetka tog bloka memorije je izgubljena
kt
menski period (moda i bez prestanka) i da obrauje vee koliine ulaza, curenje
memorije postaje vidljivo, ini program neupotrebljivim i moe da uzrokuje ve-
like 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. Postoje specijalizovani programi profajleri za curenje memo-
rije (engl. memory leaks profilers) koji olakavaju otkrivanje uzroka curenja
memorije.
5)
Pristup osloboenoj memoriji. Nakon poziva free(p), memorija na koju
01
pokazuje pokaziva p se oslobaa i ona vie ne bi trebalo da se koristi. Meu-
tim, poziv free(p) ne menja sadraj pokazivaa p. Mogue je da naredni
(2
poziv funkcije malloc vrati blok memorije upravo na toj poziciji. Naravno,
ovo ne mora da se desi i nije predvidljivo u kom e se trenutku desiti, tako
da ukoliko programer nastavi da koristi memoriju na adresi p, mogue je da
je
e greka proi neopaeno. Zbog toga, preporuuje se da se nakon poziva
free(p), odmah p postavi na NULL. Tako se osigurava da e svaki pokuaj
an
pristupa osloboenoj memoriji biti odmah prepoznat tokom izvravanja pro-
grama i operativni sistem e zaustaviti izvravanje programa sa porukom o
segmentation fault).
d
greci (najee
iz
Oslobaanje istog bloka vie puta. Nakon poziva free(p), svaki naredni
poziv free(p) za istu vrednost pokazivaa p prouzrokuje nedefinisano pon-
o
lediti iskljuivo adresu vraenu od strane funkcije malloc, calloc ili realloc.
ak i prosleivanje pokazivaa na lokaciju koja pripada alociranom bloku (a
kt
koji slobodni. Zato, i malo prekoraenje granice bloka prilikom upisa moe da
promeni te dodatne informacije i da uzrokuje pad sistema za dinamiko up-
ravljanje memorijom. Postoje i mnogi drugi sluajevi u kojima prekoraenje i
potkoraenje bafera mogu da narue ispravno izvravanje programa ili dovedu
do njegovog pada.
5)
est je sluaj da ispravne aplikacije u kojima ne postoji curenje memorije (a
01
koje esto vre dinamiku alokaciju i dealokacije memorije) tokom dugog rada
pokazuju degradaciju u performansama i na kraju prekidaju svoj rad na nepred-
vieni nain. Uzrok ovome je najee fragmentisanje memorije. U sluaju
(2
fragmentisane memorije, u memoriji se esto nalazi dosta slobodnog prostora,
ali on je rascepkan na male, nepovezane parie. Razmotrimo naredni (mini-
jaturizovan) primer. Ukoliko 0 oznaava slobodni bajt i 1 oznaava zauzeti
je
bajt, a memorija trenutno ima sadraj 100101011000011101010110, postoji
ukupno 12 slobodnih bajtova. Meutim, pokuaj alokacije 5 bajtova ne moe
an
da uspe, jer u memoriji ne postoji prostor dovoljan za smetanje 5 povezanih ba-
jtova. S druge strane, memorija koja ima sadraj 111111111111111100000000
d
ima samo 8 slobodnih bajtova, ali jeste u stanju da izvri alokaciju 5 traenih
bajtova. Memoriju na hipu dodeljenu programu nije mogue automatski reor-
iz
ganizovati u fazi izvravanja, jer nije mogue u toj fazi aurirati sve pokazivae
koji ukazuju na objekte na hipu.
o
5)
trenutku kada se iscrpi memorijski prostor dodeljen programu, hip i stek po-
tencijalno sudaraju, ali operativni sistemi obino to spreavaju i tada obino
01
dolazi do nasilnog prekida rada programa.
(2
Pitanje 10.9.1.
je
Navesti prototip, opisati njeno ponaanje i primer korienja funkcije:
an
malloc;
calloc;
d
realloc;
iz
free.
o
Pitanje 10.9.2. Fukcija realloc ima isti efekat kao funkcija free ako je:
n
char *p;
p = (char*)malloc(n);
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
q = (int*)malloc(sizeof(int)*5);
p = (int*)malloc(sizeof(int)*5);
free(p); free(p);
5)
free(p+1);
01
Pitanje 10.9.7. Zaokruiti komandu u narednom kdu koja dovodi do greke?
(2
int *f = malloc(4*sizeof(int));
int* g = f;
free(g);
je
free(f);
f=g;
an
Pitanje 10.9.8. Koje su prednosti korienja dinamike alokacije memorije
(u odnosu na statiku i automatsku alokaciju)? Koji su nedostaci?
d
ta se time postie?
Pitanje 10.9.12. Opisati ukratko bar etiri este greke koje se javljaju u vezi
sa dinamikom alokacijom memorije.
kt
ne koristi rekurzija?
Zadatak 10.9.1. ,
Napisati program koji sa standardnog ulaza uitava broj
a zatim i niz od sa standardnog ulaza.
celih brojeva, pa zatim i ceo broj
Program treba da vrati indeks broja u nizu (ako se nalazi u ) ili indeks
elementa niza koji je po apsolutnoj vrednosti najblii broju .
Zadatak 10.9.2. Napisati program koji sa standardnog ulaza uitava cele bro-
jeve dok ne uita nulu kao oznaku za kraj. Na standardni izlaz ispisati koji
broj se pojavio najvie puta meu tim brojevima. Na primer, ako se na ulazu
5)
pojave brojevi: 2 5 12 4 5 2 3 12 15 5 6 6 5 program treba da vrati broj
5. Zadatak reiti korienjem niza koji se dinamiki realokacira.
01
Zadatak 10.9.3. Napisati program koji sa standardnog ulaza uitava prvo
dimenzije matrice ( i ) a zatim redom i elemente matrice (ne postoje pret-
(2
postavke o dimenziji matrice), a zatim ispisuje matricu spiralno, krenuvi od
gornjeg levog ugla.
Zadatak 10.9.4.
je
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-
tora = (1 , . . . , ) i = (1 , . . . , ) je suma = 1 1 + 2 2 + . . . +
d
)
iz
5)
Pregled standardne biblioteke
01
(2
je
Jezik C ima mali broj naredbi i mnoge funkcionalnosti obezbeene su kroz
funkcije standardne biblioteke (engl. standard library). Standardna biblioteka
an
obezbeuje funkcije, ali i makroe i definicije tipova za potrebe rada sa da-
totekama, niskama, alokacijom memorije i slino. Standardna C biblioteka
d
datoteke 1995. godine. Verzija C99 uvela je jo est datoteka zaglavlja, a verz-
ro
ija C11 jo pet (od kojih tri mogu da ne budu podrane od implementacija, a
da se te implementacije i dalje smatraju standardnim). U tabeli 11.1 dat je
kt
269
270 11. Pregled standardne biblioteke
5)
nezavisno od karakterske tabele koja se koristi (ASCII
ili neke druge);
<errno.h> C89 Podrka za rad sa kdovima greaka koje vraaju bib-
01
lioteke funkcije.
<fenv.h> C99 Funkcije za kontrolu okruenja za brojeve u pokretnom
zarezu.
(2
<float.h> C89 Konstante koje specifikuju svojstva brojeva u pokret-
nom zarezu zavisna od implementacije.
<inttypes.h> C99 Proirena podrka za celobrojne tipovi fiksne irine.
<iso646.h> NA1 Makroi za opisivanje standardnih tokena.
je
<limits.h> C89 Konstante koje specifikuju svojstva celih brojeva zav-
isna od implementacije.
an
<locale.h> C89 Funkcije za lokalizaciju.
<math.h> C89 esto korie matematike funkcije.
<setjmp.h> C89 Makroi setjmp i longjmp.
d
izmeu niti.
<stdbool.h> bool.
sk
C99 Tip
<stddef.h> C89 Nekoliko raznorodnih tipova i konstanti (ukljuujui
NULL i size_t).
n
5)
int strncmp (char* str1, char* str2, size_t num);
01
char* strchr (char* str, int character);
char* strrchr (char* str, int character);
(2
char* strstr (char* str1, char * str2);
je
size_t strcspn (char* str1, char* str2);
char* strpbrk (char* str1, char* str2);
an
char* strtok (char * str, char* delimiters);
d
iz
nim parameterom
ran (u sluaju da je niska koja se kopira kraa od broja n ostatak se pop-
ro
jajui da prva niska ima dovoljno prostora da smesti i sve karaktere druge,
E
strchr Funkcija strchr proverava da li data niska sadri dati karakter i vraa
pokaziva na prvu poziciju na kojoj je karakter naen ili NULL ako karak-
ter nije naen. Funkcija strrchr radi slino, ali vraa pokaziva na
poslednje pojavljivanje karaktera.
5)
strtok Niz poziva funkcije strtok slue da podele nisku u tokene koji su niske
uzastopnih karaktera razdeljene karakterima navedenim u drugoj niski.
01
U prvom pozivu funkcije kao prvi argument navodi se niska koja se deli,
a u drugom navodi se NULL. Na primer, kd
(2
char str[] ="- Ovo, je jedna niska.", delims[] = " ,.-";
char *s = strtok (str, delims);
je
while (s != NULL) {
printf ("%s\n", s);
an
s = strtok (NULL, delims);
}
d
iz
ispisuje
Ovo
o
je
sk
jedna
niska
n
ro
int rand(void);
void srand(unsigned int);
5)
((double) rand() / (RAND_MAX+1.0))
01
Funkcija rand() moe biti jednostavno upotrebljena za generisanje pseudo-
(2
sluajnih brojeva u celobrojnom intervalu [, ]:
n+rand()%(m-n+1)
je
an
Ipak, bolja svojstva (bolju raspodelu) imaju brojevi koji se dobijaju na
sledei nain:
d
srand Funkcija rand niz pseudo-sluajnih brojeva generie uvek poev od iste
o
5)
greke (na primer, komandni interpretator nije rasploiv, nema dovoljno
memorije da se izvri komanda, lista argumenata nije ispravna).
01
exit Funkcija void exit(int); zaustavlja rad programa (bez obzira iz koje
funkcije je pozvana) i vraa svoj argument kao povratnu vrednost pro-
(2
grama. Obino povratna vrednost nula oznaava uspeno izvrenje pro-
grama, a vrednost ne-nula ukazuje na neku greku tokom izvravanja.
esto se koriste i simbolike konstante EXIT_SUCCESS EXIT_FAILURE za
je
uspeh i za neuspeh. Naredba exit(e); u okviru funkcije main ekviva-
lentna je naredbi return e;. Funkcija exit automatski poziva fclose
an
za svaku datoteku otvorenu u okviru programa (vie o funkciji fclose
bie reeno u glavi 12).
d
isalnum(c) vraa ne-nula vrednost ako je c slovo ili cifra, nulu inae;
isspace(c) vraa ne-nula vrednost ako je c belina (razmak, tab, novi red,
itd), nulu inae;
5)
double tan(double); double atan(double); double atan2(double);
double log(double); double log10(double); double log2(double);
double pow(double); double exp(double); double sqrt(double);
01
Zaglavlje math.h sadri deklaracije vie od dvadeset esto korienih matem-
(2
atikih funkcija. Svaka od njih ima jedan ili dva argumenta tipa double i ima
double kao tip povratne vrednosti.
je
sin(x) vraa vrednost funkcije sin(), smatra se da je zadato u radijanima;
an
cos(x) vraa vrednost funkcije cos(), smatra se da je zadato u radijanima;
koordinatni poetak.
log(x) vraa vrednost ln (mora da vai > 0); logaritam log (za , > 0,
sk
vraa vrednost
sqrt(x) vraa vrednost (mora da vai > 0); vrednost
moe se
le
5)
ispisana poruka nalik sledeoj:
01
Assertion failed: expression, file filename, line nnn
(2
i bie prekinuto izvravanje programa. Ukoliko je definisano simboliko
ime NDEBUG (direktivom #define) pre nego to je ukljueno zaglavlje
<assert.h>, pozivi funkcije assert se ignoriu. Funkcija assert se
je
obino koristi u toku razvoja programa, u takozvanoj debug verziji. Kada
an
je program spreman za korienje, proizvodi se release verzija i tada se
pozivi funkcije assert ignoriu (jer je tada obino definisano ime NDEBUG).
U fazi razvoja programa, upozorenja koja generie assert ukazuju na
d
5)
Ulaz i izlaz programa
01
(2
je
Jezik C je dizajniran kao mali jezik i ulazno/izlazne operacije nisu direktno
podrane samim jezikom, ve specijalizovanim funkcijama iz standardne bib-
an
lioteke jezika (koja je prisutna u svakom C okruenju). Poto su ove funkcije
deo standarda jezika C, mogu se koristiti u programima uz garantovanu preno-
d
<stdio.h>.
pojedinanih bajtova ili karaktera). Standardni ulaz obino ine podaci koji
ro
greke na koji se obino upuuju poruke o grekama nastalim tokom rada pro-
grama i koji se, takoe, obino prikazuje na ekranu.
le
277
278 12. Ulaz i izlaz programa
5)
./prog 2> errorfile
01
12.1.1 Ulaz i izlaz pojedinanih karaktera
(2
Najjednostavniji mehanizam itanja sa standardnog ulaza je itanje jednog
po jednog karaktera korienjem funkcije getchar:
je
int getchar(void);
an
Funkcija 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
d
<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)
iz
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.
o
Ako bi povratni tip funkcije getchar bio char, a povratna vrednost u nekom
sk
bila vrednost 255 koja bi pre poreenja sa -1 bila promovisana u tip int).
ro
int putchar(int);
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>
int main()
{
5)
int c;
while ((c = getchar()) != EOF)
01
putchar(tolower(c));
return 0;
(2
}
je
velikih slova u karaktere malih slova, ne menjajui pri tom ostale karaktere.
Funkcije poput getchar i putchar iz <stdio.h> i tolower iz <ctype.h>
an
su u mnogim implementacijama zapravo makroi (zasnovani na drugim funkci-
jama iz standardne biblioteke), ime se izbegava dodatno vreme i prostor potre-
d
gets:
o
Biblioteka funkcija
sk
ita karaktere sa standardnog ulaza do kraja tekue linije ili do kraja datoteke
ro
ispisuje nisku na koju ukazuje s na standardni izlaz, dodajui pri tom oznaku
za kraj reda. Zavrna nula se ne ispisuje. Funkcija puts vraa EOF u sluaju
da je dolo do greke, a nenegativnu vrednost inae.
280 12. Ulaz i izlaz programa
5)
karaktera. Sluajevi korienja ove funkcije iz prethodnih glava jesu najuobia-
jeniji, ali svakako nisu potpuni. Pozivi funkcija putchar i printf mogu biti
isprepletani izlaz se vri u istom redosledu u kojem su ove funkcije pozvane.
01
Funkcija printf prevodi, formatira i tampa svoje argumente na stan-
dardni izlaz pod kontrolom date format niske . Format niska sadri dve vrste
(2
objekata: obine karaktere, koji se doslovno prepisuju na standardni izlaz i
specifikacije konverzija od kojih svaka uzrokuje konverziju i tampanje sledeeg
uzastopnog argumenta funkcije printf. Svaka specifikacija konverzije poinje
je
karakterom % i zavrava se karakterima konverzije. Izmeu % i karaktera
konverzije mogue je da se redom nau:
an
Znak minus (-), koji prouzrokuje levo poravnanje konvertovanog argu-
menta.
d
iz
levo poravnanje).
sk
Broj za preciznost, koji specifikuje najvei broj karaktera koje treba tam-
ro
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
celog broja.
kt
Karakter h, ako ceo broj treba da se tampa kao short, ili l ako ceo broj
le
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
5)
s char * tampa karaktere niske do karaktera \0 ili broja
karaktera navedenog u okviru preciznosti.
f double
01
[-]m.dddddd, gde je broj d-ova odreen preciznou
(podrazumevano 6)
e,E double [-]m.dddddde+/-xx ili [-]m.ddddddE+/-xx, gde je
(2
broj d-ova odreen preciznou (podrazumevano 6)
g,G double koristi %e ili %E ako je eksponent manji od -4 ili vei
ili jednak preciznosti; inae koristi %f. Zavrne nule i
je
zavrna decimalna taka se ne tampaju
p void * pokaziva (reprezntacija zavisna od implementacije)
an
% nijedan argument se ne konvertuje; tampa %
d
celobrojne tipove, za
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
o
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
n
5)
count, count, count, count );
01
Celobrojni formati:
Dekadni: -9234 Poravnat: -009234 Neoznacen: 4294958062
Broj -9234 prikazan kao:
(2
Hex: FFFFDBEEh C hex: 0xffffdbee Oct: 37777755756
je
/* Prikaz konstanti zapisanih u razlicitim osnovama. */
an
printf("Cifre 10 predstavljaju:\n");
printf("\tHex: %i Octal: %i Decimal: %i\n",
0x10, 010, 10);
d
iz
Cifre 10 predstavljaju:
Hex: 16 Octal: 8 Decimal: 10
o
sk
char ch = h;
ro
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
5)
:%.10s: :hello, wor:
:%-10s: :hello, world:
01
:%.15s: :hello, world:
:%-15s: :hello, world :
:%15.10s: : hello, wor:
(2
:%-15.10s: :hello, wor :
je
12.1.4 Formatirani ulaz scanf
an
Funkcija scanf 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:
d
Opis format niske dat je u nastavku. Ostali argumenti moraju biti pokazi-
o
funkcije printf, ovde e biti dat samo prikaz najeih naina korienja ove
funkcije. Funkcija scanf prestaje sa radom kada iscrpi svoju format nisku ili
n
kada neki deo ulaza ne moe da se uklopi u shemu navedenu format niskom.
Funkcija vraa broj uspeno uklopljenih i dodeljenih izlaznih podataka. U
ro
sluaju kraja datoteke, funkcija vraa EOF. Ova vrednost je razliita od vred-
nosti 0 koja se vraa u sluaju da tekui karakter sa ulaza ne moe da se uklopi
kt
u prvu specifikaciju zadatu format niskom. Svaki naredni poziv funkcije scanf
nastavlja tano od mesta na ulazu na kojem je prethodni poziv stao.
le
5)
U narednoj tabeli navedeni su konverzioni karakteri.
01
Karakter Tip Ulazni podatak
(2
i ceo broj, moe biti i oktalan (ako ima vodeu 0)
ili heksadekadan (vodei 0x ili 0X)
o int* oktalni ceo broj (sa ili bez vodee nule)
unsigned*
je
u neoznaeni dekadni broj
x int* heksadekadni broj (sa ili bez vodeih 0x ili 0X)
an
c char* karakter, naredni karakter sa ulaza se smeta na
navedenu lokaciju; uobiajeno preskakanje belina
se ne vri u ovom sluaju; Za itanje prvog ne-
d
scanf("%d", n);
umesto
scanf("%d", &n);
Primeri
5)
U narednom primeru, korienjem funkcije scanf implementiran je jednos-
01
tavni kalkulator:
Program 12.2.
(2
#include <stdio.h>
int main()
je
{
an
double sum, v;
sum = 0.0;
d
char monthname[20];
kt
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
E
funkciji printf, ali rezultat njenog rada je popunjavanje niske karaktera for-
matiranim tekstom. Prototip funkcije je:
5)
Slino funkciji sprintf koja vri ispis u nisku karaktera umesto na stan-
dardni izlaz, standardna biblioteka jezika C definie i funkciju sscanf koja je
01
analogna funkciji scanf, osim to ulaz ita iz date niske karaktera, umesto sa
standardnog ulaza.
(2
int sscanf(const char* input, char* format, ...)
je
nije fiksiran, najee je dobro proitati celu liniju sa ulaza, a zatim je analizirati
korienjem sscanf. Da bi se proitao datum sa ulaza u nekom od prethodno
an
navedena formata, mogue je koristiti:
else
sk
operativnog sistema i kojima program automatski ima pristup. Iako je, me-
E
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
ine vidljivi karakteri, sa dodatkom oznake kraja reda i horizontalnog tabula-
5)
tora. 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-
01
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
(2
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
ovakvi detalji sakrili od programera i kako programer ne bi morao da se stara
je
o ovakvim specifinostima, C jezik nudi tekstualni mod rada sa datotekama.
Ukoliko se datoteka otvori u tekstualnom modu, prilikom svakog itanja i up-
an
isa u datoteku vri se konverzija iz podrazumevanog formata oznaavanja kraja
reda u jedinstven karakter \n. Tako e na Windows sistemima dva karaktera
\r\n \n
d
kraja reda, izbegavati razmake u linijama nakon oznake za kraj reda, izbega-
vati da tekstualne datoteke sadre karaktere koji nisu vidljivi karakteri, oznake
kraja reda i tabulatora i slino.
n
podravaju Unicode, jer se u tom sluaju vie bajtova ita i konvertuje u jedan
karakter.
Funkcija fopen dobija nisku koja sadri ime datoteke (na primer, datoteka.txt)
i uz pomo usluga operativnog sistema (koje nee na ovom mestu biti de-
taljnije opisane) vraa pokaziva na strukturu (najee dinamiki alociranu)
koja predstavlja sponu izmeu lokalne datoteke i programa i koja sadri infor-
macije 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,
informaciju o tome da li se dolo do kraja datoteke, da li je dolo do greke i
5)
slino. Programer ne mora i ne bi trebalo da direktno koristi ove informacije,
ve je dovoljno da uva pokaziva na strukturu FILE i da ga prosleuju svim
01
funkcijama koje treba da pristupaju datoteci. Ime FILE je ime tipa, a ne ime
strukture; ovo ime je uvedeno korienjem typedef (videti poglavlje 6.7.5).
(2
Prvi argument funkcije fopen je niska karaktera koja sadri ime datoteke.
Drugi argument je niska karaktera koja predstavlja nain (mod) otvaranja da-
toteke i koja ukazuje na to kako e se datoteka koristiti. Dozvoljeni modovi
je
ukljuuju itanje (read, "r"), pisanje (write, "w") i dopisivanje (append, "a").
Ako se datoteka koja ne postoji na sistemu otvara za pisanje ili dopisivanje,
an
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
d
FILE* stdin;
FILE* stdout;
le
FILE* stderr;
E
Funkcija
5)
Funkcija vraa naredni karakter iz datoteke odreene prosleenim
FILE pokazivaem ili EOF u sluaju kraja datoteke ili greke.
01
int getc(FILE *fp)
(2
Slino, funkcija
FILE pokazivaem i vraa upisani karakter ili EOF u sluaju greke. Iako su
greke prilikom izlaza retke, one se nekada javljaju (na primer, ako se prepuni
je
hard disk), pa bi trebalo vriti i ovakve provere.
a ne funkcije.
ulazna.txt u datoteku izlazna.txt
iz
Program 12.3.
sk
#include <stdio.h>
n
int c;
while ((c = getc(ifp)) != EOF)
le
putc(c, ofp);
}
E
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);
fclose(ulaz);
fclose(izlaz);
return 0;
5)
}
ungetc:
01
Funkcija
(2
vraa karakter u datoteku i vraa identifikator pozicije datoteke tako da
naredni poziv operacije itanja nad ovom datotekom vrati upravo vraeni karak-
je
ter. Ovaj karakter moe, ali ne mora biti jednak poslednjem proitanom karak-
teru datoteke. Iako ova funkcije utie na naredne operacije itanja datoteke,
an
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).
Funkcija ungetc vraa EOF ukoliko je dolo do greke, a vraeni karakter inae.
d
Naredni primer ita karaktere iz datoteke dok su u pitanju cifre i pri tom
iz
gradi dekadni ceo broj. Poto poslednji karakter koji je proitan nije cifra, on
se (uslovno reeno) vraa u tok kako ne bi bio izostavljen prilikom narednih
o
itanja.
sk
#include <stdio.h>
int val = 0, c;
ro
ungetc(c, fp);
}
le
E
Funkcija feof vraa vrednost tano (ne-nula) ukoliko se dolo do kraja date
datoteke.
5)
Funkcija ita jednu liniju iz datoteke.
01
Funkcija fgets ita sledeu liniju iz datoteke (ukljuujui oznaku kraja
(2
reda) iz datoteke 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
je
linije, a u sluaju kraja datoteke ili greke vraa NULL.
Funkcija fputs ispisuje nisku (koja ne mora da sadri oznaku kraja reda)
an
u datoteku:
EOF
iz
cs = s;
while (--n > 0 && (c = getc(iop)) != EOF)
E
if ((*cs++ = c) == \n)
break;
*cs = \0;
return (c == EOF && cs == s) ? NULL : s;
}
register int c;
while (c = *s++)
putc(c, iop);
return ferror(iop) ? EOF : 0;
}
Korienjem funkcije fgets jednostavno je napraviti funkciju koja ita liniju
5)
po liniju sa standardnog ulaza, vraajui duinu proitane linije, odnosno nulu
kada liniju nije mogue proitati:
01
/* getline: read a line, return length */
int getline(char *line, int max)
{
(2
if (fgets(line, max, stdin) == NULL)
return 0;
else
return strlen(line);
je
an
}
d
nje u okviru datoteka, pa se binarne datoteke mogu koristiti i kao neke vrste
memorije sa slobodnim pristupom.
Funkcija fread se koristi za itanje niza slogova iz binarne datoteke, a
funkcija fwrite za pisanje niza slogova u binarnu datoteku.
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);
293 12. Ulaz i izlaz programa
5)
bajtova). Iako primena ovih funkcija nije striktno ograniena na binarne da-
toteke, one se najee koriste sa binarnim datotekama.
01
int fseek (FILE * stream, long int offset, int origin);
long int ftell (FILE * stream);
(2
Prvi argument obe funkcije je pokaziva na datoteku. Funkcija fseek kao drugi
je
argument dobija pomeraj izraen u broju bajtova, dok su za trei argument
dozvoljene vrednosti SEEK_SET koja oznaava da se pomeraj rauna u odnosu
SEEK_CUR koji oznaava da se pomeraj rauna u
an
na poetak datoteke, odnosu
na tekuu poziciju i SEEK_END koji oznaava da se pomeraj rauna u odnosu
na kraj datoteke.
d
Program 12.4.
#include <stdio.h>
o
sk
int main() {
struct S {
n
int broj;
int kvadrat;
ro
} s;
kt
FILE* f;
int i;
le
fclose(f);
}
5)
01
12.4 Argumenti komandne linije programa
(2
Jedan nain da se odreeni podaci proslede programu je i da se navedu
u komandnoj liniji prilikom njegovog pokretanja. Argumenti koji su tako
navedeni prenose se programu kao argumenti funkcije main. Prvi argument
argc,
je
(koji se obino naziva od engleskog argument count ) je broj argume-
nata komandne linije (ukljuujui i sm naziv programa) navedenih prilikom
an
pokretanja programa. Drugi argument (koji se obino naziva argv, od en-
gleskog argument vector ) je niz niski karaktera koje sadre argumente svaka
niska direktno odgovara jednom argumentu. Nazivu programa odgovara niska
d
argv[0]. Ako je argc tano 1, onda nisu navedeni dodatni argumenti nakon
iz
na sledei nain:
sk
argumenata.
Program 12.5.
kt
#include <stdio.h>
le
argc = 5
argv[0] = ./echoargs
argv[1] = -U
argv[2] = zdravo
argv[3] = svima
argv[4] = dobar dan
5)
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
01
terima i da se navode iza karaktera
jednog simbola - moe navesti vie karaktera koji odreuju opcije. Na primer,
pozivom:
(2
./program -a -bcd 134 -ef zdravo
a, b, c, d e i f 134 i zdravo.
je
programu se zadaju opcije i argumenti
Naredni program ispisuje sve opcije pronaene u komandnoj liniji:
an
Program 12.6.
#include <stdio.h>
d
iz
int i;
sk
if (argv[i][0] == -) {
/* Ispisuju se sva njegova slova od pozicije 1 */
ro
int j;
for (j = 1; argv[i][j] != \0; j++)
kt
}
return 0;
E
Program 12.7.
#include <stdio.h>
5)
Pitanja i zadaci za vebu
01
Pitanje 12.1.
stderr?
(2
ta je to
Pitanje 12.3.
je
U kojoj datoteci zaglavlja se nalazi deklaracija funkcije scanf?
an
Navesti njen prototip. Koju vrednost vraa ova funkcija?
Pitanje 12.4. ta, u format niski koja je argument funkcije printf, specifikuje
d
opcioni broj koji se navodi iza opcione take za argument koji je niska (na
iz
Pitanje 12.5.
sk
printf("#%6.*f#", 2, 3.14159);?
ta je rezultat poziva
ta je rezultat poziva printf("%6.1f",1/7);?
n
razmakom.
E
Pitanje 12.8. Koju vrednost vraa sscanf("1 2","%i%i%i", &a, &b, &c);
Pitanje 12.9. Navesti prototip funkcije gets. Navesti prototip funkcije puts.
Kakva je razlika izmeu funkcija gets i fgets? Kakva je razlika izmeu
funkcija puts i fputs?
Pitanje 12.10. U emu se razlikuju tekstualne i binarne datoteke?
Pitanje 12.11. Navesti prototip funkcije fopen. Koju vrednost vraa ova
funkcija ukoliko se datoteka ne moe otvoriti?
297 12. Ulaz i izlaz programa
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
fprintf ipak bude prazna. Zato se to moe desiti?
5)
kraj datoteke sa datotekim pokazivaem p?
Pitanje 12.15.
01
Ukratko opisati funkcije za odreivanje mesta u datoteci.
Pitanje 12.16. emu slue funkcije fseek i fsetpos? Da li one isto rade za
(2
tekstualne i binarne datoteke?
je
lnu datoteku?
an
Pitanje 12.18. Navesti prototip funkcije main sa argumentima.
Pitanje 12.19. Kako se, u okviru funkcije main, moe ispisati ime programa
d
koji se izvrava?
iz
Zadatak 12.1. Napisati funkciju main koja izraunava i ispisuje zbir svih
argumenata navedenih u komandnoj liniji (pretpostaviti da e svi argumenti
int).
o
Zadatak 12.2. Napisati program koji iz datoteke, ije se ime zadaje kao prvi
argument komandne linije, ita prvo dimenziju kvadratne matrice , a za-
n
dinamiki alocirati. Nakon toga, na standardni izlaz ispisati redni broj kolone
koja ima najvei zbir elemenata. Na primer, za datoteka sa sadrajem:
kt
3
1 2 3
le
7 3 4
5 3 1
E
program treba da ispie redni broj 0 (jer je suma elemenata u nultoj koloni
1 + 7 + 5 = 13, u prvoj 2 + 3 + 3 = 8, u drugoj 3 + 4 + 1 = 8).
Zadatak 12.3. Data je datoteka apsolventi.txt. 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.
5)
Napisati funkciju
unsigned btoi(char s[], unsigned char b);
s b.
01
koja odreuje vrednost zapisa datog neoznaenog broja u datoj osnovi Na-
pisati zatim i funkciju
void itob(unsigned n, unsigned char b, char s[]);
(2
n zapisuje u datoj osnovi b i smeta rezultat
koja datu vrednost u nisku s.
Napisati zatim program koji ita liniju po liniju datoteke koja se zadaje kao
prvi argument komandne linije i obrauje ih sve dok ne naie na praznu liniju.
je
Svaka linija sadri jedan dekadni, oktalni ili heksadekadni broj (zapisan kako
se zapisuju konstante u programskom jeziku C). Program za svaki uneti broj
an
u datoteku koja se zadaje kao drugi argument komandne linije ispisuje njegov
binarni zapis. Pretpostaviti da e svi uneti brojevi biti u opsegu tipa unsigned
.
d
iz
o
sk
n
ro
kt
le
E
Dodatak A
5)
Tabela prioriteta operatora
01
(2
je
an
d
iz
o
sk
n
ro
kt
le
E
299
300 A. Tabela prioriteta operatora
5)
+ - unarni plus/minus
! ~ logika negacija/bitski komplement
01
(type) eksplicitna konverzija tipa (cast)
* dereferenciranje
&
(2
referenciranje (adresa)
sizeof veliina u bajtovima
* / % mnoenje, deljenje, ostatak sleva na desno
+ -
je
sabiranje i oduzimanje sleva na desno
<< >> bitsko pomeranje ulevo i udesno
an
< <= relacije manje, manje jednako sleva na desno
> >= relacije vee, vee jednako
== != relacija jednako, razliito sleva na desno
d
+= -=
ro
*= /= %=
&= ^= |=
<<= >>=
kt
5)
Reenja zadataka
01
(2
je
Softver savremenih raunara
an
Reenje zadatka 1.4:
d
mov [200], 0
mov ax, 0
mov bx, 1
n
petlja:
ro
cmp ax, bx
je uvecanje
mov cx, [100]
kt
cmp cx, ax
je kraj
le
add ax, 1
jmp petlja
E
uvecanje:
mov cx, [200]
add cx, 1
mov [200], cx
add bx, cx
add bx, cx
jmp petlja
kraj:
301
302 B. Reenja zadataka
5)
(11111110)2 , (376)8 , ( )16 ,
01
Reenje zadatka 2.3:
Prevoenjem svake etvorke binarnih cifara zasebno, dobija se
(2
(48 5566293)16 .
Prevoenjem svake heksadekadne cifre zasebno dobija se
(1010 0011 1011 1111 0100 0110 0001 1100 1000 1001 1011 1110 0010 0011 1101 0111)2
24
od 0 do 2 1 = 16 777 216 = 16 , (e) 232 1 = 4 294 967 296 = 4.
5)
Reenje zadatka 2.12:
01
46 41 4b 55 4c 54 45 54, DISKRETNE
(2
Reenje zadatka 2.13:
je
Heksadekadno: 22 50 72 6f 67 72 61 6d 69 72 61 6e 6a 65 20 31 22,
Binarno: 00100010 01010000 01110010 01101111 01100111 01110010 01100001
an
01001101 01101001 01110010 01100001 01101110 01101010 01100101 00100000
00110001 00100010
d
Oktalno: 042 120 162 157 147 162 141 115 151 162 141 156 152 145 040 061
042
iz
Dekadno: 34 80 114 111 103 114 97 109 105 114 97 110 106 101 32 49 34
informatika 11 11 11 11 22 11
UCS-2 : 006b 0072 0075 017e 0069 0107 UTF-8 : 6b 72 75 c5be 69 c487
kt
Izraunljivost
le
E
= + (1 + . . . + 1) + . . . + (1 + . . . + 1)
5)
4. (1, 3) :=
5. (4) := + 1
01
6. (4, 2, 12) = ?
7. (5) := 0
(2
8. (5) := + 1
9. (3) := + 1
10. (5, 1, 5)
je
11. (1, 1, 8)
12. (3, 1) 1
an
13. (1, 1, 100)
14. (1) 0 1
d
iz
:= 0
o
=0
sk
=0
n
0 1
ro
:=
kt
:= + 1
le
=
1
E
:= 0
:= + 1
:= + 1
= =+
Odgovarajui urm program podrazumeva sledeu poetnu konfiguraciju:
1 2 3 . . .
... ...
i sledeu radnu konfiguraciju:
1 2 3 4 ...
5)
...
01
:= 0
(2
:= 0
je
=
an
>
=
d
:= + 1
:= + 1 := + 1
iz
=
o
sk
1
n
ro
1. (3) =0
2. (4) =0
3. (1, 3, 11) = ?
kt
4. (2, 3, 7) = ?
5. (3) := + 1
le
6. (1, 1, 3)
7. (3) := + 1
E
8. (4) := + 1
9. (3, 1, 11) = ?
10. (1, 1, 7)
11. (4, 1) 1
Jezik C - uvod
#include <stdio.h>
#include <math.h>
#include <assert.h>
int main() {
double r;
printf("Unesi poluprecnik kruga: ");
scanf("%lf", &r);
5)
assert(r > 0);
printf("Obim kruga je: %lf\n", 2*r*M_PI);
printf("Povrsina kruga je: %lf\n", r*r*M_PI);
01
return 0;
}
(2
Reenje zadatka 5.2.2:
#include <stdio.h>
je
an
#include <math.h>
int main() {
d
/* Koordinate tacaka A, B, C */
iz
double s, P;
s = (a + b + c) / 2;
P = sqrt(s*(s - a)*(s - b)*(s - c));
return 0;
}
307 B. Reenja zadataka
#include <stdio.h>
#include <math.h>
#include <assert.h>
5)
int main() {
/* Duzine stranica trougla */
double a, b, c;
01
/* Velicine uglova trougla */
double alpha, beta, gamma;
(2
printf("Unesi duzinu stranice a: ");
scanf("%lf", &a); assert(a > 0);
printf("Unesi duzinu stranice b: ");
je
scanf("%lf", &b); assert(b > 0);
printf("Unesi ugao gama (u stepenima): ");
an
scanf("%lf", &gamma);
d
u radijane i obratno. */
c = sqrt(a*a + b*b - 2*a*b*cos(gamma*M_PI/180.0));
o
return 0;
}
le
#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
#include <stdio.h>
#include <assert.h>
int main() {
5)
/* Pocetna brzina u m/s, ubrzanje u m/s^2 i vreme u s*/
double v0, a, t;
01
printf("Unesi pocetnu brzinu (u m/s): ");
scanf("%lf", &v0);
(2
printf("Unesi ubrzanje (u m/s^2): ");
scanf("%lf", &a);
printf("Unesi vreme: ");
scanf("%lf", &t); assert(t >= 0);
je
printf("Trenutna brzina (u m/s) je : %lf\n", v0+a*t);
an
printf("Predjeni put (u m) je : %lf\n", v0*t+a*t*t/2);
return 0;
d
}
iz
#include <stdio.h>
n
int main() {
double a1, a2, a3, a4, a5, a6, a7, a8, a9;
ro
a4 a5 a6 a4 a5
a7 a8 a9 a7 a8
E
#include <stdio.h>
int main() {
int a1, a2, a3; /* brojevi */
int m; /* maksimum brojeva */
printf("Unesi tri broja: ");
scanf("%d %d %d", &a1, &a2, &a3);
m = a1;
5)
if (a2 > m)
m = a2;
if (a3 > m)
01
m = a3;
printf("Maksimum je: %d\n", m);
(2
return 0;
}
je
Reenje zadatka 5.2.8:
an
#include <stdio.h>
d
int main() {
iz
int a, b, i;
scanf("%d%d", &a, &b);
for (i = a; i <= b; i++)
o
printf("%d\n", i*i*i);
sk
return 0;
}
n
Jezik C - izrazi
ro
kt
#include <stdio.h>
E
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;
}
s1 = 60 - s;
m1 = 59 - m;
5)
h1 = 23 - h;
if (s1 == 60) {
s1 = 0;
01
m1++;
}
(2
if (m1 == 60) {
m1 = 0;
h1++;
}
#include <stdio.h>
sk
int main() {
double x, y, z;
n
else
printf("Trougao ne postoji\n");
le
return 0;
}
E
#include <stdio.h>
int main() {
/* Broj cija se suma cifara racuna */
int n;
/* Cifre broja*/
311 B. Reenja zadataka
5)
c0 = n % 10;
c1 = (n / 10) % 10;
01
c2 = (n / 100) % 10;
c3 = (n / 1000) % 10;
(2
printf("Suma cifara je: %d\n", c0 + c1 + c2 + c3);
return 0;
}
je
an
Reenje zadatka 6.4.4:
d
#include <stdio.h>
iz
int main() {
unsigned n, c0, c1; /* broj, poslednja i pretposlednja cifra */
o
scanf("%d", &n);
c0 = n % 10;
c1 = (n / 10) % 10;
n
#include <stdio.h>
int main() {
/*
(0, 0) -> 1
(0, 1) -> 2 (1, 0) -> 3
(2, 0) -> 4 (1, 1) -> 5 (0, 2) -> 6
(0, 3) -> 7 (1, 2) -> 8 (2, 1) -> 9 (3, 0) -> 10
...
*/
312 B. Reenja zadataka
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;
5)
else
n = z*(z + 1)/2 + y + 1;
printf("Redni broj u cik-cak nabrajanju je: %u\n", n);
01
return 0;
}
(2
Reenje zadatka 6.4.6:
#include <stdio.h>
je
an
int main() {
double A, B;
d
else if (B == 0)
sk
return 0;
ro
}
kt
#include <stdio.h>
E
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
D = a1*b2 - b1*a2;
/* Determinanta promenljive x:
c1 b1
c2 b2
*/
Dx = c1*b2 - b1*c2;
/* Determinanta promenljive y:
a1 c1
5)
a2 c2
*/
Dy = a1*c2 - c1*a2;
01
if (D != 0)
printf("x = %lf\ny = %lf\n", Dx / D, Dy / D);
(2
else if (Dx == 0 && Dy == 0)
printf("Sistem ima beskonacno mnogo resenja\n");
else
printf("Sistem nema resenja\n");
return 0;
je
an
}
d
#include <stdio.h>
o
#include <math.h>
sk
#include <assert.h>
int main() {
n
float a, b, c; /* koeficijenti */
ro
float D; /* diskriminanta */
printf("Unesi koeficijente a, b, c"
" kvadratne jednacine ax^2 + bx + c = 0: ");
kt
D = b*b - 4*a*c;
if (D > 0) {
E
#include <stdio.h>
int main() {
unsigned n; /* broj koji se ispituje */
5)
unsigned d; /* kandidat za delioca */
scanf("%u", &n);
for (d = 1; d <= n; d++)
01
if (n % d == 0)
printf("%u\n", d);
(2
return 0;
}
je
Reenje zadatka 6.4.10:
an
#include <stdio.h>
d
#include <ctype.h>
iz
int main() {
int c;
while ((c = getchar()) != . && c != , && c != EOF)
o
putchar(toupper(c));
sk
}
n
Jezik C - nizovi
ro
#include <stdio.h>
E
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
5)
/* Odredjivanje i ispis zbira */
zbir = 0;
for (i = 0; i < n; i++)
01
zbir += a[i];
printf("zbir = %d\n", zbir);
(2
/* Odredjivanje i ispis maksimuma */
max = a[0];
for (i = 1; i < n; i++)
je
if (a[i] > max)
max = a[i];
an
printf("max = %d\n", max);
return 0;
d
}
iz
#include <stdio.h>
n
int main() {
ro
int b[10], i;
b[i] = 0;
le
b[c - 0]++;
return 0;
}
#include <stdio.h>
#include <assert.h>
5)
int main() {
int d, m, g, b, M;
/* Broj dana po mesecima. Niz je napravljen tako da se broj dana za
01
mesec m moze ocitati sa br_dana[m].
*/
(2
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 */
je
if (g < 0) {
printf("Pogresna godina\n");
an
return 1;
}
if (m < 1 || m > 12) {
d
printf("Pogresan mesec\n");
iz
return 1;
}
if (d < 1 || d > (m == 2 && prestupna(g) ? 29 : br_dana[m])) {
o
printf("Pogresan dan\n");
sk
return 1;
}
n
b = 0;
ro
b += br_dana[M];
/* Broj dana u tekucem mesecu */
b += d;
le
b++;
printf("%d\n", b);
return 0;
}
#include <stdio.h>
317 B. Reenja zadataka
#include <ctype.h>
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 */
5)
/* (n n) = 1 */
a[n] = 1;
for (k = n-1; k > 0; k--)
01
/* (n k) = (n-1 k) + (n-1 k-1) */
a[k] = a[k] + a[k-1];
(2
/* (n 0) = 1 */
/* a[0] = 1; -- ovo vec vazi */
je
for (k = 0; k <= n; k++)
printf("%d ", a[k]);
an
printf("\n");
}
d
return 0;
iz
}
o
#include <stdio.h>
n
#include <assert.h>
ro
int main() {
int n, A[10][10], i, j, s;
kt
/* ucitavamo matricu */
scanf("%d", &n); assert(0 < n && n <= 10);
le
scanf("%d", &A[i][j]);
return 0;
}
5)
01
#include <stdio.h>
#include <assert.h>
(2
int main() {
int n, A[100][100], i, j, dt;
/* ucitavamo matricu */
je
scanf("%d", &n); assert(0 < n && n <= 100);
for (i = 0; i < n; i++)
an
for (j = 0; j < n; j++)
scanf("%d", &A[i][j]);
/* proveravamo da li je matrica donjetrougaona */
d
dt = 1;
iz
dt = 0;
sk
#include <stdio.h>
#include <math.h>
int main() {
/* Najveci broj */
COMPLEX max_z;
319 B. Reenja zadataka
/* Najveci moduo */
double max_m = 0.0;
int i;
for (i = 0; i < 10; i++) {
/* Tekuci broj */
COMPLEX z;
/* Moduo tekuceg broja */
5)
double z_m;
/* Ucitavanje */
scanf("%lf%lf", &z.Re, &z.Im);
01
/* Racunanje modula */
z_m = sqrt(z.Re*z.Re + z.Im*z.Im);
(2
/* Azuriranje najveceg */
if (z_m > max_m) {
max_z = z;
max_m = z_m;
je
}
}
an
printf("%lf + i*%lf\n", max_z.Re, max_z.Im);
return 0;
}
d
iz
#include <stdio.h>
#include <assert.h>
n
int main() {
ro
printf("Vikend\n");
else
E
printf("Radni dan\n");
return 0;
}
Jezik C - naredbe
#include <stdio.h>
320 B. Reenja zadataka
int main() {
int n, i;
printf("Unesi gornju granicu: ");
scanf("%d", &n);
for (i = 1; i < n; i += 2)
printf("%d ", i);
printf("\n");
5)
return 0;
}
01
Reenje zadatka 7.2:
(2
#include <stdio.h>
#include <math.h>
int main() {
je
an
int N = 100;
double l = 0.0, d = 2*M_PI;
double h = (d - l) / (N - 1);
d
double x;
iz
printf(" x sin(x)\n");
for (x = l; x <= d; x += h)
printf("%4.2lf %7.4lf\n", x, sin(x));
o
return 0;
sk
}
n
#include <stdio.h>
kt
int main() {
le
double x, s;
unsigned n, i;
E
#include <stdio.h>
#define N 4
5)
int main() {
int i, j;
01
/* Deo (a): */
(2
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++)
putchar(*);
putchar(\n);
je
}
an
printf("--------------\n");
d
/* Deo (b): */
for (i = 0; i < N; i++) {
iz
}
sk
printf("--------------\n");
n
/* Deo (c): */
ro
putchar(*);
putchar(\n);
}
le
printf("--------------\n");
E
/* 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
/* 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);
5)
}
printf("--------------\n");
01
/* Deo (f): */
(2
for (i = 0; i < N; i++) {
for (j = 0; j < i; j++)
putchar( );
for (j = 0; j < N - i - 1; j++) {
je
putchar(*); putchar( );
}
an
putchar(*);
putchar(\n);
}
d
iz
printf("--------------\n");
/* Deo (g): */
o
putchar(*); putchar( );
ro
}
putchar(*);
kt
putchar(\n);
}
le
return 0;
E
#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
*/
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)
5)
s += d + n / d;
if (d * d == n)
s += d;
01
printf("Suma: %u\n", s);
return 0;
(2
}
je
an
#include <stdio.h>
#include <assert.h>
d
*/
ro
int main() {
unsigned n, d;
int prost;
kt
scanf("%d", &n);
assert(n > 1); /* Brojevi <= 1 nisu ni prosti ni slozeni */
le
prost = 0;
printf("Broj je %s\n", prost ? "prost" : "slozen");
return 0;
}
#include <stdio.h>
324 B. Reenja zadataka
int main() {
unsigned n, d;
/* Ucitavamo broj */
scanf("%u", &n);
5)
zavrsava kada trenutni broj postane prost */
while (d*d <= n) {
/* Broj je deljiv sa d - dakle, d je prost cinioc. Zaista, ako d
01
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
(2
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);
je
n /= d;
} else
an
/* Broj nije deljiv sa d, pa prelazimo na narednog kandidata */
d++;
}
d
if (n > 1)
printf("%u\n", n);
return 0;
o
}
sk
#include <stdio.h>
#include <limits.h>
kt
#include <math.h>
le
int main() {
int a; /* broj koji se unosi */
E
p *= a;
if (a < min) min = a;
if (a > max) max = a;
sr += 1.0/a;
}
if (n == 0) {
printf("Nije unet nijedan broj\n");
return 1;
5)
}
printf("broj: %d\n", n);
printf("zbir: %d\n", s);
01
printf("proizvod: %d\n", p);
printf("minimum: %d\n", min);
(2
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);
return 0;
je
an
}
d
#include <stdio.h>
o
sk
int main() {
int ts = 0; /* Tekuca serija */
int ns = 0; /* Najduza serija */
n
scanf("%d", &pb);
if (pb != 0) {
kt
ts = ns = 1;
while(1) {
le
scanf("%d", &tb);
if (tb == 0) break; /* Prekidamo kada je uneta 0 */
E
ns = ts;
5)
return 0;
}
01
Reenje zadatka 7.10:
(2
#include <stdio.h>
je
int main() {
/* Izracunava se ceo deo korena unetog broja x. Trazi se interval
an
oblika [n^2, (n+1)^2] = [N1, N2] tako da mu x pripada i tada je n
ceo deo korena iz x.
*/
d
unsigned x;
iz
/* Ucitava se broj x */
o
scanf("%d", &x);
sk
while (x != N1) {
ro
N1++;
if (N1 == N2) {
/* Prelazi se na sledeci interval */
kt
unsigned l;
/* Uvecava se malo n */
le
n++;
/* N2 je potrebno uvecati za 2*n+1 */
E
N2++;
l = 0;
do {
l++;
N2 += 2;
} while (l != n);
}
}
/* Ispis rezultata */
printf("%d\n", n);
}
327 B. Reenja zadataka
#include <stdio.h>
#include <math.h>
5)
int main() {
double xp, x, a;
printf("Unesite broj: ");
01
scanf("%lf", &a);
x = 1.0;
(2
do {
xp = x;
x = xp - (xp * xp - a) / (2.0 * xp);
printf("%lf\n", x);
je
} while (fabs(x - xp) >= EPS);
printf("%lf\n", x);
an
return 0;
}
d
iz
#include <stdio.h>
sk
int main() {
n
unsigned fpp = 1, fp = 1, k;
scanf("%d", &k);
ro
if (k == 0) return 0;
printf("%d\n", fpp);
kt
if (k == 1) return 0;
printf("%d\n", fp);
k -= 2;
le
while (k > 0) {
unsigned f = fpp + fp;
E
printf("%d\n", f);
fpp = fp; fp = f;
k--;
}
return 0;
}
#include <stdio.h>
int main() {
unsigned n;
printf("Unesi broj: ");
scanf("%u", &n);
do {
/* Poslednja cifra broja */
5)
printf("%u\n", n % 10);
/* Brisemo poslednju cifru broja */
n /= 10;
01
} while (n > 0);
return 0;
(2
}
#include <stdio.h>
je
int main() {
unsigned n, suma = 0;
an
printf("Unesi broj: ");
scanf("%u", &n);
do {
d
suma += n % 10;
iz
n /= 10;
} while (n > 0);
printf("Suma cifara broja je: %u\n", suma);
o
return 0;
sk
}
n
#include <stdio.h>
int main() {
le
scanf("%d", &n2);
5)
Reenje zadatka 7.15:
01
#include <stdio.h>
(2
int main() {
unsigned n; /* polazni broj */
je
unsigned o = 0; /* obrnuti broj */
scanf("%d", &n);
an
do {
/* poslednja cifra broja n se uklanja iz broja n i
dodaje na kraj broja o */
d
o = 10*o + n % 10;
iz
n /= 10;
} while (n > 0);
printf("%d\n", o);
o
return 0;
sk
}
n
#include <stdio.h>
kt
int main() {
le
r = c * s + r;
s *= 10;
}
}
/* Ispis rezultata */
printf("%u\n", r);
return 0;
}
5)
Reenje zadatka 7.17:
01
#include <stdio.h>
(2
int main() {
unsigned n, s = 1;
unsigned char p, c;
je
scanf("%u%hhu%hhu", &n, &p, &c);
an
/* s = 10^p */
while (p > 0) {
s *= 10;
d
p--;
iz
}
ro
int main() {
unsigned n, a, tmp, s, poc, sred, kraj;
scanf("%u", &n);
5)
/* Prva cifra */
poc = n / s;
01
/* Cifre izmedju prve i poslednje */
sred = (n % s) / 10;
(2
/* Poslednja cifra */
kraj = n % 10;
je
printf("%u\n", s*kraj + 10 * sred + poc);
an
return 0;
}
d
iz
/* Rotiranje ulevo */
#include <stdio.h>
o
int main() {
sk
unsigned n, tmp, s;
scanf("%u", &n);
n
tmp /= 10;
}
E
return 0;
}
/* Rotiranje udesno */
#include <stdio.h>
332 B. Reenja zadataka
int main() {
unsigned n, tmp, s;
scanf("%u", &n);
5)
while (tmp >= 10) {
s *= 10;
tmp /= 10;
01
}
(2
/* 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);
je
return 0;
}
an
Reenje zadatka 7.19:
d
iz
#include <stdio.h>
#include <assert.h>
o
sk
int main() {
int d, m, g, dm;
n
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 B. Reenja zadataka
printf("Pogresan mesec\n");
return 1;
}
/* Provera dana */
if (d < 1 || d > dm) {
printf("Pogresan dan\n");
return 1;
5)
}
/* Provera godine */
if (g < 0) {
01
printf("Pogresna godina\n");
return 1;
(2
}
printf("Uneti datum je korektan\n");
return 0;
}
je
an
Reenje zadatka 7.20:
d
#include <stdio.h>
iz
#define BROJ_PREDMETA 12
int main() {
o
/* Nabrojivi tip */
sk
int broj_jedinica;
ro
float prosek;
/* Unos podataka */
E
/* 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
uspeh = DOVOLJAN;
else if (prosek < 3.5)
uspeh = DOBAR;
else if (prosek < 4.5)
uspeh = VRLO_DOBAR;
else
uspeh = ODLICAN;
5)
/* Prijavljivanje rezultata */
switch(uspeh) {
01
case NEDOVOLJAN:
printf("Nedovoljan uspeh\n");
(2
break;
case DOVOLJAN:
printf("Dovoljan uspeh\n");
break;
je
case DOBAR:
printf("Dobar uspeh\n");
an
break;
case VRLO_DOBAR:
printf("Vrlo dobar uspeh\n");
d
break;
iz
case ODLICAN:
printf("Odlican uspeh. Cestitamo!\n");
break;
o
case GRESKA:
sk
return 0;
}
kt
#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 */
5)
/* Azuriramo prosek prethodnih */
s = x; n = 1;
01
/* Obradjujemo ostale brojeve dok se ne pojavi 0 */
while (x != 0) {
(2
scanf("%d", &x);
if (x < m) {
printf("Manji od minimuma: %d\n", x);
/* Azuriramo vrednost minimuma */
je
m = x;
}
an
if (x > s / n)
printf("Veci od proseka prethodnih: %d\n", x);
/* Azuriramo prosek prethodnih */
d
s += x; n++;
iz
return 0;
o
}
sk
#include <stdio.h>
kt
int main() {
unsigned a[1000], n, i, j;
le
scanf("%d", &n);
E
/* Stampamo niz */
for (i = 0; i < n; i++)
336 B. Reenja zadataka
return 0;
}
5)
#include <stdio.h>
01
#include <assert.h>
int main() {
(2
int a[100], b[100]; /* Ulazni nizovi */
int na, nb; /* Njihov broj elemenata */
int p[100], u[200], r[100]; /* Presek, unija, razlika */
je
int np, nu, nr; /* Njihov broj elemenata */
int i, j, k; /* Pomocne promenljive */
an
/* Ucitavamo niz a proveravajuci da se uneti elementi ne ponavljaju */
printf("Unesi broj elemenata niza a: ");
d
scanf("%d", &na);
iz
assert(a[i] != a[j]);
sk
scanf("%d", &nb);
for (i = 0; i < nb; i++) {
scanf("%d", &b[i]);
kt
}
E
/* ------------------------------------------------------- */
/* 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
}
}
}
/* Ispisujemo elemente preseka */
printf("Presek: ");
for (i = 0; i < np; i++)
printf("%d ", p[i]);
printf("\n");
5)
/* ------------------------------------------------------- */
01
/* unija - u niz u kopiramo sve elemente niza a i za njima sve
elemente niza b koji se ne javljaju u a */
(2
/* Kopiramo niz a u niz u */
nu = 0;
for (i = 0; i < na; i++)
u[nu++] = a[i];
je
for (i = 0; i < nb; i++) {
/* Trazimo b[i] u nizu a */
an
for (j = 0; j < na; j++)
if (b[i] == a[j])
break;
d
ga dodajemo u uniju u */
if (j == na)
u[nu++] = b[i];
o
}
sk
printf("\n");
kt
/* ------------------------------------------------------- */
/* razlika - u niz r kopiramo sve elemente niza a koji se ne
le
javljaju u nizu b */
nr = 0;
E
printf("Razlika: ");
for (i = 0; i < nr; i++)
printf("%d ", r[i]);
printf("\n");
return 0;
}
5)
Reenje zadatka 7.24:
01
#include <stdio.h>
#include <string.h>
(2
int main() {
/* Rec koja se proverava */
je
char s[] = "anavolimilovana";
/* Bulovska promenljiva koja cuva rezultat */
an
int palindrom = 1;
int i, j;
for (i = 0, j = strlen(s) - 1; i < j && palindrom; i++, j--)
if (s[i] != s[j])
o
palindrom = 0;
sk
/* Ispisujemo rezultat */
if (palindrom)
n
else
printf("Rec %s nije palindrom\n", s);
}
kt
le
#include <stdio.h>
#include <string.h>
int main() {
/* Niska koja se obrce */
char s[] = "Zdravo";
5)
}
01
Reenje zadatka 7.26:
(2
#include <stdio.h>
#include <assert.h>
je
#define MAX 100
an
int main() {
unsigned n, i, j, k;
int m[MAX][MAX];
d
iz
/* Ucitavanje matrice */
scanf("%u", &n);
assert(n < MAX);
o
}
E
return 0;
}
#include <stdio.h>
#include <assert.h>
int main() {
unsigned m, n, i, j;
int a[MAX][MAX];
/* Ucitavamo matricu */
scanf("%d%d", &m, &n);
assert(m < MAX && n < MAX);
for (i = 0; i < m; i++)
5)
for (j = 0; j < n; j++)
scanf("%d", &a[i][j]);
01
/* Proveravamo sva polja */
for (i = 0; i < m; i++)
(2
for (j = 0; j < n; j++) {
/* Odredjujemo zbir susednih elemenata polja (i, j) */
int k, l;
int s = 0;
je
for (k = -1; k <= 1; k++)
for (l = -1; l <= 1; l++) {
an
if (k == 0 && l == 0)
continue;
if (0 <= i+k && i+k < m && 0 <= j+l && j+l < n)
d
s += a[i+k][j+l];
iz
if (s == a[i][j])
sk
return 0;
ro
}
kt
Jezik C - funkcije
le
#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 B. Reenja zadataka
return 0;
/* Ako delioc nije pronadjen, broj je prost */
return 1;
}
int main() {
/* Ucitava se broj i proverava da li je prost */
unsigned n;
5)
scanf("%u", &n);
printf(prost(n) ? "Prost\n" : "Nije prost\n");
}
01
Reenje zadatka 8.2:
(2
#include <stdio.h>
je
#include <math.h>
an
double rastojanje(double x1, double y1, double x2, double y2) {
double dx = x2 - x1, dy = y2 - y1;
return sqrt(dx*dx + dy*dy);
d
}
iz
int main() {
double xa, ya, xb, yb, xc, yc;
o
printf("%lf\n", P);
return 0;
le
}
E
#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;
}
int savrsen(unsigned n) {
return n == suma_delilaca(n);
}
5)
int main() {
unsigned n;
01
for (n = 1; n <= 10000; n++)
if (savrsen(n))
(2
printf("%u\n", n);
return 0;
}
#include <assert.h>
iz
/* Struktura razlomak */
struct razlomak {
o
};
if(a.imenilac*b.imenilac>0) {
if(a.brojilac*b.imenilac > a.imenilac*b.brojilac)
le
return 1;
else if(a.brojilac*b.imenilac == a.imenilac*b.brojilac)
E
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
5)
}
01
Reenje zadatka 8.5:
(2
#include <stdio.h>
je
int i;
for (i = 0; i < n; i++)
an
if (a[i] == x)
return 1;
return 0;
d
}
iz
if (a[i] == x)
return i;
return -1;
n
}
ro
return i;
return -1;
E
int i;
int s = 0;
for (i = 0; i < n; i++)
s += a[i];
return (double)s / (double)n;
}
5)
int min(int a[], int n) {
int i, m;
m = a[0];
01
for (i = 1; i < n; i++)
if (a[i] < m)
(2
m = a[i];
return m;
}
je
/* Pretpostavlja se da je niz neprazan */
int max_poz(int a[], int n) {
an
int i, mp;
mp = 0;
for (i = 1; i < n; i++)
d
mp = i;
return mp;
}
o
sk
return 0;
return 1;
kt
int main() {
le
#include <stdio.h>
5)
}
01
int izbaci_prvi_1(int a[], int n) {
int i;
(2
for (i = 0; i + 1 < n; i++)
a[i] = a[i + 1];
return n - 1;
}
int i;
for (i = k; i + 1 < n; i++)
n
}
kt
}
E
a[i] = a[i-1];
a[0] = x;
return n + 1;
}
5)
int i;
a[n] = a[0];
a[0] = x;
01
return n + 1;
}
(2
/* 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) {
je
int i;
for (i = n; i > k; i--)
an
a[i] = a[i-1];
a[k] = x;
return n + 1;
d
}
iz
int i, j;
ro
a[j++] = a[i];
return j;
}
le
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 B. Reenja zadataka
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);
5)
return 0;
}
01
Reenje zadatka 8.7:
(2
#include <stdio.h>
je
/* Napomena: odredjen broj funkcija u ovom zadatku se moze
implementirati i efikasnije, medjutim, uz prilicno komplikovaniji
an
kod. */
int i;
iz
}
sk
int ns = ts;
for (i = 1; i < n; i++) {
le
5)
int ns = ts;
for (i = 1; i < n; i++) {
if (a[i] >= a[i-1])
01
ts++;
else
(2
ts = 1;
if (ts > ns)
ns = ts;
}
je
return ns;
}
an
int podniz_uzastopnih(int a[], int n, int b[], int m) {
int i, j;
d
pozicije i */
sk
pocevsi od pozicije i */
if (j == m)
kt
return 1;
}
/* Nismo pronasli b unutar a (inace bi funkcija bila prekinuta sa
le
return 1) */
return 0;
E
return j == m;
}
5)
int tmp = a[n-1];
/* Sve elemente pomerimo za jedno mesto na desno */
for (i = n-1; i > 0; i--)
01
a[i] = a[i-1];
/* Raniji poslednji stavimo na pocetak */
(2
a[0] = tmp;
}
}
je
void rotiraj_levo(int a[], int n, int k) {
int i, j;
an
/* k puta rotiramo za po jednu poziciju */
for (j = 0; j < k; j++) {
/* upamtimo prvi */
d
a[n - 1] = tmp;
}
}
n
ro
5)
while (i < n)
c[k++] = a[i++];
while (j < m)
01
c[k++] = b[j++];
return k;
(2
}
je
/* Prolazimo niz paralelno sa dva kraja dok se pozicije ne
mimoidju */
an
for (i = 0, j = n-1; i < j; i++, j--) {
/* Vrsimo razmenu elemenata */
int tmp = a[i];
d
a[i] = a[j];
iz
a[j] = tmp;
}
}
o
sk
return 0;
}
#include <stdio.h>
5)
/* Funkcija radi slicno funkciji strcmp iz string.h */
int poredi(char s1[], char s2[]) {
01
/* Petlja tece sve dok ne naidjemo na prvi razliciti karakter */
int i;
for (i = 0; s[i]==t[i]; i++)
(2
if (s[i] == \0) /* Naisli smo na kraj obe niske,
a nismo nasli razliku */
return 0;
je
/* s[i] i t[i] su prvi karakteri u kojima se niske razlikuju.
an
Na osnovu njihovog odnosa, odredjuje se odnos stringova */
return s[i] - t[i];
}
d
iz
int main() {
printf("%d\n", poredi("zdravo", "svima"));
return 0;
o
}
sk
#include <stdio.h>
kt
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
5)
za re\v savanje ovog problema, od naivnog algoritma koji je ovde
naveden. */
int podniska(char str[], char sub[]) {
01
int i, j;
/* Proveravamo da li sub pocinje na svakoj poziciji i */
(2
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++)
je
/* Nismo naisli na razliku a ispitali smo
sve karaktere niske sub */
an
if (sub[j+1]==\0)
return i;
/* Nije nadjeno */
d
return -1;
iz
int main() {
o
#include <stdio.h>
le
5)
/* Nismo naisli na razliku - dakle svi karakteri se javljaju isti
broj puta */
return 1;
01
}
(2
/* Provera funkcije */
int main() {
char s[] = "tom marvolo riddle ", t[] = "i am lord voldemort";
printf("%d\n", permutacija(s, t));
je
return 0;
}
an
d
#include <stdio.h>
o
#include <assert.h>
sk
int zbir = 0;
ro
return zbir;
}
le
int i;
int zbir = 0;
assert(n < 10 && j < 10);
for (i = 0; i < n; i++)
zbir += m[i][j];
return zbir;
}
5)
int zbir = 0;
assert(n < 10);
for (i = 0; i < n; i++)
01
zbir += m[i][n-i-1];
return zbir;
(2
}
je
scanf("%d", &n); assert(1 <= n && n < 10);
for (i = 0; i < n; i++)
an
for (j = 0; j < n; j++)
scanf("%d", &m[i][j]);
return n;
d
}
iz
if (zbir_kolone(m, n, j) != zbir)
return 0;
kt
if (zbir_glavne_dijagonale(m, n) != zbir)
return 0;
if (zbir_sporedne_dijagonale(m, n) != zbir)
le
return 0;
return 1;
E
int main() {
int n, m[10][10];
n = ucitaj(m);
printf("%d\n", magicni(m, n));
return 0;
}
355 B. Reenja zadataka
#include <stdio.h>
#include <assert.h>
5)
typedef struct {
float a[MAX][MAX];
01
unsigned m, n;
} MATRICA;
(2
/* Efikasnije bi bilo prenositi matricu kao argument,
preko pokazivaca, ali to jos nije uvedeno. */
MATRICA ucitaj() {
je
MATRICA m;
unsigned i, j;
an
scanf("%u%u", &m.m, &m.n);
assert(m.n < MAX);
d
scanf("%f", &m.a[i][j]);
return m;
}
o
sk
unsigned i, j;
assert(m1.m == m2.m && m1.n == m2.n);
ro
}
E
return m;
}
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]);
5)
putchar(\n);
}
}
01
int main() {
(2
MATRICA m1, m2, m;
m1 = ucitaj(); m2 = ucitaj();
if (m1.m == m2.m && m1.n == m2.n) {
m = saberi(m1, m2);
je
ispisi(m);
}
an
if (m1.n = m2.m) {
m = pomnozi(m1, m2);
ispisi(m);
d
}
iz
return 0;
}
o
#include <stdio.h>
ro
#include <assert.h>
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);
357 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;
5)
}
void ispisi(BROJ b) {
01
int i;
for (i = b.n-1; i >= 0; i--)
(2
putchar(0 + b.c[i]);
}
je
BROJ rez;
unsigned i;
an
/* Prenos */
unsigned char p = 0;
for (i = 0; i < a.n || i < b.n; i++) {
d
unsigned char c = c1 + c2 + p;
/* Nova cifra */
rez.c[i] = c % 10;
n
p = c / 10;
}
kt
if (p > 0) {
assert(rez.n < MAX);
E
rez.c[rez.n] = p;
rez.n++;
}
return rez;
}
5)
for (j = 0; j < b.n; j++)
rez.c[i+j] += a.c[i]*b.c[j];
01
/* Normalizujemo rezultat */
p = 0;
(2
for (i = 0; i < rez.n; i++) {
unsigned char c = rez.c[i] + p;
rez.c[i] = c % 10;
p = c / 10;
je
}
/* Ako je prva cifra 0, smanjujemo broj cifara */
an
if (rez.c[rez.n-1] == 0)
rez.n--;
return rez;
d
}
iz
int main() {
BROJ a = ucitaj(), b = ucitaj(), c;
o
c = saberi(a, b);
sk
ispisi(c);
putchar(\n);
c = pomnozi(a, b);
n
ispisi(c);
ro
putchar(\n);
}
kt
Jezik C - pokazivai
le
#include <stdio.h>
#include <assert.h>
n %= 60;
*s = n;
}
int main() {
unsigned n, h, m, s;
scanf("%d", &n); assert(n < 60*60*24);
od_ponoci(n, &h, &m, &s);
5)
printf("%d:%d:%d\n", h, m, s);
return 0;
}
01
Reenje zadatka 10.8.1:
(2
#include <stdio.h>
int paran(int x) {
je
an
return x % 2 == 0;
}
d
int pozitivan(int x) {
iz
return x > 0;
}
o
int ts = 0;
/* Najduza serija je tekuca serija */
int ns = ts;
kt
if ((*f)(a[i]))
/* Nastavlja se tekuca serija */
E
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
5)
Reenje zadatka 10.5.1:
01
#include <stdio.h>
(2
size_t my_strlen(const char* s) {
const char* t;
je
for (t = s; *t; t++)
;
an
return t - s;
}
d
while(*dest++ = *src++)
;
}
o
sk
return *s - *t;
ro
void my_strrev(char* s) {
kt
char *t = s;
/* Dovodimo s ispred terminalne nule */
le
while(*s)
s++;
E
s--;
/* Obrcemo karaktere */
for (; t < s; t++, s--) {
char tmp = *s; *s = *t; *t = tmp;
}
}
}
return NULL;
}
5)
for ( ; *str; str++) {
const char *s, *t;
for (s = str, t = sub; *s && (*s == *t); s++, t++)
01
;
if (*t == \0)
(2
return str;
}
return NULL;
}
int main() {
je
an
char s[] = "abc", t[] = "def", r[4];
printf("%lu %lu\n", my_strlen(s), my_strlen(t));
my_strcpy(r, s);
d
printf("%s\n", r);
iz
my_strrev(s);
printf("%s\n", s);
printf("%d\n", my_strcmp(s, t));
o
#include <stdio.h>
le
#include <assert.h>
#include <stdlib.h>
E
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]);
5)
if (abs(a[i] - x) < abs(a[min] - x))
min = i;
01
/* Ispisujemo rezultat */
printf("a[%d] = %d\n", min, a[min]);
(2
/* Oslobadjamo niz */
free(a);
return 0;
je
}
an
Reenje zadatka 10.9.2:
d
iz
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
o
sk
#define KORAK 32
int main() {
n
int *a = NULL;
do {
if (aloc <= n) {
le
int* a_novo;
aloc += KORAK;
E
5)
if (ni > nm) {
nm = ni;
m = a[i];
01
}
}
(2
/* Ispisujemo najcesci element i njegov broj pojavljivanja */
printf("%d - %d\n", m, nm);
je
/* Oslobadjamo niz */
free(a);
an
return 0;
}
d
iz
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
n
int main() {
ro
scanf("%d", &n);
le
assert(A);
for (i = 0; i < n; i++) {
A[i] = malloc(n*sizeof(int));
assert(A[i]);
}
5)
printf("%d ", A[i][uy]);
for (j = uy-1; j >= ly+1; j--)
printf("%d ", A[lx][j]);
01
lx++; ux--; ly++; uy--;
}
(2
/* Oslobadjamo matricu */
for (i = 0; i < n; i++)
free(A[i]);
je
free(A);
an
return 0;
}
d
#include <stdio.h>
sk
#include <assert.h>
#include <stdlib.h>
n
int suma = 0, i;
for (i = 0; i < n; i++)
suma += a[i]*b[i];
kt
return suma;
}
le
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;
5)
assert(A);
for (i = 0; i < n; i++) {
A[i] = malloc(n*sizeof(int));
01
assert(A[i]);
}
(2
/* Ucitavamo elemente matrice */
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
je
scanf("%d", &A[i][j]);
an
/* Ispitujemo da li je matrica ortonormirana */
printf("%d\n", ortonormirana(A, n));
d
/* Oslobadjamo matricu */
iz
return 0;
}
n
Jezik C - ulaz/izlaz
ro
kt
#include <stdio.h>
E
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
5)
/* Racuna se zbir kolone j matrice A dimenzije n */
int zbir_kolone(int** A, unsigned n, unsigned j) {
int i, zbir = 0;
01
for (i = 0; i < n; i++)
zbir += A[i][j];
(2
return zbir;
}
je
unsigned n, i, j, max_j;
int **A, max;
an
FILE* dat;
d
if (argc < 2) {
fprintf(stderr, "Greska: nedostaje ime ulazne datoteke\n");
iz
return -1;
}
o
if (dat == NULL) {
fprintf(stderr,
n
return -1;
}
kt
/* 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;
5)
max = m;
}
}
01
/* Prijavljujemo rezultat */
(2
printf("Kolona: %u Zbir: %d\n", max_j, max);
/* Oslobadjamo matricu */
for (i = 0; i < n; i++)
je
free(A[i]);
free(A);
an
/* Zatvaramo datoteku */
fclose(dat);
d
iz
return 0;
}
o
#include <stdio.h>
ro
#include <stdlib.h>
#include <assert.h>
kt
#define KORAK 64
le
typedef struct {
char ime[20];
E
char prezime[20];
unsigned br_ispita;
} APSOLVENT;
int main() {
FILE* dat;
APSOLVENT* apsolventi = NULL, apsolvent;
unsigned aloc = 0, n = 0, i, zbir;
float prosek;
if (dat == NULL) {
fprintf(stderr,
"Greska pri otvaranju datoteke apsolventi.txt\n");
return 1;
}
5)
apsolvent.ime, apsolvent.prezime, &apsolvent.br_ispita)
== 3) {
if (n >= aloc) {
01
aloc += KORAK;
APSOLVENT* tmp = realloc(apsolventi, aloc*sizeof(APSOLVENT));
(2
assert(tmp);
apsolventi = tmp;
}
apsolventi[n++] = apsolvent;
je
}
an
/* Zatvaramo datoteku */
fclose(dat);
d
zbir = 0;
for (i = 0; i < n; i++)
zbir += apsolventi[i].br_ispita;
o
prosek = (float)zbir / n;
sk
apsolventi[i].br_ispita);
/* Oslobadjamo memoriju */
le
free(apsolventi);
E
return 0;
}
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
369 B. Reenja zadataka
5)
signed char vrednost_cifre(unsigned char c) {
if (isdigit(c)) /* Cifre */
return c-0;
01
if (isalpha(c) && islower(c)) /* Mala slova */
return c-a + 10;
(2
if (isalpha(c) && isupper(c)) /* Velika slova */
return c-A + 10;
return -1;
}
je
/* Cita zapis niske s kao broja u osnovi b. Citanje se vrsi dok se
an
javljaju validne cifre u osnovi b. Koristi se Hornerova shema. */
unsigned btoi(char s[], unsigned char b) {
unsigned rez = 0, i;
d
rez = rez * b;
sk
rez += c;
}
return rez;
n
}
ro
return 0 + c;
else if (10 <= c && c <= 36)
E
return a + c;
}
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;
5)
}
}
01
int main(int argc, char* argv[]) {
/* Broj u osnovi b koji se ucitava (niska cifara i vrednost) */
(2
char s[MAX_DIGITS];
unsigned n;
/* Preveden broj u osnovu 2 */
char bs[MAX_DIGITS];
je
/* Datoteke iz kojih se ucitava i u koje se upisuje */
FILE *ulaz, *izlaz;
an
/* Otvaranje datoteka */
if (argc < 3) {
d
return 1;
}
ulaz = fopen(argv[1], "r");
o
if (ulaz == NULL) {
sk
if (izlaz == NULL) {
fprintf(stderr, "Greska prilikom otvaranja %s\n", argv[2]);
kt
return 1;
}
le
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);
371 B. Reenja zadataka
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);
5)
}
} else {
/* Dekadni broj */
01
n = btoi(t, 10);
printf("%u\n", n);
(2
itob(n, 2, bs);
fputs(bs, izlaz); fputc(\n, izlaz);
}
}
/* Zatvaramo datoteke */
je
an
fclose(ulaz);
fclose(izlaz);
return 0;
d
}
iz
o
sk
n
ro
kt
le
E
372
E
le
kt
ro
n
sk
o
iz
d
an
je
(2
01
B. Reenja zadataka
5)
5)
Indeks
01
(2
32-bitni i 64-bitni sistem, 105, 219 getc, 289
getchar, 278
je
abakus, 12 gets, 279
ABC (raunar), 15 isalnum, 274
an
algoritam, 61 isalpha, 107, 274
analitika maina, 13 isdigit, 107
d
asembler, 29
automatska promenljiva, 200 printf, 93, 280
putc, 289
n
biblioteka funkcija
rand, 272
assert, 276 realloc, 260, 272
calloc, 258, 272
kt
sscanf, 286
fgets, 291 strcat, 269
fopen, 287 strchr, 269
fprintf, 292 strcmp, 269
fputs, 279, 291 strcpy, 136, 248, 269
fread, 292 strlen, 135, 247, 269
free, 259, 272 strstr, 269
fscanf, 292 system, 272
fseek, 293 tolower, 107, 274
ftell, 293 toupper, 107, 274
fwrite, 292
373
374 B. Reenja zadataka
5)
oktalni, 41, 109 deklaracija, 94, 168, 169
buena kartica, 13, 14 main, 93, 167, 190, 294
01
parametar, 170
C (programski jezik), 18 poziv, 168
(2
ANSI/ISO C, 92 prenos argumenata, 171, 223
C11, 92 prenos argumenata po adresi,
C99, 92 239
je
curenje memorije, 262 prenos argumenata po vrednosti,
171
an
er-Tjuringova teza, 63
prenos niza, 174, 242
prototip, vidi funkcija (deklaracija)
datoteka, 286
sa promenljivim brojem argu-
d
binarna, 287
menata, 179
iz
tekstualna, 287
void, 171
datoteka zaglavlja, 94, 186, 194, 269
funkcionalna dekompozicija programa,
<assert.h>, 276
192
o
generacije raunara, 16
<stdio.h>, 94, 277 generisanje i optimizacija koda, 187
<stdlib.h>, 258, 272
n
glif, 48
<string.h>, 269
ro
naelna, 204
izvravanje, 210, 230, 235, 262
stvarna, 204
kompilacija, 209
le
diferencijska maina, 13
digitalni zapis, 38, 39 halting problem, 72
dinamika alokacija memorije, 258 hard disk, 26
doseg identifikatora, 83, 103, 192, hardver, 11, 16, 22
198 hip, vidi segment memorije (hip)
Holeritova maina, 13
EDVAC raunar, 16
Hornerova ema, 42
elektromehanike maine, 13
ENIAC (raunar), 15 identifikator, 102, 169
enigma maina, 15 IEEE 754 standard, 47, 107, 127
375 B. Reenja zadataka
5)
izvrni program, 79, 87, 94, 185, const, 103, 171, 174, 235
218 extern, 193, 205
01
long, 104
jedinica prevoenja, 186, 192, 194, long long, 104
(2
203 register, 193
jeziki procesor, vidi programski pre- short, 104
vodilac signed, 104, 106
je
static, 193, 200, 202, 205, 207
karakter, 48
unsigned, 104, 106
an
kardinalnost, 69
kastovanje, vidi konverzija tipova (ek- l-vrednost, 114, 115, 134, 241
splicitna) Lajbnicova maina, 12
d
199, 200
windows-125x/ANSI, 51
YUSCII, 50 magistrala, 23
kt
5)
prefiksni, 112, 115
naredba, 85 prioritet, 113
01
break, 155, 159 referenciranja, 234, 244
continue, 160 relacijski, 104, 107, 117
do-while, 99, 158
(2
sizeof, 123, 134, 142, 241
for, 98, 157 sloene dodele, 121
goto, 151 uslovni, 122
if, 97, 152
je
zarez, 122
izraza, 151
an
return, 94, 168, 174 parametar funkcije, 86
switch, 155 prenos po adresi, 86
while, 98, 156 prenos po vrednosti, 86
d
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 define, 98, 194
->, 253 if-elif-endif, 197
adresni, 234 ifdef/ifndef, 197
aritmetiki, 104, 107, 114 include, 94, 193
377 B. Reenja zadataka
5)
asemblerski, 28 sistemski, 34, 91
mainski, 27, 28, 33, 87 standardna biblioteka programskog
01
mainski zavisan, 26 jezika, 86, 93, 188, 269
vii, 17, 27, 79, 87 standardni izlaz, 93, 277
(2
programski prevodilac, 78, 87, 94 standardni izlaz za greke, 208, 277
gcc, 94, 96, 187189, 210, 220 standardni ulaz, 95, 277
promenljiva, 83, 101 statika promenljiva, 201, 202
je
deklaracija, 95, 101, 102 stek, vidi segment memorije (stek)
inicijalizacija, 99, 102 string, vidi niska
an
propratni efekat, 114, 115 struktura, 140
punilac, 190 definicija, 141
inicijalizacija, 142
d
tranzistor, 17
5)
vakuumska cev, 17
vektorska grafika, 55
01
Z3 (raunar), 14
zapis
(2
fiksni zarez, 47
neoznaeni brojevi, 41
oznaena apsolutna vrednost, 45
je
oznaeni brojevi, 45
an
pokretni zarez, 47, 107
potpuni komplement, 45
realni brojevi, 46
d
slika, 55
iz
tekst, 48
zvuk, 56
o
akardov razboj, 13
sk