Download as pdf or txt
Download as pdf or txt
You are on page 1of 113

Robert Logožar

Uvod u programiranje
i
jezik C/C++

Vježbe
Uvod u programski jezik C/C++. Vježbe 1

Predgovor
Vježbe 1 iz programskog jezika C/C++ temelje se i sadržajno slijede udžbenički tekst Uvod u prog-
ramski jezik C/C++ [1]. Namijenjene su izvođenju vježbi na uvodnim kolegijima programiranja na
višim i visokim učilištima. Slijede uobičajeni pristup izlaganja gradiva u kojem se najprije savladava-
ju osnove proceduralnog (funkcijskog) programiranja, što se u bitnom izvodi primjenom jezika C
kao podskupa objektno orijentiranog jezika C++, ali koristeći sintaksu i specifičnosti jezika C++, te
suvremene razvojne okoline za rad s njima.
Osnovne ideje vodilje kod izbora zadataka obrazložene su u uvodu navedenog udžbeničkog teksta
[1]. Gdje god je to bilo moguće, pogotovo u kasnijim vježbama, nastojali smo privući čitatelja zanim-
ljivim problemima. Ponovimo ovdje ukratko da smo nastojali odabrati zadatke prikladne za određenu
temu, nastojeći ujedno da njihova rješenja budu i uzorna i primjenjiva u širem kontekstu.
Nadamo se da će upravo problemski pristup kojim se rukovodimo kroz ove primjere i zadatke, po-
nukati mnoge studente da dublje uđu u područje programiranja i računarstva.

Robert Logožar, ožujak 2009.

i
ii
iii

Sadržaj
Uvod u programski jezik C/C++. Vježbe 1.......................................................i 
Predgovor ..............................................................................................................i 
I.  Uvod ........................................................................................................... 1 
I.1  Vježbe iz programiranja .......................................................................... 1 
I.2  Samostalnost u radu ................................................................................. 1 
I.3  Dnevnik vježbi ........................................................................................... 2 
I.4  Pripreme za vježbe ................................................................................... 3 
I.5  Citiranje literature.................................................................................... 4 
I.6  Etički kodeks ............................................................................................. 4 
Vježba 1.  Osnovni pojmovi u programiranju. Organizacija rada na
računalu 6 
1.1  Algoritmi, programski jezici, programi i programiranje ...................................... 6 
1.2  Organizacija rada na računalu ................................................................................ 8 
1.3  Rezime i zaključak vježbe Vježba 1......................................................................... 9 

Vježba 2.  Od pisanja do izvođenja programa. Integrirana razvojna


okolina. Prvi program u C++: “Zdravo svijete!” ........................................ 10 
2.1  Osnove sintakse jezika C / C++ .............................................................................. 10 
2.2  Kreiranje izvorne datoteke u uređivaču teksta. Kompilacija uz „ručno“
pokretanje prevodioca ....................................................................................................... 10 
2.3  Integrirana razvojna okolina Dev-C++ ................................................................. 13 
2.4  Integrirana razvojna okolina MS© Visual Studio 2005 ...................................... 15 
2.5  Rezime i zaključak vježbe Vježba 2....................................................................... 17 

Vježba 3.  Osnovni tipovi podataka u C / C++ .......................................... 20 


3.1  Teorijska priprema ................................................................................................. 20 
3.2  Primjeri i zadaci ...................................................................................................... 21 

Vježba 4.  Osnovni operatori u jeziku C / C++ ......................................... 37 


4.1  Teorijska priprema ................................................................................................. 37 
4.2  Primjeri i zadaci ...................................................................................................... 39 
iv

Vježba 5.  Organizacija izvornog koda, programske strukture, i kontrola


toka programa ................................................................................................... 49 
5.1  Teorijska priprema ................................................................................................. 49 
5.2  Primjeri i zadaci ...................................................................................................... 51 

Vježba 6.  Osnovna podatkovna struktura – poredak .............................. 63 


6.1  Teorijska priprema ................................................................................................. 63 
6.2  Primjeri i zadaci ...................................................................................................... 65 

Vježba 7.  Kazaljke – pokazivački tip. Navodi (reference) ...................... 75 


7.1  Teorijska priprema ................................................................................................. 75 
7.2  Primjeri i zadaci ...................................................................................................... 77 

Vježba 8.  C (C++) funkcije.......................................................................... 88 


8.1  Teorijska priprema ................................................................................................. 88 
8.2  Primjeri i zadaci ...................................................................................................... 88 

Vježba 9.  Znakovni poredci i C-nizovi. Primjer uporabe C funkcija .. 98 


9.1  Teorijska priprema ................................................................................................. 98 
9.2  Primjeri i zadaci ...................................................................................................... 98 

Literatura ......................................................................................................... 107 


I. Uvod
U ovom uvodnom tekstu osvrnut ćemo se na cilj i način provođenja vježbi iz programiranja, kao i na
neke opće odrednice praktičnog rada u računarskim učionicama.

I.1 Vježbe iz programiranja


Programiranje predstavlja umijeće i vještinu koju je potrebno izgrađivati učenjem teorijskih postavki,
te njihovom primjenom kroz studiranje riješenih primjera i samostalnim rješavanjem problemskih za-
dataka. Iako je danas gotovo podrazumijevajuće da se vježbe održavaju na računalima,* valja istaknuti
da je programiranje u prvom redu apstraktna intelektualna djelatnost, za koju je neophodno [1]:
i. razumijevanje problema ili zadatka koji rješavamo;
ii. osmišljavanje rješenja i njegovo izražavanje u algoritamskom obliku;
iii. poznavanje programskog jezika (alata) u kojem se to rješenje piše.
Korištenje programskih razvojnih okolina uvelike pomaže prilikom kreiranja programa, i danas je
profesionalno programiranje bez njih nezamislivo. No s druge strane, desetljećima se uspješno prog-
ramiranje radilo i na papiru. Dakle, nikakve pogodnosti koje pružaju suvremeni alati za kreiranje sof-
tvera ne mogu umanjiti potrebu za potpunim ovladavanjem gore navedenih točaka.
U tom je smislu nužno da studenti najprije upoznaju teorijsko gradivo, prošire svoje temeljno zna-
nje, i tek potom pristupe izradi vlastitih programskih rješenja. Drugim riječima, uspješno praćenje
izloženih primjera i zadataka zahtijeva vladanje gradivom osnova programiranja, i jezika C/C++.
Svaka vježba prati gradivo izneseno u udžbeniku [1], u poglavlju istog broja, a njen početak je naj-
češće razrada tamo iznesenih primjera. Stoga je prvi i nužan korak u savladavanju svake vježbe prou-
čavanje odgovarajućeg poglavlja udžbenika. Iz njega slijede koncepti, smjernice i konkretni naputci
za rješavanje ovdje navedenih problema i zadataka.
Koncepcija vježbi je takva da studente potakne na promišljanje svih koraka prilikom programira-
nja, te na razvijanje kreativnog pristupa. Programiranje počinje od dobre analize problema, nastavlja
se nalaženjem „apstraktnog rješenja u glavi“ ― bilo da je ono izraženo dijagramom toka, pseudoko-
dom, ili je jednostavno ostalo bez eksplicitne prezentacije ― i tek na koncu slijedi realizacija rješenja
u konkretnom programskom jeziku. Izvrsna svojstva, te elegantnost sintakse jezika C / C++, doprino-
se razvoju dobrog i logički korektnog promišljanja problema na apstraktnoj razini, i omogućuju nji-
hovu izravnu prezentaciju u programskom kodu.

I.2 Samostalnost u radu


Kao i u svakom drugom području, usvajanje znanja i vještina iz programiranja je nemoguće bez teme-
ljitog studiranja i promišljanja, baziranog u prvom redu na zalaganju i samostalnom radu. Najbolja
literatura, najbolji uvjeti, i predavači sami, ne mogu nadomjestiti trud i želju studenata za spoznajom i
uspješnim savladavanjem zadataka.

*
Engl. termin je “hands on”, dakle ruke su na računalu, programiramo koristeći prikladne softverske alate.

1
2

Prilikom samostalnog rada, student mora nove spoznaje usklađivati sa svojim temeljnim znanjima
usvojenim iz prethodnog školovanja. U tom procesu produbljuje i sređuje prethodna znanja, te omo-
gućuje da se na dobrim temeljima izgrađuje kvalitetna nadgradnja.
Dobro stručno i praktično znanje mora se temeljiti na dobrom razumijevanju teorije, bez obzira o
karakteru obrazovne institucije. Stoga svi usvojeni pojmovi moraju biti jasni, posebno ako se radi o
osnovama struke. Ako se radi o tehničkim detaljima, oni se moraju poznavati načelno, i na temeljima
osnovnih pojmova, a po potrebi se upoznaju podrobnije kroz tehničke specifikacije, dodatne upute, i
sl. Jasno je da obratni pristup ne važi: razumijevanje tehničkih detalja nemoguće je bez poznavanja
teorijskih osnova, odnosno dovodi do manjkavog znanja, punog rupa i nejasnoća.
Za stjecanje kvalitetnog znanja, studenti moraju uložiti napor da rabe dobru literaturu, odnosno
onu, koja, iako na prvi pogled teža, vodi do boljih rezultata. Moraju dobro poznavati „jezik struke“,
nazive i značenje pojmova, te uvijek nastojati proniknuti u bit stvari. U tehničkom i prirodoznanstve-
nom području, podrazumijevajuća zajednička disciplina je matematika, koja se često naziva i „jezi-
kom prirode“, a danas uvriježeni, i de-facto standardni jezik je engleski, što posebice vrijedi za ra-
čunarstvo kao relativno mladu znanost.
Navedeni samostalni pristup radu presudan je da se kod studenta stvori navika učenja i proučava-
nja, što će posebice biti važno u njegovom daljnjem profesionalnom radu. Cilj vježbi u obrazovnom
procesu, nije dobiti rezultat pošto poto, već dobiti rezultat kroz rad i zalaganje studenata kao aktivnih
učesnika tog procesa. Cilj je stjecanje znanja i vještina na putu od trenutka od suočavanja s proble-
mom zadataka, do njegovog uspješnog rješenja. Stoga, prije nego student potraži pomoć od kolega ili
nastavnika, nastoji izvršiti maksimalni intelektualni napor da do rezultata dođe samostalno. Ukoliko u
tome uspije, to će biti najučinkovitije i što se tiče stjecanja znanja i razvijanja sposobnosti, i što se tiče
zadovoljstva proisteklog od rezultata vlastitog rada. A ukoliko je, nakon neuspjelih napora, potrebno
potražiti pomoć drugih, to treba učiniti tako se razazna bit problema i način njegovo rješavanja, a ne
da se prepisuje i kopira puko rješenje (vidjeti također poglavlje I.6 o etičkom kodeksu).

I.3 Dnevnik vježbi


Tijekom priprema i izvođenja vježbi potrebno je voditi dnevnik pod naslovom:
Dnevnik vježbi iz uvodnog kolegija u programiranje (u daljnjem tekstu kratko Dnevnik
vježbi, ili samo Dnevnik).
U njemu je potrebno u kratkim natuknicama zapisivati što je izvršeno, što je primijećeno u tijeku
rada, koji problemi su se pojavili i kako su riješeni.
Odrednice Dnevnika vježbi su sljedeće:
− Dnevnik se vodi u formi uvezene bilježnice A4 formata (najbolje „matematičkog tipa“), u koju se
piše tintnom pisaljkom. Na koricama je potrebno napisati ime i prezime studenta i naziv kolegija. *
− Dozvoljena su križanja nekorektnih dijelova teksta, korekcije, jasni ispravci, i sl., sve dok je ko-
načni tekst čitak i pregledan.
− Dnevnik vježbi student koristi za pripreme vježbi, tijekom vježbe, i kao podsjetnik nakon vježbe.
U Dnevnik se pišu rezultati i komentari izvršenih zadataka.

*
Uvođenje rukom pisanog Dnevnika vježbi, potaknuto je, između ostalog, i potrebom za borbom protiv kopiraj
i zalijepi (engl. copy-paste) metode. Nedopušteno kopiranje i prepisivanje je odraz nesavjesnosti i nezaintere-
siranost, čime se izravno krši etički kodeks (vidi pogl. I.6).
3

− Svaka vježba započinje na novoj stranici, s navedenim brojem i naslovom vježbe, te datumom
kad je vježba odrađena.
− Svaka vježba ima sljedeće odjeljke: A. Teorijski uvod, B.Zadaci, C. Zaključak, D. Dodatna lite-
ratura (ako postoji).
A. Teorijski uvod. Sadrži kratak uvod u temu vježbe i zabilješke koje student izrađuje tijekom
pripremanja za vježbu, s naglaskom na teorijske osnove, iznesene npr. u [1], i drugoj dostupnoj
literaturi. Također, u ovom dijelu se odgovara na teorijska pitanja postavljena u uvodu vježbe.
O važnosti i načinu pripreme govori i sljedeći odjeljak.
B. Zadaci. U ovom dijelu student rješava zadane zadatke. Prije vježbe, u fazi pripreme, tu se mo-
gu izraditi skice rješenja zadataka koji će se prorađivati na vježbama, te bilježe konkretna pita-
nja i nejasnoće koje će student razriješiti konzultiranjem voditelja vježbi.
Svaki zadatak mora biti jasno naznačen svojim brojem i izvorištem, kao i tekstom (ukoliko je
tekst zadatka vrlo opširan, dovoljno je napisati njegove najbitnije dijelove). Ako se radi o za-
datku iz ovog teksta, dovoljno je napisati broj zadatka, npr. Zad. 2.1 (vježba 2, zad. broj 1), i
njegov (kratak) tekst, po točkama (A, B, C, itd…).
Nakon vježbi student korigira i sređuje rješenja svojih zadataka. Izvorne i izvršne datoteke
čuva u odgovarajućim mapama (vidi vježbu Vježba 1 , odjeljak 1.2.3 o organizaciji mapa i
podmapa), i na njih se referira u komentarima zadataka.
Rješenja zadataka nije potrebno u cijelosti prepisivati iz datoteka izvornog koda! Ako je to
svrsishodno, u Dnevnik vježbi se prepisuju ključni, ili tipični dijelovi programskog koda, te od-
govarajuće komentiraju.
C. Zaključak. U zaključku se sažeto komentiraju bitni dijelovi i rezultati vježbe (nekoliko pasu-
sa).
D. Dodatna literatura. Ukoliko je korištena literatura van standardne literature korištene u ovom
kolegiju (lit. [1], slikoklizne prezentacije lit. [1], i ovaj tekst), u zadnjem odjeljku se navode
podaci o njoj. Za način citiranja literature, vidjeti odjeljak I.5.
U Dnevnik vježbe, nije potrebno, odnosno ne smije se, unašati sljedeće:
− Ne smiju se doslovno prepisivati dijelovi teksta ili cjeline, bio iz literature uz koju se vežu ove vje-
žbe [1], niti iz druge literature. Svi dijelovi moraju biti ispričani vlastitim riječima (vidi odjeljak
I.6). To, naravno, ne vrijedi za navođenje teksta zadataka, u skladu s komentarom pod točkom B
gore.
− Ne smiju se prepisivati rješenja, te cjeline ili dijelovi iz Dnevnika drugih kolega (vidi odjeljak
I.6).
Pregled Dnevnika vježbi, i ocjenjivanje:
− Dnevnik vježbi predstavlja jednu od osnovnih elemenata ocjenjivanja.
− Na zahtjev voditelja, student predaje Dnevnik vježbi na pregled.
− Nakon ključnih dijelova vježbi, odnosno uspješno izvedenih zadataka, student poziva voditelja
vježbi da svojim parafom (u crvenoj boji), to potvrdi.

I.4 Pripreme za vježbe


Da bi se vježba mogla uspješno provesti, neophodna je temeljita priprema. O tome je već bilo govora
prilikom obrazlaganju opisa Dnevnika vježbi u prethodnom odjeljku. Konkretno, pripreme za vježbe
obuhvaćaju sljedeće:
4

− Čitanje i studiranje teksta vježbe, te teorijskih poglavlja udžbeničkog teksta [1] na koje se vježba
odnosi.
− Odgovaranje na postavljena pitanja u pisanom obliku u Dnevniku vježbi, svugdje gdje se to traži,
i gdje je to svrsishodno. Obvezatno je navesti i tekst i izvorište pitanja, odnosno broj odjeljka
teksta i broj pitanja, ili broj zadatka.
− Proučavanje i samostalno rješavanje svih zadanih primjera, u nekoj od razvojnih programskih
okolina (vidi vježbu Vježba 1), uz odgovarajuće komentare u Dnevniku vježbi.,
− Na temelju znanja stečenog studiranjem riješenih primjera, vježbati preostale zadatke.
− U tijeku pripreme potrebno je insistirati na razumijevanju gradiva. Kod rješavanja primjera i za-
dataka potrebno je nastojati ugraditi najbolja teorijska rješenja.
− Pripremati se za pismene i usmene odgovore na pitanja u svezi teorijske cjeline koja se obrađuje
na vježbama, kao i u svezi rješenja zadataka, čime student pokazuje razumijevanje onoga što ra-
di.
Studenti koji ozbiljno pristupe pripremama vježbi, uspješno riješe zadane zadatke i odgovore na
postavljena pitanja, te zabilježe to Dnevniku vježbi, stječu uvjete da se nakon položenih kolokvija
oslobode polaganja pismenog i usmenog ispita.

I.5 Citiranje literature


Ukoliko student koristi dodatnu literaturu, potrebno ju je citirati prema sljedećem obrascu:
Red. broj. Ime autora, 2. ime djela, 3. izdavač, 4. mjesto i godina izdavanja.
Ukoliko se radi o djelu preuzetom s Interneta, tada se često može dogoditi da je čak i ime au-
tora nepoznato, ime djela (npr. nekog neformalnog članka ili slike) možemo sami kreirati
opisno, izdavač u tom slučaju ne postoji, odnosno nevažan je. Kao jedinstvenu oznaku djela,
odnosno njegovo g porijekla, navest ćemo njegov internetski URL (engl. Uniform Resource
Locator).
Literaturu u tekstu kratko navodimo njenim rednim brojem, npr. stavljenim u uglatu zagradu [L1],
[L2], ili na sličan način (npr. pisanjem tog broja kao „nadskripta“ (engl. superscript), odnosno gor-
njeg indeksaL1, L2 ).
Na kraju teksta, u posebnom odjeljku prikladnog naziva (npr. Literatura) dajemo detaljni opis dje-
la, kao u primjeru koji slijedi:
Literatura
L1. B. Stroustrup, The C++ Programming Language (Special 3rd Edition), At&T 1997.
L2. Članak: C Programming Language, http://en.wikipedia.org/wiki/C_Programming_Language.
Kao što je već naglašeno u odjeljcima I.3 i I.4, ako se radi o navodu pitanja, zadatka ili dijela iz
ovog teksta, nije ga potrebno opetovano citirati. Dovoljno je napisati Vježba n (gdje je n broj vjež-
be), te broj odjeljka teksta i broj pitanja, ili broj zadatka.

I.6 Etički kodeks


Svi studenti dužni su pridržavati se kodeksa opće, studentske i profesionalne etike. Svaki rad koji stu-
dent predaje smatra se njegovim djelom, odnosno ako to nije, student je moralno odgovoran za kopi-
ranje, prepisivanje i neovlašteno korištenje tuđih djela.
Svako korištenje rezultata tuđeg rada, a bez odgovarajućeg navoda autora je protivno etici, i zada-
ća je svih ljudi da se protiv toga bore. Etički kodeks rezimiramo u sljedećim crtama:
5

i. Zabranjeno je prepisivanje od drugih autora. Zabranjeno je prepisivanje od svojih pro-


fesionalnih kolega. Zabranjeno je prepisivanje od kolega studenata i učenika na svim
razinama školovanja. Jednako je zabranjeno davanje svojih pismenih uradaka na prepi-
sivanje drugima.
Ako želite pomoći svojim kolegama, učinite to tako da im razjasnite osnove i načela,
te ih potaknete da sami, svojim trudom, vlastitim računom, i svojim mislima, napišu
rješenje.
Ako trebate pomoć od svojih kolega, ne tražite da prepišete gotovo rješenje i cijeli
tekst! To je neetički, neprofesionalno i u krajnjem slučaju kontraproduktivno za vaš
stručni napredak.
ii. Istovjetne rečenice, identičan programski kôd, doslovno prepisivani algoritmi ili
račun, u dijelovima ili u cijelosti,istovrsne greške i sl., bit će tretirane kao prepisi-
vanje. Takve zadaće će biti ocijenjene negativno ili, u blažoj varijanti, s bitno
umanjenim brojem bodova.
iii. Na mnogim školama i sveučilištima u svijetu vrijede strogi kodeksi časti po kojima
se svako prepisivanje, bilo na ispitima, bilo u domaćim zadaćama kažnjava drasti-
čnim kaznama i isključenjem sa studija.
6

Vježba 1. Osnovni pojmovi u programiranju.


Organizacija rada na računalu
Kao što je istaknuto u uvodu, uspješno provođenje programiranje na računalima zahtijeva poznavanje
osnovnih teorijskih pojmova. Stoga je potrebno stalna konzultacija literature, priručnika i uputstava,
da se već od početka razjasni čim više pojmova.
U prvom dijelu vježbe 1 studenti imaju zadatak da u pismenoj pripremi kod kuće usvoje temeljne
pojmove programiranja, kroz koje će usvojiti potrebna znanja za izradu, prevođenje i pokretanje prvih
programa. U drugom dijelu vježbe 1, u računalnoj učionici organizirat će se korisnički računi.
Pošto praktični dio vježbe 1 zahtijeva relativno kratko vrijeme, u prvom dvosatnom terminu, izvo-
de se zajedno vježba 1 i vježba 2.

1.1 Algoritmi, programski jezici, programi i programiranje


Pismenim odgovorima, u proizvoljnom formatu, olovkom na papiru, ili u elektronskom obliku, odgo-
vorite na sljedeća pitanja. Odgovori obavezno moraju biti izraženi vlastitim riječima, bez prepisivanja
i kopiranja od drugih studenata, iz literature (ove i ostale dostupne literature). Napomene o etičkom
kodeksu vidite u uvodu ovih vježbi.
Odgovori moraju biti precizni i sažeti, ali i dovoljno dugi da budu sveobuhvatni. Za odgovore ko-
ristite svoje bilješke s predavanja, te literaturu koja je stavljena na raspolaganje preko sustava za e-
učenje (kao što je Moodle), te ostala izvorišta kojima raspolažete.

1.1.1 Pitanja u svezi algoritama


1. Navedite svojim riječima labavu definiciju algoritma?
2. Navedite svojim riječima precizniju definiciju algoritma koja se koristi u računarstvu?
3. U kojoj se formi uobičajeno prikazuju algoritmi?
4. Opišite ukratko što je to dijagram toka (blok-dijagram), a što pseudokod?

1.1.2 Pitanja u svezi s osnovnim pojmovima u programiranju


5. Što je potrebno znati prije neto što se pristupi pisanju programa koji rješava problem iz nekog
područja? Je li dovoljno poznavati samo računarstvo i programski jeziku u kojem se radi?
6. Navedite tri temeljne stvari koje programer mora znati da bi uspješno riješio neki programski
zadatak ili problem?
7. Objasnite svojim riječima pojmove: programski jezik i računalni program.
8. Što je to programiranje, i koje sve radnje ono uključuje počevši od pisanja programa?
9. Koje su četiri ključne faze kod pisanja i primjene programa u višim programskim jezicima koji
se prevode u izvršni kod? Objasnite ukratko što se događa u svakoj od faza.
10. O čemu govori peta faza (održavanje i nadogradnja programa), i u kojem vremenskom razdob-
lju je ona aktualna?
7

Zadatak 1.1 Euklidov algoritam (zadatak s predavanja).


Euklidov algoritam nalazi najveći zajednički djeljitelj (GCD, od engl. greatest common divisor) cije-
lih brojeva. Za dva broja n1 i n2 općenito iz skupa cijelih brojeva, GCD je najveći broj koji ih dijeli
bez ostatka. Npr. GCD za brojeve 21 i 14 je 7, za 24 i 16 je 8, za −16 i 24 je također 8, za
4 i 0 je 4, a za 0 i 0 nije definiran (slučaj koji treba eliminirati).
Euklidov algoritam za nalaženje GCD od dva broja n1 i n2 , prepričan riječima glasi:
− naći ostatak nmod cjelobrojnog dijeljenja prvog broja s drugim;
− ako je taj ostatak 0, GCD je prvi broj, i algoritam je gotov;
− inače ponoviti gornji postupak s drugim brojem i nmod .
Najprije dobro proučite funkcioniranje algoritma na papiru, primijenivši ga na gore navedene primje-
re. Potom izrazite algoritam uz pomoć pseudo koda sljedeći ove naputke:
− koristite matematički jezik čim je više moguće (za razliku od gore navedenog opisa operacija);
− koristite se ključnim riječima kao što su čini, dok, vrati rezultat, ako, inače (rabite od toga
samo ono što je potrebno),
− uvedite pomoćne varijable ako je potrebno, i ukratko opišite koje vrijednosti one sadrže i čemu
služe;
− koristite operatorima pridruživanja kao što su m ← n , sa značenjem: nova vrijednost od m
jednaka je desnoj strani znaka pridruživanja ← , tj. vrijednosti od n.
Uputno je najprije krenuti s algoritmom koji će vrijediti za prirodne brojeve, potom provjeriti što se
događa kad je jedan od brojeva 0. Zatim pogledajte vrijedi li program i za negativne brojeve, odnosno
kako ga treba modificirati da daje ispravan rezultat i za taj slučaj. Konačno nadogradite program tako
da, za slučaj kad su oba broja 0, ispisuje poruku: „GCD nije definiran“.
Napomena. Ukoliko ovaj zadatak ne znate riješiti u cijelosti za termin prvih vježbi, napravite barem
prvi dio zadatka, tj. proučite kako algoritam radi na papiru.
8

1.2 Organizacija rada na računalu


U vrijeme pisanja ovog teksta, standardni je izbor za izvođenje vježbi iz kolegija programiranja, upo-
raba PC računala na Wintel platformi. Prije početka vježbi izvršit ćemo nužne organizacione korake
za učinkovitiji i kvalitetniji rad na računalima u računalnoj učionici.
Za svakog studenta bit će otvoren poseban korisnički račun ograničenih ovlasti i zaštićen lozin-
kom. Time se datoteke svakog studenta zaštićuju od neovlaštenog pristupa.

1.2.1 Otvaranje korisničkih računa


Postupamo prema sljedećim koracima:
1. Obratiti pažnju da u računalo nisu utaknute vanjske memorije (npr. mem. štapići) provjerom
USB utičnica. Ako jesu, izvaditi ih prije radnji koje slijede. Ako je neki od korisničkih računa u
pogonu, odjaviti se s njega (log off).
2. Pozvati voditelja da se na računalu prijavi kao administrator. Na „kontrolnoj ploči“ otvoriti
prozor za korisničke račune (engl User Accounts).
3. Otvoriti novi korisnički račun pod nazivom prema sljedećoj shemi: Prezime Ime. Pri tom je
potrebno sve hrvatske dijakritičke znakove zamijeniti latinskim slovima. Npr. student Kreši-
mir Krešić će kreirati korisnički račun pod nazivom: Kresic Kresimir. To je mjera predos-
trožnosti da se izbjegnu problemi koji mogu nastati kad neki programi pristupaju direktorijima
(mapama) s imenima u kojima se nalaze znakovi izvan nulte stranice ASCII koda.
4. Odabrati da je otvoreni korisnički račun ograničenih ovlasti, tj. da bude: limited account.
5. Obvezatno postaviti lozinku, koju je potrebno zapisati, odnosno dobro zapamtiti (možete koris-
tit lozinku kojom pristupate i nekim drugim sustavima, i koju dobro čuvate).
6. Pozvati voditelja vježbi i pokazati mu postavke novog računa (ime, ovlasti i da je zaštićen lo-
zinkom).
7. Dok je voditelj još prisutan, potrebno je odjaviti se sa administratorskog računa (engl. Log Off),
i prijaviti se na svoj novootvoreni korisnički račun, koristeći postavljenu lozinku.
8. Tek sada, ako je potrebno, dozvoljeno je priključenje vanjskih memorija u računalo.
9. Važna napomena: za vrijeme korištenja administratorskog računa student je odgovoran za ko-
rektan rad računala, za njegovu zaštitu od virusa (vidi točke 1 i 8), te za integritet softvera na
njemu.

1.2.2 Prilagodba radne površine računala


Odaberite postavke za oblikovanje radne površine (engl. desktop) kao što ste navikli. Držite se slje-
dećih okvirnih odrednica:
1. Za pozadinu koristite neupadljiva grafička rješenja.
2. Često korištene ikonice, kao npr. My Computer, My Documents, i druge, postavite u gornji li-
jevi kut radne površine, da su lako dostupne.
3. Izvucite ikonice često korištenih programa na radnu površinu, također na lako dostupno i vid-
ljivo mjesto (vidi točku 2).
4. Kod organizacije radne površine rukovodite se načelom da želimo optimalno iskoristiti površi-
nu ekrana. Npr. dobro je koristiti pretinac za „brzo lansiranje“ (engl. “quick launch“), u lijevom
dijelu prečke zadataka (engl. task bar). U njemu je smještena ikonica za brzi pristup radnoj pov-
ršini, kao i ikonice programa koje vrlo često trebamo (npr. preglednik spletnih stranica). Fun-
kcija samoskrivanja prečke zadataka (engl. auto-hide task bar), pomoći će da se donji dio ek-
rana bolje iskoristi za aktivne prozore, itd…
9

1.2.3 Otvaranje podmapa kolegija i vježbi


Pošto otvoreni korisnički račun može poslužiti i za izvođenje vježbi drugih kolegija, potrebno je u
mapi My Documents otvoriti podmapu imena: ImeKolegija, i u njoj organizirati daljnje podmape za
pregledno pospremanje datoteka izrađenih na pojedinim vježbama.
Konkretno, postupamo na sljedeći način:
1. U mapi My Documents kreirajte podmapu imena: ProgramskiAlati1.
2. U mapi ProgramskiAlati1 kreirajte podmapu Vjezba_1 u kojoj ćete pospremati datoteke koriš-
tene tijekom vježbe 1.
3. Po potrebi, unutar mape ProgramskiAlati1 možete otvoriti i druge podmape u kojima ćete ču-
vati specifični sadržaj.
4. Za naredne vježbe potrebno je otvarati podmape imena Vjezba_nn gdje je nn broj vježbe za-
pisan s dvije znamenke, za brojeve manje od 10 predvođen vodećim nulama.
5. Unutar mape Vjezba_nn otvaramo podmape projekata, ili to za nas automatski čini radna oko-
lina (npr. Visual Studio 2005). Projekte nazivamo po broju zadatka po sljedećem obrascu: Za-
datak_nn_mm gdje je nn već spomenuti broj vježbe, a mm je broj zadatka. Npr. prvi zada-
tak vježbe 2 nazvati ćemo Zadatak_02_01, a 11. zadatak vježbe 3: Zadatak_03_11.

1.3 Rezime i zaključak vježbe Vježba 1


U Dnevniku ukratko rezimirajte rezultate ove vježbe.
10

Vježba 2. Od pisanja do izvođenja programa.


Integrirana razvojna okolina.
Prvi program u C++: “Zdravo svijete!”
U vježbi 2 cilj nam je da na primjeru vrlo jednostavnog programa ilustriramo četiri osnovne faze od
pisanja do prevođenja i izvođenja programa. Upoznat ćemo način na koji se izvorni kôd programa
može izravno prevesti u objektni i izvršni pokretanjem prevodioca iz tzv. komadne linije (po uzoru na
operacijski sustav DOS). Zatim ćemo to isto napraviti i u integriranim razvojnim okolinama Dev-
C++ i Microsoft© Visual Studio 2005.

2.1 Osnove sintakse jezika C / C++


Promotrite prvi primjer programa iz [1], poglavlje 2. Program je ponovljen ovdje radi preglednosti.

Primjer 2.1 Program Zdravo svijete!


#include <iostream> // pretprocesorska direktiva (uputa)
using namespace std; // “imenski” prostor varijabli i objekata
int main() // glavna funkcija “main”
{
// program ispisuje znakovni niz na ekran računala:
cout << "Zdravo svijete, iz C++ programa!" << endl;
return 0;
}

Zadatak 2.1 Razumijevanje osnova sintakse jezika C / C++.


Pažljivo pročitajte sve napomene o korištenim tvrdnjama i načinu pisanja programa jeziku C / C++ u
literaturi s predavanja [1]. Nastojte usvojiti i razumjeti čim više pojmova. Svoje bilješke možete pos-
premiti u podmapu Zadatak_02_1 smještenu u mapi Vjezba_2.

2.2 Kreiranje izvorne datoteke u uređivaču teksta.


Kompilacija uz „ručno“ pokretanje prevodioca
Izvorni kod programa možemo kreirati u bilo kojem uređivaču teksta, kao što je npr. program Note-
pad (Start → All Programs → Accessories → Notepad), koji pohranjuje tekst u ASCII kodu.
S pomoću ovog programa zapisan je i naš prvi program ([1] pogl. 2, primjer 2.1), koji je posprem-
ljen u datoteku izvornog koda: ZdravoSvijete.cpp.
Ideja ovog dijela vježbe je da se pokaže kako je pisanje izvornog koda programa moguća i upora-
bom najjednostavnijih programa za uređivanje teksta, a kreacija objektne i izvršne datoteke pokreta-
njem programa prevodioca. Još do kraja 80-tih godina prošlog stoljeća, to je bio uobičajeni način krei-
ranja programa.
11

2.2.1 Nalaženje i pregled datoteka iz komandne linije


Zadatak 2.2 Nalaženje i pregled datoteka izvornog, objektnog i izvršnog koda
programa ZdravoSvijete iz komandne linije.
a) U zadatku je potrebno pronaći i pregledati datoteke ZdravoSvijete.cpp, ZdravoSvijete.obj i
ZdravoSvijete.exe smještene u podmapi programskog alata Microsoft© Visual Studio 2005, čija
je podmapa zadana sljedećom stazom: c:\Program Files\Microsoft Visual Studio 2005\VC , ili:
c:\Program Files\Microsoft Visual Studio 8\VC . Naime, ovisno o tome koje inačice Visual Studia,
i u kojem redoslijedu su bile instalirane na računalu, mogu postojati direktoriji pod imenom Visual
Studio 2005, ili Visual Studio 8, ili čak i oba (u tom slučaju ustanovite u kojem od njih se nalazi
poddirektorij VC . Kratica VC se odnosi na Visual C++).
Potražite navedene datoteke najprije u prozorima operacijskog sustava Windows, a potom koristeći
komandnu liniju operacijskog sustava DOS (za pomoć vidi sljedeći odjeljak).
Nakon što ste pozicionirali gornju stazu, te provjerili da se u podmapi VC nalaze sve navedene
datoteke, otvorite datoteku ZdravoSvijete.cpp s pomoću programa Notepad . Komandna linija mo-
ra izgledati kao u sljedećem primjeru:
c:\Program Files\Microsoft Visual Studio 2005\VC > notepad ZdravoSvijete.cpp
Ukoliko datoteke ne postoje, pozovite voditelja da pospremi izvornu datoteku na navedeno mjesto
iz korisničkog računa s administratorskim ovlastima. Naime, ograničenim korisnicima nije dozvolje-
no pisanje i brisanje datoteka van njihove mape u c:\Documents and Settings\ImeKorisnickogRacuna.
Nakon što je kreirana tekstualna datoteka ZdravoSvijete.cpp i pospremljena u navedenu mapu,
prevedena je (kompilirana) i povezana iz administratorskog korisničkog računa na sljedeći način :
− otvorena je komandna linija iz Visual Studia: Start → All Programs → Microsoft Visual
Studio 2005 → Visual Studio Tools → Visual Studio 2005 Command Prompt
(ovaj korak je nužan da Visual Studio pripremi okolinu za kompiliranje za x86 platformu
(DOS);
− staza je automatski postavljena na:
c:\Program Files\Microsoft Visual Studio 2005\VC >
− potrebno je unijeti komandu: cl /EHsc ZdravoSvijete.cpp
− ona pokreće program prevodilac pod imenom cl.exe (u komandama DOSa, proširenje imena
exe datoteka izvršnog koda se može ispustiti, pa se to najčešće i čini), koji prevodi izvornu da-
toteku ZdravoSvijete.cpp u objektnu ZdravoSvijete.obj, te potom vrši povezivanje u izvršnu
datoteku ZdravoSvijete.exe. (Opcija /EHsc govori prevodiocu o specifičnim radnjama, tj. da
omogući rukovanje C++ iznimkama. Za detalje vidjeti MS dokumentaciju.)
b) Pokrenite izvršnu verziju programa jednostavnim utipkavanjem imena: ZdravoSvijete.exe (ili sa-
mo ZdravoSvijete). Je li na ekranu prikazano ono što ste očekivali?
Proučite koje su veličine datoteka izvornog , objektnog i izvršnog koda, i diskutirajte. Otvorite s
pomoću programa Notepad objektnu datoteku ZdravoSvijete.obj. Objasnite što ta datoteka preds-
tavlja, te što je uređivač teksta prikazao.
c) Kopirajte sve tri datoteke u podmapu: Zadatak_02_2 svoje mape Vjezba_2. Učinite to i s datote-
kama objektnog i izvršnog koda. Promijenite stazu komandne linije u podmapu Zadatak_02_2.
Pokrenite sada izvršnu datoteku programa na isti način kao i u podzadatku b. Radi li program kao
što očekujete? Zatim pokrenite program iz Windows okruženja na uobičajeni način na koji pokre-
ćete programe. Što primjećujete?
12

U gornjem zadatku ilustrirana je uporaba uređivača teksta Notepad kao dijela operacijskog sus-
tava Windows, te C++ prevodioca cl koji se nalazi u sastavu Visual Studia 2005. U uporabi su i
drugi obradnici teksta (npr. vim), C++ prevodioci (npr. gcc) i otklanjači pogrešaka (gdb).

2.2.2 Dodatak. Kratak podsjetnik za rad s datotekama u operacijskom


sustavu DOS
Za otvaranje komandne linije pokrenite: Start → All Programs → Accessories → Command
Prompt, ili: Start → Run… , te u polje Open upišite cmd (cmd.exe je program koji u operacij-
skom sustavu Windows otvara sučelje komandne linije). Program će otvoriti stazu koja odgovara up-
ravo podmapi aktivnog korisničkog računa. Da izlistate sadržaj te podmape, odnosno direktorija*,
utipkajte na kraju staze komandu dir , tako da komandna linija izgleda kao:
c:\Documents and Settings\ImeKorisnickogRacuna>dir
i pritisnite tipku Enter za unos.
Na ekranu će biti izlistan sadržaj mape, gdje će se zasigurno naći poznate vam podmape pod nazi-
vima Desktop, My Documents, i neke druge. Komandu dir stalno koristimo da doznamo i provjeri-
mo imena poddirektorija i datoteka unutar direktorija u kojem se nalazimo.
Da uđete u neku od podmapa, utipkajte komandu cd (engl. change directory) i iza nje ime pod-
mape: cd ImePodmape . Da izađete iz podmape u nadmapu, utipkajte komandu: cd ..
Za izravan prelazak u korijenski direktorij (engl. root directory), utipkajte jednostavno: cd \ ,
a za pozicioniranje u direktorij aktivnog korisničkog računa: cd %homepath% .
Npr. uz korištenje ove komande u direktorij My Documents aktivnog korisničkog računa dolazi-
mo unosom:
> cd %homepath%\ My Documents
Općenito, da se iz bilo kojeg direktorija pređe u drugi direktorij, dovoljno je upisati komandu cd i
nakon nje cijelu stazu tog drugog direktorija, počevši od korijenskog, koji je naznačen obrnutom ko-
som crtom.
Kopiranje datoteke se vrši komandom copy iza koje dolazi bilo puna, bilo relativna staza (u odno-
su na trenutnu poziciju komandne linije) datoteke koju kopiramo, i nakon toga puna ili relativna staza
direktorija u koji kopiramo.
Uobičajeno je da se smjestimo u direktorij u kojem se nalaze datoteke koje kopiramo, te da iza
komande copy navedemo njihovo ime, te potom ime direktorija u koji kopiramo. Želimo li npr. ko-
pirati sve datoteke istog imena a različitih ekstenzija iz nekog direktorija, navedemo ImeDatoteke.*,
a želimo li kopirati sve datoteke unutar direktorija, navodimo *.* , kao zamjenu za sva imena.
Premještanje datoteka se vrši naredbom move , po istom načelu kao i kod naredbe copy.
Brisanje datoteka se vrši naredbom del (engl. delete), iza koje slijedi ime datoteke, gdje se zvje-
zdica koristi kao zamjena za bilo koje ime, ili bilo koje proširenje imena, ili oboje, po istom načelu
kao i kod kopiranja.

*
Naš naziv direktorij dolazi od engl. izvornika directory, ili imenik. Radi se o imeniku koji u sebi sadrži druge
podimenike i datoteke, s pomoću kojih se organizira struktura datoteka u operacijskom sustavu DOS (Disc
Operating System) na PC računalima prije pojave operacijskog sustava Windows s grafičkim okruženjem. Di-
rektorij u DOSu odgovara mapi u Windowsima.
13

Direktorije kreiramo komandom: mkdir ImeDirektorija , (od engl. make directory) a brišemo s:
rmdir ImeDirektorija (od engl. remove directory).
Da skratimo pisanje, već rabljene komande možemo izlistati, ponoviti ili modificirati uporabom
strelica ↑ i ↓ na tastaturi.

2.3 Integrirana razvojna okolina Dev-C++


Pojam integrirane razvojne okoline (kratica IDE), kao osvrt na besplatni “Bloodshed Dev-C++”
IDE s MinGW kompilatorom, opisan je u [1] i [XX].
Dev-C++ (7.5 MB) se može iskrcati sa spletne stranice: http://www.bloodshed.net/devcpp.html
(na dnu stranice su ponuđena dva poslužioca), a bit će stavljen na raspolaganje studentima i na druge
načine.

2.3.1 Pokretanje Dev-C++ i otvaranje izvorne datoteke


Pokrenite Dev-C++ bilo iz izbornika Start, bilo dvoklikom na njegovu ikonicu. Ako ikonica ne posto-
ji, pronađite mapu pod nazivom Dev-Cpp u korijenskom direktoriju ili pod Program Files, i kreirajte
prečac ikonicu na radnoj površini.
Nakon otvaranja programa potrebno je otvoriti bilo novu izvornu datoteku, bilo novi projekt.
Kad imamo više izvornih datoteka koje treba povezali u jedinstvenu izvršnu verziju programa,
odabrali bismo novi projekt: File → New → Project… , te odlučili između sljedećih mogućnosti:
Windows Application, Console Application, Static Library, DLL, Empty Project. Kao najjednostavni-
ju varijantu za početne programe, odabrali bismo konzolni primjenski program (engl. Console Appli-
cation) bez grafičkog sučelja.
Pošto u našem početnom primjeru imamo samo jednu izvornu datoteku, zadovoljimo se otvara-
njem jedne izvorne datoteke: File → New → Source File.

2.3.2 Program „Zdravo Svijete!“ iz Dev-C++


Napomene o stilu pisanja. Prije upisivanja programa ponavljamo naputke o stilu pisanja programa.
Potrebno je strogo vodite računa o preglednosti i organizaciji izvornog koda. Jedno od najvažnijih
pravila je uvlačenje teksta po logičkim i programskim cjelinama. Svaku novu „potcjelinu“ potrebno
je uvući (engl. indent) u desno naspram prethodne. Također, pojedine cjeline iste hijerarhijske vrije-
dnosti odjeljujemo praznim retkom. Sve novine u programu, kao i varijable koje programer uvodi,
potrebno je jasno komentirati.
Potrebno je odlučiti se za jedan od načina pisanja otvorene vitičaste zagrade:
a) bilo u novom, zasebnom retku, u istoj koloni u kojoj je započela prethodna tvrdnja, i u kojoj će biti
zatvorena vitičasta zagrada;
b) bilo u istom retku iza tvrdnje na koji se taj blok odnosi (vidi [1]), uz zatvorenu vitičastu zagradu
kao i gore.
Nakon što je otvorena vitičasta zagrada bloka, obvezatno je potrebno izvršiti uvlačenje (indentaci-
ju) u desno prve sljedeće i svih narednih tvrdnji isto ranga, tj. sve dok se ne otvori novi blok. Pravila
je lako usvojiti promatrajući primjere. U početku je potrebno strogo slijediti navedeni način pisanja
programskog koda, nastojeći uočiti pravilnosti u pisanju pojedinih programskih tvorbi. Nepregledno
14

napisani programi, teško su čitljivi, teško se kontroliraju i održavaju, te lakše dovode do sintaktičkih i
logičkih pogrešaka.*
Uzimamo prvi primjer C4 / C++ programa iz [1], poglavlje 2:

Zadatak 2.3 Pisanje i kompiliranje† prvog programa u Dev-C++


a) Prepišite prvi program „Zdravo Svijete“ iz Primjer 2.1 u Dev-C++. Čak i ako imate tekst iz-
vornog koda u računarskom formatu, upišite ga rukom, pazeći na sve znakove i na stil pisanja.
Obavezno poštujte pravila o uvlačenju teksta i njegovoj preglednoj organizaciji!
b) Nakon upisivanja programa, pospremite izvornu datoteku u podmapu Zadatak_02_3 mape Vjez-
ba_2, pod imenom ZdravoSvijete.cpp . Pokrenite prevođenje izvorne datoteke izborom: Exe-
cute → Compile, ili prečacem: Ctrl+F9. Ukoliko je sve bilo dobro napisano, prevođenje će
okončati uspjehom, uz poruku da je bilo 0 grešaka i 0 upozorenja (engl. Errors: 0, Warnings: 0 ).
U tom slučaju zatvorite dijaloški prozor.
Ako je u programu bilo grešaka, u donjem dijelu prozora Dev-C++ pojavit će se komentari kojima
prevodilac dojavljuje greške i upozorenja. Kliknite na redak opisa greške i program će postaviti kursor
na redak na koji se taj komentar odnosi. Pažljivo čitajte poruke prevodioca i otklonite grešku. Da bi
kompilacija prošla, sve greške moraju biti otklonjene. Upozorenja ne moraju, ali je vrlo uputno da ih
također uklonimo.
c) Po uspješnoj kompilaciji pokrenite program: Execute → Run, (Ctrl+F9). Što primjećujete? Pris-
jetite se kako se program izvršavao u prijašnjem zadatku pod točkom c. Ima li sličnosti? Ukoliko
imate vremena, pokrenite program iz komandne linije, na način objašnjen u prethodnom odjeljku.
d) Vjerojatno ste primijetili da je problem u prethodnoj točki zadatka u tome da se program izvrši
prebrzo. Neke razvojne okoline (vidi sljedeći odjeljak) same osiguravaju da prozor u kojem se
izvršava konzolni program ostaje vidljiv sve dok to korisnik želi, odnosno sve dok ne pritisne proi-
zvoljnu tipku. Dev-C++ to ne čini, i stoga je prije zadnje naredbe programa potrebno umetnuti lini-
ju kojom se poziva sistemska funkcija za ostvarenje pauze:

system ("pause") ;
Ova funkcija nalaže operacijskom sustavu da prozora konzolne aplikacije ostaje aktivan sve dok ga
korisnik ne zatvori pritiskom bilo koje tipke na tipkovnici. Modificirani program prikazan je u sljede-
ćem primjeru:

Primjer 2.2 Program „Zdravo svijete!“ broj 2


#include <iostream> // pretprocesorska direktiva (uputa)

*
Čak i ako je ispravan, nečitko napisani programski kôd smatrat će se inferiornim i bit će ocijenjen nižom ocje-
nom.


Uobičajeno je da se pod nazivom kompiliranja (engl Compile) podrazumijeva i radnja povezivanja (enlg.
Link), koju će program automatski izvršiti.

Prilikom kopiranja teksta iz tekst procesora obratite pažnju da ne prenesete i neke posebne znakove koji ne
spadaju u osnovnu stranicu ASCII koda. Npr. pametni navodnici (engl. smart quotes), iz programa Word, pre-
neseni u okolinu Dev-C++ prelaze u obične navodnike i ne predstavljaju problem. Međutim, preneseni u Visual
Studio 2005 (vidi sljedeći odjeljak) ne moraju preći u obične navodnike, i mogu stvoriti probleme pri kompili-
ranju. Dovoljno ih je jednostavno obrisati i ponovo upisati u razvojnoj okolini.
15
using namespace std; // “imenski” prostor varijabli i objekata
int main() // glavna funkcija “main”
{
// program ispisuje znakovni niz na ekran računala:
cout << "Zdravo svijete, iz C++ programa!" << endl;
system("pause"); // funkcija za “pauzu” u prikazu konzol. apl.
return 0;
}
Izvršite naveden promjene u programskom kodu, te kompilirajte i izvršite program. Provjerite kako se
program izvršava iz komandne linije, a kako iz Windows okruženja.
Pošto je Bloodshed Dev-C++ vrlo kompaktna i besplatna inačica C++ IDE, možete ga instalira-
ti na svojem računalu i koristiti za učenje i vježbu programiranja.

2.4 Integrirana razvojna okolina MS© Visual Studio 2005


Microsoft© Visual Studio 2005 (VS 2005) primjer je profesionalnog IDE alata za razvoj programa
raznovrsne namjene, u više programskih jezika. Mi ćemo ga koristiti za pisanje i izvršavanje C / C++
programa, zbog njegovih velikih mogućnosti, te podrške koje, pogotovo pri pisanju složenijih prog-
rama pružaj opsežne knjižnice funkcija i njihove dokumentacije [2].
Besplatna verzija Visual Studio 2005 Express Edition može se iskrcati sa spletne stranice:
http://www.microsoft.com/express/2005/default.aspx .

2.4.1 Otvaranje projekta u Visual Studiu 2005


Postupamo na način sličan onom u prethodnom odjeljku. Pokrenite Visual Studio 2005. Pošto ćemo
ga često koristiti, uputno je da njegovu ikonicu instalirate na radnu površinu.
U Visual Studiu moramo otvoriti projekt unutar kojeg ćemo smjestiti izvornu datoteku. Učinite to
izborom: File → New → Project… , nakon čega se otvara dijaloški okvir kao na slici Slika 2.1.
Potrebno je odabrati postavke kao na slici: u padajućem izborniku jezika C++ odabiremo Win32
(platforma 32-bitnog operacijskog sustava Windows na kojoj će program biti izveden), a u desnoj
plohi prozora odabiremo konzolnu aplikaciju: Win32 Console Application. Za ime programa ovaj
put ćemo napisati ZdravoSvijete, a inače ćemo ovdje upisivati broj zadatka (Zadatak_nn_mm) pre-
ma obrascu navedenom u odjeljku 1.2.3.
Za stazu pohrane projekta odabiremo :
C:\Documents and Settings\Prezime Ime\My Documents\ProgramskiAlati1\Vjezba_nn , gdje
Prezime Ime predstavlja naziv korisničkog računa (vidi odjeljak 1.2.1).
Kvadratić provjere Create Directory for Solution označimo (kao na slici), čime razvojna okolina
sama kreira naziv mape rješenja (engl. Solution Name).
Nakon ispune navedenih podataka, pređemo na sljedeću etapu, čime se otvara novi prozor na ko-
jem je dostatno odabrati Finish. Time je proces otvaranja projekta završen, i možemo započeti s upi-
sivanjem programa.
Upisivanje izvornog koda se vrši u desni, veći prozor razvojne okoline VS 2005. S lijeve strane je
standardno smješten tzv. pogled na klase (engl. Class View) i pogled na izvorišta (engl. Resource
View), dok je donji okvir rezerviran za izlaz kompilatora i poruke otklanjača grešaka.
Uobičajeno ćemo obrisati sav programski kôd koji je automatski umetnut, tj. krećemo ispočetka.
Iznimno, možemo ostaviti neophodnu liniju za ovu razvojnu okolinu: #include "stdafx.h". Nakon
što smo napisali ili umetnuli odgovarajući programski kôd, kompiliramo ga i povezujemo kroz proces
16

gradnje (engl. build), odabirom: Build → Build ImeProjekta. Ukoliko je gradnja projekta prošla
bez grešaka, uz ključnu poruku kompilatora na dnu liste: "Build: 1 Succeeded, 0 Failed", tada mo-
žemo pokrenuti program: Debug → Start Without Debugging (Ctrl+F5). Ukoliko želimo kompili-
rati i odmah pokrenuti program za testiranje, možemo odmah odabrati ovu radnju (Ctrl-F5). Razvojna
okolina će automatski provjeriti je li bilo promjena u izvornim datotekama, te ako jest provesti kompi-
laciju i povezivanje, ta uz korektan ishod ovih radnji, pokrenuti i izvršenje programa.
Pospremanje izvorne .cpp datoteke vrši se standardnim odabirom File → Save ImeProjekta.cpp
(Ctrl+S). Prije zatvaranja projekta i razvojne okoline, potrebno je pospremiti i cijeli projekt, odabi-
rom File → Save All (Ctrl+Shif+S). Kod sljedećeg otvaranja projekta odabiremo File → Open →
Project Solution (Ctrl+Shift+O) ImeProjekta.sln unutar mape projekta.
Ukoliko prije zatvaranja razvojne okoline projekt nije pospremljen na gore opisani način, prilikom
njegovog ponovnog otvaranja, datoteka ImeProjekta.cpp se neće pojaviti u glavnoj plohi. Tada ju je
potrebno pronaći u mapi projekta i unijeti odabirom: File → Open → File ImeProjekta.cpp. Potom
je, naravno, uputno izvršiti pospremanje cijelog projekta na gore opisani način.

Slika 2.1 Dijaloški okvir za kreiranje projekta. Odabran je projekt tipa Visual C++
Win32, s predloškom za Win32 konzolnu aplikaciju, pod imenom ZdravoSvijete,
smješten u podmapu Zadatak_02_4, unutar mape Vjezba_2.

2.4.2 Program „Zdravo svijete!“ iz Visual Studia 2005


Nakon što smo otvorili projekt u Visual Studiu 2005, ponovit ćemo zadatak iz prethodnog odjeljka.
17

Zadatak 2.4 Pisanje i kompiliranje* prvog programa u Visual Studiu 2005


a) Najprije obrišite sav tekst u desnom velikom prozoru za programski kôd u Visual Studiu, i potom
umetnite program iz Primjer 2.1 (možete ga kopirati iz mape Zadatak_02_3). Po potrebi sredite
tekst, poštujući pravila o uvlačenju teksta i njegovoj preglednoj organizaciji! Izvršite kompilaciju i
povezivanje svih potrebnih datoteka odabirom: Build → Build ZdravoSvijete. Pažljivo pogle-
dajte koji je rezultat kompilacije! Izvješće prevodioca na dnu sadrži poruku:
======== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped =========
koja govori da je proces gradnje okončao s: 0 uspješno i 1 neuspješno prevedenom datotekom!
Kliknite na prvi red izvješća prevodioca, i pažljivo ga pročitajte do samoga kraja. Što prevodilac
sugereira? Bi li trebalo u programski kôd dodati još jednu uputu za uključenje tipa #include ?
b) Umetnite na početak programa liniju koju je sugerirao prevodilac: #include "stdafx.h" , i
ponovite gradbu (Build) projekta. Ako je sve ostalo bilo u redu, tada bi projekt trebao biti uspješno
izgrađen. Pokrenite program odabirom: Debug → Start Without Debugging (Ctrl+F5). Ponaša
li se program kao što očekujete iako ne poziva funkciju za „pauziranje“?
c) Provjerite u mapi Zadatak_02_4 koje je sve datoteke kreirao VS 2005. Nađite izvršnu datoteku
ZdravoSvijete.exe. Provjerite njezinu veličinu i usporedite je s veličinama istovrsne datoteke krei-
rane u prethodna dva odjeljka. Pokrenite izvršnu datoteku dvoklikom. Što primjećujete. Ponaša li
se prozor konzolne aplikacije jednako kao i kad startamo program iz IDE okoline Visual Studia?
d) Otklonite manu programa da se prozor zatvara odmah po okončanju programa. Testirajte radi li
dobiveni program i u drugim mapama (npr. kopirajte ga na radnu površinu), i na drugim računali-
ma?
e) Ukoliko Vam je preostalo vremena, pokušajte saznati o zaglavnoj datoteci stdafx.h i njenoj ulozi
u kompilaciji C++ programa u okolini Visual Studia.

2.5 Rezime i zaključak vježbe Vježba 2


Ukoliko niste stigli dovršiti vježbu Vježba 2 u predviđenom terminu, dovršite je na početku sljedeće
vježbe. U Dnevniku vježbi ukratko opišite kako ste riješili pojedine zadatke i odgovorite na pitanja
postavljena uz njih. Na koncu, provjerite stečeno znanje odgovaranjem na sljedeća pitanja:
1. Suštinski gledano, u formi kakve datoteke se piše izvorni kôd programa? Koji je najjednostavniji
program koji može poslužiti za to? U čemu je prednost korištenja razvojnih okolina?
2. U što je potrebno prevesti izvorni kôd, i koji program to čini? Što je, osim prevođenja, potrebno
da bi se dobila izvršna verzija programa?
3. Objasnite zašto je izvorni kôd programa čitak kad ga učitamo u uređivač teksta. Zašto datoteke
objektnog i izvršnog koda nisu? Usporedite veličine ovih datoteka.
4. Je li potrebno pozvati funkciju system (“pause”) da vidimo rezultat konzolne aplikacije ako je
pokrećemo: i) iz komandne linije, ii) iz grafičkog sučelja OS Windows, iii) iz razvojne okoline
Dev-C++, iv) iz razvojne okoline VS 2005. Diskutirajte svaki od slučajeva.
5. Što se događa prilikom prevođenja ako u razvojnoj okolini VS 2005 prva direktiva nije #include
"stdafx.h”. Promotrite pažljivo poruku prevodioca u tom slučaju. Je li kompilacija uopće započe-
la?

*
Uobičajeno je da se pod nazivom kompiliranja (engl Compile) podrazumijeva i radnja povezivanja (engl.
Link), koju će program automatski izvršiti.
18
19
20

Vježba 3. Osnovni tipovi podataka u C / C++


U ovoj vježbi ćemo kroz primjere i zadatke usvojiti osnovne pojmove koji se tiču tipova podataka
jezika C / C++ . Vježba slijedi gradivo izneseno u pogl. 3 lit [1], koje je potrebno proučiti prije izvo-
đenja vježbe. Pošto je gradivo ove vježbe relativno opsežno, vježba se može odraditi u dva termina,
odnosno u dijelu termina manje opsežne, vježbe.

3.1 Teorijska priprema


Odgovorite u pismenom obliku na pitanja u odjeljcima koji slijede, i pripremite se na usmenu provje-
ru na vježbama.

3.1.1 Osnovni teorijski pojmovi o kodiranju podataka


1. U kojem obliku, odnosno u kojoj abecedi, su kodirani svi podaci u računalnoj memoriji (od vanj-
ske memorije, preko glavne ili radne memorije, do priručne memorije i registara procesora)? Na-
pišite tu abecedu kao skup i definirajte njene znamenke: B = { , }.
2. Da bi ljudi lakše čitali sadržaj memorije, standardno ga, umjesto u formi iz pitanja 1 prikazuju u
heksadekadskoj formi. Koliko znakova ima heksadekadska abeceda? Napišite je u obliku skupa,
navodeći sve znamenke: H = { , , …. }. Ponovite kako se, na vrlo jednostavan način
prikaz iz pitanja 1 pretvara u heksadekadsku formu i obrnuto.
3. Objasnite što je to je to kodiranje, najprije svojim riječima. Zatim uvažite da se radi o funkciji
preslikavanja iz određene domene u određenu kodomenu, i precizirajte definiciju. Potkrijepite
definiciju primjerom nekog poznatog koda koji se primjenjuje u računarstvu.
4. Što je dekodiranje? Slično kao gore, objasnite termin svojim riječima. Potom uvažite činjenicu
da se radi o inverznoj funkciji, tj. obrnutom preslikavanju, i upotpunite definiciju.
5. Na koji način se kodiraju cijeli brojevi? Kako se razaznaju pozitivni od negativnih brojeva? Pro-
učite način kodiranja predznačenih brojeva.
6. Navedite standardni računarski kôd za kodiranje znakova u koje spadaju dekadske znamenke,
velika i mala slova latinske abecede, razmak (prazno mjesto), znakovi interpunkcije, posebni
znakovi, itd… Kolika je „duljina tog koda“, tj. duljina kodne riječi, izražena brojem bitova s ko-
jima se kodira svaki pojedini znak? U koliko bitova se on standardno posprema?
7. Ako su svi podaci u računalima kodirani s pomoću samo nula i jedinica, kako računalo zna kada
će nizove nula i jedinica prevesti npr. u brojeve, a kada u znakove? Kako zna koliko dugačke ni-
zove bitova će dekodirati? Jesu li naveden stvari bitne ili nebitne za rad računala?
8. Na temelju prethodnog pitanja, diskutirajte važnost tipova podataka kod programskih jezika?

3.1.2 Identifikatori i deklaracija varijabli


9. Objasnite što su to identifikatori, i koje je pravilo za njihovu tvorbu u jeziku C / C++.
10. Napišite nekoliko identifikatora koji su različiti i ispravni. Napišite nekoliko identifikatora koji
su neispravni zato što: i) nemaju ispravnu tvorbu imena, ii) zato što se kose s ključnim riječima.
Naglasite u tekstu da se radi o NEISPRAVNIM IDENTIFIKATORIMA!
11. Prilikom deklaracije varijabli, što se nužno mora napraviti, a što se ne mora?
21

12. Kako se elegantno deklarira više varijabli istog tipa?

3.1.3 Standardni tipovi podataka u C / C++


13. Je li jezik C / C++ programski jezik u kojem se moraju ili ne moraju definirati tipovi podataka. Je
li ta tipizacija stroga ili labava?
14. Navedite, i pregledno ispišite sve cjelobrojne (ili diskretne) tipove podataka.
15. Brojeve iz kojeg matematičkog skupa oni prikazuju?
16. Navedite sve tipove podataka za prikaz realnih brojeva.
17. Koji složeni tip je ugrađen u definiciju jezika C / C++.

3.2 Primjeri i zadaci


Proučite detaljno uvodni primjer 3.1 iz [1], koji je ponovljen ovdje. Obratite pažnju na to kako je os-
tvaren unos vrijednosti varijabli preko ulaznog objekta cin i operatora >> . Objasnite sve ostale
novine u programskom kodu.

Primjer 3.1 Deklaracija i inicijalizacija varijabli.


Napišite program u C++ koji učitava i ispisuje sljedeće tipove podataka: jedan cijeli broj, jedan realan
broj i jedan znak. Također, program ispisuje veličinu korištene memorije u bajtovima (B) za svaki od
tipova podataka, uporabom operatora sizeof .
#include <iostream>
using namespace std;
int main()
{
// Program učitava i ispisuje brojeve i pojedine znakove
// Obavezna objava (deklaracija) varijabli:
int a;
float b;
char c;
// Unos vrijednosti varijabli:
cout << "Unesite cijeli broj: a = ";
cin >> a;
cout << "Unesite realni broj: b = ";
cin >> b;
cout << "Unesite neki znak: c = ";
cin >> c;
// Novi redak u ispisu
cout << endl;
// Ispis unešenih varijabli:
cout << "Cijeli broj ( int ) a = " << a << endl
<< "Realan broj ( float ) b = " << b << endl
<< " Znak ( char ) c = " << c << endl;
// Veličina podataka, odnosno količina memorije potrebna
// za njihovu pohranu, dobiva se uporabom operatora sizeof .
// Duljina tipa izražena je brojem bajtova (B), 1B = 8 bit.
// Novi redak, s pomoću kontrolnog znaka "\n" = new line:
cout << "\n";
// Duljine uporabljenih tipova :
cout << "Duljina tipa int = " << sizeof a << "B" << "\n"
<< "Duljina tipa float = " << sizeof b << "B" << "\n"
<< "Duljina tipa char = " << sizeof c << "B" << "\n"
<< endl;
22
return 0;
}
U ovom primjeru koristimo poseban znak za kontrolu ispisa: to je znak \n koji uvjetuje prelazak
u novi red. Podsjetite se točne funkcije izlaznog manipulatora endl , i razmislite preklapa li se u ona
s funkcijom kontrolnog znaka \n ? Koju dodatnu radnju obavlja manipulator endl ? Druge kontrolne
znakove upoznat ćete u zadatku Zadatak 3.12.

Zadatak 3.1 Izvođenje primjera Primjer 3.1.


a) U razvojnoj okolini s kojom radite (na vježbama MS© Visual Studio 2005), otvorite novi projekt
pod nazivom Zadatak_03_01, unutar mape Vjezba_3, na način opisan u odjeljcima 2.3 i 2.4.
Usput provjerite da se nalazite u mapi ProgramskiAlati1, te da su tu pohranjene i vaše mape Vje-
zba_1 i Vjezba_2 (za hijerarhiju mapa vidjeti odjeljak 1.2.3 ). Ukoliko radite u okolini Dev-C++
, unutar podmape Vjezba_3 sami otvorite podmapu Zadatak_03_01. U Visual Studiu 2005 ta
podmapa će biti automatski kreirana. Ako, za vježbu, radite u obje okoline, dodajte imenu podma-
pe za okolinu Dev-C++ prikladan dodatak (npr. Zadatak_03_01_DevCpp).
U razvojnoj okolini obrišite sav programski kôd koji je bio automatski umetnut. Prenesite prim-
jer iz ovog teksta u prozor za uređivanje koda. Uklonite sve dijakritičke znakove i posebne znako-
ve (npr. pametne navodnike!). U VS 2005 možete koristiti funkciju nađi i zamijeni (engl. Find-
Replace). Po potrebi dodajte linije koje zahtijeva korištena razvojna okolina, da bi kompilacija bi-
la uspješna.
Pokrenite gradnju projekta. Za VS 2005, ta je procedura već opisna u 2.4.2: Build → Build
Zadatak_03_01 . Za Dev-C++ (opisano u 2.3.2): Execute → Compile, ili Ctrl+F9).
Provjerite ishod prevođenja, i po potrebi otklonite greške. Potom pokrenite program. Podsjeća-
mo, u VS 2005 odabiremo: Debug → Start Without Debugging, ili Ctrl+F5, a u Dev-C++:
Execute → Compile, ili Ctrl+F10.
b) Zabilježite rezultate o duljinama pojedinih tipova u bajtovima.

Zadatak 3.2 Deklaracija i inicijalizacija varijabli.


a) Proučite sljedeće odsječke programskog koda. Komentirajte svaku pojedinu liniju i navedite što
program prevodilac radi kad je prevodi. Ima li sintaktičkih grešaka? Pronađite ih i diskutirajte.
b) Otvorite novi projekt pod imenom Zadatak_03_02 i pospremite ga u odgovarajuću mapu. Umetni-
te donje programske odsječke i promotrite poruke koje će dojaviti prevodilac. Usporedite ih sa
svojim opažanjima i komentarima grešaka.
c) Otklonite sve greške na način da minimalno mijenjate „logiku“ programa, i ponovite kompilaciju.
// Deklaracija i inicijalizacija varijabli:
int i, j, k;
//
// ... ...

//
int i = 0;
// ... ...
int i1 = 1;
int i2 = i1;
int i3 = i1 + i4;
int i4 = i2;
// ... ...
23

Zadatak 3.3 Provjera duljine cjelobrojnih tipova: short int, int, long int (long),
long long int (long long).
a) Po uzoru na primjer Primjer 3.1 sastavite C++ program (projekt pod nazivom Zadatak_03_03)
u kojem ćete deklarirati, učitati i potom ispisati šest varijabli cjelobrojnih tipova, i provjeriti im du-
ljinu u bajtovima: short int, int, long int (long), long long int (long long). Ovdje su nazivi
long int i long, te long long int i long long sinonimi (provjerite da i to vrijedi).
b) Napišite zaključke o duljinama tipova podataka u bajtovima (B) i bitovima (kratica: bit), prikazav-
ši ih pregledno u tablici.
c) Otklonite sve greške na način da minimalno mijenjate „logiku“ programa, i ponovite kompilaciju.

Zadatak 3.4 Opseg cjelobrojnih tipova.


a) Pronađite u teorijskom štivu formule za opseg brojeva koje prikazuju cjelobrojni tipovi podataka, i
proučite kako su izvedene. Za n–bitni cjelobrojni predznačeni tip, one pokazuju da za mini-
malni broj Nmin (najmanji, negativni broj), te za maksimalni broj Nmax vrijedi:

N min = −2 n − 1 , N max = 2 n − 1 − 1 .
b) Izračunajte na kalkulatoru najmanje i najveće brojeve za cjelobrojne tipove iz zadatka Zadatak
3.3.

Zadatak 3.5 Provjera opsega cjelobrojnih tipova podataka u testnom C / C++


programu
a) Modificirajte program iz zadatka Zadatak 3.3 tako da bude prikladan za testiranje opsega cjelob-
rojnih tipova prema gornjoj formuli. Poslužite se metodom «probe i pogreške»: unašajte negativ-
ne i pozitivne brojeve velikih apsolutnih vrijednosti, promatrajte je li ispis istovjetan unosu. Ispro-
bavajte, tj. «griješite» sve dok niste sigurni u odgovor!
Skica rješenja. Umjesto s najkraćim tipom char (kojeg će ulazno-izlazni objekti cin i cout uvijek
interpretirati kao znak a ne kao broj, odnosno kao niz znamenaka broja u pozicionom brojevnom sus-
tavu), počnimo razmatranje na tipu short int. U glavnu funkciju testnog programa umetnite sljedeće
naredbe:
short int sX;
cout << endl << "Input: short int sX = ";
cin >> sX ;
cout << "Output: short int sX = " << sX << endl;

Upišite za ulazni podatak vrijednosti npr. 1000, 10000, 10000, –10000, –100000, pa zatim +32767,
+32768, +32769, te –32767, –32768, –32769, i provjerite koji su rezultati ispravno zabilježeni u me-
moriju, te ispravno ispisani!
Ponovite sličan program za tip int, te unašajte vrijednosti reda stotinu milijuna i milijardi: npr.
100000000, 1000000000, 2000000000, 4000000000, –2000000000, –4000000000, i zaključite koji je
traženi opseg brojeva.
Za tip long long račun zahtijeva veću matematičku preciznost i brojeve reda veličine 263 = 9.22 ×
1018 , tj. za točan izračun kalkulator mora imati 19 znamenaka (provjerite funkcionalnost kalkulatora
u OS Windows).

Zadatak 3.6 Nepredznačeni cjelobrojni tipovi.


a) Ponovite osnovne značajke nepredznačenog tipa brojeva. Zašto je uveden i čemu služi? Provjerite
u teoriji da je opseg brojeva za n–bitni cjelobrojni nepredznačeni tip:
24

N min = 0 , N max = 2 n − 1 .
Objasnite gornju formulu, te odredite maksimalne brojeve za tip char, unsigned short int, unsigned
int.
b) Modificirajte program iz zadatka Zadatak 3.3 i kreirajte projekt pod nazivom Zadatak_03_06,
tako da u njemu deklarirate nepredznačene tipove podataka unsigned short int, unsigned int,
unsigned long long. Koristite mađarsku notaciju, i označite ove varijable identifikatorima: uSInt,
uInt, uLLong.
c) Barem za prva dva tipa provjerite opseg testirajući unos i ispis, kao u prethodnom zadatku Zadatak
3.5. Što se događa kad unesete broj za 1 veći od maksimalnog? Pokušajte unijeti negativni broj i
pažljivo pogledajte što se pojavilo na ispisu. Ima li dobiveni broj ikakve veze s unesenim brojem i
nepredznačenim tipom podataka? Ako vam se čini da nema, razmislite ponovo. Unesite npr. broj
−1 i pogledajte što će biti ispisano. Koliko se ispisani broj razlikuje od maksimalnog broja danog
nepredznačenog tipa?

Zadatak 3.7 Prilagodba i konverzija tipova podataka.


a) Proučite što je to prilagodba i konverzija tipova. Što je to implicitna (uključiva) prilagodba tipova?
U kojim slučajevima prevodilac ne reagira, a u kojima reagira, te kakvom porukom? Hoće prevo-
dilac zaustaviti kompilaciju? Je li najjednostavnije rješenje ― da ignoriramo upozorenja ― i si-
gurno rješenje? Do kakvih pogreški može doći? Izvucite zaključke.
b) Što je to eksplicitna prilagodba tipova i tko je vrši? Zašto je ona bolja od implicitne? Navedite sin-
taksu eksplicitne prilagodbe tipova.
c) Proučite sljedeći programski odsječak. Pokušajte predvidjeti vrijednosti varijabli. Ponovite veličine
pojedinih tipova i objasnite komentare u programu.
// deklaracija i inicijalizacija varijabli:
int i1;
unsigned short s1 = 65535;
// Bezopasna prilagodba s “manjeg tipa” na “veći”:
i1 = ((int) s1) + 1; // i1 = ?
// Uvijek opasna prilagodba s većeg tipa na manji!
// Pri izričitoj prilagodbi programer razmatra moguće
// greške! Razmislite, hoće li se ona desiti?
s1 = (unsigned short) i1; // s1 = ?

d) Ubacite gornji programski odsječak u testni program (unutar projekta odgovarajućeg imena). Do-
dajte linije za ispis da možete ispisati vrijednosti varijabli. Nakon kompilacije promotrite što javlja
prevodilac. Izvršite program i usporedite prijašnje odgovore s rezultatima ispisa.

Zadatak 3.8 Zapis cjelobrojnih tipova u različitim brojevnim sustavima.


a) Kako se varijablama pridružuju brojevne vrijednosti iz uobičajenog dekadskog brojevnog sustava,
već smo naučili. Proučite kako se pridružuju vrijednosti iz oktalnog sustava s bazom boct = 8d , i
heksadekadskog sustava s bazom bhex = 16d. Donji primjer vam sugerira kako se to postiže.
b) Ponovite osnove o pozicionim brojevnim sustavima. Ako brojevni sustav ima bazu b , gdje je b
prirodni broj veći od 1, koliko znamenki on mora imati? Napišite redom kolika je baza sustava, i
koje znamenke sadrže: i) dekadski sustav kao općeprihvaćeni brojevni sustav danas, te računarski
motivirani sustavi: ii) binarni, iii) oktalni, iv) heksadekadski. Ponovite kako se vrši pretvorba iz
dekadskog sustava u naveden računarske i obratno. Kako se vrši pretvorba između računarskih su-
stava? Npr. brojeve iz binarnog sustava pretvaramo u heksadekadski tako da bitove organiziramo
u četvorke (tetrade), idući od postojeće (ili zamišljene) racionalne točke desno i lijevo, te svaku od
25

četvorki bitova pretvaramo u jednu heksadekadsku znamenku, što je vrlo brz i jednostavan postu-
pak. Kao primjer dajemo pretvorbu dva 32-bitna binarna broja u heksadekadske ekvivalente:
0000 0001 0010 0011 0100 0101 0110 0111b = 01234567h ,
1000 1001 1010 1011 1100 1101 1110 1111b = 89ABCDEFh .
Detalje o brojevnim sustavima, prikazu brojeva u njima, i pretvorbi iz jednog sustava u drugi, pot-
ražite u računarskim i informatičkim udžbenicima, odnosno podrobnije u literaturi o arhitekturi raču-
nala.
c) Proučite donji primjer i napišite vrijednosti koje će biti ispisane na ekranu. Obratite pažnju na bro-
jevne sustave u kojima je varijabla zadana. Najprije zaključite općenito pravilo kako se zapisuje
baza brojevnog sustava u istom tom sustavu. Objasnite potom kako je varijabla pohranjena u me-
moriji.
d) Potom Kompilirajte donji programski kôd u okviru testnog programa, i provjerite svoje odgovore
iz prethodnog podzadatka. Koji je standardni brojevni sustav za prikaz na ekranu?
#include <iostream>
using namespace std;
int main()
{
// Zapis brojeva u dekadskom, oktalnom i heksadekadskom
// sustavu
int iBDec = 10; // Što predstavlja broj iBDec?
int iBOct = 010; // Što predstavlja broj iBOct?
int iBHex = 0x10; // Što predstavlja broj iBHex?
// Ispis vrijednosti baza sustava (u dekadskoj formi):
cout << "iBDec = " << iBDec << endl;
cout << "iBOct = " << iBOct << endl;
cout << "iBHex = " << iBHex << endl;
// Pridruživanje brojeva, N = 100 u raznim bazama:
int iDec = 100;
int iOct = 0100;
int iHex = 0x100;
/ Ispis dekadskog, oktalnog i heksadekadskog broja:
cout << "(100)Dec = " << iDec << endl;
cout << "(100)Oct = " << iOct << endl;
cout << "(100)Hex = " << iHex << endl;
// Pridruživanje istog niza znamenaka: "777" u raznim bazama:
iDec = 777;
iOct = 0777;
iHex = 0x777;
// Ispis vrijednosti dekadskog, oktalnog i heksadekadskog broja
// u dekadskoj formi:
cout << "(777)Dec = " << iDec << endl;
cout << "(777)Oct = " << iOct << endl;
cout << "(777)Hex = " << iHex << endl;
// Ispis istog broja u različitim sustavima
// (uporaba izlaznog manipulatora, vidi kasnije):
cout << "0x100 (Hex) = " << hex << 0x100 << endl;
cout << "0x100 (Oct) = " << oct << 0x100 << endl;
cout << "0x100 (Dec) = " << dec << 0x100 << endl;
return 0;
}

Zadatak 3.9 Znakovni tip char.


a) a) Znakovni tip je spomenut u kontekstu cjelobrojnih tipova podataka. Objasnite u čemu je nje-
gova specifičnost, i zašto se naziva znakovni tip? Prema kojem poznatom računarskom kodu se
26

kodiraju znakovi ovog tipa. Može li se s tipom char vršiti aritmetičke operacije kao i s brojevi-
ma? Kako će se njegove vrijednosti ispisivati na ekranu? Ponovite kako se varijabla ovog tipa ini-
cijalizira na neku brojevnu vrijednost, a kako na brojevnu vrijednost koja odgovara nekom proiz-
voljnom znaku z.
b) b) Razmotrite sljedeći programski odsječak. Predvidite izlaz ako je kodna zamjena za znak praz-
nine: ASCII(' ') = 20h , znamenka 0: ASCII ('0') = 30h , znak @: ASCII ('@') = 40h , slovo A:
ASCII ('A') = 41h , slovo a: ASCII ('a') = 61h , itd. (vidjeti tablicu ASCII koda u dodatku). Ovdje
smo indeksom h označili da se radi o heksadekadskom prikazu broja.
c) Umetnite donji programski odsječak u testni program unutar zasebnog projekta izvršite ga. Provje-
rite svoja predviđanja usporedbom s rezultatima ispisa.
char cSpace = ' ', cA = 'A', cX1, cX2, cX3, cX4;
unsigned short int uInt1, uInt2, uInt3;
// Račun s tipom char (8-bitni):
cX1 = cSpace + 1; // cX1 = ?
cX2 = cSpace + 10; // cX2 = ?
cX3 = cSpace + 0x10; // cX3 = ?
cX4 = cSpace + 0x20; // cX3 = ?
// Ispis (znakovi ili njihove kodne zamjene?):
cout << "' ' + 1 = " << cX1 << endl;
cout << "' ' + 10 = " << cX2 << endl;
cout << "' ' + 10h = " << cX3 << endl;
cout << "' ' + 20h = " << cX4 << endl;
// Podrazumijevajuća prilagodba (promocija) sa char (8-bitni)
// na short int (16 bitni):
uInt1 = cSpace + 1; // uInt1 = ?
uInt2 = cSpace + 10; // uInt2 = ?
uInt3 = cSpace + 0x10; // uInt3 = ?
// Ispis (znakovi ili njihove kodne zamjene?):
cout << "ASCII( ' ' + 1) = " << uInt1 << endl;
cout << "ASCII( ' ' + 10) = " << uInt2 << endl;
cout << "ASCII( ' ' + 10h) = " << uInt3 << endl;
// Izravan izlaz na objekt cout!
// Ispis – znakovi ili njihove kodne zamjene?
cout << "' ' + 10h = " << cSpace + 0x10 << endl;
cout << "' ' + 11h = " << cSpace + 0x11 << endl;
cout << "' ' + 12h = " << cSpace + 0x12 << endl;
cout << "' ' + 19h = " << cSpace + 0x19 << endl;
// Izravan izlaz na objekt cout, uz prisilno pridjeljivanje
// (down-casting) na niži tip char.
// ASCII brojke:
cout << "' ' + 10h = " << (char) (' ' + 0x10) << endl;
cout << "' ' + 11h = " << (char) (' ' + 0x11) << endl;
cout << "' ' + 12h = " << (char) (' ' + 0x12) << endl;
cout << "' ' + 19h = " << (char) (' ' + 0x19) << endl;
// Izravan izlaz na objekt cout, uz odgovarajuće pridjeljivanje tipa.
// ASCII slova:
cout << "'A' + 1 = " << (char) (cA + 1) << endl;
cout << "'A' + 25 = " << (char) (cA + 25) << endl;
cout << "'A' + 20h = " << (char) (cA + 0x20) << endl;
cout << "'A' + 57 = " << (char) (cA + 57) << endl;
////////////////////////////////////////////////////

Zadatak 3.10 Logički tip.


a) Ponovite osnove o logičkom tipu podataka. Koliko vrijednosti imaju varijable tog tipa, i navedite
koje su (hrvatski i engleski nazivi). Prema tome, koliko bi bitova bilo dovoljno za pohranu tih vri-
27

jednosti? Objasnite kako se u praksi implementira taj tip podataka, tj. uzima li se za njega mini-
malno potreban niz bitova ili što drugo?
b) Kako je implementiran logički tip podataka u jeziku C? Koje logičko značenje ima broj 0? Koje
logičko značenje imaju npr. brojevi: −1, 1, −13, 100, … ? Kako je implementiran logički tip u
jeziku C++. Jesu li promjene bitne, ili više kozmetičke naravi? Hoće li programski kôd s logič-
kim varijablama definiranim u C-stilu biti ispravan i u jeziku C++?
c) U sljedećem programskom odsječku deklarirane su dvije logičke varijable. Varijablama se pridje-
ljuje vrijednost na nekoliko načina (pridruživanjem vrijednosti logičkih konstanti false i true, te
cijelih brojeva). Također, provjeravamo duljinu logičkog tipa. Proučite program i predvidite ispis.
d) Umetnite donji programski odsječak u testni program koji ćete ugraditi u projekt odgovarajućeg
imena. Provjerite rezultate i usporedite sa svojim odgovorima.
e) Ustanovite koje pravilo vrijedi za pridjeljivanje cjelobrojnog tipa na tip bool.
f) Je li opravdano ignorirati upozorenja prevodioca? Predstavlja li strogo vođenje računa o tipu poda-
taka kao što je logički, tek puki formalizam? Ako jezik dopušta određene slobode u radu s tipovi-
ma, na kome preostaje da vodi računa o njihovoj pravilnoj uporabi?
Napomena: ukoliko vam komentari na engleskom jeziku nisu razumljivi, prevedite ključne riječi s
pomoću rječnika, i zatim dopišite komentare u hrvatskoj inačici.
// Logic Variables declaration:
bool bLogic0;
bool bLogic1;
// Size of bool type:
cout << "Size of bLogic0 = " << sizeof bLogic0 << "B\n"
<< "Size of bLogic1 = " << sizeof bLogic1 << "B\n"
<< "Size of (bool) = " << sizeof(bool) << "B\n"
<< endl;
// Formally correct initialization:
bLogic0 = false;
bLogic1 = true;

// Output values:
cout << "bLogic0 [= true] = " << bLogic0 << "\n"
<< "bLogic1 [= false] = " << bLogic1 << "\n" << endl;
// Formally incorrect initialization (automatic casting).
// Will there be compile-time warnings?
bLogic0 = 0;
bLogic1 = 1;
// Output values:
cout << "bLogic0 [= 0 ] = " << bLogic0 << "\n"
<< "bLogic1 [= 1 ] = " << bLogic1 << "\n" << endl;
// Formally incorrect initialization (truncation from
// int to bool). Will there be compile-time warnings?
bLogic0 = 256;
bLogic1 = 65536;
// Output values through bool type:
cout << "bLogic0 [= -256] = " << bLogic0 << "\n"
<< "bLogic1 [= 65536] = " << bLogic1 << "\n" << endl;
// Formally incorrect initialization (truncation from
// int to bool). Will there be compile-time warnings?
bLogic0 = 0;
bLogic1 = 65535;
// Output values through short int type:
cout << "(short) bLogic0 [= 0] = " << (short) bLogic0 << "\n"
<< "(short) bLogic1 [= 65535] = " << (short) bLogic1 << "\n"
<< endl;
28
// ... ... ...

Zadatak 3.11 Tipovi s pomičnom točkom.


a) Ponovite teorijske osnove o tipovima podataka za zapis realnih brojeva. Kako izgleda tzv. znan-
stvena notacija brojeva? Slijedi li format tipova s pomičnom točkom znanstvenu notaciju realnih bro-
jeva, ili njihov prikaz u formi jednokomponentnog broja?
b) U sljedećem primjeru vidljiva je sintaksa zapisa realnih brojeva u tipu double i float. Pažljivo ga
proučite. Što se postiže uporabom modifikatora const kod objave varijable? Može li se takva „vari-
jabla“ mijenjati?
c) Uvrstite programski odsječak u testni program, dodajte linije za ispis svih definiranih varijabli i
komentirajte rezultate programa. Jesu li ispisane sve znamenke pojedinih konstanti? U čemu bi mogao
biti problem? Odgovor nađite u [1] pogl. 3, odjeljak o izlaznim manipulatorima, odnosno u zadatku
xxx niže.
float fR1 = 1.0E-10f ; // = 0.0000000001
float fR2 = -123.4567E6f ; // = -1.234567 x 108 = 123 456 700
float fRazlomak_1kroz16 = 6.25E-2f ; // 1/16 u točnom zapisu
float fRazlomak_1kroz3 = .333333 ; // 1/3 , točno ili približno?
//Matematičke konstante
const double dPi = 3.14159265358979 ; // Ludolfov broj Pi s 15
// značajnih znamenaka
const double de = 2.71828182845904 ; // Baza prirodnog
// logaritma
//Neke prirodne konstante:
const double dEl = -1.6E-19; // Naboj elektrona
const double dAn = 6.023e23; // Avogadrov broj
const double dG = 6.67e-11; // Gravitaciona konstanta

Zadatak 3.12 Tretman zapisa realnih konstanti (brojeva) u VS 2005.


Ako ste se zapitali zašto je u inicijalizaciji realnih brojeva tipa float u gornjem primjeru, na kraju
brojčane vrijednosti dodano slovo f, u ovom zadatku ćemo odgovoriti na to. Brojevne konstante,
koje pišemo s desne strane operatora pridruživanja '=' (vidi sljedeću vježbu), podrazumijevaju se da
su tipa double precision. Općenito je double precision podrazumijevajući tip s pomičnom točkom,
dok se tip float može smatrati skraćenim tipom za realne vrijednosti, kojeg ćemo rabiti kad nije pot-
rebna velika točnost izračuna.
a) Proučite sljedeći programski odsječak, umetnite ga u testni program, i pažljivo promotrite poruke
prevodioca u IDE VS 2005. Ako ste sve ispravno unijeli, kompilacija će proći. No, ima li upozore-
nja? Koliko ih je? Pogledajte pažljivo redove na koje se upozorenja odnose. Treba li dodati slovo f i
kod definicije varijable fC. Izvedite zaključak? Što treba napraviti da se otkloni drugo upozorenje?
// Tretman realnih konstanti u VS 2005: float ili double?
float fA = 0.123456 ;
float fB = 0.123456f ;
float fC = 1. ;
double dD = fA + fB ;
float fE = fC + dD ;
cout << "fA = " << fA << "\t"
<< "fB = " << fB << "\t"
<< "fC = " << fC << "\t" << "\n\n"
<< "dD = fA + fB = " << dD << "\n"
<< "fE = fC + dD = " << fE << "\n"
<< endl;
b) U ovom primjeru koristimo nove posebne znakove za kontrolu ispisa. Znak \n smo već upoznali u
primjeru Primjer 3.1. Kontrolni znak \t ima funkciju tabulatora, tj. pomaka za propisani broj mjesta
29

(ustanovite koliko on iznosi u našem slučaju). Pored navedenih kontrolnih znakova postoji kontrolni
znak \0 = NULL s kodnom zamjenom ASCII (NULL) = 00h (vidi tablice ASCII koda).

Zadatak 3.13 Pobrojani tipovi.


Ponovite osnove o pobrojanom tipu i zatim ih utvrdite proučavanjem i izvršenjem donjeg primjera.
a) Ako se posebno ne definiraju cjelobrojne vrijednosti pridijeljene pojedinim „pobrojnicima“, tj.
elementima liste pobrojanog tipa, tada se uvodi podrazumijevajuće pobrojavanje, koje ide redom
od početne vrijednosti tipične u računarstvu, i u jezicima C / C++. Pogledajte za koji od dva pobro-
jana tipa u zadatku imamo takav slučaj, i ustanovite kako je pobrojavanje organizirano. Je li to u
skladu sa skupom koji se koristi za brojanje u matematici? Diskutirajte i opravdajte računarski iz-
bor?
b) Pogledajte kako i za koji pobrojani tip je osigurano da pobrajavanje odgovara onom koje je uobiča-
jeno u matematici (navedite s kojim skupom brojeva se ono vrši). Pronađite gdje je napisana uni-
verzalna formula za broj elemenata u skupu, gdje su elementi označeni slijednim indeksima istart ,
istart + 1 , … … , iend − 1 , iend .
c) Dodajte linije koda potrebne da se ispišu svi mjeseci na hrvatskom i engleskom jeziku s pripadnim
rednim brojevima.
#include <iostream>
using namespace std;
// Definicija pobrojanog tipa ključnom riječi enum. Naziv tipa (prsti)
// može se ispustiti ukoliko iza njega slijedi lista varijabli:
enum prsti {Palac, Kaziprst, Srednjak, Prstenjak, Mali};

// Deklaracija i inicijalizacija tipa month:


enum month {Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
int main()
{
// 1. Ispis vrijednosti pobrojanog tipa:
cout << "1. Ispis vrijednosti pridjeljenih pobrojanom tipu\n"
<< "===================================================\n"
<< " Palac = " << Palac << "\n"
<< " Kaziprst = " << Kaziprst << "\n"
<< " Srednjak = " << Srednjak << "\n"
<< " Prstenjak = " << Prstenjak << "\n"
<< " Mali = " << Mali << "\n"
<< endl;
cout << " Na jednoj ruci ima " << Mali - Palac + 1 << " prstiju. \n"
<< endl; // Je li ovo univerzalna formula za broj pobrojnika?

// 2. Redni brojevi mjeseci.


// Dodajte linije koda za ispis svih mjeseci redom!
cout << "2. Redni brojevi mjeseci\n"
<< "===================================================\n"
<< "Hrv. mjesec Red. broj Engl. month \n"
<< "===================================================\n"
<< " Sijecanj " << Jan << ". " << "\t\t January\n"
<< " Travanj " << Apr << ". " << "\t\t April\n"
<< " Srpanj " << Jul << ". " << "\t\t July\n"
<< " Listopad " << Oct << ". " << "\t\t October\n"
<< "===================================================\n"
<< endl;
// 3. Račun s pobrojanim tipom:
30
cout << "3. Račun s pobrojanim tipom\n"
<< "===========================================================\n"
<< "Sijecanj + 3 mjeseca = " << Jan + 3 << ". mjesec.\n"
<< "January + 4 months = " << Jan + 4 << ". month.\n"
<< "Travanj + 6 mjeseca = " << Apr + 6 << ". mjesec.\n"
<< "April + 7 months = " << Apr + 7 << ". month.\n"
<< endl;
cout << "Od sijecnja do veljace je " << Feb - Jan << " mjesec.\n"
<< "From Jan. to Feb. there is " << Feb - Jan << " month.\n\n"
<< "Od ozujka do prosinca je " << Dec - Mar << " mjesec(i).\n"
<< "From March to Dec. there are " << Dec - Mar << " months.\n\n"
<< "Ljetni semestar, od ozujka do srpnja, traje: "
<< Jul - Mar << " mjeseca.\n"
<< "The summer semester, from March to July, lasts: "
<< Jul - Mar << " months.\n"
<< "===========================================================\n"
<< endl;
// 4. Deklaracija nove varijable pobrojanog tipa:
month thisMonth = Mar;
cout << "Ovaj mjesec je " << thisMonth << ". mjesec u godini.\n"
<< "Od ovog mjeseca do rujna je " << Sep - thisMonth
<< " mjeseci.\n"
<< endl;
return 0;
}

Zadatak 3.14 Izlazni manipulatori oct, hex, dec, setfill(char ), setw(int ) .


U sljedećem zadatku dajemo primjer uporabe izlaznih manipulatora. S pomoću njih modificiramo po-
stavke u izlaznom objektu cout u svrhu podešavanja ispisa. Svrha i način uporabe nekoliko korisnih
manipulatora objašnjen je u programskom kodu. Detalji o izlaznim manipulatorima mogu se doznati
u dokumentaciji razvojne okoline VS 2005 (MSDN knjižnice), upitom u izborniku pomoći (Help →
Search). Npr. upitom “iomanip members” (za članove objavljeni u zaglavnoj datoteci iomanip.h), te
odabirom članka <iomanip> Standard C++ Library, te klikom na veznik <iomanip> Members , do-
lazimo do liste manipulatora, odakle možemo dalje doći do detaljnijih objašnjenja.
Ideja zadatka je da kroz ispis karakterističnih varijabli (između ostalog i najmanjih i najvećih vri-
jednosti pojedinog tipa), u dekadskoj i heksadekadskoj formi, naučimo rabiti izlazne manipulatore, da
ponovimo osnovne pojmove o cjelobrojnim tipovima, te da učinimo ispis preglednim.
a) Proučite pažljivo programski kôd i uočite novine u njemu. Pažljivo čitajte komentare koji će Vam
pomoći da shvatite o čemu se radi u pojedinom dijelu programa. Uočite da se mnogi dijelovi prog-
rama jednostavno ponavljaju, te da su kreirani metodom „kopiraj i zalijepi“ uz manje naknadne
izmjene. Pronađite navedene izlazne manipulatore. Koji se od manipulatora spomenutih u naslovu
zadatka ne pojavljuje u programu? Kako je ostvareno djelovanje operatora setfill i setw ? Kako
su promijenjene podrazumijevajuće postavke?
b) Odgovorite na sva pitanja postavljena u komentarima zadataka. Pošto brojeve možemo ispisati u
heksadekadskoj formi, to je prilika da ponovite konverziju iz dekadskog u heksadekadski sustav i
obrnuto, te da ponovite kodiranje cijelih predznačenih i nepredznačenih brojeva.
c) Otvorite novi projekt pod uobičajenim nazivom (Zadatak_03_14), i kopirajte tekst programa u raz-
vojnu okolinu. Izvedite uobičajene popravke u programskom kodu (indentacije, uklanjanje dijakri-
tičkih znakova, i sl.). Pokrenite program i pažljivo proučite ispis. Jesu li u prvim ispisima (1a do
4a) cijeli brojevi pregledno potpisani? Pogledajte ispis 1b i uočite promjene.
31

d) Dopišite dijelove programa 2b, 3b i 4b u kojima ćete po uzoru na dio 1b ostvariti pravilno potpi-
sivanje cijelih brojeva. Također, promijenite varijablu kojom se mijenja vodeći znak (znak „ispu-
ne“) lijevo od broja, tako da umjesto zvjezdice on bude praznina ili razmak (engl. space, blank).
Učinite to i za dio programa 1b.

// MS Visual Studio: #include <stdafx.h>


#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
// Cjelobrojne (predznacene) varijable tipa int:
int iHexB = 16;
int iMinus1 = -1;
int iMin = 0x80000000; // Inicijalizacija broja u hex formi.
// Koji je to broj? Napišite ga u binar. formi!
int iMax = 0x7FFFFFFF; // Inicijalizacija broja u hex formi.
// Koji je to broj? Napišite ga u binarnoj formi!
// 1a. Ispis predznačenih var. u podrazumijevajucem dekadskom sustavu:
cout << "1a. Ispis varijabli tipa int u dekadskom sustavu:\n"
<< "============================================================\n"
<< "iHexB (= 16d ) = " << iHexB << "\n"
<< "iMinus1 (= -1d ) = " << iMinus1 << "\n"
<< "iMin (= 80000000h) = " << iMin << "\n"
<< "iMax (= 7FFFFFFFh) = " << iMax << "\n"
<< endl;
// "Redefinicija" varijabli. Mijenja li se vrijednost varijabli?
iMin = -2147483648; // Redefinicija broja u dekadskoj formi.
// Koji je to broj? Napišite ga u heksadek. formi!
iMax = 2147483647; // Redefinicija broja u dekadskoj formi. broj?
// Koji je to broj? Napišite ga u heksadek. formi!
// 2a. Ispis predznacenih varijabli u heksadekadskom sustavu:
cout << "2a. Ispis varijabli tipa int u heksadekadskom sustavu:\n"
<<"============================================================\n"
<< hex // izlazni manipulator hex -- mijenja bazu sustava u
// B = 16 i osigurava izlaz u heksadekskoj formi
<< "iHexB (= 16d ) = " << iHexB << "\n"
<< "iMinus1 (= -1d ) = " << iMinus1 << "\n"
<< "iMin (= -2147483648d) = " << iMin << "\n"
<< "iMax (= 2147483647d) = " << iMax << "\n"
<< dec // izlazni manipulator dec -- vraća bazu sustava u
// B = 10 i osigurava izlaz u dekadskoj formi.
<< endl;
// Cjelobrojne nepredznacene varijable tipa unsigned int:
unsigned int uHexB2 = 256;
unsigned int uMinus1 = (unsigned int) -1; // eksplicit. prilagodb. tipa
unsigned int uHalf1 = 0x7FFFFFFF; //Inicijalizac. u hex formi. Broj = ?
unsigned int uHalf2 = 0x80000000; //Inicijalizac. u hex formi. Broj = ?
unsigned int uMax = 0xFFFFFFFF; // Inicijalizac. u hex formi. Broj = ?
// 3a. Ispis nepredznač. var. u podrazumijevajućem dekadskom sustavu:
cout << "3a. Ispis varijabli tipa unsigned int u dekadskom sustavu:\n"
<< "============================================================\n"
<< "uHexB2 (= 16*16d) = " << uHexB2 << "\n"
<< "uMinus1 (= -1d) = " << uMinus1 << "\n"
<< "uHalf1 (= 7FFFFFFFh) = " << uHalf1 << "\n"
<< "uHalf1 (= 80000000h) = " << uHalf2 << "\n"
32
<< "uMax (= FFFFFFFFh) = " << uMax << "\n"
<< endl;
// Redefinicija varijabli. Mijenja li se vrijednost varijabli?
uHalf1 = 2147483647; // Redefincija broja u dekadskoj formi.
uHalf2 = 2147483648; // Redefinicija broja u dekadskoj formi.
uMax = 4294967295; // Redefinicija broja u dekadskoj formi.
// 4a. Ispis nepredznacenih varijabli u heksadekadskom sustavu:
cout << "4a. Ispis varijabli tipa unsigned int u heksadek. sustavu:\n"
<< "============================================================\n"
<< hex // izlazni manipulator dec -- postavlja bazu sustava u
// B = 16 i osigurava izlaz u heksadekadskoj formi
<< "uHexB2 (= 16*16d) = " << uHexB2 << "\n"
<< "uMinus1 (= -1d) = " << uMinus1 << "\n"
<< "uHalf1 (= 2147483647d) = " << uHalf1 << "\n"
<< "uHalf1 (= 2147483648d) = " << uHalf2 << "\n"
<< "uMax (= 4294967295d) = " << uMax << "\n"
<< dec // izlazni manipulator dec -- vraca bazu sustava u
// B = 10 i osigurava izlaz u dekadskoj formi
<< endl;
// Gornji ispisi uz ispravno poravnanje:
cout << "\n" // Dodatni novi redak
<< "Prethodni ispisi uz ispravno (desno) poravnanje brojeva\n"
<< "************************************************************\n"
<< endl;
unsigned short usW = 12; // Sirina polja za ispis brojeva
char cFill = '*'; // Znak za ispunu vodecih praznih polja
// 1b. Ispis predznač. varijabli u dekad. sust. uz ispravno poravnanje:
cout << "1a. Ispis var. tipa int u dekad. sust. uz desno poravnanje:\n"
<< "(sirina polja = " << usW << ", znak ispune = '" << cFill << "'.\n"
<< "============================================================\n"
// Postavka znaka "ispune", tj. znaka za vodeca mjesta lijevo od
// broja u rezerviranom polju:
<< setfill(cFill)
// Sirina polja rezervirana za varijablu postavlja se neposredno
// prije ispisa varijable operatorskom verzijom funkcije setw(width):
<< "iHexB (= 16d ) = " << setw(usW) << iHexB << "\n"
<< "iMinus1 (= -1d ) = " << setw(usW) << iMinus1 << "\n"
<< "iMin (= 80000000h) = " << setw(usW) << iMin << "\n"
<< "iMax (= 7FFFFFFFh) = " << setw(usW) << iMax << "\n"
<< endl;
// 2b:
// 3b:
// 4b:
return 0;
}

Zadatak 3.15 Izlazni manipulatori setprecision(int ), scientific, fixed, resetiosflags()


U ovom zadatku nastavljamo upoznavanje nekoliko korisnih izlaznih manipulatora pri radu s tipovi-
ma s pomičnom točkom. Opći naputci jednaki su onima iz prethodnog zadatka.
Ideja zadatka je da se objasni djelovanje izlaznog operatora setprecision(int ) u sprezi s manipu-
latorima setw(int ), te scientific i fixed, te da se ilustriraju različiti oblici ispisa. Kroz donje primje-
re i proučavanje rezultata programa treba uočiti da je kod tipa s pomičnom točkom sačuvana relativna
točnost (ukupan broj signifikantnih ili točnih znamenaka), ali ne i apsolutna točnost.
33

a) Proučite donji programski kôd. Uočite da se on, usprkos opsežnosti, svodi na ponavljanje sličnih
linija koda. Pažljivo proučite sve naveden komentare i odgovorite na pitanja postavljena u njima.
b) Odgonetnite specifičnosti u radu manipulatora setprecision(int) kad je on postavljen na inicijalne
(podrazumijevajuće) postavke izlaznog objekta cout, odnosno nakon što je djelovao manipulator
fixed. Objasnite o čemu se radi, i kako se to odražava na format ispisa.
c) Umetnite donji programski odsječak u glavnu funkciju C++ programa u projektu Zadatak_03_15 ,
te osigurajte potrebne uključne datoteke. Prevedite i izvršite program, povećajte prozor konzolne
aplikacije i proučite dobiveni ispis.
d) Što je karakteristično za ispise 1a i 2a? Što se događa s pomičnom točkom? Možemo li reći da ona
pluta, kroz broj znamenaka koji je određen za zadanu preciznost? Što je karakteristično za ispise
1b i 2b, te kako su oni dobiveni? Jesu li ispisi 1b i 2b pregledni s obzirom na položaj decimalne
točke? Navedite primjere područja u kojem bi takvo potpisivanje rezultata bilo obvezatno. Zatim
pažljivo provjerite jesu li ispisi 1b i 2b potpuno točni, s obzirom kako su varijable zadane? Potkri-
jepite svoje odgovore činjenicama o točnom broju dekadskih znamenaka za oba promatrana tipa s
pomičnom točkom.
e) Modificirajte program i provjerite rezultate ispisa. Najprije promijenite vrijednost znaka za ispunu
nepopunjenih mjesta u prazninu, što će ispis učiniti preglednijim. Mijenjajte vrijednosti za preciz-
nost i širinu polja. Koja je podrazumijevajuća preciznost tipova s pomičnom točkom, prije nego se
bilo što definira? Kako biste „resetirali“ postavke za preciznost na one podrazumijevajuće? Za
ideju pogledajte kako smo resetirali djelovanje manipulatora scientific i fixed.

////////////////////////////////////////////////////////////////////////////////
// Varijable tipa float: 7 točnih znamenaka
// Obratite pažnju što će biti točno zabiljezeno i ispisano!
float f0 = 0.1234567890f;
float f1 = 1.234567890f;
float f2 = 12.34567890f;
float f3 = 123.4567890f;
float f4 = 1234.567890f;
float f5 = 12345.67890f;
float f6 = 123456.7890f;
float f7 = 1234567.890f;
float fExMin2 = 0.01234567890f;
float fExMin3 = 0.001234567890f;
float fExMin4 = 0.0001234567890f;
// Varijable za definiranje izlaznih manipulatora tipa float:
unsigned short usPrec1 = 7;
unsigned short usW1 = 12;
char cFill1 = '*';
// 1a. Ispis varijabli tipa float:
cout
<< "1a. Ispis varijabli tipa float uz preciznost usPrec1 = " << usPrec1 << "\n"
<< " (sirina polja = " << usW1 << ", vodeci znak = '" << cFill1 << "')\n"
<< "==================================================================\n"
// Postavka preciznosti: broj signifikantnih (značajnih) znamenaka.
// Obratite pažnju: ulazi li tu i vodeća nula (lijevo od dec. točke)?
<< setprecision(usPrec1)
// Postavka znaka za vodeća mjesta lijevo od broja u rezerviranom polju:
<< setfill(cFill1)
// Širina polja rezervirana za varijablu postavlja se neposredno
// prije ispisa varijable operatorskom verzijom funkcije, setw(width):
<< " f0 (= 0.1234567890) = " << setw(usW1) << f0 << "\n"
<< " f1 (= 1.234567890) = " << setw(usW1) << f1 << "\n"
<< " f2 (= 12.34567890) = " << setw(usW1) << f2 << "\n"
<< " f3 (= 123.4567890) = " << setw(usW1) << f3 << "\n"
<< " f4 (= 1234.567890) = " << setw(usW1) << f4 << "\n"
34
<< " f5 (= 12345.67890) = " << setw(usW1) << f5 << "\n"
<< " f6 (= 123456.7890) = " << setw(usW1) << f6 << "\n"
<< " f7 (= 1234567.890) = " << setw(usW1) << f7 << "\n"
<< "\n"
// Ispis u "znanstvenoj notaciji":
<< scientific
<< "fExMin2 (1.234567e-2) = " << setw(usW1) << fExMin2 << "\n"
<< "fExMin3 (1.234567e-3) = " << setw(usW1) << fExMin3 << "\n"
<< "fExMin4 (1.234567e-4) = " << setw(usW1) << fExMin4 << "\n"
// Poništenje znanst. notacije i povratak na 1-komponentni zapis:
<< resetiosflags(ios_base::scientific)
// Završetak ispisa 1a, novi red:
<< endl;
// Varijable tipa double, 14-15 (uglavnom 15) tocnih znamenaka.
double d0 = 0.12345678901234567890;
double d1 = 1.2345678901234567890;
double d2 = 12.345678901234567890;
double d3 = 123.45678901234567890;
double d4 = 1234.5678901234567890;
double d5 = 12345.678901234567890;
double d6 = 123456.78901234567890;
double d7 = 1234567.8901234567890;
double dExMin2 = 0.012345678901234567890;
double dExMin3 = 0.0012345678901234567890;
double dExMin4 = 0.00012345678901234567890;
//
// Varijable za definiranje izlaznih manipulatora tipa double:
unsigned short usPrec2 = 15;
unsigned short usW2 = 20;
char cFill2 = '*';
// 2a. Ispis varijabli tipa double
cout
<< "2a. Ispis varijabli tipa float uz preciznost usPrec2 = " << usPrec2 << "\n"
<< " (sirina polja = " << usW2 << ", vodeci znak = '" << cFill2 << "')\n"
<< "==================================================================\n"
// Postavka preciznosti: broj signifikantnih (značajnih) znamenaka:
<< setprecision(usPrec2)
// Postavka znaka za vodeća mjesta:
<< setfill(cFill2)
// Postavka širine rezerviranog polja i ispis varijabli:
<< " d0 (= 0.12345678901234567890) = " << setw(usW2) << d0 << "\n"
<< " d1 (= 1.2345678901234567890) = " << setw(usW2) << d1 << "\n"
<< " d2 (= 12.345678901234567890) = " << setw(usW2) << d2 << "\n"
<< " d3 (= 123.45678901234567890) = " << setw(usW2) << d3 << "\n"
<< " d4 (= 1234.5678901234567890) = " << setw(usW2) << d4 << "\n"
<< " d5 (= 12345.678901234567890) = " << setw(usW2) << d5 << "\n"
<< " d6 (= 123456.78901234567890) = " << setw(usW2) << d6 << "\n"
<< " d7 (= 1234567.8901234567890) = " << setw(usW2) << d7 << "\n"
<< "\n"
// Ispis u "znanstvenoj notaciji":
<< scientific
<< "dExMin2 (1.2345678901234567890e-2) = " << setw(usW2) << dExMin2 << "\n"
<< "dExMin3 (1.2345678901234567890e-3) = " << setw(usW2) << dExMin3 << "\n"
<< "dExMin4 (1.2345678901234567890e-4) = " << setw(usW2) << dExMin4 << "\n"
// Povratak na "jednokomponentni" zapis broja:
<< resetiosflags(ios_base::scientific)
<< endl;
cout << "\n"
<< "Ispis uz fiksni polozaj decimalne tocke (manipulator: fixed)\n"
<< "*****************************************************************\n"
// Uporaba manipulatora fixed za fiksiranje dec. točke:
<< fixed // Nakon uporabe ovog izlaznog manipulatora, setprecision(n)
// postavlja BROJ ISPISANIH DECIMALA na n. Dakle, ne djeluje
35
// kao prije, da odredjuje broj signifikantnih znamenaka!
<< endl;
//
// Postavka novih vrijednosti preciznosti i širine polja:
usPrec1 = 4;
usW1 = 15;
// 1b. Ispis varijabli tipa float uz fiksni položaj točke
cout
<< "1b. Ispis varijabli tipa float uz preciznost usPrec1 = " << usPrec1 << "\n"
<< " (sirina polja = " << usW1 << ", vodeci znak = '" << cFill1 << "')\n"
<< "==================================================================\n"
36
// Postavka preciznosti: BROJ DECIMALA (vidi gornju napomenu)!
<< setprecision(usPrec1)
<< setfill(cFill1)
// Uporaba manipulatora setw(width) i ispis:
<< "f0 (= 0.1234567890) = " << setw(usW1) << f0 << "\n"
<< "f1 (= 1.234567890) = " << setw(usW1) << f1 << "\n"
<< "f2 (= 12.34567890) = " << setw(usW1) << f2 << "\n"
<< "f3 (= 123.4567890) = " << setw(usW1) << f3 << "\n"
<< "f4 (= 1234.567890) = " << setw(usW1) << f4 << "\n"
<< "f5 (= 12345.67890) = " << setw(usW1) << f5 << "\n"
<< "f6 (= 123456.7890) = " << setw(usW1) << f6 << "\n"
<< "f7 (= 1234567.890) = " << setw(usW1) << f7 << "\n"
<< "\n"
<< "fExMin2 (1.234567e-2) = " << setw(usW1) << fExMin2 << "\n"
<< "fExMin3 (1.234567e-3) = " << setw(usW1) << fExMin3 << "\n"
<< "fExMin4 (1.234567e-4) = " << setw(usW1) << fExMin4 << "\n"
<< endl;
//
// Postavka novih vrijednosti preciznosti i širine polja:
usPrec2 = 7;
usW2 = 20;
// 2b. Ispis varijabli tipa double uz fiksni polozaj tocke
cout
<< "2b. Ispis varijabli tipa float uz preciznost usPrec2 = " << usPrec2 << "\n"
<< " (sirina polja = " << usW2 << ", vodeci znak = '" << cFill2 << "')\n"
<< "==================================================================\n"
// Manipulator fixed vrijedi od zadnje postavke u 2a.
// NAKON fixed, OVO JE BROJ DECIMALA (vidi komentar pod 2a):
<< setprecision(usPrec2)
<< setfill(cFill2)
// Postavka širine polja i ispis:
<< " d0 (= 0.12345678901234567890) = " << setw(usW2) << d0 << "\n"
<< " d1 (= 1.2345678901234567890) = " << setw(usW2) << d1 << "\n"
<< " d2 (= 12.345678901234567890) = " << setw(usW2) << d2 << "\n"
<< " d3 (= 123.45678901234567890) = " << setw(usW2) << d3 << "\n"
<< " d4 (= 1234.5678901234567890) = " << setw(usW2) << d4 << "\n"
<< " d5 (= 12345.678901234567890) = " << setw(usW2) << d5 << "\n"
<< " d6 (= 123456.78901234567890) = " << setw(usW2) << d6 << "\n"
<< " d7 (= 1234567.8901234567890) = " << setw(usW2) << d7 << "\n"
<< "\n"
<< "dExMin2 (1.2345678901234567890e-2) = " << setw(usW2) << dExMin2 << "\n"
<< "dExMin3 (1.2345678901234567890e-3) = " << setw(usW2) << dExMin3 << "\n"
<< "dExMin4 (1.2345678901234567890e-4) = " << setw(usW2) << dExMin4 << "\n"
// Ponistenje djelovanja manipulatora fixed:
<< resetiosflags(ios_base::fixed)
<< endl;
////////////////////////////////////////////////////////////////////////////////

Zadatak 3.16 *Provjera opsega cjelobrojnih tipova podataka u testnom C / C++


programu*
Napomena. Zadaci sa zvjezdicom su za naprednije i ambicioznije studente. Tekst ovog, i nekolicine
drugih zadataka sa zvjezdicom bit će dodan naknadno.

*
Zadatke sa zvjezdicom možete ispustiti ako ste u vremenskom tjesnacu. Oni su namijenjeni naprednijim stu-
dentima s ambicijama za višu ocjenu.
37

Vježba 4. Osnovni operatori u jeziku C / C++


Vježba Vježba 4 slijedi gradivo, te razrađuje primjere i zadatke istobrojnog poglavlja lit. [1].

4.1 Teorijska priprema


Proučite gradivo u svezi operatora u jeziku C / C++ i odgovorite ukratko na dolje postavljena pitanja.
Svoje odgovore zabilježite u Dnevnik vježbi, i na taj se način pripremite za usmenu provjeru.

4.1.1 Operatori u jeziku C / C++


1. Koja je općenita uloga operatora u programskim jezicima? Koje su specifičnosti uporabe opera-
tora u jeziku C / C++ ?
2. Na koje dvije vrste dijelimo operatore glede broja izraza na koje djeluju? Objasnite nazive za
svaku vrstu.
3. Ako imamo n izraza, između kojih treba postaviti odgovarajuće operatore, koju vrstu (iz pret-
hodnog pitanja) i koliko ih moramo postaviti?
4. Što je to prefiksna, odnosno postfiksna, forma operatora.
5. Objasnite što je to operator pridruživanja i koja mu je oznaka u jezicima C / C++. Treba li razli-
kovati taj znak naspram istog znaka u matematici? Objasnite na primjerima.
6. Navedite kako se operator pridruživanja označava u nekim varijantama pseudo koda i opravdajte
taj izbor. Kako se taj operator označava u Pascalu?
7. Objasnite što je to l-vrijednost, a što r-vrijednost u programskom jeziku C / C++. Koji uvjet mo-
ra zadovoljavati l-vrijednost? Može li svaka l-vrijednost biti i r-vrijednost? A obrnuto? Pot-
krijepite svoje odgovore jednostavnim primjerima.

4.1.2 Aritmetički operatori


8. Navedite koji su unarni aritmetički operatori. Koji od njih su C / C++ specifični, uvedeni u jezi-
ku C? Koji od njih mogu biti i u prefiksnoj i u postfiksnoj formi, a koji ne mogu? Objasnite.
9. Navedite sve jednostavne aritmetičke operatore, te na jednostavnim primjerima prikažite njihovu
uporabu.
10. Ponovite koji je rezultat djelovanja operatora modulo (%). Ilustrirajte to na nekoliko primjera.
11. Navedite sve složene aritmetičke operatore. Objasnite kako se tvore i kako djeluju. Napišite
primjere iz prethodnog pitanja uporabom složenih aritmetičkih operatora.

4.1.3 Logički operatori


12. Navedite koji su logički operatori. Navedite engleske i hrvatske varijante njihovih naziva. Potra-
žite kako se oni označavaju u matematičkoj logici, i u digitalnoj elektronici.*

*
U različitim područjima osnovne logičke operacije pišu se na različite načine. Npr. u matematičkoj logici,
danas je za logičke operacije I, ILI i NE uobičajena uporaba simbola Λ , V i ¬ (ili ¯ ). Tako bismo C/C++
38

13. Koji logički operatori su unarni, a koji binarni?


14. Objasnite djelovanje logičkih operatora dovršenjem tablica istinitosti za sve moguće kombinacije
dviju vrijednosti logičkih varijabli: true (T) i false (F):

&& (AND) F T | | (OR) F T ! (NOT)


F F F
T T T

15. Kao podsjetnik na osnove računarstva: mogu li se prethodne logičke operacije povezati s aritme-
tičkima u aritmetici modulo 2? Koja logička operacija odgovara kojoj aritmetičkoj operaciji?
Objasnite?
16. Kako je logički tip bio prvobitno organiziran u jeziku C? Na što se svodi logička operacija I, a
na što logička operacija ILI? Objasnite i povežite s prethodnim zadatkom.
17. Glede logičkog tipa, što je dodano u jeziku C++? Jesu li uvedene promjene bitne? Što je to cje-
lobrojna promocija? Izračunavaju li se logičke operacije na isti ili različiti način u odnosu na je-
zik C?
18. Što je to kratkospojna provedba (engl. short-circuit evaluation)? Objasnite njezino značenje ko-
risteći gornje tablice istinitosti. Objasnite koja je kritična logička vrijednost za operaciju I, a
koja za ILI? (Natuknica. Ako je jedna logička varijabla F, treba li znati drugu varijabli da se
odredi rezultat operacije I ? Odnosno, ako je jedna logička varijabla T, treba li znati drugu da
se odredi rezultat operacije ILI ? Objasnite, i primijenite zaključke na kratkospojnu provedbu).

4.1.4 Relacijski operatori


19. Navedite što i na koji način rade relacijski operatori. Vrijednost kojeg tipa oni vraćaju? Kao što
vrijedi i za sve ostali operatore, jesu li to l-vrijednosti ili r-vrijednosti?
20. Navedite sve relacijske operatore i opišite njihovo značenje. Za svaki od operatora napišite kon-
kretne primjere u kojem je rezultat false , i true, prema sljedećem uzoru: ( 1 < 0 ) == false,
( 1 < 2 ) == true .
21. Pošto su rezultati djelovanja relacijskih operatora logičkog tipa, može li se kombinirati više rela-
cijskih izraza? Operatori kojeg tipa moraju biti između njih? Potkrijepite to vlastitim primjerima.

4.1.5 Izvođenje izraza u C / C++


22. Ukratko ponovite koji je postupak izvršavanja izraza u C / C++ ? U bitnom, slijedi li on uobiča-
jeni način na koji bismo izraze računali i u matematici? Koja je, već spomenuta velika razlika,
glede uporaba znaka = .
23. Dopušta li jezik C / C++ uporabu znaka pridruživanja u izrazima tipa r-vrijednosti (koji su i
sami s desne strane znaka pridruživanja)? Ako da, kako teče određivanje vrijednosti tih izraza?

izraze: a && b , a || b , !a , pisali redom: a Λ b , a V b , ¬a (ili ā ). U digitalnoj elektronici, za iste je opera-


cije uobičajeno korištenje znakova · , + , ¯ , pa bi gornji izrazi bili: a · b = ab , a + b , ā. Pri tom se
znakovi · i + nipošto ne smiju pomiješati s njihovim aritmetičkim značenjem. Uz dogovor da operator ·
ima prednost pri izvršavanju ispred + , ovakav način pisanja smanjuje potreban broj zagrada i čini logičke
izraze lakše čitljviim, ali ima i teorijskih mana što se na taj način gubi iz vida “jednakovrijednost” logičkih
operacija I i ILI. Također, u digitalnoj elektronici se tradicionalno za logičku vrijednost laž koristi 0, za istinu
1 (usporedi cjelobrojnu promociju logičkog tipa u C++).
39

24. Je li uputno zlorabiti slobodu koja je dopuštena u pisanju izraza, nauštrb preglednosti i jasnoće?
Ako se previše izraza združi u jednu dugačku tvrdnju, mogu li se pojedinosti adekvatno komenti-
rati? Što je posljedica slabog komentiranja pojedinih dijelova programa?

4.1.6 Prethodnost operatora


25. Objasnite ukratko što je to prethodnost operatora. Koji aritmetički operatori imaju prethodnost
izvršavanja u odnosu na ostale? Vrijede li tu pravila uobičajena u matematici?
26. Čemu služe zagrade? Kako se u C / C++ tretira par zagrada? Napišite primjer izraza u kojem je
nužno korištenje zagrada. Zatim maknite zagrade i obrazložite kako se u tom slučaju izračunava
izraz.
27. Koji će se operatori prije izvršavati: i) relacijski ili aritmetički, ii) logički ili relacijski, iii ) ari-
tmetički ili operator pridruživanja, iv) relacijski ili operator pridruživanja, logički ili operator
pridruživanja.
28. Glede stila pisanja izraza u tvrdnjama jezika C / C++, što je bolje: ostvariti preglednost i jasnoću
izraza uvođenjem nekoliko „suvišnih“ zagrada, ili se strogo držati pravila o prethodnosti operato-
ra, strogo izbjegavajući uporabu zagrada kad god je to moguće.
29. Što je bolje: koristiti uobičajena (matematička) pravila o prethodnosti izvršavanja operatora i
izbjeći suvišne zagrade, uvijek pisati zagrade bez obzira na prethodnost operatora.
30. Odredite vrijednost sljedeća tri izraza. Koji od njih daju isti rezultat i zbog čega? Je li izraz s
više zagrada u ovom slučaju ipak pregledniji? Za tablicu prethodnosti operatora konzultirajte
članak: http://www.cppreference.com/wiki/operator_precedence. Obratite pažnju da operatori
unutar iste grupe imaju istu prethodnost, tj. da se izvršavaju kako se pojavljuju, s lijeva na desno.
a) ( −111 < −11 ) | | ( (−11 <= −10) && true );
b) ( ( −111 < −11 ) | | ( (−11 <= −10) ) && true ;
c) ( −111 < −11 ) | | ( (−11 <= −10) && true .

4.2 Primjeri i zadaci


Primjer 4.1 Uporaba aritmetičkih operatora.
U sljedećem programu izložen je primjer uporabe aritmetičkih operatora. Proučite ga pažljivo i riješite
zadatke Zadatak 4.1 i Zadatak 4.2 u svezi s njime. (Opaska: u programski kôd namjerno su ugrađene
3 sintaktičke pogreške. Pronađite ih i ispravite.).
#include <iostream>
using namespace std;
int main()
{
// Cjelobrojne varijable koje će biti definirane unosom:
int i1, i2, i3;
// Cjelobrojna varijable za međurezultate i rezultate:
int iRes, iHlp;
// Unos cjelobrojnih varijabli:
cout << "Unesite cijeli broj, i1 = " ;
cin >> i1;
cout << "Unesite cijeli broj, i2 = " ;
cin >> i2;
cout << "Unesite cijeli broj, i3 = " ;
cin >> i3;
cout << endl;
40
// Primjeri aritmetičkih operacija s unesenim brojevima
// Uvećajte prvi broj za drugi, i tako dobiveni broj pomnožite trećim:
iRes = (i1 + i2)*i3;
cout << "(i1 + i2)*i3 = Izraz1 = " << iRes << "\n";
// Prethodni izraz uvećajte za 1 i potom podijelite prvim brojem:
iRes = (iRes + 1/i1;
cout << "(Izraz1 + 1)/i1 = Izraz2 = " << iRes << "\n";
// Rezultat cjelobrojnog djeljenja prethodnog izraza s i2 pohranite u
// pomoćnu varijablu, i ispišite ga:
iHlp = iRes / i2;
cout << " Izraz2 / i2 = Izraz3 = << iHlp << "\n";
// Odredite ostatak cjelobroj. dijelj. izraza Izraz2 s i2 i ispišite:
iRes = iRes % i2;
cout << " Izraz2 mod i2 = Izraz4 = " << iRes << "\n";
<< endl;
// Je li nakon zadnje arit. operacije sačuvana vrijednost Izraz2?
// Gdje je bila pohranjena? Rekonstruirajte je iz vrijednosti i2,
// Izraz3 i Izraz4, na temelju definicije cjelobrojnog dijeljenja i
// operacije modulo, bez uvođenja novih varijabli.
// Dodajte potrebne linije, i ispišite "rekonstruiranu vrijed. Izraz2.
// Izračun (rekonstrukcija), izraza Izraz2 u varijabli iRes,
// iRes = ?
// Ispis: "Rekonstr. Izraz2 = ...
// ...
system ("pause");
return 0;
}

Zadatak 4.1 Analiza primjera (Primjer 4.1)


a) Pažljivo proučite prođite kroz programski kôd gornjeg primjera i objasnite sve korištene tvrdnje
(naredbe). Usput odgonetnite 3 sintaktičke pogreške.
b) Prije nego izvršite program, pretpostavite da su učitane ulazne varijable vrijednosti 3, 4, 5 i pred-
vidite ispis. Potrebno je postaviti početne vrijednosti: i1 = 3, i2 = 4, i3 = 5, te zatim nakon sva-
kog aritmetičkog izraza napisati vrijednosti koje se mijenjaju (iRes, iHlp), te na temelju toga od-
rediti što će biti ispisano.

Zadatak 4.2 Dovršenje zadatka (Primjer 4.1)


a) Prateći kako se u varijabli iRes za pohranu međurezultata mijenjaju vrijednosti izraza, odgovorite
vrijednost kojeg izraza je zadnja pohranjena u njoj? Je li sačuvana vrijednost izraza Izraz2 (pita-
nje postavljeno u komentaru pri kraju programa). Razmislite kako ćete bez uvođenja novih varija-
bli i promjene prijašnjeg dijela programa, rekonstruirati vrijednost Izraz2. Najprije, na temelju
razumijevanja operacija cjelobrojnog dijeljenja i modulo, riješite problem na papiru.
b) Otvorite novi projekt pod nazivom Zadatak_04_01_2 i u njega kopirajte programski kôd iz gor-
njeg primjera. Sredite stil pisanja, otklonite problematične znakove, sintaktičke greške i pokrenite
program. Provjerite da ste dobro riješili sve prethodne zadatke. Dopišite linije koje nedostaju.
Provjerite vaše rješenje usporedbom s vrijednosti Izraz2 u prethodnim retcima ispisa.
c) Diskusija uz poziv funkcije system ("pause“). Primijetimo da je u ovom primjeru dodan poziv
funkcije za „pauzu“. Izvršite program iz razvojne okoline i uočite koliko se puta pojavljuje poru-
41

ka: “Press any key to continue…” prije izlaska iz prozora konzolne aplikacije? Pronađite izvršnu
verziju programa u podmapi projekta (Zadatak_04_01_2). Pokrenite program izravno iz grafičke
okoline operacijskog sustava Windows i odgovorite na prethodno pitanje. Zatim uklonite poziv si-
stemske funkcije pauze, i ponovite pokretanje programa na dva načina: iz razvojne okoline VS
2005, te iz grafičkog sučelja OS Windows. Izvedite zaključke.

Zadatak 4.3 Uporaba inkrementnih, dekrementnih i složenih operatora.


Proučite sljedeći programski odsječak. Odgovorite na pitanja prije provjere programa na računalu.
a) Koji će biti rezultat ispisa 1. Obratite pažnju na djelovanje pre i post inkrementnih operatora. Pre-
dvidite rezultate ispisa 2 i diskutirajte razlike u odnosu na ispis 1.
b) Zamijenite 5 izraza koji koriste složene aritmetičke operatore, s izrazima u kojima će se pojavljiva-
ti samo jednostavni operatori. Odredite stanje varijabli u svakom koraku i na temelju toga odredite
ispis ovih varijabli.
c) Umetnite ovaj programski odsječak u glavnu funkciju novog projekta. Usporedite ispise računala s
vašim predviđanjima. Ukoliko ste predvidjeli krive rezultate, ponovite gradivo o radu aritmetičkih
operatora.
/////////////
// Cjelobrojne varijable:
int i1 = 10, i2 = 20, i3 = 30, i4 = 40;
// Ispis 0. Inicijalne vrijednosti:
cout << " i1 = " << i1 << "\n"
<< " i2 = " << i2 << "\n"
<< " i3 = " << i3 << "\n"
<< " i4 = " << i4 << "\n"
<< endl;
// Uporaba pre i postfiksnih inkrementnih i dekrementnih operatora.
// Ispis 1. Objasnite i predvidite ispis!
cout << "++i1 -> " << ++i1 << "\n"
<< " i2++ -> " << i2++ << "\n"
<< "--i3 -> " << --i3 << "\n"
<< " i4-- -> " << i4++ << "\n"
<< endl;
// Ispis 2. Trenutne vrijednosti varijabli:
cout << " i1 = " << i1 << "\n"
<< " i2 = " << i2 << "\n"
<< " i3 = " << i3 << "\n"
<< " i4 = " << i4 << "\n"
<< endl;
// Uporaba složenih aritmetičkih operatora.
i1 -= i4; // Raspišite preko jednostavnih operatora: i1 =
i2 += i3; // Raspišite preko jednostavnih operatora: i2 =
i3 *= i2; // Raspišite preko jednostavnih operatora: i3 =
i4 /= i1; // Raspišite preko jednostavnih operatora: i4 =
// Ispis 3. Nove vrijednosti. Objasnite i predividite ispis:
cout << "i1 -= i4, i1 = " << i1 << "\n"
<< "i2 += i3, i2 = " << i2 << "\n"
<< "i3 *= i2, i3 = " << i3 << "\n"
<< "i4 /= i1, i4 = " << i4 << "\n"
<< endl;
// Uporaba složenog operatora, uz složeni izraz s desne strane:
i4 += i3 + i2/i1 ; // Raspišite: i4 =
42
// Ispis 4. Nova vrijednost var. i3. Objasnite i predividite ispis:
cout << "i4 += i3 + i2/i1, i4 = " << i4 << "\n"
<< endl;
/////////////

Zadatak 4.4 Program za izračun ukupne neto i bruto cijene za skup do 10 artikala.
Sastavite program u C++ koji će učitati bruto cijene do maksimalno 10 artikala, i njihove količine.
Ako artikla nema, cijena mu je 0.00 Kn. Kao rezultat, program mora ispisati ukupnu neto cijenu bez
poreza u iznosu od 22% (PDV), zatim iznos poreza, te ukupnu (bruto) cijenu svih artikala, sve popra-
ćeno odgovarajućim komentarima. Koristite modifikatore za kontrolu ispisa, koji mora biti s dvije
decimale i zadovoljavajućim brojem mjesta (vidjeti zad. Zadatak 3.15).
Napomene. Program je na razini početničkog primjera i ne rabi iteracije (vidi vježbu Vježba 5), kon-
trolu unosa i druge pogodnosti koje bi korisnik očekivao. Koristite dolje sugerirane tipove i nazive za
varijable. Slijedite naputke u komentarima i dodajte potrebne linije programskog koda. Pregledno or-
ganizirajte programski kôd i služite se kopiranjem istih i sličnih dijelova programa. Zatim funkcijom
find-replace zamijenite dijelove koji se mijenjaju (npr. broj artikla). Dodatno odgovorite na sljedeća
pitanja u svezi ovog programa.
a) Koje su mane ovog programa glede organizacije pohrane podataka? Je li program praktičan ako
imamo npr. svega nekoliko artikala? Je li uporabljiv za općeniti slučaj, npr. broja artikala većeg od
10? Jesu li to ozbiljne mane?
b) Kako je riješen slučaj kad artikala ima manje od 10? Što će korisnik morati unositi u tom slučaju?
// Konstantni iznos poreza:
const float fPDV = .22f;
/////////////
// Varijable za cijenu artikala:
double dCijArtkl_01, dCijArtkl_02, dCijArtkl_03, fCijArtkl_04,dCijArtkl_05,
dCijArtkl_06, dCijArtkl_07, dCijArtkl_08, dCijArtkl_09,dCijArtkl_10;
/////////////
// Varijable za ukupnu cijenu:
double dCijUkupna; // Po potrebi uvedite i druge varijable.
/////////////
// Varijable za količinu artikala:
unsigned short int
sKolArtkl_01, dKolArtkl_02, dKolArtkl_03, fKolArtkl_04,dKolArtkl_05,
sKolArtkl_06, dKolArtkl_07, dKolArtkl_08, dKolArtkl_09,dKolArtkl_10;
/////////////
// Izračun ukupne cijene
// ...

// Ispis neto cijene, iznosa poreza, ukupne cijene:


// ...

Zadatak 4.5 *Nadopuna prethodnog programa ispisom podataka za pojedine artikle.


Kod izrade računa uobičajeno je da on sadrži specifikacije svih artikala po njihovoj cijeni i količini.
Nadopunite prethodni program tako da prije ispisa ukupne cijene ispišete listu svih artikala (naruče-
nih, kupljenih i sl.). Lista započinje zaglavljem po uzoru na zaglavlja tablice, s rednim brojem artikla
u prvoj koloni, cijenom u drugoj, količinom u trećoj, neto cijenom u četvrtoj i bruto cijenom u petoj.
Na isti način treba organizirati i ispis. Koristite izlazne manipulatore fixed, setprecision(n) te setw(n),
43

da biste ostvarili pregledan ispis (zad. Zadatak 3.15). Ukoliko ćete imati problema kod organizacije i
preglednosti ispisa, možete ga, za početak, pojednostaviti ispuštanjem nekih od navedenih veličina.

Zadatak 4.6 Produženi izrazi pridruživanja.


Promotrite šest izraza u donjem programskom odsječku. Koji od njih su jasni i pregledni a koji nisu?
Napišite komentare za izraze 2 do 6. Odgovorite na pitanja:
a) Predvidite koje će biti stanje varijabli nakon svakog od izraza. Ako niste sigurni proučite ponovo
teorijsko gradivo o značenju operatora i načinu izračuna izraza. Tek potom umetnite u testni prog-
ram naredbe za ispis (npr. preko cout) nakon svakog izraza i provjerite svoje odgovore.
b) Za svaki od «produženih» izraza napišite ekvivalentni programski kôd s naredbama u kojima se
pojavljuje samo jedan znak jednostavnog pridruživanja ( = ).
//////////////////
int iN1, iN2, iN3;
// Inicijalizacija varijabli kroz produženi izraz
// Izraz 1:
iN1 = iN2 = iN3 = 10; // svi iNk = 10, k = 1, 2, 3.
// Izraz 2:
iN3 += iN2 += iN1; // iN1 = ?, iN2 = ?, iN3 = ?
// Izraz 3:
iN3 -= iN2 -= iN1 /= 4 + 4; // iN1 = ?, iN2 = ?, iN3 = ?
// Reinicijalizacija varijabli (kao gore)
iN1 = iN2 = iN3 = 10; // svi iNk = 10, k = 1, 2, 3.
iN3 += iN2 += iN1; // iN1 = ?, iN2 = ?, iN3 = ?
// Izraz 4 (modificirani izraz 3):
iN3 -= iN2 -= (iN1 /= 4) + 4; // iN1 = ?, iN2 = ?, iN3 = ?
// Reinicijalizacija:
iN1 = iN2 = iN3 = 12; // svi iNk = 12, k = 1, 2, 3.
// Izraz 5:
iN1 *= iN2 /= iN3 %= 5; // iN1 = ?, iN2 = ?, iN3 = ?
// Izraz 6:
iN1 /= (iN2 /= 3 - iN2 % 5); // iN1 = ?, iN2 = ?, iN3 = ?

/* // Primjer koda za ispis:


cout << "iN1 = " << iN1 << "\n"
<< "iN2 = " << iN2 << "\n"
<< "iN3 = " << iN3 << "\n"
<< endl;
*/
//////////////////

Zadatak 4.7 *Inkrementni i dekrementni operatori u pre i post fiksnoj formi.


Kroz sljedeći zadatak produbite svoje znanje o djelovanju operatora ++ i -- u prefiksnoj i postfik-
snoj formi. Prije provjere programskog odsječka u testnom programu, nastojte predvidjeti sve vrijed-
nosti koje će se ispisati. Provjerite zatim mijenja li se i kako djelovanje operatora stavljanjem izraza
unutar zagrada. Događa li se ono što ste očekivali? Objasnite!
Napomena. Ovdje koristimo skraćenica UINT za unsigned int. Za njeno ispravno raspoznavanje
nužno je uključiti datoteku "windows.h".
/////////////////////////////////////
// UINT zahtjeva #include "windows.h"
//
44
UINT uI1 = 0, uI2 = 0;
UINT uIPre = 0, uIPost = 0;
//Ispis stanja (početno):
cout << "1.0 Inicijalno stanje:\n"
<< "===================================================\n"
<< "uIPre = " << uIPre << "\t"
<< "uIPost = " << uIPost << "\n";
cout << "uI1 = " << uI1 << "\t"
<< "uI2 = " << uI2 << "\n\n"
<< endl;
// Pridruživanje inkrementiranih vrijednosti po djelovanju
// 1. preinkrementnog, i 2. postinkrementnog operatora:
uIPre = ++uI1 ;
uIPost = uI2++ ;
// Ispis stanja po djelovanju ++ operatora:
cout << "1.1 Stanje po djelovanju ++ operatora:\n"
<< "===================================================\n"
<< "uIPre = ++uI1 = " << uIPre << "\t"
<< "uIPost = uI2++ = " << uIPost << "\n";
cout << "uI1 = " << uI1 << "\t"
<< "uI2 = " << uI2 << "\n\n"
<< endl;
// Pre i post-inkrementni operatori uz uporabu zagrada
//
// Reinicijalizacija:
uI1 = uI2 = uIPre = uIPost = 0;
// Ispis stanja (početno):
cout << "2.0 Novo inicijalno stanje:\n"
<< "===================================================\n"
<< "uIPre = " << uIPre << "\t"
<< "uIPost = " << uIPost << "\n";
cout << "uI1 = " << uI1 << "\t"
<< "uI2 = " << uI2 << "\n\n"
<< endl;
// Djelovanje operatora
uIPre = (++uI1) ;
uIPost = (uI2++) ;
//Ispis stanja po djelovanju ++ operatora uz zagrade:
cout << "2.1 Stanje po djelovanju ++ operatora uz zagrade:\n"
<< "===================================================\n"
<< "uIPre = (++uI1) = " << uIPre << "\t"
<< "uIPost = (uI2++) = " << uIPost << "\n";
cout << "uI1 = " << uI1 << "\t"
<< "uI2 = " << uI2 << "\n\n"
<< endl;
cout << "Sto zakljucujete? Objasnite kako djeluju zagrade!\n\n"
<< endl;
//
///////////////////////
45

Zadatak 4.8 *Operatori ++ i -- , dodatni zadatak.


Prije provjere programskog odsječka u testnom programu, odgonetnite sve vrijednosti koje će se ispi-
sati. Usput ponovite što ste već ranije naučili o tipu UINT (unsigned int)? Kako će se izvršiti pret-
vorba tipa UINT u int? Hoće li, i što, dojaviti kompilator?
UINT uPPPre, uPPPost, uMMPre, uMMPost;
uPPPre = uPPPost = uMMPre = uMMPost = 0;
cout << "UINT uPPPre, uPPPost, uMMPre, uMMPost \n"
<< "========================================\n"
<< endl;
// Ispis stanja (početno):
cout << "uPPPre = " << uPPPre << "\n"
<< "uPPPost = " << uPPPost << "\n"
<< "uMMPre = " << uMMPre << "\n"
<< "uMMPost = " << uMMPost << "\n"
<< endl;
// Ispis uz djelovanje pre i post inkrementirajućih i
// dekrementirajućih operatora 1. put:
cout << "uPPPre = ++uPPpre = " << ++uPPPre << "\n"
<< "uPPPost = uPPPost++ = " << uPPPost++ << "\n"
<< "uMMPre = --uMMPre = " << --uMMPre << "\n"
<< "uMMPost = uMMPost-- = " << uMMPost-- << "\n"
<< endl;
// Ispis stanja (nakon prvog djelovanja):
cout << "uPPPre = " << uPPPre << "\n"
<< "uPPPost = " << uPPPost << "\n"
<< "uMMPre = " << uMMPre << "\n"
<< "uMMPost = " << uMMPost << "\n"
<< endl;
// Ispis uz djelovanje pre i post inkrementirajućih i
// dekrementirajućih operatora 2. put:
cout << "uPPPre = ++uPPpre = " << ++uPPPre << "\n"
<< "uPPPost = uPPPost++ = " << uPPPost++ << "\n"
<< "uMMPre = --uMMPre = " << --uMMPre << "\n"
<< "uMMPost = uMMPost-- = " << uMMPost-- << "\n"
<< endl;
// Ispis stanja (nakon drugog djelovanja):
cout << "uPPPre = " << uPPPre << "\n"
<< "uPPPost = " << uPPPost << "\n"
<< "uMMPre = " << uMMPre << "\n"
<< "uMMPost = " << uMMPost << "\n"
<< endl;
// Prijelaz s UINT na int:
int iMMPre = uMMPre;
int iMMPost = uMMPost;
cout << "iMMPre = " << iMMPre << "\n"
<< "iMMPost = " << iMMPost << "\n"
<< endl;
//////////////////////

Zadatak 4.9 *Uporaba operatora ++ i -- u izrazima složenog tipa.


U ovom zadatku možete provjeriti svoje razumijevanje djelovanja operatora ++ i -- u izrazima slo-
ženijeg tipa. Odgonetnite što će se ispisati nakon izvođenja sljedećeg programskog odsječka i potom
provjerite izvođenjem u testnom programu. Pokušajte maknuti neku od zagrada oko izraza čije se
46

vrijednosti ispisuju i vidite što se događa. Na koncu razmislite, ima li, osim za vježbu, smisla pisati
izraze ovakvog tipa? Zadovoljavaju li oni načelo jasnoće i preglednosti pisanja?
///////////
int i = 5;
cout << "int i = " << i << "\n" << endl;
// ispis = ?, i = ?
cout << " -(--i)++ \tispis : " << -(--i)++ << endl;
cout << "\t\ti = " << i << "\n" << endl;
// ispis = ?, i = ?
cout << "( i -= - i++ ) \tispis : " << ( i -= - i++ ) << endl;
cout << "\t\ti = " << i << "\n" << endl;
// ispis = ?, i = ?
cout << "( i += - ++i ) \tispis : " << ( i += - ++i ) << endl;
cout << "\t\ti = " << i << "\n" << endl;
////////////

Zadatak 4.10 Uporaba logičkih operatora.


U sljedećem programskom odsječku odredite rezultat ispisa.
bool b0 = false;
bool b1 = true, bVar;
cout << " b0 = " << b0 << "\t b1 = " << b1 << "\n"
<< endl;
bVar = b0 && b1; // AND
cout << " b0 && b1 = " << bVar << "\n"
<< " !(b0 && b1) = " << !bVar << "\n"
<< endl;
bVar = b0 || b1; // OR
cout << " b0 || b1 = " << bVar << "\n"
<< " !(b0 || b1) = " << !bVar << "\n"
<< endl;

Zadatak 4.11 *Logičke funkcije sume i prijenosa za poluzbrajalo


Napišite program koji upisuje vrijednosti dva bita x0 i y0 kao dvije logičke varijable (npr. bool bX0,
bY0), te ispisuje vrijednosti dvije logičke funkcije, sume i prijenosa, za poluzbrajalo (HA = Half Ad-
der). Podsjetite se binarnog zbrajanja, te napišite najprije tablicu istinitosti za funkcije sume i prijeno-
sa (vidi također kolegije Informatika, te područje Logike sudova u matematici).
Skica rješenja. Suma dva bita je 1 ako su bitovi različiti, tj. jedan je 0, a drugi 1. To se opisuje lo-
gičkom funkcijom isključivo ili (engl. exclusive OR). Rabeći oznake kao u digitalnoj aritmetici, tj.
znak · za logičko I, te znak + za logičko ili, logička funkcija S za sumu dva bita ima oblik:
S =xy + xy .
Dakle, gornja funkcija će dati jedinicu kad je jedan od bitova 1, a nulu kad su oba bita ili 0 ili 1.
U slučaju kad su oba bita 1, još treba osigurati i prijenos 1 (1 + 1 = 0 , i 1 dalje). Logička funkcija
koja daje 1 samo kad su oba bita 1 je upravo AND, pa za prijenosa koju ćemo označiti s CHA (od
engl. carry), vrijedi jednostavno:
C= xy.
Implementirajte ove funkcije rabeći odgovarajuće C / C++ logičke operatore.
47

Zadatak 4.12 *Logičke funkcije sume i prijenosa za potpuno zbrajalo.


Napišite program koji upisuje vrijednosti dva bita b1 i b2, te prijenos iz nižeg bita b0, kao tri lo-
gičke varijable, te ispisuje vrijednosti sume i prijenosa, za potpuno zbrajalo (FA = Full Adder). Pod-
sjetite se binarnog zbrajanja, te napišite najprije tablicu istinitosti za funkcije sume i prijenosa (vidi
također kolegije Informatika, te područje Logike sudova u matematici).
Skica rješenja. Kod zbrajanja dva n-bitna cijela broja, na svim pozicijama i višim od početnih (s
težinskim indeksom i = 0), dakle uz i = 1, 2 , … n −1 , imamo zbrajanje po 2 bita xi i yi , ali i
prijenos C i−1 iz nižeg bita. Suma tri bita je 1 ako je samo jedan od njih, ili sva tri 1, pa za funkciju
sume pišemo:
S i = x i bi C i −1 + x i bi C i −1 + x i bi C i−1 + x i bi C i −1 .
Prijenos će biti 1 kad su najmanje 2 , ili sva tri bita na 1, što se piše kao:

Ci = xi bi Ci−1 + xi bi Ci−1 + xi bi Ci−1 + xi bi Ci−1 .


Posljednja logička funkcija dade se skratiti (minimizirati), kad prelazi u:
Ci = xi bi + bi Ci−1 + xi Ci−1 .
Implementirajte gornje dvije logičke funkcije s pomoću logičkih operatora u C / C++. Time se do-
biva potpuno zbrajalo. Želimo li zbrajati n-bitne brojeve, povežemo n takvih zbrajala i dobivamo
osnovni sklop aritmetičko logičke jedinke (ALU). (Napomena. Za detaljnija objašnjena gornjih lo-
gičkih funkcija, potrebno je konzultirati gradivo logike sudova ili digitalne elektronike.)

Zadatak 4.13 Relacijski operatori.


U sljedećem programskom odsječku odredite vrijednosti svih varijabli, logičkih i cjelobrojnih, te od-
govorite na dodatna pitanja:
a) Najprije dobro promislite o odgovorima, i prisjetite se «kratko-spojnog» načina izvršavanja logič-
kih izraza. Za svaku od logičkih operacija && i || odredite koja je vrijednost «kritična», odnosno
nakon koje vrijednosti lijeve strane izraza, desnu stranu nije potrebno određivati. Tek potom testi-
rajte vrijednosti ispisujući njihove vrijednosti na ekranu.
b) Skratite (pojednostavite) sve izraze koji se daju skratiti, i ispitajte ih i tako skraćene.
////////
bool b1, b2, b3, b4, b5, b6;
int i1 = 0, i2 = -1;
b1 = (i1 >= i2) && !(i1 == i2); // b1 = ?
b2 = (i1 > -i2) || !(i1*i2 <= i2); // b2 = ?
// Nove vrijednosti cjelobrojnih varijabli:
i1 = i2 = 0 ;
// b3 = ?, b4 = ?
b3 = (++i1 > i2++) && (--i1 < i2--); // i1 = ? , i2 = ?
b4 = (++i1 <= i2++) || (--i1 < i2--); // i1 = ? , i2 = ?
// b5 = ?, b6 = ?
b5 = (++i1 < i2++) && (--i1 < i2--); // i1 = ? , i2 = ?
b6 = (++i1 > i2++) || (--i1 < i2--); // i1 = ? , i2 = ?
//////////
48

Zadatak 4.14 Složeni logički izrazi.


Napišite odsječak programa u kojem ćete deklarirati sve potrebne varijable i napisati logički izraz za
logičku varijablu bProsaoIspitIzProg1 pridružuje vrijednost true ako je student zadovoljio kriterije,
a u suprotnom vrijednost false. Prvi preduvjet je da vrijednost nepredznačene cjelobrojne varijable
uBrojPrisustNaPred nije manja od 60% maksimalnog broja prisustvovanja koji je sadržan u
cjelobrojnoj nepredznačenoj konstanti uMaxPrisustNaPred (koja iznosi 8). Drugi preduvjet je da
vrijednost nepredznačene cjelobrojne varijable uBrojPrisustNaVjez nije manja od 80%
maksimalnog broja prisustvovanja koji je sadržan u cjelobrojnoj nepredznačenoj konstanti
uMaxPrisustNaVjez (koja iznosi 12). U slučaju da su oba kriterija prisustvovanja zadovoljena,
varijabli bApsolvirao se uspust (untar logičkog izraza) pridružuje vrijednost true. Potom se gleda je
li student prošao oba kolokvija, čije su ocjene dane u nepredznačenim varijablama uOcjKolok1 i
uOcjKolok2, ili je zadovoljio na pismenom ispitu čija je ocjena u varijabli uOcjPisIspita . Testirajte
napisani kod u testnom programu.
49

Vježba 5. Organizacija izvornog koda, programske


strukture, i kontrola toka programa
Zadatak ove vježbe je usvojiti osnovna znanja o organizaciji izvornog koda u blokove, te o program-
skim strukturama koje omogućuju pisanje funkcionalnih programa.

5.1 Teorijska priprema


Kao pripremu za ovu vježbu potrebno je proučiti gradivo odgovarajućeg poglavlja u lit. [1] o bloko-
vima naredbi, te o osnovnim programskim strukturama: sekvenca (slijed), selekcija (izbor), iteracija
(ponavljanje). Odgovorite na pitanja koja slijede.

5.1.1 Blokovi tvrdnji (naredbi) u C / C++


1. Što je blok naredbi, kako se označava i čemu služi? Kako se odjeljuju tvrdnje unutar bloka?
2. Navedite gdje smo u dosadašnji primjerima koristili blokove naredbi. Je li bilo primjera korište-
nja više od jednog bloka u programu? Što ste naučili iz teorije – gdje ćemo redovito koristiti blo-
kove naredbi?
3. Ako se radi o samo jednoj tvrdnji, treba li organizirati blok i pisati vitičaste zagrade? Objasnite i
navedite prednosti takvog načina pisanja. S druge strane, je li i u tom slučaju dozvoljeno otvara-
nje bloka vitičastim zagradama?
4. Objasnite detaljno dogled lokalnih varijabli u podređenim (ugniježđenim) blokovima. Što se do-
gađa ako u podređenom bloku deklariramo varijablu istog imena kao i u nadređenom? Hoće li
doći do dojave greške? Ili ako ne, koju varijablu će kompilator koristiti?
5. Neka je unutar glavne funkcije otvoren blok naredbi i unutar njega deklarirana lokalna varijabla.
Blok je zatvoren, i zatim je otvoren blok iste, nazovimo je, paralelne hijerarhijske razine. Mo-
žemo li u tom bloku koristiti prethodnu varijablu, dakle bez ponovne deklaracije. Hoće li i što
dojaviti kompilator. Ako postoji problem, objasnite ga i predložite rješenje.
6. Mogu li se, i kakve, tvrdnje pisati izvan bloka funkcija (glavne ili ostalih)? Provjerite svoj odgo-
vor testiranjem u testnom programu.

5.1.2 Slijed naredbi (sekvenca)


7. Navedite što je to slijed tvrdnji ili naredbi, kako su oni odijeljeni, te kako se izvode u jeziku
C / C++.
8. Koja je osnovna i najjednostavnija programska struktura? Jesmo li je koristili u dosadašnjim
primjerima? Jesmo li koristili još koju programsku strukturu osim nje?
9. Kakvi algoritmi se mogu implementirati s pomoću jednostavnog slijeda tvrdnji? Za koje algori-
tme to neće vrijediti? Navedite ograničenja ove programske strukture, te ilustrirajte ukratko na
primjerima.
50

5.1.3 Izbor (selekcija) i uvjetne tvrdnje


10. Navedite nekoliko jednostavnih algoritama koji zahtijevaju izbor različitih putova izvođenja u
ovisnosti o nekim testiranim vrijednostima. Diskutirajte npr. algoritam nalaženja najmanjeg i
najvećeg broja iz nekog skupa, rješavanje kvadratne jednadžbe, i sl.
11. Uporabom kojih tvrdnji u C / C++ se ostvaruje programska struktura izbora? Napišite opći oblik
ovih tvrdnji. Prevedite sve korištene rezervirane riječi s engleskog na hrvatski.
12. Objasnite izvršavanje uvjetne tvrdnje: if (condition) block1 else block2 . Navedite kojeg je
tip izraz condition, tj. koji tip vrijednosti on vraća. Kakva može biti njegova vrijednost, te što se
točno događa za svaku od navedenih vrijednosti. Raspišite gornju tvrdnju na uobičajeni način u
više redaka.
13. Objasnite izvršavanje proširenog uvjetne tvrdnje: if (cond1) block1 else if (cond2) block2
else block3 . Odgovorite detaljno na sva potpitanja kao i gore. U kojem slučaju se izvršava
block3 ?
14. U svezi s proširenom if naredbom, koliko može biti else if dijelova? Na što se odnosi else
dio naredbi ako prethodno ima više if i else if dijelova?
15. Da objasnite način njenog izvođenja, raspišite proširenu if – else if naredbu korištenjem samo
if i else dijelova.
16. Koju ćemo uvjetnu tvrdnju rabiti u C / C++ ako treba odabrati između više od dva slučajeva od-
ređenih nekom diskretnom varijablom, npr. cjelobrojnog ili pobrojanog tipa? Navedite primjere u
kojima bi to bilo prikladno.
17. Napišite sintaksu tvrdnje tipa skretnice (engl. switch). Koje se ključne riječi tu pojavljuju? Pre-
vedite ih na hrvatski i uvedite u svoj rječnik računarskih pojmova.
18. Objasnite kakvog tipa mora biti izraz u zagradi iza ključne riječi switch? Što mislite što će se
desiti ako je taj izraz drugog tipa, npr. tipa za realne brojeve? Provjerite u testnom programu.
19. U duhu prethodnog pitanja, smije li izraz naredbe switch biti logičkog tipa? Provjerite također u
testnom programu. Strogo uzevši, koliko najviše može biti označenih naredbi u tom slučaju?
Zaključite – ima li smisla organizirati naredbu switch za ovaj slučaj, te koju bi naredbu bilo upu-
tnije koristiti.
20. Čemu služi naredba break unutar switch tvrdnje? Opišite kako se točno izvodi naredba switch
kad iza konstantne tvrdnje umećemo naredbu break . Što se događa ako se naredba break ispus-
ti?
21. Čemu služi ključna riječ default ? Navedite primjer njene uporabe.

5.1.4 Iteracija (ponavljanje)


22. Kako se naziva tvrdnja programskog jezika s pomoću kojeg se ostvaruje iteracija pojedinih dije-
lova programa? Navedite i engleski naziv.
23. Navedite koliko i koje strukturirane petlje posjeduje jezik C / C++.
24. Što označava pojam „strukturirana petlja“?
25. Napišite općenitu sintaksu petlje while i objasnite kako se točno ona izvršava: što se provjerava
na početku, dokle točno traje ponavljanje, kada prestaje ponavljanje, i što se događa po završetku
izvođenja petlje.
51

26. Kada je uputno koristiti while petlju, odnosno zašto je ona uvedena? Općenito uzevši, znamo li
kod nje „unaprijed“ broj iteracija koje će se izvršiti? Koliko se najmanje puta može izvršiti
while petlja?
27. Napišite općenitu sintaksu do – while petlje, i objasnite točno kako se ona izvršava: kako zapo-
činje, dokle se izvršava iteracija, što se mora desiti da se završi ponavljanje petlje, te kako se po-
tom nastavlja izvođenje programa.
28. Koliko se najmanje puta izvršava do – while petlja? Ilustrirajte u kojim se slučajevima to svoj-
stvo dade prikladno iskoristiti.
29. Može li se svaka do – while petlja svesti na while petlju, naravno uz dopušteno pisanje dodatnih
linija koda? A obrnuto – može li se svaka while petlja svesti na do – while petlju? Iskoristite
odgovore o najmanjem broju iteracija svake od ovih petlji, iz čega možete zaključiti o njihovoj
općenitosti, i svodljivosti jedne na drugu.
30. Napišite općenitu sintaksu for petlje. Objasnite značenje svakog od tri izraza u zagradi. Preciz-
no, u algoritamskom stilu objasnite kako se petlje izvršava.
31. Smije li se u prvom izrazu deklarirati varijabla, npr. novog brojača for petlje? Koliki je dogled
te varijable? Koliki je općenito dogled varijabli deklariranih u tri izraza unutar zagrade for
petlje?
32. S obzirom na odgovore na prethodno pitanje, razmotrite sljedeće: i) Možemo li varijable dekla-
rirane u for petlji koristiti u njoj ugniježđenoj petlji, tj. petlji koja se nalazi unutar njenog tijela?
ii) Možemo li te varijable koristiti u drugoj for petlji, otvorenoj van tijela prve?
33. Koja je standardna primjena for petlje? Što se standardno veže uz funkcioniranje for petlje —
varijabla koje namjene? Uz koje strukture podataka se ova petlja najčešće koristi?
34. Napišite reduciranu for petlju koja ima funkcionalnost while petlje. Sljedeći algoritamski prikaz
izvršavanja for petlje, dokažite da je njeno izvršavanje istovjetno while petlji.
35. *Za vježbu napišite for petlju koja ima funkcionalnost do – while petlje. Proširenjem uvjetnog
izraza potrebno je osigurati da je minimalan broj prolaza kroz petlju istovjetan kao i kod do –
while petlje. Na koncu, slijedeći algoritamski prikaz izvršavanja for petlje, dokažite da je njeno
izvršavanje istovjetno do – while petlji.
36. Napišite kako se for petlja može ostvariti s pomoću while petlje. Učinite to najprije za općeniti
slučaj, pišući apstraktnu sintaksu, a potom i za konkretan slučaj.

5.2 Primjeri i zadaci


Primjer 5.1 Globalne i lokalne varijable.
Promotrite sljedeći programski odsječak u svezi s dogledom varijabli izvan i unutar bloka. Objasnite
sve korištene izričaje i tvrdnje, te riješite zadatak koji slijedi.
#include <iostream>
using namespace std;
int iGlobal1 = 11; // Varijable def. van glavne f-je:
int iGlobal2 = 22; // globalne varijable.
int main()
{
int iInMainBlock = 33; //
// Ispis 1:
52
cout
<< "1. Deklaracija varijabli van i unutar bloka glavne funkcije: \n"
<< "===============================================================\n"
<< " iGlobal1 = " << iGlobal1 << "\n"
<< " iGlobal2 = " << iGlobal2 << "\n"
<< "iInMainBlock = " << iInMainBlock << "\n"
<< endl;
// Ponovna objava iGlobal2. Hoće li prevodilac javiti grešku?
int iGlobal2 = 222;
// Ispis 2:
cout
<< "2. Dekl.var. van i unutar bloka gl. f-je, redeklarac. iGlobal2:\n"
<< "===============================================================\n"
<< " iGlobal1 = " << iGlobal1 << "\n"
<< " iGlobal2 = " << iGlobal2 << "\n"
<< "iInMainBlock = " << iInMainBlock << "\n"
<< endl;
return 0;
}

Zadatak 5.1 Globalne i lokalne varijable.


U svezi prethodnog primjera (Primjer 5.1), odgovorite na sljedeća pitanja:
a) Zašto smo varijable deklarirane izvan glavne funkcije nazvali «globalnim» varijablama? Jesu li
one „sagledljive“ u unutarnjim blokovima?
b) Što se događa kad u podređenom bloku deklariramo varijablu istog imena kao i u nadređenom.
Hoće li to rezultirati greškom? Predvidite rezultate izvođenja i potom testirajte program.

Primjer 5.2 Lokalne varijable u ugniježđenim i „paralelnim“ blokovima.


U sljedećoj glavnoj funkciji, lokalne varijable deklarirane su u ugniježđenim i „paralelnim“ blokovi-
ma (blokovima iste hijerarhije).
int main() // Block 0 (nesting sublevel 0)
{
int iM = 10; // Variables with scope to inner blocks
int i0 = 100; // - " - - " - - " –
cout << "Block 0: " << "\n"
<< "iM = " << iM << "\n"
<< "i0 = " << i0 << "\n"
<< endl;
i0 /= iM; // Referencing local variables.
cout << "i0 /= iM, i0 = " << i0 << "\n"
<< endl;
// Block 1.1 (nesting sublevel 1, block 1):
{
// Local variable declaration and initialization:
int i0 = 1100;
cout << "Block 1.1: " << "\n"
<< "iM = " << iM << "\n"
<< "i0 = " << i0 << "\n"
<< endl;
i0 /= iM; // Referencing local variables in a nested block.
cout << "i0 /= iM, i0 = " << i0 << "\n"
<< endl;
53
}
// Block 1.2 (nesting sublevel 1, block 2):
{
// Local variable declaration and initialization:
int i0 = 1200;
cout << "Block 1.2: " << "\n"
<< "iM = " << iM << "\n"
<< "i0 = " << i0 << "\n"
<< endl;
i0 /= iM; // Referencing local variables in a nested block.
cout << "i0 /= iM, i0 = " << i0 << "\n"
<< endl;
// Block 2.1 (nesting sublevel 2, block 1):
{
int i2 = 2100;
cout << "Block 2.1: " << "\n"
<< "iM = " << iM << "\n"
<< "i0 = " << i0 << "\n"
<< "i2 = " << i2 << "\n"
<< endl;
i2 /= iM; // Referencing local var. in a doubly-nested block
cout << "i2 /= iM, i2 = " << i2 << "\n"
<< endl;
}
}
// Is something missing?
cout << "Block 0: " << "\n"
<< "iM = " << iM << "\n" // iM = ?
<< "i0 = " << i0 << "\n" // i0 = ?
<< "i2 = " << i2 << "\n" // i2 = ?
<< endl;
return 0;
}

Zadatak 5.2 Lokalne varijable u ugniježđenim i „paralelnim“ blokovima.


Nakon što ste proučili prethodni primjer (Primjer 5.2), odgovorite na sljedeća pitanja.
a) Koje varijable tretiramo kao zajedničke svim blokovima? Koje od njih redefiniramo u podbloko-
vima?
b) Uočite koliko ukupno ima podblokova unutar glavne funkcije. Koja je najdublja razina gniježđe-
nja. Koji su blokovi paralelni po hijerarhiji?
c) Na temelju teorijskog znanja nastojte predvidjeti sve vrijednosti varijabli i ispis programa.
d) Prođite kroz sve linije programskog koda i predvidite je li program sintaktički ispravno napisan, tj.
hoće li proći kompilaciju? Ako ne, objasnite zašto i otklonite grešku.
e) Pokrenite program i prodiskutirajte ispisane vrijednosti, te provjerite jesu li u skladu s
predviđenima u podzadatku c.

Primjer 5.3 Selekcija s pomoću tvrdnje if – else if . [Napomena: u novijoj inačici na ovo će
mjesto doći jednostavniji primjer, a numeracija ovoga će se povećati za 1.]
U sljedećem primjeru dana je if – else if tvrdnja u kojoj se kroz dva relacijska izraza uspoređuju dvije
varijable fVar1 i fVar2 tipa float , te se nakon toga ispisuje odgovarajuća poruka oblika: fVar1 rel
54

fVar2 , gdje je rel jedna od aritmetičkih relacija: < , = , > . Dakle, program će ispisati je li prva
varijabla manja, jednaka ili veća od druge varijable. U ovom stilu pisanja, s lijeve strane relacije je
uvijek prva, a s desne strane druga varijabla.
float fVar1, fVar2;
// ... ...
// ... ...

if (fVar1 < fVar2)


cout << "fVar1 = " << fVar1 << "\t<\t"
<< "fVar2 = " << fVar2 << "\n"
<< endl;
else if (fVar1 == fVar2)
cout << "fVar1 = " << fVar1 << "\t=\t"
<< "fVar2 = " << fVar2 << "\n"
<< endl;
else
cout << "fVar1 = " << fVar1 << "\t>\t"
<< "fVar2 = " << fVar2 << "\n"
<< endl;

Zadatak 5.3 uz Primjer 5.3. [Napomena: u novijoj inačici na ovo će mjesto doći jednostavniji
zadatak, a numeracija ovoga će se povećati za 1.]
Uz Primjer 5.3 odgovorite na sljedeća pitanja:
a) Zašto nakon naredbi if, else if, i else nismo morali otvarati blok pisanjem vitičastih zagrada? U
kojem slučaju bi to bilo nužno? Što znači kontrolni znak \t u ispisu?
b) Diskutirajte kako se izvršava selekcija za sve moguće odnose dvije varijable ( fVar1 > fVar2,
fVar1 == fVar2 i fVar1 < fVar2 ).

Zadatak 5.4 Dodatni zadatak uz Primjer 5.3.


Nadopunite Primjer 5.3 na sljedeći način:
a) Dodajte naredbe za unos dviju varijabli koje se uspoređuju, kompletirajte glavnu funkciju i
testirajte program. „Potcrtajte“ unos podataka, kao i prvi redak ispisa rezultata, da izgled na ekranu
bude pregledniji.
b) Neka je pored ispisa relacije između dviju unesenih varijabli, potrebno pohraniti vrijednost manje
u varijablu fSmaller, a vrijednost veće u fGreater. Ako su varijable jednake, obje ove vrijednosti
će biti jednake. Modificirajte gornji program uz minimalne preinake, i bez dodavanja novih if
naredbi. Hoće li sada biti potrebno otvarati blokove naredbi iza ključnih riječi if, else if i else ?
c) *Programu treba dodati ispis drugačijeg stila od već ostvarenog, bez uvođenja novih izraza
selekcije. Sada manju varijablu treba napisati slijeva, a veću sdesna. Također potrebno je navesti
njihovih vrijednosti, kao i znak relacije < ili = , pošto varijable mogu biti i jednake. Npr. uz
izbor fVar1 = 1.1, fVar2 = 1.2, ispis mora biti:
fVar1 = 1.1 < fVar2 = 1.2
Uz obrnuti izbor brojeva, ispis mora biti:
fVar2 = 1.1 < fVar1 = 1.2
Ako su varijable jednake, npr. fVar1 = fVar2 = 1.1 , ispis mora biti:
fVar1 = 1.1 = fVar2 = 1.1
55

Također, ispis mora biti ostvaren jednom, jedinom tvrdnjom. Usporedite to s prijašnjim
ostvarenjem ispisa!
Naputak. Iskoristite varijable uvedene u podzadatku b, te uvedite tri nove varijable tipa char,
kojima ćete opisati indeks manje i veće varijable (1 ili 2), te znak relacije između njih. Sva
pridruživanja je potrebno obaviti u već postojećim blokovima naredbe selekcije.

Zadatak 5.5 Minimalna i maksimalna vrijednost tri varijable.


Zadane su tri varijable tipa float, fVar1, fVar2, fVar3. Sastavite izraz selekcije koji određuje
maksimalnu i minimalnu vrijednost, te ih pohranjuje u varijablama fMin i fMax. Sastavite program
koji učitava navedene tri varijable, te ispisuje minimalnu i maksimalnu vrijednost u konzolnoj
aplikaciji.

Primjer 5.4 Uporaba skretničkog izraza switch.


U ovom je primjeru ostvarena programska struktura višestrukog izbora s pomoću skretničkog izraza
switch. Radi se o jednostavnom ispisu naziva ocjena u hrvatskom školskom sustavu.

// Hrvatske ocjene
unsigned short int usOcjena;
cout << "Unesite ocjenu od 1 do 5 : ";
cin >> usOcjena;
cout << "\nOcjena: " << usOcjena << " = ";
switch (usOcjena)
{
case 5 : cout << "izvrstan" << "\n";
break;
case 4 : cout << "vrlo dobar" << "\n";
break;
case 3 : cout << "dobar" << "\n";
break;
case 2 : cout << "dovoljan" << "\n";
break;
case 1 : cout << "nedovoljan" << "\n";
break;
default : cout << "neispravna ocjena!" << "\n";
break; // Je li ovaj break neophodan?
}
cout << endl;

Zadatak 5.6 Analiza skretničkog izraza switch.


a) Unesite gornji programski odsječak u glavnu funkciju C++ programa i testirajte ga. Unesite naj-
prije vrijednosti regularnih ocjena, a potom nevaljale vrijednosti. Radi li program kao što se oče-
kuje? U kojem slučaju se izvršava izraz iza ključne riječi default ?
b) Testirajte ulogu naredbe break. Maknite najprije prvu, a potom i drugu ovu naredbu tako da je „is-
komentirate“, tj. pretvorite u komentar. Testirajte ponovo program i diskutirajte rezultate. Kako
se naziva ovo svojstvo skretničke naredbe? Razmislite kako bi se ono moglo iskoristiti! Bismo li s
pomoću njega mogli organizirati ispis poruke o tome koja je od gornjih ocjena prolazna, a koja ni-
je? Promotrite sljedeći zadatak.
56

Zadatak 5.7 Iskorištenje svojstva „propadanja“ naredbe switch.


a) Modificirajte gornji program tako da nakon gornje skretničke naredbe napišete još jednu koja će za
ocjene od 2 do 5 ispisivati poruku: prolazna ocjena, a za ocjenu 1 nedovoljna ocjena, korište-
njem svojstva propadanja kroz naredbu.

Zadatak 5.8 Dani u tjednu.


Definirajte pobrojani tip tjedan, koji definira dane u tjednu.
a) Po uzoru na gornji primjer sastavite program koji unaša broj dana u tjednu i ispisuje njegov naziv.
Pri tom želimo da dan broj 1 bude ponedjeljak, a dan broj 7 nedjelja.
b) Dodajte zatim još jednu skretničku naredbu koja će korištenjem svojstva propadanja, ispisivati je li
to radni dan (ponedjeljak do petak), ili dan vikenda (subota i nedjelja).

Zadatak 5.9 *Mjeseci u godini.


Definirajte pobrojani tip mjesec, koji definira mjesece u godini (vidjeti također Zadatak 3.13 ).
a) Slično kao u prethodnom zadatku sastavite program koji unaša broj mjeseca u godini, te ispisuje
njegov naziv.
b) Dodajte još dvije skretničke naredbe koja će korištenjem svojstva propadanja, ispisivati u kojem je
godišnjem kvartalu taj mjesec (1. 2. 3. ili 4.tom), te je li to mjesec s 30, 31 dan, ili 28 (29) dana.
Prilikom organizacije skretničke naredbe za zadnji zadatak, uočite da slučajevi konstantnih izraza
u naredbi ne moraju biti navedeni redom, već na proizvoljan način.

Primjer 5.5 Uporaba while petlje za ostvarenje ulaznog filtra.


Sljedeći programski odsječak osigurava ispravan unos ocjene u hrvatskom školskom sustavu, od 1 do
5, te predstavlja tzv. ulazni filtar (engl. input filter). Unos se ponavlja sve dotle dok korisnik unosi
neispravnu iznos ocjene, a završava kad je uneseni podatak cijeli broj u rasponu od 1 do 5, odnosno
kad je element skupa: O = { 1, 2, 3, 4, 5}.
short int sOcj;
cout << "Unesite ocjenu (1 - 5): ";
cin >> sOcj;

while ( !((sOcj >= 1) && (sOcj <= 5)) )


{
cout << "Ocjena " << sOcj << " je neispravna!\n\n"
<< "Unesite ocjenu (1 - 5): ";
cin >> sOcj;
};
cout << "Unesena ocjena = " << sOcj << "\n"
<< endl;

Zadatak 5.10 uz Primjer 5.5.


Promotrite prethodni primjer i utvrdite svoje odgovore na pitanja u svezi while petlje (odjeljak 5.1.4,
pitanja 25 i 26).
a) Ugradite gornji kôd u testni program i provjerite njegovo izvršavanje. Namjerno unosite neregu-
larne ocjene da provjerite ispravnost ulaznog filtra. Prilikom testiranja, uvijek pomno provjerite
„rubne vrijednosti“, kako neispravne, tako i ispravne. Dakle unesite, između ostalog i vrijednosti
0, 6, zatim i neke negativne vrijednosti, pa onda 1, 5, itd…
b) Objasnite izračun logičkog izraza u zagradi while petlje za ulazne vrijednosti, 0, 6, 3.
57

c) Preformulirajte logički izraz while petlje uporabom pravila Booleove algebre:

d)
ab =a +b ,
e) koje zapisano logičkim operatorima u jeziku C / C++ glasi:
f) !(a && b) = !a || !b .

Primjer 5.6 Uporaba do – while petlje za ostvarenje ulaznog filtra.


U ovom primjeru ulazni filtar je realiziran na jednostavniji način, uporabom do – while petlje:
short int sOcj;
do
{
cout << "Unesite ocjenu (1 - 5): ";
cin >> sOcj;
} while ( ((sOcj < 1) || (sOcj > 5)) );
cout << "Unesena ocjena = " << sOcj << "\n"
<< endl;

Zadatak 5.11 uz Primjer 5.6.


Promotrite prethodni primjer i utvrdite svoje odgovore na pitanja u svezi do – while petlje (odjeljak
5.1.4, pitanja 27 do 29).
a) Usporedite ovu realizaciju ulaznog filtra naspram one s pomoću while petlje. Što nismo ponavljali
u ovom programski kodu? Je li ovaj ulazni filtar elegantniji? Ipak, primijetite — imamo li i ovdje
mogućnost dodatnog upozorenja nakon prvog krivog unosa?
b) Objasnite kako je promijenjen logički izraz u zagradi iza ključne riječi while . Pročitajte ga riječi-
ma i objasnite. Je li to isti ili različit logički izraz od onog u prethodnom primjeru (Primjer 5.5)?
Povežite zaključak s odgovorom o preoblikovanju logičkog izraza u prethodnom zadatku.

Zadatak 5.12 Uporaba do – while petlje za opetovano korištenje programskih


odsječaka
a) Modificirajte program za ispis dana u tjednu (Zadatak 5.8) tako da se korisniku omogući opeto-
vani unos i ispis rezultata. Unos treba ponavljati primjenom selekcije tipa do – while. Nakon pr-
vog unosa treba postaviti upit:
b) "Želite li unositi još brojeva (da / ne, ne = 'n')?".
c) Izrazom u zagradi upućuje se korisnika da je za prekid programa potrebno unijeti slovo n , dok je
za nastavak dovoljno utipkati bilo što, uključujući i ništa, tj. izravan pritisak na tipku CR = Re-
turn. Usavršite program tako da omogućite korisniku da izvrši prekid i unosom velikog slova N.
d) Učinite isto kao i u prethodnom podzadatku za ispis mjeseci u godini ( Zadatak 5.9).

Primjer 5.7 Uporaba for petlje


Ovdje ilustriramo rad for petlje na primjeru zbrajanja prvih n prirodnih brojeva. Naglasimo odmah
da se tražena suma izravno dobiva iz formule za sumu aritmetičkog niza, tj. nije ju potrebno računati
prohodom kroz petlju, no ovdje to činimo da podastremo jednostavan primjer for petlje pune funkci-
onalnosti (vidi također komentare na kraju primjera i zadatke koje slijede),
#include <iostream>
using namespace std;
int main()
58
{
unsigned int uN; // Prirodni broj
unsigned int uSumN = 0; // Suma prvih n = uN prirodnih brojeva
unsigned int uSumNA ; // Suma prvih n = uN prirordnih brojeva
// dobivena preko sume aritm. reda
cout << "Suma prvih n prirodnih brojeva\n"
<< "===================================================\n\n"
<< "Unesite n = ";
cin >> uN;
for (unsigned int i = 1; i <= uN; i++) // for petlja
uSumN += i; // - || -
cout << "\nSuma dobivena zbrajanjem, S[i = 1 do i = "
<< uN << "] = " << uSumN << "\n" << endl;
// Dovršite izračun sume aritmetičkog reda koristeći
// formulu iz log. tablica ili drugog izvora (vidi zad. dolje)
// uSumNA = ... ...
// Ispišite rezultat prema gornjem uzoru:
// "Suma dobivena formulom, ... ... "
// ... ... ... ...
return 0;
}

Zadatak 5.13 uz Primjer 5.7.


a) Navedite značenje tri izraza u zagradi for petlje i navedite kako se ona izvršava. Ustanovite potom
kako se u gornjem primjeru sumiraju brojevi od 1 do uN? Gdje se akumuliraju djelomične (par-
cijalne) sume? Gdje je pohranjen rezultat?
b) Primijetite: u koliko redova je organizirana petlja koja obavlja suštinski dio programa? Može li se
reći da se radi o „elegantnom rješenju“? Na što je potrošen veći dio gornjeg programskog koda?
c) Otvorite u programskoj okolini novi projekt odgovarajućeg imena i testirajte program. Unosite
najprije male vrijednosti, pa zatim veće, npr. redom, 10, 100, 1 000, 10 000. Što primjećujete?
Povećanjem ulaznog broja za jedan red veličine, za koliko se povećavala suma? Unesite zatim vri-
jednost od 100 000 i 1 000 000? Izgledaju li ovi rezultati „slični“ onima ranije? Izgledaju li toč-
no? Je li se suma povećavala kao i ranije? Što zaključujete, koji je razlog pogreške? Povećajte cje-
lobrojni tip sume na long long i ponovite testiranje.

Zadatak 5.14 uz Primjer 5.7. Nadopuna programa izravnim izračunom sume


aritmetičkog niza.
U opisu gornjeg primjera već je istaknuto da se zbroj uzastopnih brojeva od 1 do n izračunava iz-
ravno na temelju formule za sumu aritmetičkog niza. Konkretno, za sumu niza prirodnih brojeva od
1 do n vrijedi formula (za općenitu formulu vidi niže):
n
n (n + 1)
∑i =
i =1 2
.

a) Umetnite na kraj programskog odsječka aritmetički izraz kojim ćete izravno izračunati sumu prvih
n brojeva s pomoću gornje formule, i pohraniti je u već deklariranu varijablu uSumNA.
b) Zatim napravite ispis varijable prema uzoru na već postojeći, uz napomenu da se radi o sumi arit-
metičkog niza dobivenoj izravno preko formule.
c) Testirajte program i potvrdite istovjetnost rezultata dobivenih zbrajanjem u for petlji i preko for-
mule za sumu aritmetičkog niza.
59

d) Izvedite zaključke o brzini izračuna rezultata sumiranjem i preko formule – što je brže? Izvedite
opći zaključak: je li opravdano „programiranjem“ i nepotrebno dugotrajnim računom nadomje-
štavati nedostatak matematičkog znanja?
e) Prema pričanju, mladi Gauss je našao sumu prvih 100 brojeva za svega nekoliko minuta još u
osnovnoj školi, upravo s pomoću gornje formule. Nađite detalje o tome dostupnoj literaturi.

Zadatak 5.15 Suma aritmetičkih nizova neparnih i parnih brojeva.


Aritmetički niz (engl. arithmetic series, arithmetic progression) definiran je svojim prvim članom a1 , i
konstantnom razlikom između svojih članova d , tako da je opći, n-ti član iznosa:

an = a1 + (n − 1) d .
Za sumu prvih n članova aritmetičkog niza vrijedi jednostavna formula (vidi dodatke u [1], [3xx]):
n
Sn = (a1 + a n ) .
2
a) Provjerite važenje gornje formule za prvih 5 i prvih 10 neparnih, i parnih, brojeva , izračunom na
papiru.
b) Po uzoru na Zadatak 5.13 i Zadatak 5.14 sastavite C++ program koji će nalaziti sumu prvih n
neparnih brojeva zbrajanjem u for petlji, te pored toga napisati isti rezultat uz korištenje gornje
formule.
c) Ponovite prethodni podzadatak za prvih n parnih brojeva.

Primjer 5.8 Realizacija for petlje s pomoću while .


U ovom primjeru petlja for iz prethodnog primjera (Primjer 5.7) zamijenjena je s pomoću while pet-
lje istovjetne funkcije.
unisgned int uN, uSumN;
// ... ...
uSumN = 0;
int i = 1;
while ( i <= uN )
{
uSumN += i;
i++;
};
Ovo se dade elegantno skratiti kao:
int i = 1;
while ( i <= uN )
uSumN += i++;

Zadatak 5.16 Zamjena for petlje s while .


Po uzoru na prethodni primjer, zamijenite for petlje u zadacima za sumaciju prvih n prirodnih broje-
va (Zadatak 5.14, Zadatak 5.15) s while petljom. Provjerite korektnost rezultata.

Zadatak 5.17 for petlje sa dekrementirajućim brojačem.


U zadacima za sumaciju prirodnih brojeva zamijenite for petlje s rastućim brojačem s petljama u ko-
jima se brojač dekrementira. Drugim riječima, ostvarite sumaciju koja ide od najvećeg do najmanjeg
broja u nizu, uz minimalne preinake programskog koda. Za pomoć promotrite sljedeći primjer.
60

Primjer 5.9 Petlje s dekrementirajućim brojačima predznačenog i nepredznačenog


tipa
Donji programski odsječak koji vrši odbrojavanje od nekog cijelog broja n ≥ 0 do 0, uz korištenje
for petlji s dekrementirajućim brojačima. Dodatno, odbrojavanje se može vršiti u koracima k ≥ 1.
Tako npr. ako je početni broj paran (neparan) i odaberemo korak 2, bit će odbrojavani svi parni
(neparni) brojevi do uključivo 0 (1), gdje 0 (1) možemo smatrati najmanjim parnim (neparnim)
brojem. Ili, kao sljedeći primjer, ako smo za početni broj odabrali n = 10, a za veličinu koraka k =
3, tada odbrojavanje treba rezulitrati nizom: 10, 7, 4, 1.
// Programski odsječak za odbrojavanje od n do 0, uz korak k.
int iN, iK = 1; // Podrazumijevajući korak iK = 1
unsigned int uN, uK = 1; // Podrazumijevajući korak uK = 1
cout << " Program za odbrojavanje od n do 0, uz korak k \n"
<< "========================================================\n"
<< endl;
cout << "Unesite pocetni broj odbrojavanja, n = ";
cin >> uN;
do
{
cout << "Unesite korak odbrojavanja, k >= 1, k = ";
cin >> iK;
} while ( iK < 1);
cout << endl;
iN = (int) uN; // Prilagodba unesenih vrijednosti na tip int.
uK = (unsigned) iK; // Prilagodba unes. vrijed. na unsigned int.
// 1. Petlja s dekrementirajućim predznačenim brojačem:
cout << "Odbrojavanje s dekrementirajućim predznačenim brojačem: \n"
<< "========================================================"
<< endl;
for ( int i = iN; i >= 0; i -= iK)
cout << "i = " << i << endl;
cout << endl;
// 2. Petlja s dekrementirajućim nepredznačenim brojačem (OPREZ!):
for ( unsigned int u = uN; u >= 0; u -= uK) // Okončanje petlje!?
cout << "u = " << u << endl;
cout << endl;
// Korigirajte for petlju br. 2 s dekrementirajućim nepredznačenim
// brojačem, tako da korektno izvršava odbrojavanje!
// Modificirajte uvjet petlje tako da se ona ispravno okončava za
// proizvoljnu vrijednost koraka uK.
// Prilikom testiranja uputno je koristiti posebnu varijablu (uEnd)
// za određivanje donje granice uvjeta.
// // // // // // // // // // // // // // // // // // // // // // // //

Zadatak 5.18 uz Primjer 5.9.


a) Proučite programski kôd gornjeg primjera. Diskutirajte rad prve for petlje. Možete li predvidjeti
ispis koji se obavlja u njezinom tijelu?
b) Proučite drugu petlju i diskutirajte kako ona radi. Kako bi, na prvi pogled, trebala okončati ova
petlja. Obratite pažnju na tip brojača i razmislite što će se točno desiti.
61

c) Testirajte gornji programski odsječak na računalu. Usporedite rezultate s vašim predviđanjima i


korigirajte zaključke. Kako se naziva druga petlja? Promotrite promjene koje se dešavaju u ispisu.
Biste li mogli procijeniti koliko vremena bi trebalo da se ispisani brojevi primaknu vrijednostima
bliskim nuli?

Zadatak 5.19 * uz Primjer 5.9.


Korigirajte uvjet u drugoj petlji tako da njen rad bude korektan. Poslužite se znanjem o nepredznače-
nom tipu, kao i primjerima petlje s dekrementirajućim brojačima nepredznačenog tipa iz [1]. Potreb-
no je razmisliti kako osigurati ispravan rad za svaku vrijednost koraka k.

Zadatak 5.20 Broj prolazaka kroz petlju i konačno stanje brojača.


Promotrite niže navedene primjere for petlji. Donja vrijednost indeksa petlje je n1 , a gornja je n2 ,
tj. uvijek vrijedi da je n1 ≤ n2 . Cjelobrojni korak petlje je k ≥ 1 , dakle pozitivan i veći od 0. Radi
jednostavnosti i povećane općenitosti, tj. mogućeg uključenja i pozitivnih i negativnih vrijednosti
početnih i konačnih vrijednosti, sve su veličine deklarirane kao predznačene.
a) Diskutirajte koje su petlje s rastućim, a koje s padajućim brojačem.
b) Na temelju definicije rada odredite koliko se puta izvršavaju i s kojom vrijednosti brojača okonča-
vaju ove for petlje. Za početak pretpostavite da je korak jedinični, k = 1, a potom razmotrite i
složenije slučajeve.
c) Umetnite ove petlje u testni program. Brojač deklarirajte van bloka petlje, tako da je zajednički i
ima dogled za sve četiri petlje. Osigurajte unos varijabli, te ispis brojača unutar tijela petlje, kao i
njegove vrijednosti po izlasku iz petlje. Provjerite svoja predviđanja iz podzadatka b.
int iN1, iN2, iK, i;
// 1. for petlja
for ( int i = iN1; i <= iN2; i += iK )
{
// Blok naredbi ...
}
// 2. for petlja
for ( int i = iN1; i < iN2; i += iK )
{
// Blok naredbi ...
}
// 3. for petlja
for ( int i = iN2; i > iN1; i -= iK )
{
// Blok naredbi ...
}
// 4. for petlja
for ( int i = iN2; i >= iN1; i -= iK )
{
// Blok naredbi ...
}

Zadatak 5.21 Izračun aritmetičke sredine n brojeva.


Napišite program koji izračunava aritmetičku sredinu n brojeva ( n > 1 ) tipa float. Korisnika se
najprije pita da unese broj n (prikazati nepredznačenom cjelobrojnom varijablom uN), i potom se
unaša n realnih vrijednosti, koristeći varijablu fSum. Sumacija se obavlja uzastopnim pridodavanjem
unesenih vrijednosti varijabli fSum po uzoru na prethodni primjer. Na osnovi fSum i uN, na koncu
62

se izračuna srednja vrijednost: fAve = fSum / uN , i ispisuje se na ekranu. Zadatak je potrebno riješiti
uporabom for petlje. Na koncu, osigurajte ponvaljanje programa tako dugo dok ga korisnik ne želi
prekinuti (vidi Zadatak 5.12).

Zadatak 5.22 Izračun faktorijela n!


a) Napišite C/C++ program koji unosi cijeli nenegativni broj n i primjenom for petlje izračunava n!
n
(čitaj n faktorijela). Definicija funkcije faktorijela glasi: n ! = ∏ i = 1× 2 × ... ...× (n − 1) n ,
i =1
tj.

faktorijela od n je umnožak svih prirodnih brojeva od 1 do n. Po definiciji je 0! = 1. Nakon iz-


računa i ispisa, korisnik može odabrati želi li ponovni unos i izračun, ili završetak programa, što se
provjerava odgovarajućim upitom. Za opetovano izvršavanje cijelog programa iskoristite povoljnu
iterativnu strukturu. Dodatna pitanja:
b) Razmislite o mogućim problemima pri izvršavanju zadatka. Pošto funkcija faktorijela ima trend
rasta jednak eksponencijalnoj funkciji, što će se dogoditi već i kod relativno malih n? Ostvarite
ulazni filtar, tj. barem grubo ograničenje ulaznih brojeva. Ukoliko korisnik unese preveliki broj,
potrebno ga je upozoriti.
c) Kako možete proširiti opseg ispravnih rezultata? Koji je najveći cjelobrojni tip kojeg možete isko-
ristiti?
d) Razmislite postoji li način da dojavite da je rezultat premašio dozvoljeni opsega brojeva? Promot-
rite za koji faktor se razlikuju brojevi n! i (n – 1)! . Bi li se to moglo iskoristiti za provjeru je li
izračun funkcije faktorijela za naredni n točan? Razmislite kako biste to učinili.
e) Je li dobiveni program računarski zahtijevan ili nije, s obzirom da množenje dva n bitna broja ima
otprilike težinu n-strukog zbrajanja n bitnih brojeva?
f) Ako funkcija faktorijela doseže ogromne vrijednosti već i za relativno male n, ima li je smisla
svaki put iznova računati? Kako biste to riješili u praksi?
g) Pronađite značenje pojma «robustnost programa», i prodiskutirajte ga u svezi s ovim jednostavnim
primjerom.
63

Vježba 6. Osnovna podatkovna struktura – poredak


Programske strukture iz prethodne vježbe postaju učinkovite tek ako se provode nad odgovarajućim
podatkovnim strukturama. U ovoj vježbi obrađuje se temeljna podatkovna struktura: poredak, koja je
poznata i pod nazivima: niz (engl. array), ili polje. Osnovni poredak je 1-dimenzionalni, kod kojeg je
njegov element specificiran jednim indeksom. Kod n-dimenzionalnog polja, svaki je element odre-
đen s n indeksa.

6.1 Teorijska priprema


Proučite gradivo istobrojnog poglavlja u udžbeniku [1]. U Dnevnik vježbi svojim riječima napišite
osnovne pojmove o strukturi poretka (polja), načinu pristupa do pojedinih njegovih elemenata. Obja-
snite formulu za izračun adrese i-tog elementa:

A(i ) = A0 + t × i . (6.1)

Objasnite koncept višedimenzionalnog poretka. Nadovežite ovo razmatranje na podatkovni tip kazalj-
ki. Uočite odmah da se radi o tipu u kojem pohranjujemo adrese na kojima se nalaze varijable, objek-
ti, pa i funkcije proizvoljnih, drugih, tipova.

6.1.1 Poredak (polje, niz) – temeljna struktura podataka


1. Navedite motive za uvođenje podatkovne strukture poretka. Pronađite zadatke iz prijašnjih pog-
lavlja koje bismo riješili puno elegantnije uporabom ove strukture (promotrite npr. Zadatak 4.4,
Zadatak 4.5, Zadatak 5.22). Diskutirajte ukratko u čemu bi se ostvarila poboljšanja, i glede fun-
kcionalnosti, i glede programske realizacije.
2. Promotrite zadatke za izračun prosječne vrijednosti (Zadatak 5.21). Korisnik unosi n podataka.
Jesu li unesene vrijednosti sačuvane? Pretpostavimo da osim srednje vrijednosti kao najjednos-
tavnijeg statističkog parametra želimo iznaći i druge, kao npr. standardnu devijaciju, prikazati
podatke u formi dijagrama i sl. Što moramo napraviti osiguramo bolju funkcionalnost programa?
3. Čime je u potpunosti određen i-ti element poretka? Što je potrebno znati osim veličine indeksa
i da bi se odredila mjesto gdje je on pohranjen u memoriji, odnosno njegova adresa? Napišite
formulu za izračun te adrese iz koje su razvidni odgovori na prethodna pitanja.
4. Neka je adresa strukture poretka, tj. adresa njegovog početnog elementa dana 32-bitnim brojem
koji je u heksadekadskoj formi zapisan kao: A0 = 0001 0000h . Ako su elementi poretka duljine
4B, odredite na kojoj adresi su smješteni elementi s indeksima dekadske vrijednosti: i = 0, 1, 2,
10, 15, 16, 160, 255, 256, 1023, 1024. Rezultat mora biti izražen u heksadekadskoj formi u ob-
liku:
A(0d ) = … … , A(1d) = … … , … … A(1024d) = … … .
Naputak. Račun je najbolje obavljati u heksadekadskom sustavu (u kojem se standardno izraža-
vaju memorijske adrese). Pretvorite vrijednosti traženih indeksa u heksadekadske, te korište-
njem formule za nalaženje adrese i-tog elementa poretka, riješite zadatak. Ako niste vješti u pre-
tvorbi brojeva između dekadskog i heksadekadskog sustava, prilikom izračuna koristite se kalku-
latorom iz skupine priručnih programa OS Windows (engl. Accessories). Potrebno je odabrati
64

„znanstveni pogled“ (engl. Scientific View), te odabirom željene baze ostvariti pretvorbu. Za
usporedbu, promotrite i Primjer 6.1.
5. Napišite općenitu sintaksu za objavu poretka u jeziku C / C++. Redom objasnite svaki dio objave
i razmislite zašto se ni jedan od parametara ne može ispustiti.
6. Kakav mora biti broj kojim se objavljuje veličina strukture poretka prilikom njegove objave?
Može li njega unijeti korisnik naknadno, prilikom izvođenja programa? U kojoj fazi i tko (što)
mora znati ukupnu veličinu poretka i zašto? Objasnite temeljito svoj odgovor.
7. U svezi s prethodnim pitanjem, odgovorite kakva je struktura poretka glede promjenjivosti svoje
veličine? Diskutirajte mane i prednosti koje proizlaze iz toga.
8. Opišite kako se vrši inicijalizacija elemenata poretka odmah pri deklaraciji. Ako je sve elemente
potrebno postaviti na vrijednost 0 , treba li to napisati za svaki od njih? A ako se radi o nekoj
drugoj vrijednosti?
9. Deklarirajte poredak prikladnog imena tipa double s 500 elemenata, i odmah ih inicijalizirajte
prilikom objave tako da prvih deset poprime vrijednosti od 1.0 do 10.0 , a svi ostali da su 0.0 .
10. Kako se navodi pojedini element poretka u jeziku C / C++ ? U svezi s prethodnim zadatkom,
napišite izraze kojima ćete prvih pet elemenata podijeliti s 2.0 , a sljedećih pet pomnožiti s 2.0.
11. Podsjetite se iz osnova računarstva ili pronađite u literaturi kako je organizirana glavna memorija
računala, koja se često označava i kao RAM memorija, ili u slobodnom prijevodu memorija s iz-
ravnim pristupom. Njeno je svojstvo da se na osnovu adrese izravno pristupa sadržaju te memo-
rijske lokacije, jednako kao i to da je brzina pristupa do svake memorijske lokacije u osnovi jed-
nako brza*. Podsjeća li to na podatkovnu strukturu poretka? Obrazložite svoj odgovor.

6.1.2 Dvodimenzionalni i višedimenzionalni poredak


12. Kako se deklarira poredak s dvije dimenzije? Napišite najprije općenitu sintaksu ove objave, a
zatim i vlastiti primjer.
13. Kako je najprimjerenije objasniti dvodimenzionalni poredak u jeziku C / C++ korištenjem kon-
cepta jednodimenzionalnog poretka.
14. Kojoj matematičkoj tvorbi odgovara dvodimenzionalan poredak numeričkog tipa? Navedite ka-
kva je uobičajena indeksacija u matematici, a kakva u jeziku C / C++.
15. Objasnite kako se dvodimenzionalni poredak smješta u „linearnu“ memoriju, koja po svojoj
strukturi odgovara jednodimenzionalnom poretku (vidi pitanje 11). Kako se naziva taj uređaj
elemenata u memoriji. Koji se indeks najbrže vrti?
16. Objasnite što je deklarirano sljedećim izrazom: double dMatrix[12][6] ; // O kojoj i kakvoj
podatkovnoj strukturi se tu radi. Kojeg su tipa njeni elementi, koliko ih ukupno ima, te koju ko-
ličinu memorije zauzimaju. Navedite u kojem rasponu se kreću vrijednosti indeksa njenih ele-
menata. Ako je početni element pohranjen na adresi A0 , na kojim su adresama pohranjeni slje-
deći elementi: dMatrix[0][0] , dMatrix[0][5] , dMatrix[1][0] , … … , dMatrix[11][0] ,
dMatrix[11][5] .
17. Deklarirajte dvodimenzionalnu matricu s 5 redaka i 4 stupca, tipa short int , i odmah je inicijali-
zirajte tako da svaki element ima vrijednost umnoška svojih indeksa.

*
Ovdje zanemarimo mehanizam priručne memorije (engl. cache memory)i utjecaj koji on može imati na doh-
vat memorijskog sadržaja.
65

18. Ako je početna adresa dvodimenzionalne matrice iz prethodnog zadatka A0 = 0080 0000h , skici-
rajte dio memorije u kojem je smještena. Navedite adrese i memorijski sadržaj na tim adresama,
odnosno vrijednosti elemenata matrice.
19. Objasnite što je deklarirano sljedećim izrazom: float fTensor [3][2] [4] ; // O kojoj i kakvoj
podatkovnoj strukturi se tu radi. Kojeg su tipa njeni elementi, koliko ih ukupno ima, te koju ko-
ličinu memorije zauzimaju. Navedite u kojem rasponu se kreću vrijednosti indeksa njenih ele-
menata. Ispišite redom sve elemente ovog poretka i navedite njihove relativne adrese naspram
adrese A0 početnog elementa.
20. Na što se odnosi pojam „dimenzija“ kod višedimenzionalnih poredaka? Je li to u izravnoj svezi s
veličinom ove programske strukture, odnosno s brojem njenih elemenata, ili s čime drugim. Ob-
jasnite!

6.2 Primjeri i zadaci


Primjer 6.1 Smještaj podatkovne strukture poretka u memoriji.
Vizualna predodžba podatkovne strukture poretka vrlo je jednostavna, a istovremeno i važna. Radi
boljeg zora, potrebno je skicirajte raspored elemenata (njihove adrese i sadržaj) u memoriji računala,
za poredak deklarirano na sljedeći način:
const int cN = 100; // Konstantna veličina n.
float fX[cN]; // Objava jednodimenzionalnog poretka fX
// s n elemenata.

Adresa poretka, odnosno adresa početnog elementa, neka je A0 = 0000h (adrese se uobičajeno pišu u
heksadekadskoj formi). Rješenje je dano na slici 4.1.
66

Indeks Adresa Sadržaj (vrijednost) elementa fX[i]


elementa elementa
i A( i ) B0 B1 B2 B3
0011 FFF8 ## ## ## ##
0011 FFFC ## ## ## ##
0 0012 0000 fX [0]
1 0012 0004 fX [1]
2 0012 0008 fX [2]
3 0012 000C fX [3]
4 0012 0010 fX [4]
… … … … …
… … … … …
… … … … …
49 0012 00C4 fX [49]
50 0012 00C8 fX [50]
… … … … …
… … … … …
… … … … …
98 0012 0188 fX [98]
99 0012 018C fX [99]
0012 0190 ## ## ## ##
0012 0194 ## ## ## ##

Slika 6.1 Prikaz podatkovne strukture poretka u memoriji.


Na slici je ilustrirano kako je u glavnoj memoriji računala pohranjen 1-dim. poredak
sa 100 elemenata tipa float . Deklaracija je obavljena tvrdnjama:
const int cN = 100; float fX[cN] ; // vidi Primjer 6.1.

Uređaj elemenata slijedi formulu (6.1). Element s indeksom 0 je početni element fX[0] koji općenito ima
neku adresu A0 unutar glavne memorije računala. Radi jednostavnosti, za nju je pretpostavljen okrugli
iznos: A0 = 0012 0000h (za primjer ispisa konkretne vrijednosti vidi zad. xx). Sadržaj i-tog elementa
fX[i] pohranjen je na adresi A(i) = A0 + 4 × i , unutar četiri bajta B0 do B3, kojih su adrese redom: A( i
) + 0, A( i ) + 1, A( i ) + 2 i A( i ) + 3. Adresa posljednjeg elementa je:
A(100 ) = ( A0 + 4 × 99 ) d = ( A0 + 396 ) d = ( A0 + 18C ) h = 0012 018C h = 0x0012018c .
Zadnja vrijednost je napisana u „C / C++ stilu“, malim latinskim slovima A do F, na način kako adrese, od-
nosno općenito heksadekadske vrijednosti, ispisuju mnogi prevodioci. Gornji poredak ima 100 elemenata
duljine 4B i zauzima ukupnu memoriju od 400B. Označimo to kao njegov kapacitet C = 400d B =
= 190h B , gdje je drugi prikaz u heksadekadskoj formi. Iz gornjeg izlaganja slijedi da početni, nulti, bajt po-
lja ima adresu A0 = 0012 0000h , a zadnji, 399-ti A399 = 0012 018F h (primijetite: 190h – 1 = = 18Fh ). Isti
prikaz i razmatranje vrijedi za sve poretke s jednakim brojem i duljinom elemenata. Na gornjoj slici prika-
zano je i osam bajtova prije i poslije deklariranog poretka. Za njih, naravno, ne postoje „legalne“ vrijednos-
ti indeksa, pa nisu niti napisane. Radi se o dijelovima memorije u kojima su pohranjeni drugi sadržaji, kao
npr. druge lokalne varijable. Vrijednost ovih bajtova nevezana je uz poredak, te označena s ## Dva znaka
# sugeriraju dvije heksadekadske znamenke kojima je u potpunosti određen sadržaj jednog bajta.

Zadatak 6.1 uz Primjer 6.1


Proučite strukturu poretka u gornjem primjeru i odgovorite na sljedeća dodatna pitanja:
a) Provjerite adrese navedenih elemenata, te izračunajte adrese još nekih po vlastitom izboru.
67

b) Odredite koliko elemenata duljine 4B možemo pohraniti u poredak koje zauzima ukupnu duljinu
od 1KB, koliko u poredak duljine 16KB, 64KB i 1 MB.
c) Može li se struktura poretka primijeniti i na cijelu radnu memoriju računala? Objasnite! Usporedite
s odgovorom na pitanje 11 u odjeljku 6.1.1.
d) U svezi s potpitanjem c — ako se sve ostale strukture pohranjuju u memoriju računala, što zaklju-
čujete o važnosti strukture poretka? Mora li se onda bilo koja zamisliva programska struktura mo-
ći implementirati s pomoću strukture poretka?

Primjer 6.2 Deklaracija poretka i inicijalizacije elemenata.


U sljedećem programskom odsječku ostvarena je:
a) Deklaracija bez inicijalizacije ostavlja elemente nedefiniranima. U tom slučaju mora postojati ek-
splicitna definicija dimenzije polja konstantnim izrazom u uglatoj zagradi.
b) Elementi poretka se redom inicijaliziraju na vrijednosti navedene unutar vitičaste zagrade. Ukoliko
je ispuštena eksplicitna definicija dimenzije polja, kao u našem slučaju, dimenzija je jednaka broju
elemenata navedenih u listi (odijeljenih zarezima). U našem slučaju deklarirano je polje s elemen-
tima tipa float dimenzije 3.
c) Elementi liste mogu biti konstante ili proizvoljni C/C++ izrazi (r-value).
d) Uporaba izraza prilikom inicijalizacije elemenata polja.
// Konstanta za definiciju veličine polja:
const unsigned int cN = 10;
// a) Deklaracija bez inicijalizacije:
float fX[cN]; // Objava jednodimenzionalnog polja fX
// s 10 elemenata tipa float.
// Elementi polja su nedefinirani!
// b) Deklaracija bez eksplicitnog navođenja dimenzije
// uz inicijalizaciju iz liste:
float fY[] = { 5.2f, 4.7f, 23.4f }; // Dim. polja = ?
// c) Deklaracija s eksplicitnim navođenjem dimenzije
// uz djelomičnu inicijalizaciju. Je li što pogrešno?
const int i4 = 4;
int iA1[cN] = { 1, 2, 3, i4, i4 + 1 };
// Provjerite kolika je vrijednost neinicijaliziranih elemenata
// sljedećim ispisom:
for(i = 0; i < cN; i++)
cout << "iA1[" << i << "] = " << iA[i] << '\n';
cout << endl;
// d) Deklaracija s eksplicitnim navođenjem dimenzije
// uz inicijalizaciju iz liste. Je li što pogrešno?
int iA2[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 + 1, 9 + 1 };

Zadatak 6.2 uz Primjer 6.2


U svezi s dijelovima programa od a do d, odgovorite:
a) Kakvog tipa i kojih atributa mora biti izraz kojim se objavljuje dimenzija poretka. Maknite kvalifi-
kator const iz prve deklaracije (označene s a) i ponovite kompilaciju. Što zaključujete?
b) Objasnite kako kompilator određuje dimenziju poretka u ovom dijelu programa.
c) Provjerite: ako se u vitičastoj zagradi inicijalizira barem jedan element, kolika je vrijednost onih
koji nisu inicijalizirani? Kako ćete to koristiti?
68

d) Otklonite grešku u ovom dijelu programa. Izvedite zaključak o dozvoljenom broju elemenata liste
pri inicijalizaciji polja eksplicitno zadane veličine.
e) Dodajte ispise elemenata svih poredaka u dijelovima programa a, b i d, kako je to učinjeno u
dijelu programa označenom c.

Zadatak 6.3 Pristup elementima poretka.


a) Odredite vrijednosti elemenata sljedećeg polja nakon naznačenih operacija. Obratite pažnju koji
su elementi inicijalizirani eksplicitno od strane programera. Koji nisu?
b) Objasnite način na koji je ostvaren ispis elemenata polja s pomoću naredbe for.
// 1-dim poredak tipa short int:
const unsigned int cuN = 7;
short int sI[cuN] = {1, 2, 3}; // Ispišite vrijednosti svih elemenata
// redom, sI[0] = ?, sI[1] = , ...
// Ako niste sigurni, dodajte ovdje njihov ispis:
/* cout << "Ispis inicijalnih vrijednosti elemenata poretka \n”
<< endl;
// ... ... ...
*/
// Pristup i aritmet. operacije s elementima polja:
sI[4] = sI[3]; // sI[4] = ?
sI[5] = ++sI[4]; // sI[5] = ? , sI[4] = ?
sI[5]++ ; // sI[5] = ?
sI[6]-- ;

// Ispis vrijednosti nakon aritmetičkih operacija s elementima:


for (int i = 0; i < cuN ; i++)
cout << "sI[" << i << "] = " << sI[i] << "\n";
cout << "\n" << endl;
// ... ...

Zadatak 6.4 Pristup elementima poretka – provjera dopuštenih vrijednosti indeksa.


a) Objasnite najprije što je problematično, a zatim pokušajte predvidjeti kako će se prevesti sljedeći
programski odsječak. Uočite koje vrijednosti poprima indeks for petlje, te je li to u skladu s doz-
voljenim indeksima elemenata deklariranog polja? Razmislite, hoće li biti grešaka pri prevođenju?
Možete li predvidjeti što će se ispisati?
b) Testirajte program i provjerite ispis pokrećući program nekoliko puta. Što zaključujete? Hoće li
prevodilac upozoriti na uporabu nevaljalih indeksa elemenata polja? Tko o tome mora strogo vo-
diti računa? Objasnite što predstavljaju ispisane vrijednosti za nepostojeće elemente poretka?
Napomena. Izvršni kôd dobiven kompilacijom u razvojnoj okolini Dev-C++ neće se izvršavati
korektno za negativne indekse elemenata, iako će kompilacija proći bez upozorenja i grešaka. Ini-
cijalni izraz for petlje je u tom slučaju potrebno prepraviti u: int i = 0 ; .
const unsigned int cuN = 5;
// 1-dim polje tipa short int:
short int sI[cuN] = {0, 1, 2, 3, 4}; // min. indeks, i(sI)min = ?
// max. indeks, i(sI)max = ?
// Ispis:
for (int i = 0 - 5; i < cuN + 5 ; i++) // Oprez!!! i(sI)min = ? ,
i(sI)max = ?
cout << "sI[" << i << "] = " << sI[i] << "\n";
69
cout << "\n" << endl;
// ... ...

Zadatak 6.5 Implicitna inicijalizacija elemenata polja prevodioca MS Visual Studio


(2005).
a) Inicijalizira li C++ prevodilac (MS Visual Studio 6.0, platforma Win32) vrijednosti elemenata po-
retka nakon njegove deklaracije u kojoj nije bilo eksplicitne inicijalizacije? Specifično, ostaju li
elementi takvog polja potpuno nedefinirani, tj. slučajnih vrijednosti koje odgovaraju prethodnim
sadržajima u rezerviranom dijelu memorije, ili se elementi ipak postavljaju na određenu vrijed-
nost? To ćete lako provjeriti jednostavnim programskim odsječkom. Što zaključujete nakon nje-
govog izvršenja? Je li moguće da se ovakav rezultat dobije slučajno? Obrazložite svoj odgovor.
Usput promotrite i objasnite kako je ostvaren ispis.
b) Često je zgodno da i elementi velikih polja budu inicijalizirani na neku željenu vrijednost, npr. 0
ako se radi o poljima brojeva. Kako se to može postići i bez inicijaliziranja svakog elementa pose-
bice, tj. bez uporabe for petlje? Ako niste sigurni, ponovite gradivo o inicijalizaciji elemenata po-
retka.
c) Ako nismo izvršili inicijalizaciju varijabli, što vrijedi i za elemente poretka, a koristimo ih u prog-
ramu (npr. prilikom ispisa), što će dojaviti prevodilac? Objasnite i komentirajte njegovu poruku.
Izvršite program, ignorirajući poruke otklanjača pogrešaka i provjerite rezultate ispisa.
d) *Provjerite kolika je vrijednost elemenata polja u ovom slučaju, i to najprije uz uobičajeni, de-
kadski ispis, a potom uz heksadekadski. Liči li broj u dekadskom sustavu kao neki pomno odabra-
ni broj? A u heksadekadskom sustavu? Postupite po sljedećem receptu. Označimo nađenu vrijed-
nost s x'. Njenu heksadekadsku vrijednost prevedite u dekadsku, i potom je oduzmite od modula
aritmetike m = 2n u kojoj se vrši račun. Ovdje je n broj bitova cjelobrojnog tipa podataka. Dobi-
veni broj je x = 2n − x' . Usporedite taj broj s vrijednosti dekadskog ispisa elemenata poretka.
Što zaključujete. Broj x' se naziva potpuni komplement (potpuna nadopuna) broja x do modula
aritmetike m, i služi za prikaz negativnih brojeva. (Za detalje vidjeti aritmetiku potpunog kom-
plementa.)
e) Usporedite svoje odgovore s odgovorima o internoj inicijalizaciji varijabli iz poglavlja 3.
// a)
// Skica rješenja:
int iA[0x100];
cout << endl;
for (UINT i = 0; i < 0x100; i++)
{
cout << "[" << i << "]" << iA[i] ;
if ( (i + 1) % 4 )
cout << "\t";
else
cout << "\n";
}
// b)
// Djelomična(?) inicijalizacija:
int iY[0x100] = {0, }
// Ispis b:
// ... ... ...
70

Zadatak 6.6 Unos podataka u elemente poretka.


Potrebno je objaviti poredak sP tipa short int, dimenzije: const unsigned int cuN = 10. Zatim
napišite program koji će s tastature unašati vrijednosti za sve elemente poretka. Nigdje, osim na
početku kod definicije konstante n ne smije se u programu pojavljivati njena konkretna vrijednost,
tj. pisati broj 10 (razmislite zašto!?). Na početku programa ispisuje se poruka korisniku: "Unos niza
P od n cjelobrojnih podataka:", gdje n mora imati stvarnu vrijednost. Zatim slijedi unos podataka,
tako da se prilikom unosa vrijednosti za i-ti element na ekranu pojavi poruka:
Unesi podatak P(j) =
gdje je j = i + 1. Tj. za korisnika će pobrojavanje elemenata polja biti s pomoću indeksa iz skupa
prirodnih brojeva, a ne od 0. Po završenom unosu program ispisuje poruku "Ispis niza P od n
cjelobrojnih podataka:", nakon čega slijedi ispis podataka s porukom:

Podatak P(j) =

ponovo uz konkretnu vrijednost indeksa j.

Zadatak 6.7 Unos u i ispis iz elemenata poretka.


Potrebno je objaviti poredak sP tipa short int, dimenzije: const unsigned int cuN = 10. Zatim
napišite program koji će s tastature unašati vrijednosti za sve elemente poretka. Nigdje, osim na
početku kod definicije konstante n ne smije se u programu pojavljivati njena konkretna vrijednost,
tj. pisati broj 10 (razmislite zašto!?). Na početku programa ispisuje se poruka korisniku: "Unos niza
P od n cjelobrojnih podataka:", gdje n mora imati stvarnu vrijednost. Zatim slijedi unos podataka,
tako da se prilikom unosa vrijednosti za i-ti element na ekranu pojavi poruka:
Unesi podatak P(j) =
gdje je j = i + 1. Tj. za korisnika će pobrojavanje elemenata polja biti s pomoću indeksa iz skupa
prirodnih brojeva, a ne od 0. Po završenom unosu program ispisuje poruku "Ispis niza P od n
cjelobrojnih podataka:", nakon čega slijedi ispis podataka s porukom:

Podatak P(j) =
ponovo uz konkretnu vrijednost indeksa j.

Primjer 6.3 Deklaracija, inicijalizacija i pristup elementima 2-dim poretka.


Najprije je objavljen dvodimenzionalni poredak tipa float, veličine 3 × 4, što odgovara matrici s 3
retka i 4 stupca. U duhu jezika C možemo reći da se radi o poretku s tri elementa (retka) u kojem je
svaki element poretka s četiri elementa (stupca). Kod višedimenzionalnih poredaka, za sve dimenzije
osim prve, veličina mora biti eksplicitno zadana unutar uglatih zagrada, a veličina prve dimenzije mo-
že biti određena kroz inicijalizaciju, potpunu ili djelomičnu (navođenjem vitičastih zagrada).
// a) Objava 2-dim poretka bez inicijalizacije:
float fMtrx1[3][4] = { {0.f}, };
// Koliko elemenata ima poredak fMtrx1?
// Koliko memorije zauzima?
// b) Objava uz potpunu inicijalizaciju:
float fMtrx2[ ][4] = { {1.1, 1.2, 1.3, 1.4}, {2.1, 2.2, 2.3, 2.4},
{3.1, 3.2, 3.3, 3.4} };
// Koliko elemenata ima poredak fMtrx1?
// Koliko memorije zauzima?
// c) Objava uz djelomičnu inicijalizaciju
// Dopišite vrijednosti svih elemenata po započetom obrascu!
71
float fMtrx3[ ][3] = {{1.1, 1.2, 1.3}, {2.1, 2.2, 2.3},
{3.1, 3.2, }, { },
{5.1 } };
// Koliko elemenata ima poredak fMtrx1?
// Koliko memorije zauzima?
// Ispis elemenata poredaka.
// "Ručni" ispis elemenata fMtrx1:
cout << "fMtrx1[0][0] = " << fMtrx1[0][0]
<< "\tfMtrx1[0][1] = " << fMtrx1[0][1]
<< "\tfMtrx1[0][2] = " << fMtrx1[0][2]
<< "\tfMtrx1[0][3] = " << fMtrx1[0][3] << '\n'
<< "fMtrx1[1][0] = " << fMtrx1[1][0]
<< "\tfMtrx1[1][1] = " << fMtrx1[1][1]
<< "\tfMtrx1[1][2] = " << fMtrx1[1][2]
<< "\tfMtrx1[1][3] = " << fMtrx1[1][3] << '\n' // !!! !!!
// Dovršite ovaj produženi ispis ... ...
// ... ... ...
// "Ručni" ispis elemenata fMtrx2 (vidi primjer za fMtrx1):
// ... ... ...
// "Ručni" ispis elemenata fMtrx3 (vidi primjer za fMtrx1):
// ... ... ...
// // // // //

Zadatak 6.8 uz Primjer 6.3.


a) Promotrite različite načine objave i inicijalizacije elemenata. Odgovorite na pitanja u komentarima
o veličini pojedinih poredaka. Dopišite početne vrijednosti elemenata poretka fMtrx3 prema za-
početom obrascu.
b) Dovršite produženu tvrdnju za „ručni“ ispis svih elemenata poretka fMtrx1 ispisivanjem svih vri-
jednosti indeksa redom. Obratite pažnju na uporabu kontrolnih znakova za tabulator i novi red, ta-
ko da ispis odgovara matričnom. Prilikom korištenja „kopiraj i zalijepi“ tehnike, pazite da odgova-
rajuće korigirate vrijednosti indeksa.
c) Dovršite ručni ispis elemenata ostala dva polja.
d) Maknite (iskomentirajte) dio za inicijalizaciju elemenata poretka fMtrx1 , i napravite provjeru ho-
će li elementi polja imati slučajne vrijednosti ili ne. Ponovite svoje odgovore na istovjetni zadatak
s 1-dim poretkom (Zadatak 6.5d).

Zadatak 6.9 Dodatni zadatak uz Primjer 6.3. Ispis sadržaja 2-dim poretka.
a) Zamijenite nezgrapni „ručni“ ispis u prethodnom primjeru i zadatku s ispisom ostvarenim s pomo-
ću for petlje. Provjerite najprije kako je tekao prolaz kroz elemente 1-dim poretka, u prethodnim
zadacima. Koliko for petlji treba za prolaz kroz njegove elemente? Razmislite, koliko će for
petlji treba za ispis elemenata 2-dim poretka?
b) Ostvarite prolaz kroz 2-dim poredak tako da za svaki njegov indeks otvorite po jednu petlju, s time
da su one ugniježđene. Vanjska neka ima indeks unsigned int i ; , koji prolazi kroz sve vrijednos-
ti prve dimenzije (indeksi redaka matrice). Unutarnja petlja neka ima indeks unsigned int j , koji
prolazi vrijednostima druge dimenzije (indeksi stupaca matrice). Za jedan prolaz vanjske petlje,
unutarnja petlja se izvrši u cijelosti. Ispis organizirajte u unutarnjoj petlji. Unutar retka elemente
razmaknite tabulatorom. Nakon što je cijeli redak ispisan, tj. nakon cijelog prolaska unutarnje pet-
lje, pomaknite ispis u novi redak. Koristite ideje iz „ručnog“ ispisa.
72

c) Ukoliko se niste dosjetili kako organizirati dvostruku petlju, proučite programski kôd u sljedećem
zadatku (Zadatak 6.10), te se potom vratite na ovaj.

Zadatak 6.10 Ispis sadržaja 2-dim poretka. Ugniježđene petlje.


Potrebno je ispisati sadržaj dvodimenzionalnog poretka (slične veličine kao u gornjem primjeru) na
dva načina: i) ispisujući elemente redom jedan ispod drugog, po načelu «retci prvo», te ii) ispisujući
elemente u dvodimenzionalnu shemu analognu matrici. Dodatna pitanja:
a) Na što liči ispis i)? Podsjeća li on na način na koji su elementi dvodimenzionalnog poretka pohra-
njeni u (jednodimenzionalnu) memoriju? Objasnite!
b) Je li potrebna velika preinaka programa da se ostvari 2-dim (matrični) zapis, u kojem će elementi s
jednakim prvim indeksom biti ispisani u istom redu? Ostvarite to. Za razmak između elemenata
unutar retka, koristite kontrolni znak tabulatora. Ukoliko preglednost zahtijeva, oznaku elementa
"sMtrx[i][j] = " možete prikladno skratiti, uklanjajući detalje mađarske notacije i pišući samo
oznake bitne za korisnika, kao npr. "M[i][j] = ".
c) Ostvarite ispis iii) matrice na obrnuti način, tj. tako da se u istom retku nađu elementi s istim
drugim indeksom. Primijetite da to upravo odgovara matrici koja je transponirana u odnosu na
prvobitnu.
// Objava konstantnih dimenzija:
const int cN = 3, cM = 4;
// Deklaracija i djelomična inicijalizacija:
short int sMtrx[cN][cM] = { {1, 2, 3, 4}, {5, 6, 7, 8 }, {9, } };
// Ispis podataka o poretku:
cout << "2-dim poredak sM dimenzija " << cN << " x " << cM
<< "tipa short int." << "\n\n";
// Ispis i), rješenje:
// Poruka i:
cout << "i) Linearni ispis – retci prvo (Row Major Ordering):\n"
<< "=======================================================\n "
<< endl;
// Vanjska petlja (indeks i = 0, 1, ... , n – 1):
for (UINT i = 0; i < cN ; i++)
{
// Unutarnja petlja (indeks j = 0, 1, ... , m – 1):
for (UINT j = 0; j < cM ; j++)
cout << "sMtrx[" << i << "][" << j << "] = " << sMtrx[i][j] << "\n";
cout << "\n" ; // prazna linija nakon svakog retka matrice
}
// Ispis ii)
// Poruka ii:
cout << "ii) 2-dim (matrični) ispis:\n"
<< "=======================================================\n "
<< endl;
// ... ... ...

Zadatak 6.11 Ispis matrice sa zaglavljem


a) Potrebno je ispis iz prethodnog zadatka učiniti preglednijim. Program treba najprije ispisati opće
podatke o matrici, tj. njen naziv (prikladan za korisnika), tip elemenata, i dimenzije. Zatim prog-
ram u jednom retku ispiše indekse stupaca, i to u matematičkom stilu, od 1 na dalje. Zatim se taj
redak podvuče prikladnom linijom (ostvarenom npr. uzastopnim znakovima '-'). Prilikom ispisa
73

retka, najprije treba ispisati njegov indeks, napraviti odgovarajući razmak, i tek potom ispisivati
elemente retka.
b) Dodajte ovom programu i mogućnost inverznog ispisa, za slučaj da su elementi pohranjeni na sup-
rotan način od uobičajene matematičke konvencije. Npr. u poznatom tabličnom programu MS©
Excel, indeksi stupaca označeni slovima, pišu se prvi, a tek potom indeksi redaka (koji su brojča-
ni), što je suprotno od navedenog standarda.

Zadatak 6.12 *Unos i jednostavne operacije s matricama.


a) Potrebno je rezervirati prostor za tri matrice tipa float dimenzija 20 20. Korisnika se pita za
dimenzije matrica s kojima želi raditi, uz poruku o maksimalnoj veličini matrice. Potrebno je os-
tvariti ulazne filtre, tj. onemogućiti unošenje granica većih od dopuštenih. Program zatim ostvaruje
unos podataka u dvije matrice jednakih dimenzija. Korisnika se pita kako želi unositi podatke, po
redcima ili po stupcima, te se ovisno o izboru, organizira unos.
b) Nakon unosa, program zbraja dvije matrice i pohranjuje rezultat u treću matricu (vidi naputak o
matričnom računu dolje).
c) Program zatim testira jesu li matrice simetrične, tj. jesu li jednake sebi transponiranoj matrici. Po-
datak o tome se čuva u logičkoj varijabli bIsSquare_1 ( _2, _3, za ostale matrice). Tek potom se
prelazi na provjeru uvjeta simetričnosti. Ako je matrica i simetrična, odgovarajuće se postavlja lo-
gička varijabla bIsSymmetric_1 ( _2, _3 ).
d) Nakon unosa, omogućuje se ispis podataka o tome jesu li matrice kvadratne i simetrične. Također
omogućuje se ispis sumarne matrice. Ispis matrice treba biti s podacima o tipu i dimenzijama, te
sa zaglavljem kao u prethodnom zadatku (Zadatak 6.11), čija je rješenja potrebno koristiti.
e) Čim više koristite istovjetne dijelove programskog koda. Da li bi bilo korisno da jedan te isti dio
programskog koda možemo primjenjivati za raznovrsne podatke? (Vidi pogl. o funkcijama.)
Naputak o matričnom računu. Neka su zadane matrice A i B dimenzija n m s elementima
aij i bij , što se kratko piše kao: A = [aij]n× m , B = [bij]n× m . Zbroj ovih dviju matrica je matrica
C = [cij]n× m za čije elemente vrijedi: cij = aij + bij , i = 1, … n , j = 1, … , m.
Transponirana matrica od A se označava kao AT , i ona je općenito jednaka matrici D za koju
vrijedi: AT = D = [dij]m× n , uz dij = aji , te aij = dji . Ovo se svodi na to da se redci početne mat-
rice napišu kao stupci, ili obrnuto, da se stupci napišu kao redci. Definicija. Matrica A je simetri-
čna ako vrijedi: A = AT. Očiti je preduvjet za simetričnost matrice je da bude kvadratna, tj. da ima
jednak broj redaka i stupaca.

Zadatak 6.13 3-dim poredak.


Promotrite deklaraciju 3-dim poretka iTnsr, uz istovremenu inicijalizaciju kojom mu je prvih 12
elemenata u prvom redu postavljeno na vrijednosti koje odražavaju vrijednosti njegovih indeksa uve-
ćanih za 1 (dakle, indeksa prema matematičkom stilu pisanja). Ostali su elementi postavljeno na 0
(treći red inicijalizacije).
a) Smije li se, kod deklaracije višedimenzionalnih poredaka, veličina prva dimenzija ostaviti nespeci-
ficiranom, ako je izvršena odgovarajuća inicijalizacija elemenata? Smiju li se veličine ostalih di-
menzija ostavite nespecificirane? Odgonetnite koliko je ukupno elemenata, te kolika je veličina pr-
ve dimenzije ovog poretka.
b) Umetnite donju deklaraciju u testni program unutar projekta odgovarajućeg imena. Napišite tros-
truko ugniježđenu petlju za ispis svih elemenata ovog poretka, tako da se najbrže vrti vanjski in-
deks.
74

c) Dodatno, napišite trostruko ugniježđenu petlju za ispis svih elemenata ovog poretka u obrnutom
redoslijedu, tj. tako da se najbrže vrti unutarnji indeks.
d) Dopišite vrijednosti elemenata u trećem redu u skladu sa započetim obrascem, i provjerite rezultate
ispisa.
int iTnsr[ ][3][4] = { { {111, 112, 113, 114}, {121, 122, 123, 124},
{131, 132, 133, 134} },
{ {0, }, } } ;
75

Vježba 7. Kazaljke – pokazivački tip.


Navodi (reference)
Kazaljke predstavljaju poseban, pokazivački tip podataka, namijenjen pohrani adresa. Ukratko se
kazaljke mogu opisati kao tipizirane adrese, u smislu da prevodilac vodi računa koji je tip podataka
pohranjen na danoj adresi. Navodi ili reference također predstavljaju adrese određenog tipa podataka,
uz sintaktičku posebnost da ih programer piše kao uobičajene varijable. Dakle, na mjestu objave pre-
vodilac bilježi adresu varijable preko koje pristupa do njene vrijednosti, ali je način pisanja i tretman
takve varijable isti kao i za one uobičajene. Navodnički tip je posebice primjeren za prijenos argume-
nata funkcija (sljedeća vježba), zbog čega je prvenstveno i uveden.

7.1 Teorijska priprema


Za razumijevanje kazaljki i navoda nužno je poznavati osnovni programski model memorije. Osnove
tog modela već su korištene kod prikaza pohrane strukture poretka u memoriji (Slika 6.1). Slika 7.1
prikazuje programski model memorije za 32-bitni adresni prostor (za detalje vidjeti [1]).
U Dnevnik vježbi unesite zabilješke o osnovnim teorijskim pojmovima vezanim uz gradivo ove
vježbe, te odgovorite na pitanja koja slijede.

7.1.1 Kazaljke (pokazivački tip)


1. U kojoj vrsti programskih jezika je rad s adresama podrazumijevajući, tj. programer mora voditi
računa o adresama varijabli i programskih struktura?
2. Objasnite zašto se programeru stavlja na raspolaganje pokazivački tip? Što mislite, je li moguće
realizirati složene i dinamičke podatkovne strukture na učinkovit i elegantan način bez ovog tipa?
3. Navedite svojim riječima što su to kazaljke odnosno što predstavlja pokazivački tip.
4. Navedite razliku između memorijskih adresa kako se one rabe u zbirnim jezicima i kazaljki.
5. Kako se organizira rad s adresama u višim programskim jezicima.
6. Proučite i objasnite programski model memorije. Skicirajte ga u Dnevnik vježbi. Objasnite os-
novne pojmove kao što su naslovni prostor, adresno zrno, maksimalni kapacitet memorije.
7. Na slici programskog modela memorije objasnite kako se memorija popunjava programima. Ka-
ko rastu standardni memorijski stogovi.
8. Objasnite kakva je to podatkovna struktura stoga. Koja kratica opisuje princip pristupa podacima
ove strukture. Navedite nekoliko primjera iz računarstva i šire, koji opisuju pristup elementima
ili predmetima po načelu kako se to dešava na stogu.
9. Koji su tipovi podataka uvedeni u C / C++ za rad s adresama?
76

Osnovna memorijska lokacija,


Adresa Adresa
«memorijsko zrno» = 1B = 8 bit
(općenita) 32-bitna
b7 b6 b5 b4 b3 b2 b1 b0
Amin = 0 = 0000 0000 XXh = sadržaj bajta 0
Amin + 1 = 0000 0001 XXh = sadržaj bajta 1
Amin + 2 = 0000 0002 XXh = sadržaj bajta 2
Amin + 3 = 0000 0003 XXh = sadržaj bajta 3
… … … … …
… … … … …


… … Smjer pohrane
programa i
Adresni potprostor A
podataka
… … (prema većim
… … adresama)

… …

… … … … …


Adresni potprostor B Smjer rasta
stogova --
… …
(prema manjim
… … adresama)
… …
… …
… … … … …
Amin + NA – 2 = FFFF FFFE XXh = sadržaj bajta FFFF FFFE
Amin + NA – 1 = FFFF FFFF XXh = sadržaj bajta FFFF FFFF

Slika 7.1 Programski model memorije. Svako memorijsko zrno (danas je to standardno
1B = 8bit) ima jedinstvenu adresu iz adresnog prostora. Adresni prostor se može dijeliti na
potprostore određene veličine, npr. za smještaj operacijskog sustava, za korisničke progra-
me itd… Standardno se programi i globalne varijable, uključujući i globalno deklarirane
poretke, pohranjuju u memoriju u smjeru od manjih adresa prema većima. Lokalne varijab-
le pohranjuju se na stog. Stogovi rastu u suprotnom smjeru. Sa XXh (dvije heksadekadske
znamenke) označen je heksadekadski ekvivalent sadržaja jednog bajta. Radi jednostavnosti, istom su
oznakom označeni općenito različiti sadržaji.

10. Kakva je sintaksa za deklaraciju kazaljke na neki tip u jeziku C / C++. Navedite sintaksu na op-
ćenit način, i zatim to potkrijepite primjerom deklarirajući kazaljke na nekoliko cjelobrojnih ti-
pova i na tipove s pomičnom točkom. Za kazaljke odaberite prikladna imena u skladu s Mađar-
skom notacijom.
11. Objasnite sintaksu i način djelovanja operatora „adresa-od“. Naglasite čemu on služi? Na koje
tipove podataka, odnosno općenito na koje programske entitete on može djelovati? Kakvom tipu
smijemo pridružiti rezultat djelovanja ovog operatora?
12. Objasnite sintaksu i način djelovanja operatora dereferenciranja. Na koje tipove podataka on
može djelovati? Kakvom tipu podatka smijemo pridružiti rezultat njegovog djelovanja?
13. Navedite koja sve različite operatore predstavlja isti znak * u jeziku C / C++ . Objasnite kako
razlučujete o čemu se radi, i kako će to učiniti kompilator?
77

14. Smijemo li dereferencirati rezultat djelovanja operatora adresa-od? Smijemo li djelovati opera-
torom adresa-od na rezultat djelovanja operatora dereferenciranja? Razmislite o odgovoru a po-
tom ga provjerite u testnom programu.
15. Deklarirajte nekoliko varijabli tipa float, te nekoliko kazaljki na taj isti tip. Kazaljkama pridije-
lite adrese varijabli. Zatim dereferencirajte kazaljke i komentirajte što se dobiva. Provjerite zak-
ljučke u testnom programu.

7.1.2 Kazaljke i poredci


16. Xxxx (Dodati pitanja.)

7.1.3 Dinamičko alociranje memorije operatorom new


17. Xxxx (Dodati pitanja.)

7.1.4 Navodnički (referencijski) tip


18. Xxxx (Dodati pitanja.)

7.2 Primjeri i zadaci


Primjer 7.1 Deklaracija i inicijalizacija kazaljki. Memorijski prikaz.
Promotrite donji programski odsječak u kojem se deklarira i inicijalizira nekoliko varijabli, kazaljka i
podatkovna struktura poretka. Memorijski prikaz dan je na slici koja slijedi (Slika 7.2).
// Deklaracija kazaljki i definiranje njihovih vrijednosti.
// 1. dio
const unsigned int cuN = 100; // Nepredznačena konstanta.
int iX1 = +1, iX2 = -2; // Deklaracija i inic. 2 var. tipa int
int* pI1 ; // Deklaracija kazaljke pI1 na tip int
int iX[cuN]; // Deklaracija poretka sa cuN = 100 el. tipa int.
pI1 = &iX1 ; // Adresa var. iX1 pohranjuje se u kazaljku pI1.
// 2. dio
iX2 = *pI1 ; // Ekvivalentno izrazu: tx2 = *(&tx1),
// odnosno pridruživanju: tx2 = tx1.

Zadatak 7.1 uz Primjer 7.1


a) Promotrite donji programski odsječak i objasnite sve korištene tvrdnje. Uočite gdje se deklarira
kazaljka, i na koji tip podataka. Objasnite korištenu sintaksu. Na koji je način kazaljci pridružena
vrijednost, i o kojoj se vrijednosti radi?
b) Objasnite prikaz pohrane varijabli, kazaljke i polja u memoriji. Je li to prikaz stanja memorije pri-
je ili poslije izvođenja 2. dijela programskog odsječka, tj. njegove zadnje tvrdnje. Ako je stanje
prije, napišite kakvo je ono poslije izvođenja zadnje tvrdnje.
c) Neka je adresa konstante cuN , A(cuN) = 0012 06A0. Odredite sve ostale adrese i sadržaj memo-
rije za sve deklarirane varijable, kazaljku i poredak. Skicirajte stanje po uzoru na prethodni prim-
jer, i to prije i poslije izvođenja 2. dijela programskog odsječka.
78

Memorijska Sadržaj memorije Značenje


adresa: (4 uzastopna bajta) sadržaja
… … … … … …
0011 FFF8 XXXX XXXX –
0011 FFFC XXXX XXXX –
0012 0000 CCCC CCCC fX [0]
0012 0004 CCCC CCCC fX [1]
… … … … … …
… … … … … …
… … … … … …
0012 0188 CCCC CCCC fX [98]
0012 018C CCCC CCCC fX [99]
0012 0194 0012 019C pI1
0012 0198 FFFF FFFE iX2
0012 019C 0000 0001 iX1
0012 01A0 0000 0064 cuN = 100d
0012 01A4 XXXX XXXX –
0012 01A8 XXXX XXXX –
… … … … … …

Slika 7.2 Prikaz memorijske pohrane varijabli i kazaljki deklariranih u prethodnom


primjeru (Primjer 7.1) Lokalne varijable pohranjuju se na stog koji raste prema manjim adresama.
Prva je deklarirana konstanta cuN tipa int koja se smješta na najveću adresu 0012 01A0. Sljedeća vari-
jabla iX1 istog tipa, smješta se na adresu za 4 manju od prethodne, tj. na 0012 019C. Iza toga se smješ-
taju sljedeće dvije varijable, od kojih je druga kazaljka na cjelobrojni tip. Njoj se u zadnjoj tvrdnji prvog dije-
la programskog koda pridružuje adresa varijable iX1 (masno pisana vrijdenost). Strelice sugeriraju značenje
pokazivačkog tipa: njegova vrijednost je adresa koja pokazuje gdje se nalazi promatrana programska tvorba
(varijabla, poredak, objekt, vidi dalje). Navedene vrijednosti adresa su fiktivne. Stvarne adrese ovise o verziji
kompilatora i operacijskom sustavu. Čitatelj ih može provjeriti u svojim razvojnim okolinama.

Zadatak 7.2 Dodatni zadatak uz Primjer 7.1


a) Umetnite gornji programski odsječak u testni program. Dodajte linije za ispis adresa i sadržaja
varijabli i kazaljki s prikladnim objašnjenjima, tako da dobro možete pratiti ispisane vrijednosti.
Također dodajte linije za izravan ispis adresa svih varijabli s pomoću operatora adresa-od. Kao
primjer, adresu i vrijednost konstante cuN možete dobiti izravno primjenom sljedeće tvrdnje:
cout << "A(cuN)= << &cuN << "\t cuN = " << cuN << '\n';
Na isti način ispišite adrese i vrijednosti svih ostalih varijabli, iX1, iX2, uključujući i samu adresu
te vrijednost kazaljke pI1. Konačno, ispišite i adresu poretka, tj. adresu i sadržaj njegovog počet-
nog elementa, prvog i zadnjeg. Razmislite na koje sve načine to možete napraviti. Nakon što ste
napisali linije koda za ispis, umetnite ih na dva mjesta ― nakon prvog, te nakon drugoj dijela pro-
grama.
b) Pokrenite dobiveni program najprije u razvojnoj okolini Dev-C++. Provjerite je li prevodilac re-
zervirao mjesta za varijable kako smo predvidjeli? Je li razlika između susjednih adresa 32-bitnih
podatka uvijek 4, kao i na slici uz gornji primjer (Slika 7.2)? Izračunajte tu razliku jednostavnim
računom u heksadekadskom sustavu „na papiru“. Potom provjerite rezultat i na heksadekadskom
79

kalkulatoru.* Isto napravite i za elemente poretka, odnosno poredak u cijelosti. Promijenite za


kratko tip varijabli iX1 te iX2 , te tip poretka iX u short int, te ponovite izvršavanje programa.
Što ćete još morati promijeniti da bi kompilacija bila uspješna? Kakav je sada rezervirani prostor?
Izvedite zaključak: pakira li ovaj prevodilac navedene tipove „gusto“ ili ne?
c) Ponovite podzadatak b) u razvojnoj okolini Visual Studio 2005. Izračunajte razliku između adre-
sa u ovom slučaju? Je li ona ista kao i prethodnom podzadatku? Što vrijedi za elemente poretka i
poredak u cjelini? Izvršite promjenu varijabli iX1 te iX2 , te tip poretka iX u short int kao i go-
re. Je li se promijenio rezervirani prostor za varijabli. Izvedite zaključak: pakira li ovaj prevodilac
navedene tipove pojedinih varijabli „gusto“ ili ne? A što vrijedi za poretke? Izvedite zaključke i
usporedite ih s diskusijom o rezervaciji mjesta za varijable i poretke u Visual Studiu 2005 u udž-
beniku [1].

Zadatak 7.3 Deklaracija i inicijalizacija kazaljki. Aritmetika s pokazivačkim tipom.


a) Proanalizirajte sljedeći programski odsječak i odgonetnite što će se ispisati. Razlučite što od ispisa
možemo predvidjeti, a što je u načelu teško ili čak nemoguće znati bez poznavanja mnogih dodat-
nih detalja? Hoće li biti sintaktičkih grešaka u dijelu A programskog koda?
b) *Hoće li biti grešaka u dijelu B? Ako da otklonite ih. Razmotrite što je ispisano odnavođenjem
kazaljke pI1 s pomoću operatora * ? Jeste li to očekivali? Što zaključujete o kazaljkama kao ad-
resama? Smije li se kazaljci pridruživati adresa drugog tipa (naravno, osim ako programer dobro
zna što radi)?
c) *Napomena. Kao što proizlazi iz zaključaka prethodne vježbe, kompilatori ne rezerviraju mjesta
za varijable na jednak način. kompajler koji rabimo svim varijablama duljine 4B ili manje pridje-
ljuje po 4B, ili čak i više. Prilikom rezervacije mjesta inicijalizira sve rezervirane bajtove na vri-
jednost CCh (vidjeti primjere u poglavlju 3). U dijelu koda C smo uveli kazaljku pC tipa char, i
tri više značajna bajta (koji su na većim adresama, prema uređaju ”Little Endian Byte Ordering”)
koji su nakon inicijalizacije c1 = '@' ostali na vrijednosti CCh smo postavili na nulu. Rezultat
ispisa će sada biti kao što očekujemo. Odgovorite za koliko se poveća adresa sadržana u pC prili-
kom inkrementacije ++pC? A za koliko bi se povećala adresa sadržana u pI1? Ako niste sigurni,
provjerite!
int *pI1; // Deklaracija kazaljke na tip int
// bez inicijalizacije.
int i1 = 0x40; // Varijabla istog tipa kao i kazaljka
// Ox40 = ?

// A. Definiranje kazaljki:
pI1 = &i1; // Kazaljka pI1 ima značenje adrese koja pokazuje
// na tip int – pridružujemo joj vrijednost adrese
// varijable i1 s pomoću operatora & (address-of)

// Ispis A:
cout << " i1 = " << i1 << "\n"
<< " pI1 = " << pI1 << "\n"
<< " *pI1 = " << *pI1 << "\n"

*
Iskoristite kalkulator iz skupa priručnih programa OS Windows: All Programs\ Accessories\Calculator.
Odaberite znanstvenu (engl. Scientific) inačicu kalkulatora i podesite je da radi u heksadekadskom sustavu.
Izvršite oduzimanje pazeći da od većeg broja oduzimate manji. U protivnom ćete dobiti negativan rezultat koji
je prikazan kao potpuni komplement, tj. na istovjetan način kao što bi on bio pohranjen u memoriji računala.
80
<< " *&i1 = " << *&i1 << "\n"
<< "&*pI1 = " << &*pI1 << "\n"
<< endl;

// *B. Nova lokalna varijabla:


char c1 = '@'; // Varijabla različitog tipa od pI1
// ASCII(@) = 40h

// Smije li kazaljka pokazivati na drugi tip?


pI1 = &c1; // Što dojavljuje prevodilac?
// Popravite to prisilnim pridjeljivanjem:
// pI1 = (int *) &c1

// Ispis B. Što je problematično?


cout << " char c1 = " << c1 << "\n"
<< "(int) c1 = " << (int) c1 << "\n"
<< " pI1 = " << pI1 << "\n"
<< " *pI1 = " << *pI1 << "\n"
<< endl;

// *C. Nova kazaljka:


char *pC = &c1; // pC = Adress(c1), tip char!

// Objasnite što se događa


// Za koliko se
*(++pC) = 0; *++pC = 0; *++pC = 0;

// Ispis C:
cout << " char c1 = " << c1 << "\n"
<< "(int) c1 = " << (int) c1 << "\n"
<< " *pC = " << (int) *pC << "\n"
<< " pI1 = " << pI1 << "\n"
<< " *pI1 = " << *pI1 << "\n"
<< endl;

Zadatak 7.4 Kazaljke. Aritmetika kazaljki.


Odredite sve vrijednosti varijabli, i odgovorite na pitanja postavljena u komentarima donjeg program-
skog odsječka. Potom provjerite svoje odgovore odgovarajućim ispisom.
int i1, i2, iP*
// 1.
iP = &i1;
i1 = 99;
*iP = 100;
// Ispis 1: i1 = ?, i2 = ?, *iP = ?, kuda pokazuje iP?
// ... ... ...
// 2. Preusmjeravanje kazaljki:
iP = &i2;
*iP = ++i1;
// Ispis 2: i1 = ?, i2 = ?, *iP = ?, kuda pokazuje iP?
// ... ... ...
// 3.
++iP; // Oprez – znamo li što radimo!?
*iP *= *iP; // Je li ovo neizvjesno?
// Ispis 3: i1 = ?, i2 = ?, *iP = ?, kuda pokazuje iP?
// ... ... ...
81

Zadatak 7.5 * NULL i korektne vrijednost kazaljki.


U sljedećem primjeru odredite sve vrijednosti koje se mogu odrediti prije testiranja programa. Posebi-
ce odgovorite na sljedeća pitanja u svezi s odgovarajućim dijelom koda.
a) Ako pokušamo ispisati sadržaj sa adresa na koje pokazuju kazaljke vrijednosti NULL, što će se
desiti? Promotrite upozorenja prevodioca, te otklonite problematičan dio naredbi da možete nasta-
viti s testiranjem programa.
b) Kako su ispisane vrijednosti kazaljki, u kojem brojevnom sustavu? Kako to da su lokalne varijable
smještene obrnutim redom od onog kojim smo ih deklarirali? Znate li kako se zove podatkovna
struktura kod koje je redoslijed uzimanja obrnut od redoslijeda umetanja? Promotrite na kojim je
adresama rezerviran prostor za varijable tipa int, te short int. Znajući duljine pojedinih tipova,
diskutirajte je li preostalo praznog (neiskorištenog prostora)? Što mislite zašto je prevodilac pojed-
nostavio rezervaciju mjesta za varijable? Bi li to bilo prihvatljivo i za poretke?
c) Do lokalnih varijabli u našem primjeru možemo doći na normalan način navođenjem imena varija-
ble (kao pod a), ali i "odnavođenjem" kazaljki. Osim za vježbu, je li to potrebno raditi?
d) Promotrite navedenu aritmetiku kazaljki i diskutirajte. Može li nevaljala uporaba kazaljki biti uz-
rokom slučajnih, ili čak i namjernih subverzija u programu?
// Varijable:
int i1 = 1, i2 = 2 ;
short int s1 = 1, s2 = 2 ;
// Kazaljke na "ništavnu" vrijednost (NULL)
int *pI1 = 0, *pI2 = NULL;
short int *pS1 = 0, *pS2 = 0;
// 0) Ispis vrijednosti kazaljki vrijednosti NULL,
// i sadržaja s tih adresa. Zahtijeva li ovo oprez?
cout << " pI1 = " << pI1 << "\t*pI1 = " << *pI1 << "\n"
<< " pI2 = " << pI2 << "\t*pI2 = " << *pI2 << "\n"
<< " pS1 = " << pS1 << "\t*pS1 = " << *pS1 << "\n"
<< " pS2 = " << pS2 << "\t*pS2 = " << *pS2 <<"\n "
<< endl;
// Konkrente i korisnički korektne vrijednosti kazaljki
pI1 = &i1; pI2 = &i2; // kazaljke na i1 i i2
pS1 = &s1; pS2 = &s2; // kazaljke na s1 i s2
// a) Ispis adresa i sadržaja adresa:
// A(var) = adresa od varijable var
cout << "A(i1) = " << pI1 << "\t i1 = " << i1 << "\n"
<< "A(i2) = " << pI2 << "\t i2 = " << i2 << "\n"
<< "A(s1) = " << pS1 << "\t s1 = " << s1 << "\n"
<< "A(s2) = " << pS2 << "\t s2 = " << s2 << "\n"
<< endl;
// b) Ispis kazaljki i dereferenciranih kazaljki:
cout << " pI1 = " << pI1 << "\t*pI1 = " << *pI1 << "\n"
<< " pI1 = " << pI2 << "\t*pI2 = " << *pI2 << "\n"
<< " pS1 = " << pS1 << "\t*pS1 = " << *pS1 << "\n"
<< " pS2 = " << pS2 << "\t*pS2 = " << *pS2 <<"\n "
<< endl;
// c) Aritmetika kazaljki (ima li to smisla raditi?):
pI1 -= 1; // Za koliko se smanjila adresa A(pI1)?
pI2 -= 1; // Za koliko se smanjila adresa A(pI2)?
pS1 -= 1; // Za koliko se smanjila adresa A(pS2)?
pS2 += 5; // Za koliko se povećala adresa A(pS2)?
// Provjera:
82
cout << " pI1 = " << pI1 << "\t*pI1 = " << *pI1 << "\n"
<< " pI2 = " << pI2 << "\t*pI2 = " << *pI2 << "\n"
<< " pS1 = " << pS1 << "\t*pS1 = " << *pS1 << "\n"
<< " pS2 = " << pS2 << "\t*pS2 = " << *pS2 <<"\n "
<< endl;

Zadatak 7.6 Kazaljke i poredci. Ime poretka kao kazaljka.


a) U sljedećem primjeru odgonetnite na koje elemente poretka pokazuju kazaljke, odgovorite na pita-
nja postavljena u komentarima, te predvidite ispise programa za programske odsječke A, B i C.
b) Otklonite sintaktičke greške te izvršite testiranje.
const short int cN = 5;
short int sArr[cN] = {0, 1, 2, 3, 4}; // 1-dim poredak veličine 5
short int *pS1, *pS2; // Pokazivači na short int
cout << "\n1-DIM POREDAK: short int sArr[" << cN << "]\n\n"
<< "Adresa 0-tog el. = &sArr[0] = sArr = " << sArr << "\n\n\n"
<< " ADRESA A"
<< "\t\tSADRŽAJ od A\n"
<< "===================================================\n"
<< endl;
// A.
pS1 = &sArr[0] ; // Kuda pokazuje pS1?
pS2 = sArr + 1 ; // Kuda pokazuje pS2?
sArr++; // Možemo li promijeniti vrijednost od sArr?

// Ispis A:
cout << "pS1 = sArr = " << pS1 << "\t *pS1 = " << *pS1 << "\n"
<< "pS2 = sArr + 1 = " << pS2 << "\t *pS2 = " << *pS2 << "\n"
<< endl;
// B.
pS1 = sArr; // Kuda pokazuje pS1?
pS2 = sArr + cN – 1 ; // Kuda pokazuje pS2?
// Ispis B:
cout << "pS1 = sArr = " << pS1 << "\t *pS1 = " << *pS1 << "\n"
<< "pS2 = sArr + cN – 1 = " << pS2 << "\t *pS2 = " << *pS2 << "\n"
<< endl;
// C.
pS1 = sArr + cN/2 ; // Kuda pokazuje pS1?
pS2 = sArr + cN/2 + 1; // Kuda pokazuje pS2?
// Ispis C:
cout << "pS1 = sArr + cN/2 = " << pS1 << "\t *pS1 = " << *pS1
<< "\n"
<< "pS2 = sArr + cN/2 + 1 = " << pS2 << "\t *pS2 = " << *pS2
<< "\n"
<< endl;

Zadatak 7.7 Pristup elementima poretka preko kazaljki.


a) U sljedećem primjeru odgonetnite na koje elemente poretka pokazuju kazaljke, odgovorite na pita-
nja postavljena u komentarima, te predvidite ispise programa za programske odsječke A, B i C.
b) Dodatno odgovorite u svezi dijela programa pod B, je li pristup elementima poretka nizanjem na-
redbi u redu? Koju programsku strukturu treba uporabiti za ispis elemenata između proizvoljnog
početnog i konačnog elementa poretka?
c) Provjerite sintaktičku korektnost i izvršite testiranje programa.
83
const short int cN = 10;
// Cjelobrojni poredak:
int iA[cN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int * pI = iA; // Uvodimo pokazivač koji pokazuje na početni element
// poretka iA, dakle na iA[0]
cout << "1-DIM POREDAK: int iA[" << cN << "]\n\n"
<< " iA = " << iA << "\n"
<< "======================================================\n"
<< endl;
// A.
cout << "Adresa: iA = " << iA
<< "\t\tSadržaj: *iA = " << *iA << "\n"
<< endl;
// B.
// Pristup k prva dva elementa poretka iA[0], iA[1],
// te zadnjem elementu iA[cN-1] preko kazaljki (pI = iA ):
cout << "Adresa: pI = " << pI
<< "\t\tSadržaj: *pI = " << *pI << "\n";
pI++;
cout << "Adresa: pI = " << pI
<< "\t\tSadržaj: *pI = " << *pI << "\n";
<< endl;
pI = iA + cN – 1;
cout << "Adresa: pI = " << pI
<< "\t\tSadržaj: *pI = " << *pI << "\n";
<< endl;
// Je li gornji ispis elemenata nizanjem naredbi u redu?
// Kako ćete to napisati elegantnije i općenitije?

Zadatak 7.8 Pristup elementima poretka preko kazaljki i for petlje.


Zadan je isti poredak kao i u prethodnom primjeru. Pažljivo proučite korištenje for petlje i pokazivača
te odgovorite:
a) Što koristimo umjesto cjelobrojnog brojača kao indeks petlje. Kako smo inicijalizirali taj indeks, tj.
koja mu je početna a koja konačna vrijednost za koju se «tijelo» petlje (tj. blok naredbi petlje)
izvršava?
b) Koja je vrijednost «indeksa» petlje po izlasku iz nje? Zapazite da u općenitom slučaju valjana vri-
jednost pokazivača!
c) Smijemo li ipak iskoristiti tu vrijednost za izračun broja elemenata u poretku i raspona njegovih
adresa, ili treba štogod modificirati?
d) Uočite što vraća operator sizeof primijenjen na ime poretka.
const short int cN = 10;
// Cjelobrojni poredak:
int iA[cN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
cout << "1-DIM POREDAK: int iA[" << cN << "]\n\n"
<< " iA = " << iA << "\n"
<< "======================================================"
<< endl;
// A.
// Pristup proizvoljnom broju slijednih elemenata poretka
// preko pokazivača, korištenjem for petlje:
84
for (int *pI = iA ; pI < iA + cN ; pI++)
cout << "Adresa: pI = " << pI
<< "\t\tSadržaj: *pI = " << *pI << "\n";
cout << "======================================================"
<< "\n" << endl;
// B.
// Kuda pokazuje pokazivač pI po izlazu iz petlje?
// Je li to dio našeg poretka? Provjera:
cout << "Vrijednost pokazivača nakon prolaska kroz poredak:" << "\n\n"
<< "Adresa: pI = " << pI
<< "\t\tSadržaj: *pI = " << *pI << "\n"
<< endl;
// C.
// Pokazivač pokazuje na prvo prazno mjesto iza poretka!
// => Broj elemenata poretka:
UINT uNel = pI – iA ;
// => Broj bajtova u poretku:
UINT uSizeiA1 = uNel * sizeof *pI; // pI – iA = ?
UINT uSizeiA2 = (UINT) pI – (UINT) iA; // (UINT) pI – (UINT) iA = ?
// Ispis C:
cout << "Broj elemenata u poretku: uNel = pI – iA = "
<< uNel << "\n\n"
<< "Vel. poretka iA preko razl. kazalj. = (pI–iA)* sizeof *pI = "
<< uSizeiA1 << "B\n"
<< "Vel. poretka iA preko razl. adresa = (UINT) pI – (UINT) iA =
" << uSizeiA1 << "B\n"
<< "Vel. poretka iA preko funkcije (oper.) sizeof = sizeof(iA) =
" << sizeof(iA) << "B\n"
<< endl;
///////

Zadatak 7.9 Kazaljke i indeksi. Pohrana varijabli na stogu.


Na korisničkom izvedbenom stogu pohranjene su lokalne varijable. Zatim je definirana kazaljka s
adresom zadnje pohranjene varijable. Odgovorite:
a) Ako je varijabla i7 pohranjena na adresu ABP , na kojim su adresama sve ostale varijable?
b) Provjerite što se ispisuje for petljom. Vrijedi li jednakost pI[i] == *(pI + i)?
c) Koju činjenicu možemo ponovo utvrditi o redoslijedu pohrane lokalnih varijabli, te o uobičajenom
redoslijedu pohrane elemenata poretka?
// ... ...
int main() // Pointers and indexation
{
const unsigned short int cN = 8;
// cN integer variables on the local run-time stack:
int i7 = 7, i6 = 6, i5 = 5, i4 = 4;
int i3 = 3, i2 = 2, i1 = 1, i0 = 0;
int* pI = &i0;
cout << "// Variables on the run-time stack \n"
<< "//(arranged from lower to higher addresses):\n\n"
<< "int i7 = 7, i6 = 6, i5 = 5, i4 = 4 ;\n"
<< "int i3 = 3, i2 = 2, i1 = 1, i0 = 0 ;\n\n"
<< "int* pI = &i0; \n\n"
<< "Pointers and indices:\n"
<< "=============================================\n";
85
// Validation: pI[i] == *(pI + i) ??
for (UINT i = 0; i < cN; i++)
cout << "pI[" << i << "] = " << pI[i]
<< "\t*(pI + " << i << ") = " << *(pI + i) << "\n";

cout << "=============================================\n"


<< endl;
return 0;
}

Primjer 7.2 Dinamička kreacija poretka operatorom new.


Potrebno je kreirati poredak tipa int dinamički, uporabom operatora new. Veličinu poretka unosi ko-
risnik sa tastature. Program dojavljuje slučaj kad je dodjela memorije neuspješna, te ispisuje indeks,
adresu i vrijednost prvog i posljednjeg elementa poretka. Prije završetka programskog odsječka oba-
vezno izmjestite poredak operatorom delete.
// Dinamička kreacija poretka
UINT uN;
char c;
do
{
cout << "\n1-dim poredak iA kreiran dinamicki\n";
do
{
cout << "\nUnesite dimenziju n > 0, n = ";
cin >> uN;
} while(uN == 0);
cout << endl;
int *piA = new int[uN];
if (piA == NULL)
cout << "Alokacija neuspjela! Premalo slobodne memorije!!!\n";
else
{
UINT uI = 0;
cout << "Indeks\t\tAdresa el.\t\tVrijednost el. \n"
<< "======================================================\n";
cout << uI << "\t\t" << piA << "\t\t" << *piA << "\n";
uI = uN – 1;
cout << uI << "\t\t" << piA + uI << "\t\t" << *(piA + uI) << "\n"
<< endl;
}
cout << " \nPonovo? (d/n): ";
cin >> c;
// Obavezna dealokacija svega kreiranog s new:
delete [] piA;
}while (c != 'n');

Zadatak 7.10 uz Primjer 7.2


a) Objasnite redom sve tvrdnje u gornjem primjeru. Diskutirajte što i kako program radi.
b) Prilikom testiranja programa ustanovite koliko memorije stoji na raspolaganju na memorijskoj hr-
pi, unašanjem velikih brojeva za dimenziju poretka (npr. 106, 107, 108, 109 ).
86

Zadatak 7.11 Curenje memorije.


Istražite kako se ponaša računalo prilikom curenja memorije. U prethodnom zadatku uklonite naredbu
delete prevađajući je u komentar. Zatim nekoliko puta uzastopce unašajte najveće dimenzije poreda-
ka koji su se u primjeru 7.8 normalno alocirali. Što primjećujete? Što se događa s računalom? Kako
se ponašaju ostali programi? Što morate učiniti da se rad računala normalizira?

Primjer 7.3 Navodnički tip.


U sljedećem programskom odsječku deklariran je navodnički tip podataka.
int i1 = 10, i2 = 20;
// Navodnički tip (The Reference Type)
// Obavezna inicijalizacija pri objavi:
int& rI = i1; // Što prevodilac bilježi na mjestu navoda rI?
// Što se "sintaktički" podrazumijeva pisanjem rI?
// rI = ?
// Ispis A:
cout << "Ispis nakon: int i1 = 10, i1 = 20; int& rI = i1;\n"
<< "===================================================\n"
<< "i1 = " << i1 << "\t\ti2 = " << i2 << "\t\t rI = " << rI << "\n"
<< endl;
rI = i2; // Što se mijenja – adresa pridijeljena navodu rI ili
// sadržaj na toj adresi?
// rI = ?, i1 = ?, i2 = ?
// Ispis B:
cout << "Ispis nakon: rI = i2;\n"
<< "===================================================\n"
<< "i1 = " << i1 << "\t\ti2 = " << i2 << "\t\t rI = " << rI << "\n"
<< endl;
//////////////////////

Zadatak 7.12 uz Primjer 7.3


Odgonetnite vrijednosti svih varijabli u gornjem primjeru, odgovorite na pitanja postavljena u komen-
tarima, te predvidite ispis.

Zadatak 7.13 *Specifičnosti navodničkog tipa.


U ovom primjeru, koji se nastavlja na prethodni, pobliže promatramo sintaktičke osobitosti navodnič-
kog tipa i njegov način pohrane u memoriji. Prve tri varijable objavljene su i začete kao i gore. Kao
što je rečeno ranije u ovom poglavlju, sve lokalne varijable smještaju se na korisnički izvedbeni stog
(vidi odjeljak o programskog modelu memorije i o smještaju lokalnih varijabli, te Primjer 7.11). U
našem primjeru, najprije je na stog stavljena cjelobrojna varijabla i1. Neka to bude na adresi AS . Za-
tim je na adresu AS – 4 stavljena varijabla i2, a poslije nje na adresu AS – 8 dolazi referenca rI.
Nakon toga smo definirali još četiri varijable pokazivačkog tipa, koje se po istom načelu smještaju na
lokalni stog. Kazaljka prI je definirana kao prI = &rI, što bismo uobičajeno čitali kao «adresa od
rI». Međutim, važno je primijetiti da prevodilac u prI neće pohraniti adresu na kojoj je smještena
referenca rI, kao što bismo mogli očekivati, već će u duhu sintaktičke posebnosti navodničkog tipa
kazaljci prI pridružiti adresu koja je smještena u rI. Stoga da dobijemo adresu od rI, poznavajući
smještaj lokalnih varijabli na stogu, uvodimo kazaljku prA koja sadrži adresu za 4 manju od pI1. Na
tako dobivenoj adresi se zaista nalazi navod rI. Ukoliko ste razumjeli prije izneseno gradivo ove vje-
žbe, sada ćete lako odgovoriti na sljedeća pitanja vezana uz pojedine dijelove programskog koda.
87

a) Objasnite sve vrijednosti ispisanih kazaljki. Skicirajte lokalni stog, odredite kolika je vrijednost
adrese AS prve i adresa ostalih varijabli u konkretnom slučaju, te smjestite varijable. Na kojoj je
adresi smješten navod rI? Što je upisano na toj adresi (za ispis sadržaja uporabljen je izlazni «ma-
nipulator» hex koji sav naknadni ispis mijenja u heksadekadsku formu, vidi pogl. 3).
Napomena: zaključke možete provjeriti i pokretanjem ispravljača (engl. “debugger”), uz prethod-
nu postavku stojnih točaka (engl. break point), te unutar izbornika pogleda (view) odabirom is-
pravljačkog prozora (debug window) kao zbirnog obratnika (disassembly).
b) Što se zaista promijenilo nakon pridruživanja rI = i2? Je li došlo do promjena sadržaja na adresi
na kojoj je pohranjena referenca rI? Kako to da se promijenila vrijednost od i1? Objasnite detalj-
no što se događa.
int i1 = 10, i2 = 20; // Lokalne varijable i1, i2, duljine 4B.
// A.
// Navodnički tip (reference type)
int& rI = i1; // Lokalna varijabla rI, tipa “int ref”.
int *pI1 = &i1, *pI2 = &i2; // Kazaljke na i1 i i2 respektivno.
int *prI = &rI; // Kazaljka prI pokazuje na što?
int *prA = pI2 - 1 ; // Kazaljka prA pokazuje na što?
// Ispis A:
cout << "a: int i1 = " << i1 << ", i2 = " << i2 << "; int& rI = i1;\n"
<< " int *pI1 = &i1, *pI2 = &i2; int* prI = &rI;\n"
<< " int* prA = pI2 – 1 ;\n"
<< "========================================================\n"
<< "i1 = " << i1 << "\t\ti2 = " << i2 << "\t\t rI = " << rI << "\n\n"
<< "pI1 = " << pI1 << "\n"
<< "pI2 = " << pI2 << "\n"
<< "prI = " << prI << "\n" // prI = ???
<< "prA = " << prA << "\n" // prA = ???
<< "*prA = " << hex << *prA << dec << "\n" // *prA = ???
<< endl;
// B.
rI = i2; // rI = ?, i1 = ?, i2 = ?
// Ispis B:
cout << "b: rI = i2;\n"
<< "========================================================\n"
<< "i1 = " << i1 << "\t\ti2 = " << i2 << "\t\t rI = " << rI << "\n\n"
<< "pI1 = " << pI1 << "\n"
<< "pI2 = " << pI2 << "\n"
<< "prI = " << prI << "\n" // prI = ???
<< "prA = " << prA << "\n" // prA = ???
<< "*prA = " << hex << *prA << dec << "\n" // *prA = ???
<< endl;
//////////////////////
88

Vježba 8. C (C++) funkcije


Sve „zasebne programske cjeline“ mogu se elegantno svesti na funkcije (engl. functions). Tako se
programiranje u jeziku C/C++ organizira unutar funkcija, pa govorimo o funkcijskom programira-
nju. I glavni program je organiziran kao funkcija, ali posebnog i jedinstvenog imena main(). Razlog
za takav pristup leži u činjenici da ne postoji suštinska razlika između pozivnog programa A (onog iz
kojeg je izvršen poziv programa B), i pozvanog programa B (onog kojeg je program A pozvao), osim
u možebitnom prvenstvu izvršavanja. Posebice je to očito kod rekurzivnih poziva, gdje «potprog-
ram», odnosno u C / C++ funkcija, poziva samog sebe. Na koncu, i glavnu funkciju main() svakog
C / C++ programa poziva neka funkcija operacijskog sustava, u okviru mehanizma punioca (engl. loa-
der). Njemu je zadaća da učita izvršnu verziju programa u radnu memoriju i potom «prenese kontrolu
izvođenja» s operacijskog sustava na strojni kod dobiven prevođenjem izvorne verzije programa, što
je ekvivalentno pozivu vanjskog potprograma, odnosno C / C++ funkcije.
Stoga se programiranje u jeziku C/C++ ostvaruje unutar jedinstvene programske cjeline —
funkcije, i govorimo o funkcijskom programiranju (engl. functional programming). Po uzoru na ma-
tematičke funkcije, na temelju nekih ulaznih veličina ili argumenata (parametera), određuje se rezul-
tat ili više rezultata djelovanja funkcije. Djelovanje funkcije je ostvareno izvršavanjem tvrdnji odre-
đenih samom funkcijom, što uključuje i pozive drugih ili iste funkcije.

8.1 Teorijska priprema


Proučite poglavlje 8. udžbeničkog teksta [1] o C (C++) funkcijama. U Dnevnik vježbi unesite svoje
zabilješke vezane uz gradivo ove vježbe, te odgovorite na pitanja koja slijede.

8.1.1 C (C++) funkcije


1. Kako su programske cjeline organizirane u drugim programskim jezicima? Po čemu se glavni
program razlikuje od potprograma?
2. Koje su specifičnosti unutarnjeg potprograma, vanjskog potprograma i funkcije u jeziku
FORTRAN. Koja od ovih cjelina je zavisna od glavnog programa, a koja nezavisna? U čemu je
bit funkcije?
3. Koje programske cjeline ima jezik Pascal?
4. Odgovaraju li C (C++) funkcija unutarnjem ili vanjskom potprogramu? Zašto jezik C / C++ nema
drugih programskih cjelina? Kako je organiziran glavni program?

8.2 Primjeri i zadaci


Primjer 8.1 Definicija i poziv funkcije. Funkcija cjelobrojne pozitivne potencije ipow.
Potrebno je ostvariti funkciju pod imenom ipow (od engl. power function = hrv. potencija), koja za
bazu tipa int računa cjelobrojnu n-tu potenciju, gdje je n ≥ 0 tipa unsigned short int. Rezultat mn
neka je standardnog cjelobrojnog tipa (int ) . U glavnoj funkciji programa korisnika se pita za broj i
stupanj (cjelobrojni eksponent) potencije, te ispisuje rezultat. Beskonačna petlja unutar koje se to od-
vija, prekida se pritiskom na Ctrl+Break.
Napomena. U matematici se n-ta potencije baze b smatra funkcijom baze, tj. pišemo pn (b) = bn .
89

Dakle, varijabla je b , a cjelobrojni eksponent n se tu smatra parametrom. Tako npr. govorimo o


drugoj potenciji različitih brojeva b, što daje kvadratnu funkciju. Općenito, govorimo o n-toj po-
tenciji varijable b . Prilikom programske implementacije, prirodno je da i bazu b i eksponent n
tretiramo kao argumente funkcije, što poopćuje gornju matematičku definiciju.
// Potrebna uključenja (#include):
// ... ...
// Funkcija cjelobrojne potencije:
int ipow(int iK, unsigned short int usL)
{
int iPw = 1;
for (unsigned int i = 0; i < usL; i++)
iPw *= iK;
return iPw;
}

int main()
{
const short int cNmax = 128; // Maksimalni eksponent.
short int iN; // Eksponent iN potencije iM^iN.
int iM; // Baza iM potencije iM^iN.
cout << "Racun potencije: m^n; int m, unsigned short int n.\n\n"
<< "(Stop = 'Ctrl+Break')\n"
<< "======================================================\n"
<< endl;

// Beskonačna petlja (zaustavlja se "izvana" s Ctrl+Break)


while(true)
{
cout << "m = "; cin >> iM;
cout << "n = "; cin >> iN;
// Ulazni filtar. Uvjet na eksp. iN : 0 <= iN <= cNmax.
while( (iN < 0) || (iN > cNmax) )
{
cout << "n( >= 0 ) = "; cin >> iN;
};
cout << "\n(" << iM << ")^" << iN << " = " << ipow(iM, iN)
<< "\n================================\n"
<< endl;
}
return 0;
}

Zadatak 8.1 uz Error! Reference source not found.


a) Pokažite u gornjem primjeru gdje je definicija funkcije ipow, a gdje je njezin poziv. Kako bi iz-
gledao njezin prototip.
b) Koliko argumenata ima ova funkcija? Moraju li se formalni i aktualni argumenti slagati po svojem
nazivu? Navedite koja su imena formalnih argumenata, a koja su imena stvarnih argumenata. Po
čemu se moraju slagati formalni i aktualni argumenti?
c) Daje li ova funkcija dobar rezultat za potenciju n = 0? Obrazložite to na temelju poznavanja nači-
na izvršavanja for petlje, a zatim i provjerite izvođenjem glavnog programa. Daje li ova funkcija
dobar rezultat za 00 ? Najprije se prisjetite koliki bi taj rezultat trebao biti! Testirajte funkciju za
negativne brojeve. Sumarno: izvršite testiranje na papiru za sljedeće potencije: 20, 23, (−2)3, (−2)4
90

34, (−10)5. Potrebno je proći kroz sve tvrdnje funkcije ipow bilježeći sve međurezultate i konačne
rezultate.
d) Potencije u n rastu kao eksponencijalna funkcija, tj. vrlo brzo. Testirajte rezultate za 10n gdje je
n = 7, 8, 9, 10, pa zatim za 2n uz n = 10, 20, 30, 31, 32, … , te za (–2)n za iste vrijednosti od n.
Što primjećujete? Je li ova «jednostavna i elegantna» funkcija ujedno i robusna? Dojavljuje li se
kako pozivnoj funkciji da je rezultat pogrešan? Objasnite.

Zadatak 8.2 Funkcija cjelobrojne potencije pow s proširenim opsegom vrijednosti.


Poboljšajte prethodnu cjelobrojnu funkciju ipow tako da proširite raspon njenih korektnih vrijednos-
ti. Argumenti ove funkcije identični su kao i kod prethodne, (baza tipa int, cjelobrojnu n-ta potenci-
ja, n ≥ 0 tipa unsigned short int ). Rezultat mn neka je sada maksimalnog cjelobrojnog tipa za
računarsku platformu na kojoj radite. Razmislite, ako koristimo unutar istog programa obje funkcije, i
prethodnu ipow i ovu novu, bi li njihova imena smjela biti jednaka? Na temelju prethodnog odgo-
vora opravdajte izbor jednostavnog imena: pow. Glavnu funkciju možete preuzeti iz gornjeg primje-
ra, uz minimalne promjene.
// Skica rješenja.
// Funkcija cjelobrojne potencije proširenog opsega:
long long int pow(int iK, unsigned short int usL)
{
long long int lPw = 1;
// ... ... ...
// ... ... ...
}

Primjer 8.2 Funkcija cjelobrojne potencije dpow uz bazu tipa double.


Potrebno je ostvariti funkciju pod imenom dpow koja za bazu tipa double računa cjelobrojnu poten-
ciju. Stupanj potencije (eksponent) sada može biti i negativan.
double dpow(double dX, short int n)
{
double dPw = 1. ; // Varijabla za pohranu iznosa potencije.
bool bSign = false; // Predznak potencije (eksponenta) '-' = true.
if (n < 0)
{
bSign = true;
n *= -1;
}
for (unsigned i = 0; i < (unsigned short int) n; i++)
dPw *= dX;
if (bSign)
dPw = 1./dPw;
return dPw;
}

Zadatak 8.3 uz Primjer 8.2


a) Detaljno objasnite što i kako radi gornja funkcija u matematičkom obliku. Kojeg je tipa broj koji
potenciramo. Može li on biti negativan? Kojeg je tipa potencija. Može li ona biti negativna?
b) Objasnite što se izvršava izrazom: (unsigned short int) n ? Može li se izostaviti tvrdnja u zagra-
di?
91

c) Na papiru provjerite kako radi gornja funkcija za sljedeće slučajeve stvarnih argumenata:
dpow(1.5, 0), dpow(1.5, -1), dpow(1.5, 2), dpow(1.5, -3), dpow(0.5, 5). Za provjeru izračuna
koristite se kalkulatorom.
d) Objasnite kako je ostvaren izračun negativne potencije? Čemu služi logička varijabla bSign? U
kojem slučaju i zašto se potencija n množi s −1 ?

Zadatak 8.4 uz Primjer 8.2. Poziv i uporaba funkcije dpow.


Napravite glavnu funkciju koja poziva prethodnu funkciju dpow. Korisniku se omogućava da proiz-
voljan broj puta unosi broj x tipa double, cjelobrojni eksponent n proizvoljnog predznaka, i da do-
bije ispisanu potenciju xn . Dodatni zadaci:
a) Podesite točnost izlaznog ispisa s pomoću rukovaoca setprecision(int n) (vidi pogl. 2) na maksi-
malnu vrijednost za tip double.
b) Testirajte funkciju za velike iznose koji se približavaju donjoj i gornjoj granici apsolutnih vrijed-
nosti za tip double.
c) Kakav je ispis u slučaju da se premaši maksimalan, odnosno minimalan broj? Što će se ispisati u
slučaju da je x = 0, a n = – 1, tj. za 0 – 1 ?

Zadatak 8.5 *uz Primjer 8.2. Poziv i uporaba funkcije dpow. Uporaba funkcije scanf.
Proanalizirajte sljedeću glavnu funkciju koja poziva funkciju dpow. Podaci se unašaju preko funkcije
scanf koja omogućuje višestruki formatirani unos, a ispisuju preko funkcije printf koju smo već
susreli u pogl. 2.
a) U izborniku Pomoć potražite detalje o ove dvije funkcije. Naučite osnove o načinu formatiranja
ispisa i unosa. Primijetite da se taj format navodi u početnom C nizu. Na mjestu gdje se navede
znak % bit će redom ispisana (upisana) vrijednost varijable iz liste iza C niza. Broj znakova %
očito ne smije biti veći od broja varijabli (izraza) u listi. Iza znaka % se navode detalji formata,
npr. l za int i double, f za float, zatim slijede pobliže oznake ispisa, kao d za decimalni, o za
oktalni, x i X za heksadekadski ispis, itd.
b) Navedite gdje se u glavnoj funkciji poziva funkcija dpow.
c) Provjerite mnoge odlike formata ove funkcije unošenjem ključnog pojma «Format Specification
Fields” u tražilicu MSDN knjižnice.
d) Ugradite funkciju dpow i donju glavnu funkciju u testni program i provjerite njezin rad.
int main()
{
double dX;
short int n;
cout << "Racun potencije: x^n, doulbe x, short int n, n je el. iz Z\n"
<< "Stop = Ctrl+Break\n"
<< "======================================================\n"
<< endl;
// Beskonačna petlja:
while(true)
{
printf("\nx = ");
scanf("%lf", &dX);
printf("n = ");
scanf("%hd", &n);
printf("\n%le ^%hd = %le\n", dX, n, dpow(dX, n));
92
printf("=====================================\n");
}
return 0;
}

Zadatak 8.6 Binomni koeficijenti (kombinacije).


Napišite program koji izračunava binomne koeficijente, odnosno kombinacije:
⎛n⎞ n! n(n − 1)(n − 2) ... ... (n − k + 1)
⎜⎜ ⎟⎟ = C nk ≡ = .
⎝k ⎠ k!(n − k )! 1 × 2 × ... ... × k

⎛n⎞
Binomni koeficijent ⎜⎜ ⎟⎟ označava k-ti koeficijent (k = 0, 1, 2, … … , n) u razvoju n-te potencije
k ⎝ ⎠
*
binoma :

⎛n⎞ ⎛n⎞ ⎛ n⎞ ⎛n ⎞ 2 n − 2 ⎛ n ⎞ 1 n −1 ⎛ n ⎞ 0 n
(a + b )n = ⎜⎜ ⎟⎟a n b 0 + ⎜⎜ ⎟⎟a n −1b1 + ⎜⎜ ⎟⎟a n − 2 b 2 + ... ... + ⎜⎜ ⎟⎟a b + ⎜⎜ ⎟⎟a b + ⎜⎜ ⎟⎟a b
⎝0⎠ ⎝1 ⎠ ⎝ 2⎠ ⎝ n − 2⎠ ⎝ n − 1⎠ ⎝n⎠
n(n − 1) n − 2 1 n(n − 1) n − 2 2
= a n + na n −1b1 + a b + ... ... + a b + na n −1b1 + b n .
2 2
C nk je ujedno i broj kombinacija k-tog reda od n-elementa, odnosno broj podskupova od k elemena-
6
ta koji se mogu sastaviti od skupa od n elemenata. Tako npr. C 45 predstavlja broj kombinacija «lo-
7
ta 6 od 45», a C 39 «lota 7 od 39». Za binomne koeficijente vrijedi simetrija, tj. C nk = C nn − k , pa je:

⎛n⎞ ⎛n⎞ ⎛n⎞ ⎛n ⎞ ⎛ n ⎞ ⎛ n ⎞ n(n − 2)


⎜⎜ ⎟⎟ = ⎜⎜ ⎟⎟ = 1, ⎜⎜ ⎟⎟ = ⎜⎜ ⎟⎟ = n , ⎜⎜ ⎟⎟ = ⎜⎜ ⎟⎟ = , itd.
⎝0⎠ ⎝n⎠ ⎝1 ⎠ ⎝ n − 1⎠ ⎝ 2⎠ ⎝ n − 2⎠ 2
Primijetimo da je izračun binomnih koeficijenata preko faktorijela (prvi izraz u gornjoj formuli),
numerički vrlo neprikladan. Naime prilikom izračuna faktorijela, posebice n! ( jer je n ≥ k ) ti
međurezultati mogu biti vrlo veliki i premašivati opseg brojeva. S druge strane, pošto se iznos bi-
nomnog koeficijenta dobiva kao rezultat njihovog djeljenja, doći će do kraćenja velikih cijelih brojeva
i rezultati mogu biti bitno manji. Stoga će dobar algoritam za izračun binomnog koeficijenta uvijek
koristiti drugu formulu. Da ilustriramo to primjerima, broj kombinacija igre lota određuju se prema
sljedećim konkretnim formulama:

⎛ 45 ⎞ 45 × 44 × 43 × 42 × 41 × 40
6
C 45 = ⎜⎜ ⎟⎟ = ,
⎝6 ⎠ 1× 2 × 3 × 4 × 5 × 6
⎛ 39 ⎞ 39 × 38 × 37 × 36 × 35 × 34 × 33
C397 = ⎜⎜ ⎟⎟ = .
⎝7 ⎠ 1× 2 × 3 × 4 × 5 × 6 × 7
Program treba pozivati funkciju tipa int pod nazivom binomcoef(), koja računa binomne koefici-
jente tako da se pri računu ostvaruje maksimalno kraćenje. U programu je potrebno ostvariti pregle-
dan unos i kontrolu veličina k i n ( k ≤ n ), te omogućiti korisniku da ponavlja izračun proizvoljan
broj puta. Naputak. Pokušajte ostvariti vlastito rješenje. pažljivo proučite navedeno rješenje funkcije

*
Za detalje, te za obrazloženje kako se binomni koeficijenti za n-tu potenciju elegantno računaju s pomoću Pas-
calovog trokuta konzultirajte matematičku literaturu.
93

koju ćete pozivati iz programa. Odgovorite može li se zbog greške cjelobrojnog dijeljenja desiti da
funkcija vrati pogrešan rezultat? Razmotrite to na jednostavnijim primjerima, a zatim pokušajte izves-
ti opći zaključak.

Primjer 8.3 Prijenos argumenata po vrijednosti i po navodu.


Potrebno je ostvariti funkciju sort2() koja uređuje dvije varijable tipa int u rastućem (nepadajućem)
nizu.
a) Promotrimo najprije sljedeću funkciju s pozivom po vrijednosti:
// a) Call by Value:
void sort2(int i1, int i2)
{
int iTmp; // Temporary variable
if (i1 > i2) // Swap i1 i i2!
{
iTmp = i1;
i1 = i2;
i2 = iTmp;
}
/* cout << "Ispis unutar funkcije sort2(), ‘call by value’:\n"
<< "i1 = " << i1 << "\ti2 = " << i2 << "\n"
<< endl;
*/
}
Neka je funkcija pozvana iz sljedećeg odsječka programa:
// ... ...
int iA = 2, iB = 1;
sort2(iA, iB);
cout << "Ispis iz pozivnog programa:\n"
<< "iA = " << iA << "\tiB = " << iB << "\n"
<< endl;
b) Očito je da prijenosom po vrijednosti ne možemo utjecati na varijable pozivnog programa. Stoga
funkciju preuredimo da prima argumente po navodu:
// b) Call by Reference:
void sort2(int& i1, int& i2)
{
int iTmp; // Temporary variable
if (i1 > i2) // Swap i1 i i2!
{
iTmp = i1;
i1 = i2;
i2 = iTmp;
}
}

// ... ...
// Poziv funkcije je oblika:
sort2(iA, iB);

c) Potrebno je ostvarite istu funkcionalnost kao pod (b), ali bez prijenosa po navodu.
// b) Pointer arguments:
94
void sort2(int* pI1, int* pI2);
{
int iTmp; // Temporary variable
if (*pI1 > *pI2) // Swap integers!
{
iTmp = *pI1;
*pI1 = *pI2;
*pI2 = iTmp;
}
}

// ... ...
// Poziv funkcije je oblika:
sort2( &iA, &iB );

Zadatak 8.7 uz Primjer 8.3


a) Programski odsječak a. Testirajte funkciju sort2 iz gornjeg primjera izvođenjem programskog
odsječka a) i odgovorite je li ona izvršila željenu zadaću? Objasnite što se događa? Da se uvjerite
gdje je problem, maknite komentare oko ispisa unutar funkcije, i vidite vrijednosti argumenata i1
i i2 unutar funkcije. Jesu li oni ispravno «sortirani»? Je li se zamjena vrijednosti varijabli i1 i
i2 unutar funkcije ikako odrazila na varijable iA i iB ? Što moramo napraviti da bi vrijedilo iA
<= iB ?
b) Uz programski odsječak b. S pomoću kojeg tipa podataka je ostvaren prijenos argumenata? Kako
se taj prijenos ostvaruje, i što se prenosi pozvanoj funkciji sort2 ? Je li trebalo mijenjati tijelo fun-
kcije u odnosu na prethodno rješenje u a)? Objasnite! Pozovite novu funkciju s pozivom po na-
vodu iz testnog programa i komentirajte rezultate! Ima li potrebe ispisivati rezultate unutar funkci-
je? Ponovite na koji način pozvana funkcija utiče na varijable u pozivnoj funkciji?
c) Uz programski odsječak c. Objasnite kako je ovdje ostvaren prijenos argumenata? Koji su stvarni
argumenti? Usput odgovorite smatraju li se funkcije pod (a), (b) i (c) istim ili različitim? Podsjetie
se, u slučaju da su iste, došlo bi do konflikta imena, odnosno višestruke definicije. Prenesite i ovu
funkciju u testni program i provjerite je. U glavnu funkciju unesite odgovarajuću tvrdnju za njezin
poziv.

Zadatak 8.8 Modificirana funkcija sort2().


a) Unaprijedite gornju funkciju sort2() tako da korisnik može birati način sređivanja u uzlaznom ili
silaznom niz. Odaberite prikladnu varijablu s kojom će korisnik to odabirati. Također, neka je fun-
kcija tipa bool koja vraća vrijednost false ako nije trebala zamjena, odnosno true ako je zam-
jena bila izvršena.
b) Ponovite gornji zadatak i ostvarite funkcije za sređivanje dvije varijable tipova s pomičnom toč-
kom. Jesu li potrebne velike preinake da se to ostvari? Smiju li sve ove funkciji nositi isto ime? Je
li bolje u imenu funkcije naglasiti koji tip varijabli ona sortira, ili je bolje koristi jedno te isto ime?
Gdje se u tom slučaju vidi razlika u tipu argumenata? Objasnite.

Zadatak 8.9 Funkcija sort3().


Iako se sortiranje (sređivanje) proizvoljnog broja podataka vrši općenito njihovom pohranom u struk-
turu poretka (vidi pogl. 8), radi vježbe preradite zad. 3.4 tako da ostvarite funkcije sort3() koja sređu-
je vrijednosti tri varijable za tipove int, float i double, u skladu sa zahtjevima postavljenim u pret-
hodnom zadatku. Konstruirajte glavnu funkciju iz koje se vrši unos varijabli, poziva funkcija i potom
ispisuju varijable sređene po iznosu.
95

Zadatak 8.10 Unaprijeđena funkcija pow s kontrolom ispravnosti rezultata.


Potrebno je unaprijediti funkciju pow za cjelobrojnu potenciju iz zadatka 8.2xx tako da ona preko
zastavice iFlag = ±1 dojavljuje da je došlo do prekoračenja opsega brojeva. Ukoliko je rezultat u
redu zastavica ostaje na vrijednosti 0. Ukoliko je došlo do prekoračenja, tj. ukoliko je rezultat izvan
opsega danog tipa, funkcija vraća maksimalni (pozitivni) cijeli broj ako je rezultat trebao biti poziti-
van i postavlja zastavicu iFlag = 1, odnosno minimalni (negativni) broj ako je rezultat trebao biti
negativan i zastavicu postavlja na iFlag = –1. Promotrite donje rješenje te:
a) Objasnite kako se prenašaju pojedini argumenti funkcije. Smijemo li istovremeno koristiti staru
inačicu funkcije s dva argumenta, i novu inačicu s tri, pod istim imenom pow?
b) Objasnite detaljno kako je ostvarena kontrola točnosti rezultata, tj. kako je ustanovljeno je li došlo
do prekoračenja opsega cijelih brojeva. Ako je došlo do prekoračenja, kako je ustanovljen točan
predznak rezultata, iako ovaj, očito ne može biti izračunat. Razmislite je li «računarski skupo» ovo
rješenje (obratite pažnju na broj i vrstu operacija koje se stalno ponavljaju) u usporedbi s rješenjem
bez kontrole rezultata?
c) Napravite glavnu funkciju koja će unositi broj i cjelobrojni eksponent te pozivati funkciju pow
proizvoljan broj puta prema želji korisnika. U slučaju pogrešnog rezultata program će ispisivati da
je došlo do greške, odnosno da je rezultat konkretno veći, odnosno manji od ispisanog broja, već
prema predznaku rezultata. Npr. za slučaj potencije (–13)9 ispis mora biti:
ERROR! n^m = (-13)^9 < -2147483648 ,
a za (13)9 :
ERROR! n^m = (13)^9 > 2147483648 .

// Funkcija pow() sa zastavicom ispravnosti rezultata


long long int pow(int iX, unsigned short int n, int& iFlag)
{
const int iMin = -2147483647 – 1, iMax = 2147483647;
iFlag = 0;
long long int lPw = 1;
long long int lPwOld = lPw;
for (UINT i = 0; i < n; i++)
{
lPw *= iX ;
if (lPw / iX == lPwOld)
lPwOld = lPw;
else
{
if (iX < 0 && (n/2)*2 < n)
{
iFlag = -1;
lPw = iMin;
}
else
{
iFlag = 1;
lPw = iMax;
}
break;
}
}
return lPw;
96

Primjer 8.4 Prijenos poredaka po navodu. Funkcija meanValue().


Potrebno je napisati funkciju tipa float koja vraća srednju vrijednost niza od n brojeva istog tipa
(vidi rješenje).
float meanValue(float fX[], unsigned int n)
{
float fS = 0.f;
for(float *pF = fX; pF < fX + n ; pF++)
fS += *pF;
return fS / n;
}

Zadatak 8.11 uz Primjer 8.4


a) Napišite glavnu funkciju u kojoj ćete pozvati gornju funkciju za izračun srednje
vrijednosti. Kako ćete ostvariti poziv, i koji će biti stvarni argumenti?
b) Ponovite zadatke iz prethodnih poglavlja u kojima se određivala srednja vrijednost
uporabom gornje funkcije.

Zadatak 8.12 Funkcija standDev().


Na sličan način kao u prethodnom primjeru ostvarite funkciju standardne devijacije pod imenom.
standDev(), pazeći da se prilikom izračuna ne ponavlja već odrađeni izračun. Ponovite gornje pod-
zadatke.

Zadatak 8.13 *Prijenos poredaka po navodu preko navodničkog tipa.


Da provjerite jeste li u potpunosti razumjeli pokazivački i navodnički tip, te mehanizam prijenosa ar-
gumenata funkcija, razmotrite kako je pozvan poredak u ovom primjeru. Iako su prije prikazani načini
poziva poredaka jednostavniji, razumijevanje donjeg koda je dobra vježba.
a) Kako je prenesen formalni argument s1, a kako n?
b) Prilikom pridruživanja int* pS = &s1 koja je adresa pridružena kazaljci pS? Ona na kojoj je poh-
ranjena referenca s1 ili ona na koju se s1 odnosi?
c) Preinačite funkciju i njezin poziv tako da se poredak poziva na prethodna dva načina, tj. i) navo-
đenjem imena i praznih uglatih zagrada, te ii) preko kazaljki. Usporedite!
#include <iostream>
#include <windows>
using namespace std;
void strangeArrayCallByRef(short int& s1, unsigned short int n)
{
short int* pS = &s1; // Kuda pokazuje pS?
for (UINT i = 0; i < n; i++)
if (i < 0x8 || i > 0xf7)
cout << "S["<< i << "] = " << pS[i] << "\n";
}
int main()
{
const unsigned short int cN = 0x100;
short int sX[cN];
97
// Inicijalizacija elementa sX[i] na vrijednost indeksa i:
for (UINT i = 0; i < cN; i++)
sX[i] = i;

// Poziv funkcije:
strangeArrayCallByRef(sX[0], cN);
short int *pS1, *pS2; // Kazaljke za pohranu adresa.
pS1 = &sX[0]; // Adresa početnog elementa.
pS2 = &sX[cN-1]; // Adresa zadnjeg elementa.
// Raspon adresa za poredak sX[0x100]
cout << "\n"
<< "pS1 = &sX[ 0] = " << pS1 << "\n"
<< "pS2 = &sX[cN-1] = " << pS2 << "\n"
<< endl;
return 0;
}
98

Vježba 9. Znakovni poredci i C-nizovi.


Primjer uporabe C funkcija
Poznavanje načina pohrane i obrada tekstualnih podataka od velike je važnosti. U ovoj vježbi ćemo se
upoznati sa osobitostima znakovnog poretka i C-niza. Usput ćemo ilustrirati primjenu nekih od veli-
kog broja funkcija za rad s C-nizovima iz standardnih C i C++ biblioteka funkcija.

9.1 Teorijska priprema


Kao uvod u vježbu potrebno je ukratko ponoviti gradivo poglavlja 6 (poredci), 8 (funkcije), te proći
poglavlje 9 udžbeničkog teksta [1] koje se odnosi na ovu vježbu. Prilikom pripreme u Dnevnik vjež-
bi unesite potrebne zabilješke i odgovorite na sljedeća pitanja:

9.1.1 Znakovni poredci i C-nizovi


1. Kako se deklariraju znakovni poredci? Ako je deklariran poredak s n elemenata, koliki dio
memorije on zauzima?
2. Ima li suštinske razlike između znakovnih i poredaka drugog tipa? U čemu je jedina razlika?
3. Postoji li strogi propis koji ASCII znakovi i na kojim mjestima se smiju pojavljivati unutar zna-
kovnog poretka?
4. Koja je definicija C-niza? Gdje je C-niz uvijek pohranjen?
5. Je li svaki C-niz sadržan unutar znakovnog poretka? Je li svaki znakovni poredak ujedno i C-
niz? Objasnite!
6. Objasnite koja je uloga znaka NULL kod C nizova. Ako u znakovnom poretku ima više NULL
znakova, kako će biti interpretiran C-niz unutar njega. Što ako nema niti jednog znaka NULL?
7. Provjerite detalje o znaku NULL u tablici ASCII koda. U koju skupinu znakova on spada?
Možemo li ga ispisati na ekranu u sklopu nekog C-niza? Što moramo napraviti da bismo ga ispi-
sali, i kako je on predstavljen na ekranu?
8. Ako je potrebno pohraniti C-niz sa n znakova, kolika je najmanja duljina poretka u koji taj niz
možemo smjestiti? Možemo li uzeti poredak veće duljine? Što će biti s prekobrojnim elementi-
ma?
9. Kako se odmah pri deklaraciji znakovnog poretka može jednostavno definirati C-niz? Je li prak-
tičnije da se pri tom definira broj elemenata, ili ne? Objasnite. Što se događa ako smo odredili
premali broj elemenata? A preveliki?

9.2 Primjeri i zadaci


Primjer 9.1 Deklaracija i inicijalizacija C-nizova.
Pažljivo promotrite sljedeći primjer. Prođite kroz sve linije programskog koda i odgonetnite njihovo
značenje.
// Uobičajena inicijalizacija unutar dvostrukih navodnika:
99
char cStr0[] = "C++ program" ; // sizeof cStr0 = ?
// C niz duljine 11 u poretku duljine 12
char cStr1[5] = "abcd"; // cStr1[4] = ?
char cStr2[5] = "abc"; // cStr2[3] = ?, cStr2[4] = ?
// C niz duljine 3 u poretku duljine 5
char cStr3[5] = "12345"; // ???
// Inicijalizacija kao za poredak (po elementima):
char cStr4[] = {'a', 'b', 'c', 'd', '\0'}; // sizeof cStr0 = ?
char cStr5[5] = {'a', 'b', 'c', 'd', }; // cStr5[4] = ?
char cStr6[5] = {'e', 'f', 'g', }; // cStr6[3] = ?, cStr6[4] = ?
// Je li cArr legalan C niz?
char cArr[5] = {'1', '2', '3', '4', '5'}; // ? ? ?
// Ispis:
cout << "cStr0 = " << cStr0 << "\t sizeof cStr0 = " << sizeof cStr0 << "\n"
<< "cStr1 = " << cStr1 << "\t sizeof cStr1 = " << sizeof cStr1 << "\n"
<< "cStr2 = " << cStr2 << "\t sizeof cStr2 = " << sizeof cStr2 << "\n"
<< "cStr3 = " << cStr3 << "\t sizeof cStr3 = " << sizeof cStr3 << "\n"
<< endl;
cout << "cStr1[3]= " << cStr1[3] << "\t ASCII = " << (int) cStr1[3] << "\n"
<< "cStr1[4]= " << cStr1[4] << "\t ASCII = " << (int) cStr1[4] << "\n"
<< "cStr2[3]= " << cStr2[3] << "\t ASCII = " << (int) cStr2[3] << "\n"
<< "cStr2[4]= " << cStr2[4] << "\t ASCII = " << (int) cStr2[4] << "\n"
<< "cStr3[3]= " << cStr3[3] << "\t ASCII = " << (int) cStr3[3] << "\n"
<< "cStr3[4]= " << cStr3[4] << "\t ASCII = " << (int) cStr3[4] << "\n"
<< endl;
cout << "cStr4 = " << cStr4 << "\t sizeof cStr4 = " << sizeof cStr4 << "\n"
<< "cStr5 = " << cStr5 << "\t sizeof cStr5 = " << sizeof cStr5 << "\n"
<< "cStr6 = " << cStr6 << "\t sizeof cStr6 = " << sizeof cStr6 << "\n"
<< "cArr = " << cArr << "\t sizeof cArr = " << sizeof cArr << "\n"
<< endl;
cout << "cStr5[3]= " << cStr5[3] << "\t ASCII = " << (int)cStr5[3] << "\n"
<< "cStr5[4]= " << cStr5[4] << "\t ASCII = " << (int)cStr5[4] << "\n"
<< "cStr6[3]= " << cStr6[3] << "\t ASCII = " << (int)cStr6[3] << "\n"
<< "cStr6[4]= " << cStr6[3] << "\t ASCII = " << (int)cStr6[4] << "\n"
<< endl;

Zadatak 9.1 uz Primjer 9.1.


a) Obratite pažnju na pitanja u komentarima i pokušajte odgovoriti na njih. Posebice obratite pažnju
na retke s višestrukim upitnicima. Hoće li oni proći kompilaciju? Objasnite svoje odgovore.
b) Umetnite gornji programski odsječak u testni program, po potrebi otklonite greške, provjerite ispis
i usporedite ga sa svojim odgovorima. Podsjetite se što daje operator sizeof, duljinu poretka ili
duljinu C niza? Pogotovo obratite pažnju na to kako je ispisan znakovni poredak cArr.

Zadatak 9.2 Dodatni zadatak uz Primjer 9.1


a) Da utvrdite znanje o standardnim C nizovima, ustanovite koja je duljina svakog od 8 nizova
(cStr0 do cStr6 , i cArr) iz primjera 9.1 uporabom funkcije strlen(). Razlikuje li se duljlina C-
niza od broja elemenata znakovnog poretka?
b) Što je sa znakovnim poretkom cArr ? Jeste li odgonetnuli njegov ispis? Razmislite odakle niz
"efg" na njegovom kraju?
c) S pomoću funkcije strlen() provjerite svoje odgovore. Primjer ispisa koji je potrebno dodati u
testni program dan je u sljedećim linijama programskog koda:
100
// Broj znakova C niza
// Ispis:
cout << "cStr0 = " << cStr0 << "\tstrlen(cStr0) = " << strlen(cStr0)<< "\n"
<< "cStr1 = " << cStr1 << "\tstrlen(cStr1) = " << strlen(cStr1)<< "\n"
<< "cStr2 = " << cStr2 << "\tstrlen(cStr2) = " << strlen(cStr2)<< "\n"
<< "cStr3 = " << cStr3 << "\tstrlen(cStr3) = " << strlen(cStr3)<< "\n"
<< endl;
cout << "cStr0 = " << cStr4 << "\tstrlen(cStr4) = " << strlen(cStr4)<< "\n"
<< "cStr1 = " << cStr5 << "\tstrlen(cStr5) = " << strlen(cStr5)<< "\n"
<< "cStr2 = " << cStr6 << "\tstrlen(cStr6) = " << strlen(cStr6)<< "\n"
<< "cStr3 = " << cArr << "\tstrlen(cArr) = " << strlen(cArr) << "\n"
<< endl;

Primjer 9.2 Unos proizvoljnog niza znakova funkcijom getchar, ispis funkcijom
putchar.
Potrebno je napisati program koji sa tastature učitava jednu liniju znakova u znakovni poredak kao
standardni C-niz uz pomoć funkcija getchar za učitavanje ASCII znaka, te potom ispisuje tu istu
liniju uporabom funkcije putchar za ispis. Standardna linija sadrži maksimalno 80 znakova, što je
jednako standardnom broju znakova jednog retka na konzolnom prikazniku, odnosno na matričnom
printeru. Alternativno, korisnik može okončati liniju i kontrolnim znakom '\n' = new line.
// Prethodna uključenja:
// ... ...
#include <stdio.h>
// Unos teksta preko getchar(), ispis preko putchar(char c):
int main()
{
const unsigned int cN = 80; // Broj znakova u liniji
char c, cL[cN + 1]; // Znakovni poredak za jednu liniju teksta
cout
<< "Unos reda proizvoljnih znakova (za kraj ‘return’ ili ‘enter’):\n"
<< "================================================================"
<< endl;
unsigned int i = 0;
while( ((c = getchar()) != '\n') && (i < cN) )
cL[i++] = c;
cL[i] = '\0';
putchar('\n'); // Jedan red razmaka
cout
<< "Ispis reda teksta, kao C-niza iz znakovnog poretka cLine[81]:\n"
<< "================================================================"
<< endl;
i= 0;
while( (c = cL[i++]) != '\n' ) // Ispis do kraja C-niza(!?!)
putchar(c);
putchar('\n'); // Novi red
putchar('\n'); // Jedan red razmaka
}
101

Zadatak 9.3 uz Primjer 9.2.


a) Prisjetite se --- kako mora biti definirana varijabla da bi se mogla pojaviti u tvrdnji koja određuje
dimenziju statičkog poretka? Smije li se dimenzija poretka definirati aritmetičkim izrazom kao što
je učinjeno dolje: char cLine[cN + 1]? Zašto je za poredak uzeta dimenzija cN + 1, a ne cN?
b) Obratite pažnju na značenje konstante cN te na uvjet u prvoj while petlji. Zašto je nužan drugi
uvjet u prvoj while petlji?
c) Zamijenite while petlje s odgovarajućim for petljama.
d) Testirajte program i uočite pogrešan ispis. Pronađite logičku grešku (engl. bug) koja je tome
uzrok! Što treba promijeniti u uvjetu druge while petlje da bi ona korektno ispisivala standardni
C-niz?
e) Je li nužno da ova funkcija upisuje i ispisuje samo jedan redak teksta, tj. maksimalno 80 znakova?
Promijenite konstantu cN na 100 znakova i upišite točno 100 znakova, tako da redom upisujete
znamenke: 12345678901234567890… Prva nula u nizu označava 10-ti znak, druga nula 20-ti,
itd…

Zadatak 9.4 Dodatni uvjet u petljama za unos i ispis s pomoću getchar i putchar
(Primjer 9.2).
a) U prethodnom programu poopćite uvjet u petljama za unos i ispis znakova tako da se petlja preki-
da i pri nailaženju na znak EOF (od engl. End Of File), ASCII(EOF) = FFh = −1(8bit). U prog-
ramu možete izravno koristiti i navedenu kraticu EOF, ili zamjenske oznake.
b) Podsjetite se na značenje ovog kontrolnog znaka i na njegov zapis u ASCII kodu. Nalazi li se on u
0.-toj ili 1.-voj stranici ASCII koda? Ima li taj znak zasebnu tipku na tastaturi s pomoću koje ga
možemo unijeti i prekinuti unos znakova? Postoji li kombinacija tipki s pomoću koje ga možemo
unijeti? Pokušajte provjeriti eksperimentom. Da biste bili sigurni da ste unijeli upravo znak EOF, u
uvjetu petlje za unos morate iskomentirati dio koji se odnosi na znak za novi red.

Zadatak 9.5 Formulacija unosa i ispisa iz prethodnog zadatka kao funkcija


(uz Zadatak 9.4)
Definirajte vlastite funkcije getlineOfChars i putlineOfChars, obje tipa int, koje će obavljati unos,
odnosno ispis linije znakova kao u prethodnom primjeru. Osim što obavljaju unos, odnosno ispis,
obje funkcije vraćaju broj znakova C-niza koji su unijele, odnosno ispisale. Razmislite koji moraju
biti argumenti tih funkcija, te kako ćete ih prenijeti. Zatim napišite kratak glavni program iz kojeg
ćete ih pozivati i koristiti.

Zadatak 9.6 Znak EOF.


Kako ćete provjeriti da je znak EOF ekvivalentan kodnoj zamjeni s vrijednosti –1 ?
Naputak. Provjerite npr. istinitost logičkog izraza EOF == -1, te EOF == 0xff (FFh = −1 u 8-
bitnoj ili aritmetici modulo 256) i ispišite odgovarajuće poruke. Ili umetnite vrijednost EOF u
varijablu tipa char , te je ispišite kao znak, a potom i kao cijeli broj.

Zadatak 9.7 Unos niza znakova u poredak izravno iz objekta cin.


Prenesite niz znakova izravno iz objekta cin u znakovni niz objavljen kao u sljedećem programskom
odsječku:
const unsigned int cN = 25;
char cArr[cN];
// ... ...
102
cin >> cArr;
Npr. upišite rečenicu ”Riječi,riječibezrazmaka. Riječi sa razmacima.” Zatim ispišite cArr preko
cout i odgovorite:
a) Što je upisano u znakovni niz cArr? Kako ćete to provjeriti?
b) Kako je okončan taj C-niz? Koja je vrijednost elementa cArr[cN-1]? Tko ili što je obavilo takvo
okončanje, tj. umetanje odgovarajuće vrijednosti?
c) Promijenite vrijednost zadnjeg elementa u EOF: cArr[cN-1] = -1 ; Je li sada cArr valjani C-
niz? Ispišite ga i objasnite ispis.
d) Izvedite zaključak: je li izravnim kopiranjem iz objekta cin moguće ostvariti unos proizvoljnog
teksta u znakovni poredak?

Primjer 9.3 Funkcija get() bez argumenata.


Zadatak je primijeniti funkciju get() bez argumenata za unos znakova u znakovni poredak, te
ostvariti valjani C-niza s odgovarajućim okončanjem.
// ... ...
const unsigned int cN = 80;
char cArr[cN + 1]; // Znakovni poredak za 1 red teksta.
// Unos linije teksta:
cout << "Unesite jedan redak teksta:\n"
<< "===========================\n";
char c;
for(UINT i = 0; (c = cin.get()) != '\n' && i < cN; i++)
cArr[i] = c;
cArr[i] = '\0'; // Okončanje C-niza znakom null.
// Ispis linije teksta:
cout << "\nIspis retka:\n"
<< "===========================\n"
<< cArr << '\n'
<< endl;
// ... ...

Zadatak 9.8 uz Primjer 9.3.


a) Iz teorijskog izlaganja u [1] o tome na koji objekt djeluje funkcija get() zaključite koju zaglavnu
datoteku treba uključiti da se ona razazna, i da se gornji programski odsječak uspješno kompilira?
b) Objasnite detaljno izvršavanje petlje for. Što se događa ako korisnik unese manje ili točno 80
znakova i pritisne tipku VRATI? Je li znak '\n' unesen u znakovni poredak ili nije? Što se događa
ako korisnik unese više od 80 znakova? Što zaključujete, gdje moraju biti pohranjeni znakovi koje
vidimo na ekranu prilikom unosa prije nego što će biti učitani u znakovni poredak?
c) Zamijenite petlju for odgovarajućom petljom while.
d) Modificirajte programski odsječak tako da u svakom C-nizu koji je kraći od 80 znakova ostane
znak novog retka '\n' koji je unio korisnik. Objasnite zašto to nije poželjno za niz koji ima točno
80 znakova. Gdje bi se ispisao redak koji bi uslijedio poslije takvog niza?

Primjer 9.4 Funkcija get() s tri argumenta.


Proučite ovaj programski odsječak i odgovorite na pitanja u sljedećem zadatku.
// ... ...
103
const unsigned int cN = 80; // Konstanta: broj znakova u retku.
char cArr1[cN + 1]; // Znakovni poredak za 1. red teksta.
char cArr2[cN + 1]; // Znakovni poredak za 2. red teksta.
// Unos linije teksta:
cout << "Unesite dva retka teksta:\n"
<< "===========================\n";
cin.get(cArr1, cN + 1, '\n');
// cin.get(); // Čemu služi ova linija koda?
cin.get(cArr2, cN + 1, '\n');
// Ispis teksta:
cout << "\nIspis dva retka:\n"
<< "===========================\n"
<< cArr1 << '\n'
<< cArr2 << '\n'
<< endl;
// ... ...

Zadatak 9.9 uz Primjer 9.4


a) Podsjetite se, je li moguće za dimenziju poretka navesti izraz kao što je cN + 1, gdje je cN
konstanta? Je li to sintaktički korektno?
b) Testirajte izvođenje programskog odsječka kako je ovdje napisan. Pokušajte unijeti dva retka
teksta. Objasnite što se događa. Podsjetite se da funkcija get s tri parametra ostavlja znak novog
retka u ulaznom toku.
c) Maknite komentare ispred retka u kojem se poziva funkcija cin.get(), te ponovo testirajte
program. Je li sada unos dva retka moguć? Objasnite.
d) Promijenite cN na neku malu vrijednost, npr. cN = 10, te testirajte programski odsječak za unos
niza od 10 i više znakova. Objasnite rad obiju funkcija get. Za jednostavnu kontrolu broja
unesenih znakova postupite kao gore (Zadatak 9.3e), tj. upišite niz “12345678901234567890…”,
iz kojeg ćete lako zaključiti koliko je znakova utipkano.

Primjer 9.5 Funkcija getline().


Zadatak iz prethodnog primjera (Primjer 9.4) ovdje se ostvaruje uporabom funkcije getline.
Promotrite kako je to učinjeno te riješite zadatak koji slijedi. Proučite u literaturi koju je zaglavnu
datoteku potrebno uključiti da bi se pronašla i kompilirala ova funkcija.
// ... ...
const unsigned int cN = 80; // Broj znakova u retku.
char cArr1[cN + 1]; // Znakovni poredak za 1. red teksta.
char cArr2[cN + 1]; // Znakovni poredak za 2. red teksta.
// Unos linije teksta:
cout << "Unesite dva retka teksta:\n"
<< "===========================\n";
cin.getline(cArr1, cN + 1, '\n');
cin.getline(cArr2, cN + 1, '\n');
// Ispis teksta:
cout << "\nIspis dva retka teksta:\n"
<< "===========================\n"
<< cArr1 << '\n'
104
<< cArr2 << '\n'
<< endl;
// ... ...

Zadatak 9.10 uz Primjer 9.5.


a) Kako je moguće funkciju objavljenu s tri argumenta pozvati s dva? Radi li se ovdje o grešci? Koja
je vrijednost delimitera u funkciji getline u tom slučaju?
b) Testirajte programski odsječak i odgovorite zašto sada nije potrebno umetnuti poziv cin.get()
između poziva funkcije getline()? Podsjetite se koja je razlika u radu funkcije getline u odnosu
na funkciju get s tri argumenta.
c) Jednako kao i u prethodnom zadatku promijenite cN na neku malu vrijednost, npr. cN = 10, te
testirajte programski odsječak za unos niza od 10 i više znakova.
d) Ponovite podzadatak d iz prethodnog primjera i za ovaj slučaj. Radi li funkcija kao što očekujemo
za unos cN ili više znakova?

Primjer 9.6 Uporaba funkcije getline i strlen.


Potrebno je napisati program koji sa tastature učitava ime i prezime osobe u znakovni poredak
uporabom članske funkcije getline klase istream. Potom je taj C-niz i njegovu duljinu potrebno
ispisati na prikazniku.
#include <iostream>
#include <string>

int main()
{
char cImeIPrez[30]; // Znakovni poredak dovoljne dimenzije
cout << "\nUnesite ime i prezime: ";
cin.getline(cImeIPrez, sizeof cImeIPrez);

cout << "\nUneseno ime i prezime je: " << cImeIPrez


<< "\nDuljina C niza = " << strlen(cImeIPrez) << "znakova.\n"
<< endl;
return 0;
}

Zadatak 9.11 uz Primjer 9.6


a) Modificirajte prethodni program tako da se poredak kreira dinamički uporabom operatora new.
Najprije se korisnika pita kolika je maksimalna duljina imena i prezimena, i potom se kreira
poredak prikladne duljine.
b) Sastavite program za unos imena i prezimena studenata u grupi. Korisnika se najprije pita koliki je
broj studenata, i koja je maksimalna duljina imena i prezimena. Zatim se dinamički stvara 2-dim
znakovni poredak odgovarajuće veličine za pohranu tih tekstualnih podataka. Program zatim
upisuje sva imena navodeći redni broj studenta. Potom se lista studenata ispisujue, također s
prethodećim rednim brojem. Po završetku uklanja se generirani poredak operatorom delete.
105

Primjer 9.7 Poredak C-nizova (2-dim znakovni poredak).


Definirajte dvodimenzionalni poredak znakova i inicijalizirajte ga punim nazivima mjeseci (Siječanj,
Veljača, … … , Prosinac). Zatim ispišite sadržaj tog poretka tako da imena mjeseci budu jedno ispod
drugog. Ako je ispis hrvatskih dijakritičkih znakova nezgrapan, zamijenite ih latinskim slovima.
#include <windows>
int main()
{
char cMjes[12][9] =
{"Siječanj", "Veljača", "Ožujak", "Travanj",
"Svibanj", "Lipanj", "Srpanj", "Kolovoz",
"Rujan", "Listopad", "Studeni", "Prosinac" };
cout << endl;
for(UINT i = 0; i < 12 ; i++)
cout << i + 1 << ". mjesec:\t " << cMjes[i] << "\n";
cout << endl;
return 0;
}

Primjer 9.8 Poredak kazaljki (na znakovni tip).


U prethodnom zadatku drugu dimenziju poretka morali smo podesiti prema najduljem imenu. Elegan-
tnije se to može riješiti uvođenjem poretka kazaljki na tip char. Prevodilac smješta sve C-nizove de-
finirane unutar znakova navodnika "" na odgovarajuće mjesto u memoriji (npr. na izvedbeni stog ako
je poredak deklariran lokalno), i zatim adrese početnih bajtova posprema u poredak kazaljki.
char * pCMjes[12] =
{"Siječanj", "Veljača", "Ožujak", "Travanj",
"Svibanj", "Lipanj", "Srpanj", "Kolovoz",
"Rujan", "Listopad", "Studeni", "Prosinac" };
cout << endl;
for(UINT i = 0; i < 12 ; i++)
cout << i + 1 << ". mjesec:\t " << pCMjes[i] << "\n";
cout << endl;

Zadatak 9.12 uz Primjer 9.8.


a) Pokušajte dereferencirati pokazivač pCMjes[i] u ispisu. Objasnite što ste dobili, i zašto?
b) Objasnite kako to da se navođenjem pCMjes[i] ispisuje C-niz, a ne vrijednost kazaljke?

Primjer 9.9 Poredak C-nizova (prim. 2).


Potrebno je ostvariti program za unos određenog broja znakovnih nizova koji predstavljaju retke teks-
ta. Korisnika se pita za broj redaka koji želi unijeti, uz uvjet da je taj broj manji od neke odabrane
konstante (npr. 10). Retke teksta treba pohraniti u «poredak C-nizova», a zatim ih ispisati. Nakon što
ste proučili program riješite zadatak koji slijedi.
#include <iostream>
int main()
{
const unsigned int cN = 80; // Max. broj znakova u nizu.
const unsigned int cNL = 10; // Broj nizova.
106
// Poredak znakovnih nizova (2-dim poredak znakova):
char cNiz[cNL][cN+1];
unsigned int iN; // Broj nizova.
do
{
cout << "Unos n [n < " << cNL << "] znakovnih nizova, n = ";
cin >> iN;
// cin.get(); // Čemu bi mogla poslužiti ova tvrdnja?
cout << "===================================================\n";
}while(iN > cNL);
// Unos iN C-nizova:
for (UINT i = 0; i < iN; i++)
cin.getline(cNiz[i], cN + 1);
cout << "===================================================\n"
<< endl;
// Ispis iN C-nizova:
cout << "Ispis n = " << iN << " znakovnih nizova:\n"
<< "===================================================\n";
for (i = 0; i < iN ; i++)
cout << cNiz[i] << "\n";
cout << "===================================================\n"
<< endl;
return 0;
}

Zadatak 9.13 uz Primjer 9.9.


a) Kako je ostvaren poredak C-nizova? Kako drugačije možemo okarakterizirati taj isti poredak?
b) Testirajte program i primijetite u čemu je pogreška. Npr. za uneseni broj nizova 2, koliko se nizo-
va upisuje? Pažljivo promotrite (brojeći retke) koliko ih se ispisuje? Ako ne možete odgonetnuti u
čemu je logička greška, potražite rješenje u odgovorima na sljedeća pitanja.
c) Koja funkcija je uporabljena za unos linije teksta? Podsjetite se kako ta funkcija radi?
d) Što je neposredno prije unosa teksta bilo kopirano operatorom >> iz istog «ulaznog» objekta
cin? Je li moguće da taj operator, slično kao i funkcija get, ostavlja u ulaznoj struji neki znak?
Koji bi to znak mogao biti?
e) Maknite komentare ispred poziva funkcije cin.get() i provjerite radi li sada program u redu. Na
koncu obrazložite svoj odgovor u čemu je bila pogreška razmatranjem primjera funkcije getline s
tri argumenta (Primjer 9.4).
107

Literatura
1. R. Logožar, Uvod u programiranje i jezike C/C++, VELV, interno izdanje, dostupno na
http://moodle.velv.hr/moodle/ .
2. B. W. Kernighan, D. M. Ritchie, The C Programming Language, 2nd ed., Upper Saddle River, NJ,
Prentice Hall, 1988.
3. B. Stroustrup: The C++ Programming Language, 3rd ed., Reading, Massachusetts, 1997.
4. C. S. Horstmann, Mastering Object-Oriented Design in C++, John Wiley & Sons, New York,
1995.
5. A. B. Tucker at al. Fundamentals of Computing I & II, C++ Edition, McGraw-Hill, New York,
1995.
6. Motik, Šribar: Demistificrani C++, 2. izdanje Element Zagreb, 2001.
7. L. Budin, Informatika 1, udžbenik za 1. razred gimnazije, Element d.o.o., Zagreb, 2001.
8. Wikipedia članak: www.wikipedia.org. – članak imena navedenog u tekstu.
9. Microsoft Developers Network (MSDN) Library, http://msdn.microsoft.com/en-us/library/ .

You might also like