Professional Documents
Culture Documents
OPknjigast
OPknjigast
Osnove programiranja
u programskom jeziku C++
1
Sadraj
1. Uvod 4
1.1. Kratki pregled razvoja raunala 4
1.2. Razvoj programskih jezika 8
1.3. Postupak izrade programa 11
1.4. Opis rada u okruenju Dev C++ 22
1.5. Uvod u C++ 25
2. Varijable i konstante 29
2.1. Deklaracija varijabli 31
2.2. Konstante 37
2.3. Primjeri programa s varijablama i konstantama 39
3. Operatori 40
3.1 Operator pridruivanja 40
3.2. Aritmetiki operatori 41
3.3. Kombinirani operatori 42
3.4. Poveanje i smanjenje vrijednosti varijable 42
3.5. Relacijski i logiki operatori 44
3.6.Uvjetni operator (?) 45
3.7. Konverzija podataka 45
3.8.Overflow (prekoraenje vrijednosti) 47
3.9. Zaokruivanje rezultata 48
3.10. Komunikacija preko konzole 49
4. Naredbe za kontrolu toka programa 51
4.1. Naredba if ..else 51
4.2. Naredba (petlja) while 55
4.3. Naredba dowhile 56
4.4. Naredba for 57
4.5. Naredbe break 59
4.6. Naredba continue 60
4.7. Naredba goto 61
4.8. Naredba switch 63
4.9. Generiranje sluajnih brojeva 63
5. Funkcije 68
5.1. Prijenos argumenata po vrijednosti i po referenci 72
5.2. Podrazumijevane (default) vrijednosti argumenata 73
5.3 Prenapregnute funkcije 74
5.4. Jo neka svojstva funkcija 75
5.5. Postupak izrade programa - pseudokod 76
6. Polja (tablice) 84
6.1. Jednodimenzionalna polja 84
6.2. Prijenos polja funkcijama 86
6.3. Program za sortiranje podataka (Buble sort) 87
6.4. Linerano pretraivanje polja 92
6.5. Binarno pretraivanje polja 93
6.2. Dvodimenzionalna (viedimenzionalna) polja 95
2
7. Znakovni nizovi 97
7.1. Primjer uporabe znakovnih nizova za obradu prijavnica 100
8. Pokazivai i reference 107
8.1. Operator adrese 107
8.2 . Operator dereference 110
8.3. Uporaba pokazivaa 111
8.4. Odnos pokazivaa i polja 114
8.5. Dinamiko alociranje memorije (operatori new i delete) 115
9. Ulazno/izlazni tokovi 121
9.1. Standardni razred string 121
9.2. Ulazni i izlazni tokovi 124
10. Koncept objektno orijentiranog programiranja 136
10.1. Nestrukturirano programiranje 137
10.2. Proceduralno (strukturirano) programiranje 138
10.3. Modularno programiranje 140
10.4. Objektno orijentirano programiranje 141
10.5. Razredi 142
10.6. Konstruktori i detruktori 149
10.7.Konstruktor kopije 152
10.8. Nasljeivanje 153
10.9. Polimorfizam 156
11. Predloci 158
3
1. Uvod
Gledajui u povijest, moe se primijetiti da su ljudi oduvijek nastojali olakati svoj rad,
odnosno trudili su se da uz to manja osobnog napora postignu to vee uinke. S tim su
ciljem najprije uzgojili i upregnuli domae ivotinje i koristili njihovu snagu, da bi
nakon toga poeli koristiti i snagu drugih ljudi, robova. Nauili su iskoritavati i prirodne
izvore energije poput rijenog toka za nizvodni prijevoz, snagu vjetra za pokretanje
plovila itd. Kada su stvoreni uvjeti da pojedinci mogu preivjeti bez osobnog fizikog
rada, oni su dobili vie vremena za razmiljanje. Razvile su se nove, intelektualne
djelatnosti iz kojih su nastale umjetnost i znanost. Znanost je s jedne strane irila granice
ljudske spoznaje, pa s time postavljala pred ljude nove i sloenije ciljeve, a s druge strane
je razvijala sredstva, danas bi rekli tehnologiju, koja je olakavala postizane ovih ciljeva.
Navedena je tehnologija bila preteno orijentirana na svladavanje fizikih prepreka, tako
na primjer izum kotaa je omoguio prijevoz tekih predmeta uz mali utroak energije,
katapulti su dobacivali velike gromade na dodat nezamislivu udaljenost, a vodovod je na
primjer, koristio prirodni tok vode i na taj nain nije vie trebalo fiziki prenositi vodu od
njenog izvora do mjesta troenja, itd. Izum strojeva i industrijska revolucija, su ubrzale
taj proces do dotad nesluenih razmjera. Dolo je do velikog porasta broja ljudi koji se
bavi intelektualnim aktivnostima, u odnosu na one koji se bave fizikim radom. Zbog
toga je bilo za oekivati da e se ljudska tenja za prenoenje rada na strojeve, prenijeti i
na podruje intelektualnih aktivnosti. Izum elektronikog raunala predstavlja dosad
najznaajniji korak na tom planu. Iako se iz samog naziva vidi da je osnovna aktivnost
raunala bila raunanje tj. izvoenje nekih matematikih operacija, iz dosadanjeg se
razvoja vidi da raunalo zamjenjuje sve vie rutinskih i ne samo rutinskih intelektualnih
aktivnosti.
Danas se moe utvrditi da je razvoj raunala proao kroz etiri glavne faze:
1. Runa obrada abacus kojeg su koristili ve babilonci 300 godina prije Krista i koji
se u raznim oblicima zadrao skoro do dananjih dana.
2. Mehanika obrada Francuski matematiar i filozof Blaise Pascal (1623-1662)
izradio je 1642. mehaniki stroj za zbrajanje i oduzimanje. Gottfried Wilhelm Von
Leibniz (1646-1716) je pedesetak godina kasnije izradio mehaniki stroj koji je mogao
obavljati sve etiri osnovne raunske operacije.
3. Elektromehanika obrada - iako su se strojevi za mehaniko razvijanje neprekidno
razvijali, novi impuls razvoju raunala dao je izum buene kartice u drugoj polovici 19
stoljea.
4. Elektronika obrada Prvim elektronikim raunalom smatra se ENIAC
(Electronic Numerical Integrator And Computer) koje je izraeno 1946. godine. Bio je
tisuu puta bri od bilo kojeg stroja dotad, a mogao je u jednoj sekundi izvesti 5000
operacija zbrajanja1, 357 mnoenja i 38 dijeljenja. Bio je teak 30 tona i zauzimao
povrinu od 167 etvornih metara.
1
Usporedbe radi dananja osobna raunala mogu izvesti nekoliko desetaka milijuna zbrajanja u sekundi.
4
ENIAC se u slijedeih par godina usavravao i uslijedila je i izrada raunala za
komercijalne svrhe. Uslijedio je brzi razvoj u kojemu je vrijedno istaknuti slijedee
vane dogaaje:
Elektroniko
raunalo
Tipkovnica
Zaslon monitor Magnetni zapis
Mi i inaice
Pisa- tampa Disk
Svjetlosna olovka Plotter -crtalo Disketa
Touch screen Projektor Vrpca
Skener Robotizirani
Digitalni fotoaparat strojevi Optiki zapis
Mikrofon CD ROM
Bar code itai DVD
itai magnetnih
kartica
5
Slika 1.2. Struktura sredinje (centralne) jedinice
U sredinjoj se jedinici izvode programi. Programi kao i podaci koje treba obraditi
privremeno se pohranjuju u memoriji. Programi se sastoje od pojedinanih naredbi
kojima se obrauju pojedini podaci, koji su takoer pohranjeni u pojedinim dijelovima
memorije, koje nazivamo poljima. Ti se podaci prebacuju na druge lokacije u memoriju
ili u aritmetiko- logiku jedinicu gdje se po potrebi usporeuju, zbrajaju ili se nad njima
izvode neke druge aritmetike ili logike operacije. Podaci se obino uitavaju iz neke
ulazne jedinice i nakon to su na njima izvrene odgovarajue operacije, upisuju se na
neku izlaznu jedinicu ili na vanjsku memoriju.
Softver se moe shvatiti kao suelje pomou kojega ovjek komunicira s raunalom.
6
Memoriju raunala je najjednostavnije zamisliti kao sae u kojem svaka elija
predstavlja osnovnu adresibilnu jedinicu- bajt. Jedan bajt se sastoji od 8 binarnih
znakova bitova i moe sadravati 28=256 razliitih znakova2.
Svaki bajt u memoriji ima svoju adresu koja poinje od 0 te se slijedea adresa
poveava za 1. Uobiajeno je da se adrese prikazuju u heksadecimalnom sustavu (s
bazom 16).
0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 1819 1A 1B1C1D1E 1F 20 21 22 23
24 25 26 .
. . . . . . .
U raunalu se sve aktivnosti odvijaju na temelju protoka elektrine struje, koja ima
brzinu svjetlosti tj. 300.000 km/sekundi.
300.000.000 metara
3.000.000.000
daje rezultat 1/10 metra, odnosno svjetlo u jednom ciklusu prevali 10 cm.
2
Postoje i raunala kod kojih jedan bajt nema 8 nego na primjer 6 bitova, ali su rijee u upotrebi.
7
1.2. Razvoj programskih jezika
Softver
Sistemski Korisniki
(Sustavni)
8
Razvoj programskih jezika tekao je usporedno s razvojem elektronikih raunala .
Sve je bilo prikazano u u binarnom kodu, s time da su polja Odakle treba uzeti i Kamo
staviti rezultat predstavljaju adrese nekih polja u memoriji. Broj naredbi strojnog jezika
je ogranien, on ovisi o samom raunalu i danas se kree od 80-tak za RISC (Reduced
Instruction Set Computer) do oko 150 za velika CISC (Complex Instruction Set
Computer) raunala. Treba napomenuti da bez obzira na razvoj raunala i softvera,
strojni je jezik ostao jedini kojeg raunalao neposredno 'razumije'. Meutim s obzirom da
je taj jezik neprikladan za ljude, razvoj je iao prema programskim jezicima koji su bili
blii logici i nainu izraavanja koje koriste ljudi. Usporedno su se razvili programi
prevoditelji (compileri), koji takve naredbe prevode na strojni jezik.
add broj, 4
broj=broj + 4;
9
u memoriji smjestiti program u fazi njegovog izvoenja. Programi se prilikom izvoenja
naime, pune jedan iza drugog redom kako se pozivaju, pa lokacija pojedinog programa u
memoriji ovisi o sluaju. Dakle, program se kod svakog poziva moe puniti na drugu
adresu. Zbog toga polja dobivaju relativnu adresu koja pokazuje poloaj (odmak)
dotinog polja u odnosu na poetak programa. Stvarna adresa pojedinih polja (apsolutna
adresa)dobiva se kao zbroj relativne adrese i adrese punjenja programa, koja je poznata
tek neposredno prije izvoenja programa.
Danas se spominje broj od preko 2500 programskih jezika koji su razvijeni u pedesetak
godina3 .
Kao prvi programski jezik tree generacije uzima se FORTRAN. Njegov je razvoj
zapoeo 1954. ali se kao godina u kojoj je objavljena verzija koja slii dananjoj, uzima
1957. Naziv mu potjee od engleskog 'FORmula TRANslation' iz ega je oito da mu je
namjena bila za znanstveno-tehnike proraune.
Prvi program tree generacije za poslovne primjene bio je COBOL (COmon Business
Oriented Language) koji je objavljen 1959. godine.
10
(Programming Language 1) koji je nastao kao spoj Fortrana i Cobola, pa je bio
univerzalno primjenljiv. Iako je jezik bio univerzalne namjene i koristio se vie od 30
godina, njega nisu prihvatili drugi proizvoai raunala, pa ga je konano istisnuo u
meuvremenu razvijeni jezik C.
Orijentacija na ovjeka
Osim profesionalnim programerima dostupan i krajnjem korisniku
'Izravna' komunikacija s bazama podataka
Izbjegavanje proceduralnih elemenata (ako ih ima, onda moraju biti strukturirani)
Omoguiti interakcijsku komunikaciju ovjeka i stroja
Jednostavni za uenje
11
obliku (ili meu obliku koji se naziva bytecode) u kojem ostaje i u fazi izvoenja
programa.
Ove su mogunosti prikazane na slici 5. Vidljivo je da jezik C++ kao i C i Cobol
spadaju u prevoditelje koji se u fazi izvoenja (RUN) izvode u strojnom jeziku.
Za razliku od njih JAVA i Visual Basic se prevode u tzv. bytecode oblik, dok dBase i
Basic ostaju trajno u izvornom kodu.
12
1.3. Postupak izrade programa
Postupak izrade programa, odvija se kroz nekoliko koraka koji su prikazani na slici 6:
Definiranje problema
Definiranje algoritma
Dokumentiranje
algoritma
Pisanje programa
Testiranje programa
Program
OK?
Ne
Dokumentiranje
programa
Implementiranje
programa
Koritenje i
odravanje
13
ax 2 bx c 0
b b 2 4ac
x1, 2
2a
Ispitati diskriminantu (tj. b 2 4ac ) pa ako je manja od nule, program treba napisati
poruku 'Jednadba nema realnih rjeenja' i zavriti s radom.
Test podaci:
a=1, b=4, c=4 rezultati su: x1= x2=-2
a=1, b=2, c=-3 rezultati su: x1= -3, x2=1
a=0, b=-2, c=6 rezultati su: 'Postoji samo jedan rezultat ex= 3'
a=-1, b=0, c=9 rezultati su: x1= x2=3
a=2, b=1, c=2 rezultati su: 'Jednadba nema realnih rjeenja'
4
est je sluaj da o odravanju programa trajno brine onaj tko ga je isporuio.
14
Neformalni tekstualni opis
Pseudokod koji za opis algoritma koristi obini jezik uz potivanje nekih
ogranienja programskih jezika
Grafiki opisi koje koriste razliite tipove dijagrama.
Primjer1:
U studentskoj referadi se prikupljaju prijavnice o poloenim ispitima studenata.
Svaka prijavnica sadri slijedee podatke: matini broj studenta, ime i prezime,
naziv predmeta, ocjena na ispitu i datum polaganja. Osobe koje rade u studentskoj
referadi su za svaki ispitni rok sortirale prispjele prijavnice po matinom broju
studenata. Sada imaju dvije hrpe prijavnica, jednu kojoene prijavnice iz ljetnog
ispitnog roka i drugu u kojoj su prijavnice iz jesenskog ispitnog roka. Dakle svaka je
hrpa sortirana po matinom broju studenata. Treba izmijeati prijavnice iz te dvije
hrpe u jednu hrpu, tako da i ta nova hrpa bude sortirana po matinom broju studenta.
Navedeni primjer je klasini sluaj spajanja sortiranih datoteka koje se na engleskom
naziva merge.
Na slici 7. prikazana su dva skupa prijavnica (svaki red u tablici predstavlja jednu
prijavnicu) gdje su radi jednostavnosti isputeni ime i prezime studenta a i predmeti
su ifrirani sa P1, P2 itd.
15
Rezultat nakon spajanja te dvije tablice (hrpe) mora biti nova tablica (hrpa), kao to
je prikazano na slici 1.8.
1002 P1 3
1002 P2 4
1003 P1 3
1003 P2 4
1006 P4 2
1006 P3 4
1006 P1 2
1007 P1 5
1008 P3 4
1010 P1 5
1022 P2 3
16
Jedno rjeenje (koje je djelomino ispravno) prikazuje dijagram slici 1.9.
Ulaz
Start
1003 Izlaz
1003
Uzmi 1002
1006 A
A 1002
1008
1003
1010
Uzmi 1003
1022 B
C 1006
1006
NE 1006
DA A<B
1002 ? 1007
1002
B Sloi Sloi 1010
1006 A B
1022
1006
17
Uvjet A<B (1003 nije <od 1002) pa se opet izvodi naredba Sloi B koja (na drugo
mjesto, odnosno prekriva prethodnu prijavnicu u hrpi) stavlja tekuu prijavnicu
uzetu iz hrpe B, dakle opet onu koja nosi MBR jednak 1002.
Nakon toga slijedi naredba Uzmi B koja u hrpi B pronalazi slijedeu prijavnicu koja
nosi MBR jednak 1006 (prve dvije su ve uzete iz hrpe i sloene u hrpu C), te ide
na usporedbu A i B .
Uvjet A <B je sada ispunjen, pa se izvoenje logike nastavlja u drugoj grani.
Slijedi naredba sloi A, dakle na hrpu C se stavlja prijavnica iz hrpe A, to je jo
uvijek ona koja je bila prva uzeta i koja nosi MBR jednak 1003.
Slijedi naredba Uzmi A, koja opet nosi MBR jednak 1003 itd.
Sve e biti u redu do trenutka kad se iz hrpe B uzme zadnja prijavnica, koja nosi
MBR jednak 1007 i kada se ona sloi na hrpu C. (U tom trenutku e tekua
prijavnica iz hrpe A biti ona s MBR 1008 !).
Nakon naredbe Sloi B, nuno slijedi naredba Uzmi B, a hrpa B je u tom trenutku
prazna. ovjek e tada intuitivno uzeti prijavnice iz hrpe A, za koje zna da su ve
sortirane po MBR i jednu po jednu prebaciti na hrpu C.
Raunalo meutim nema intuicije, kada pokua 'uzeti prijavnicu iz hrpe ' a tamo ne
nae nita, dolazi do nenormalnog zavravanja programa koje se programerskom
govoru naziva 'pucanje programa'.
Raunalo nikad ne moe uzimati prijavnice iz 'hrpe' nego iz neke datoteke. Kod
slaganja podataka u datoteku, radi izbjegavanja navedenog problema, na kraju se
postavlja oznaka 'kraj podataka'. Formalni sadraj oznake ovisi od raunala, odnosno
operacijskog sustava ali se prilikom svakog itanja datoteke moe ukljuiti provjera
da li je uitan 'kraj podataka' odnosno engleski 'end of file' ili skraeno EOF.
18
Slika 1.10: Cjelovita logika
slaganja prijavnica START
Uzmi
A
Uzmi
B
DA NE
A<B
Sloi Sloi
A B
Uzmi EO
Uzmi
A F B EO
A FB
EOF EOF
A B
Sloi B Sloi A
Uzmi B Uzmi A
END
EOF B
EOF A
19
Na slici 1.10. prikazano je kompletna logika rjeenja primjera 1. Vidi se da je
problem 'pucanja programa' prilikom uitavanja zadnjeg sloga izbjegnut sa
testiranjem uvjeta EOF koji se obino povezuje crtkanim linijama kako bi se
pokazalo da se ta grana izvodi samo izuzetno, tj. kada je zadovoljen navedeni uvjet.
Potrebno je skrenuti pozornost na jo dva detalja. Prvi detalj je da u grani nazvanoj
EOF B, dakle kada se prije zavrilo s uzimanjem prijavnica iz hrpe B, ponovno moe
desiti (i kad-tad mora se desiti) uvjet EOF A. Kad se taj uvjet dogodi, znai da su
iscrpljene i sve prijavnice iz hrpe A, pa program moe zavriti.
Drugi, ne manje bitan detalj, je da se uvjet EOF A mogao dogoditi i kod itanja (ili
uzimanja prijavnica) u glavnoj grani dijagrama. To bi se uostalom desilo da u
primjeru 1 podaci iz tablica A i B zamjene mjesta. Tada se, meutim ne smije zavriti
program, nego on mora ii na granu EOF A, kada mora zavriti s preslagivanjem
prijavnica iz hrpe B, pa da bi po nastanku uvjeta EOFB opet otiao na kraj programa.
Pitanja za vjebu:
1. Logika programa iz slike 1.10. ipak ima jednu 'rupu' zbog koje bi moglo doi do
pucanja programa. Moete li je identificirati ?
2. Kako bi na temelju rjeenja spajanja dvije hrpe prijavnica, rijeili program
spajanja tri hrpe prijavnica ?
Primjer2: Treba napisati program koji ispisuje redom prim brojeve od 3 do N. Prim ili
prosti brojevi su prirodni brojevi koji su djeljivi samo s 1 i samim sobom. Dakle da bi
utvrdili je li neki broj prim broj treba ga dijeliti redom s 2,3, itd. pa ako nije djeljiv ni s
jednim brojem do njega samog, on je prim broj kojeg treba ispisati.
Kao prvo treba primijetiti da nije potrebno da J poprima sve vrijednosti od 2 do I, jer ako
na primjer I nije djeljiv s nijednim brojem do njegove polovice, nije djeljiv ni s jednim
poslije. Ta logika dodue vrijedi i za drugi korijen od I, to je posebno pokazano u
plavom pravokutniku. SQRT(I) je standardna funkcija koju imaju mnogi programski
jezici meu kojima i C++ koja vraa drugi korijen od I (SQuare RooT).
Zato moemo tvrditi da ako broj K nije djeljiv ni s jednim brojem koji je manji od
njegovog drugog korijena, nije djeljiv ni s jednim drugim brojem osim sa samim sobom ?
Neka je Q drugi korijen od K, onda vrijedi da je K = Q*Q. Neka je K djeljiv i s nekim
drugim brojem, osim sa 1 i samim sobom, na primjer M. Dakle K nije prim broj. Onda
mora postojati i neki drugi broj N takav da vrijedi K=M*N! Ako je M<Q onda je nuno
N>Q i obratno. Dakle ne moe umnoak dva broja koji su oba vea od Q ili oba manja
od Q, biti jednak Q*Q!
20
Slika 1.11. Dijagram za ispisivanje prim brojeva od 3 do N
Start
C++ rjeenje
K=I/J
K=I%J;
NE
J>I/2 NE
B
?
DA
Pii I
A
DA
21
U zelenom pravokutniku je prikazana jedna druga varijanta logike koja se temelji na
injenici da u jeziku C++ postoji poseban operand % (modul) koji kao rezultat daje
ostatak kod dijeljenja dva cijela broja. Na primjer ako je K=11%3; (ita se K
jednako 11 modul 3) rezultat je da K poprima vrijednost 2, ili za K=18%5; rezultat je
K=3.
Osim ovih nunih alata najee se pri programiranju koristi i mnotvo drugih kao to
su:
Da bi se olakalo koritenje tog mnotva alata i ubrzao proces razvoja softvera svi
proizvoai razvojnih alata danas nude jedinstvene razvojne okoline (IDE - Integrated
development environment). Jedinstvene razvojne okoline (IDE) su produkti koji
objedinjavaju sve alate potrebne za razvoj softvera u homogenoj cjelini. Cjelokupan
razvoj programa obavlja se unutar jednog suelja, koje programer moe prilagoditi
22
svojim specifinim potrebama. Osim to su prilagodljivi potrebama korisnika IDE su i
proirivi dodatnim komponentama (koje moe ponuditi proizvoa IDE ili netko drugi).
Obino se IDE nudi u vie verzija (sa istom jezgrom, ali razliitim brojem dodatnih
alata) kako bi se to bolje prilagodili razliitim potrebama korisnika. Te verzije osim to
razliitih mogunosti, imaju i razliite cijene.
Da bi se nauilo programirati nije dovoljno proitati ovu knjigu (niti bilo koju
drugu knjigu), ve je nuno i pisati programe. Da bismo mogli isprobati primjere i
rijeiti zadatke iz ove knjige potrebno je imati neki razvojni alat. Na tritu je vie
kvalitetnih proizvoda razliitih proizvoaa koji mogu posluiti u tu svrhu, i ako imate
bilo koji od njih moete ih iskoristiti. Ako ne posjedujete niti jedan od komercijalnih
proizvoda i niste ih spremni nabaviti postoje naravno i alternativa - besplatni razvojni
alati. Svi primjeri navedeni u ovoj knjizi isprobani su sa dva takva alata:
Dev C++ IDE je vjerojatno prihvatljivije rjeenje jer osim prevoditelja nudi i sve ostale
alate nune za rad u jedinstvenoj cjelini. Vie je razloga zato je ovaj alat pogodan za
poetnika:
Bez obzira odabrali Dev C++ ili neki drugi alat veina primjera bi trebala raditi bez
ikakvih izmjena. Ako nauite bilo koji programski jezik svaki slijedei e vam biti laki, i
ako nauite koritenje bilo kojeg razvojnog alata ovladavanje slijedeim bit e lake.
Rad u Dev-C++
Da bismo mogli raditi u Dev C++ najprije ga moramo upoznati. Na slici je prikazan
uobiajen izgled suelja u Dev C++.
23
A
C B
Na slici su slovima oznaeni razliiti dijelovi suelja. Dio oznaen slovom A slian je kao
i u svim drugim Windows programima. Sastoji se od izbornika sa padajuim
podizbornicima i traka sa alatima. Na izborniku odabiremo onu opciju ili naredbu koju
elimo aktivirati. Opcije su podijeljene u grupe (npr. u grupi "Pomo" nalaze se sve
opcije vezane uz pomo korisniku). Ispod izbornika nalaze se trake sa alatima. U svakoj
traci se nalaze naredbe kojima na ovaj nain moemo pristupiti bre (klikom na gumb)
nego preko izbornika. Ovaj dio suelja se moe prilagoditi pa moemo odabrati koje
alatne trake nam trebaju, a koje ne. Na alatnim trakama se nalaze samo one naredbe koje
se esto koriste.
Najvei dio suelja zauzima editor (ureiva teksta) oznaen je slovom B. U
ovom dijelu korisnik pie program. Pri pisanju koda editor razliite dijelova koda
oznaava razliitom bojom (kljune rijei su u jednoj boji, varijable u drugoj) da bi
kod bio itljiviji. Sa lijeve strane se nalazi i traka sa numeracijom linija. Istovremeno
moe biti otvoreno vie datoteka za editiranje.
Na lijevoj strani zaslona (oznaen slovom C) nalazi se preglednik projekta i klasa. U
ovom dijelu zaslona moemo pregledavati dijelove projekta, klase koje sadri na projekt
ili ispis debugera (ovisno o tome koju karticu smo odabrali).
Dno zaslona zauzima dio u kojem moemo pregledavati razliite poruke IDE-a
preglednik izvjea (oznaen slovom D). Preglednik se sastoji od vie kartica (greke,
resursi, ispis kompajlera, debug i traenje). Ovisno o tome koju karticu odaberemo
24
vidimo odgovarajue izvjee. Ako na primjer elimo provjeriti kako je prolo
prevoenje naeg programa u izvrni kod ukljuimo karticu Ispis kompajlera i
pogledamo izvjee o prevoenju.
#include <iostream>
Use namespace std;
int main ()
{
cout <<''Dobar dan'';
system("PAUSE");
return 0;
}
Kad smo zavrili pisanje naeg koda trebamo ga prevesti na strojni jezik i pokrenuti.
Prevoenje pokreemo ili preko izbornika ili preko gumba na alatnoj traci
(kompajliraj). Kako je proao postupak prevoenja moemo provjeriti u prozoru za
izvjee kompajlera. Ako je pri prevoenju dolo do greaka njih moemo pogledati na
dnu ekrana u pregledniku izvjea (kartica greke). U izvjeu greaka za svaku greku
pie u kojoj se liniji koda nalazi i kratki opis greke. Na osnovu ovog opisa moemo
ispraviti greke u kodu. Kad ispravimo sve greke i prevoenje proe bez njih program je
ispravno preveden i spreman za pokretanje.
Pokretanje programa obavljamo ili preko izbornika ili preko alatne trake odabirom opcije
pokreni. Poto su svi primjeri koji su napisani u ovoj knjizi programi koji se vrte u
prozoru konzole kod pokretanja takvih programa otvori s prozor konzole, program se
izvri i prozor se automatski zatvori im program doe do kraja. To u naem sluaju nije
ba prikladno jer bi na program samo ispisao poruku i prozor bi se odmah zatvorio (ne bi
stigli proitati poruku). Zato se na kraj programa stavlja naredba:
system("PAUSE");
25
Ova naredba zaustavlja izvoenje programa sve dok korisnik ne klikne bilo koju tipku na
tipkovnici. Na taj nain kad pokrenemo program, on ispie pozdravnu poruku i eka
pritisak na bilo koju tipku da zatvori prozor konzole. Ako radite programe koji se vrte u
prozoru konzole mudro je uvijek koristiti ovu naredbu.
26
1.5. Uvod u C++
Programski jezik C++ sadri 60tak kljunih rijei koje su navedene u prilogu B, na kraju
knjige. Kada bi se radilo o ljudskom jeziku, s obzirom na tako mali broj rijei bilo bi ga
jako lako nauiti. Kako se radi o programskom jeziku ono to oteava njegovo uenje
nije broj rijei, ve drugaija logika (koja odgovara raunalu)
Postoje razliite verzije programskog jezika C++ koje se u nekim detaljima mogu
razlikovati. Primjeri iz ovog teksta su raeni s prevoditeljem Bloodshed Dev-C++
4.9.9.2 i/ili s Borland C++ Compiler 5.5.
Primjer 1.1.
1. // Primjer programa u C++
2. /* Ovaj program ispisuje na ekranu
3. Dobar dan */
4. #include <iostream.h>
5. int main ()
6. {
7. cout <<''Dobar dan'';
8. system("PAUSE");
9. return 0;
10. }
27
naredbu using namespace std; koja kae da se koristi standardno nazivlje. Dakle
umjesto #include <iostream.h> , moe se upisati
#include <iostream>
using namespace std;
Za naredbu 5. int main () za sada je dovoljno rei da se na taj nain oznaava toka u
kojoj poinje izvoenje programa. Ova naredba odgovara toki koja se na dijagramu
toka oznaava sa Start. Sadraj cijelog programa se nalazi unutar para vitiastih zagrada
(6. i 10.)
Obine zagrade iza izraza main su dio sintakse (pravila za pisanje) C++ koja vrijedi za
sve funkcije meu koje spada i main. Unutar tih zagrada mogu stavljati neki argumenti,
o emu e biti govora kasnije.
Sve izvrne naredbe u C++ (one koje neto rade) moraju zavravati sa ; (toka zarez).
Primjer 1.2:
1. // Primjer programa u C++
2. /* Ovaj program ispisuje na ekran poetak
3. hrvatske himne */
4. #include <iostream.h>
5. int main()
6. {
7. cout<< "Lijepa naa domovino, "<<endl;
8. cout<< "oj junaka zemljo mila,"<<endl;
28
9. cout<< "stare slave djedovino" <<endl;
10. cout<< "da bi vazda, sretna bila."<<endl;
11. return 0;
12. }
2.Varijable i konstante
U C++ se mogu definirati dva osnovna tipa podataka: varijable i konstante. Konstante
su one veliine koje u tijeku izvoenja programa ne mijenjaju vrijednost, a mogu biti
numerike ili alfanumerike. Numerike konstante se pojavljuju u poznatom obliku kao
npr. 1, -5, 0 (kod runog je pisanja uobiajeno da se nula prekrii kako bi se razlikovala
od slova O). Ako se radi o alfanumerikim konstantama (tj. tekstu), one se kao u
prethodnim primjerima, stavljaju u navodnike.
Dok raunalo izvrava program ono barata sa odreenim podacima (brojevi, slova,
rijei...), sve te podatke i rezultate matematikih operacija treba privremeno spremiti u
memoriju. Varijable su ustvari memorijske lokacije u koje raunalo privremeno
sprema podatke. Da bi programer lake zapamtio u koju lokaciju (varijablu) je
spremio koji podatak, svakoj varijabli (lokaciji) dodijeli naziv. Poto je koliina
memorije u raunalu ograniena, prije izvoenja programa treba rezervirati mjesto za
sve varijable u programu i to se radi pomou deklaracije varijabli. U deklaraciji se C+
navodi ime varijable (koje mora biti jedistveno) i tip varijable (jer je za razliite
+
tipove podataka potrebna razliita koliina memorije). Deklaracija za jedan
cijelobrojni podatak moe izgledati ovako: int a; kad raunalo pri izvoenju programa
doe do ove linije ono rezervira u memoriji mjesto za jedan cijeli broj (integer) i i
adresi te lokacije pridruuje naziv a. Kad se kasnije u tu varijablu (lokaciju) eli
spremiti neki podatak, to se radi pomou znaka jednakosti. Naredba a=5 sprema broj
5 u lokaciju (varijablu) koja se zove a.
29
compiler razlikuje velika i mala slova, pa e na primjer Broj1 i broj1 tretirati kao dvije
razliite varijable.
i nekoliko neispravnih:
30
Slika 2.1. Osnovni tipovi varijabli u C++
2.1.Deklaracija varijabli
31
Cjelobrojne varijable (int, short, long i char) mogu biti s predznakom (signed) ili bez
(unsigned) .
ili
U C++ se deklaracija varijabli moe nalaziti bilo gdje u programu i svaka se varijabla
mora deklarirati. U nekim jezicima postoje konvencije zbog kojih to nije uvijek
potrebno uiniti. Bitno je upamtiti da se varijabla u programu ne smije koristiti prije
nego to je deklarirana, na primjer:
broj =5;
int broj;
Prevoditelj bi u takvom sluaju javio greku, jer u trenutku kada 'vidi' naredbu broj=5; on
jo 'ne zna' kakva je varijabla broj.
Program se moe sastojati od vie zasebnih dijelova, koji su izdvojeni parom vitiastih
zagrada. U naelu, ako je varijabla deklarirana unutar jednog para vitiastih zagrada, ona
se prepoznaje samo unutar tog para vitiastih zagrada, a ne izvan njih.
S tog se stajalita varijable dijele na globalne tj. one ija deklaracija nije unutar
nijednog para vitiastih zagrada, pa im deklaracija vrijedi u cijelom programu i na
lokalne ija deklaracija vrijedi samo unutar para vitiastih zagrada u kojoj se nalazi
njihova deklaracija. Smisao ove konvencije vidi se, izmeu ostalog, kada se jedan veliki
32
program spaja iz manjih dijelova (potprograma) koje su razvijali razliiti programeri.
Svaki programer moe slobodno koristiti nazive lokalnih varijabli bez bojazni da e biti
problema, u sluaju da u nekom drugom dijelu programa postoji lokalna varijabla s
istim nazivom.
Logike varijable ili u C++ notaciji bool su varijable koje mogu poprimiti samo dvije
vrijednosti 0 ili 1, Pri tome se 0 odnosi na neistinu (false), a 1 na istinu ( true).
C++ omoguava i da korisnik definira vlastite tipove podataka o emu e biti jo puno
govora kasnije. Zasad se spominje samo vrlo jednostavan tip pobrojenih varijabli
(enumerated) koji se definiraju s kljunom rijei enum.
ili
33
Primjer 2.1:
1. // primjer koritenja enumerated varijabli
2. #include <iostream.h>
3. enum dani {ponedjeljak, utorak, srijeda, cetvrtak, petak, subota, nedjelja};
4. int main() { Izlaz je :
5. dani d1, d2;
6. d1= utorak; Danas je 1 7
7. cout<< " Danas je "<<d1<<endl; Sutra je 2 9
8. d2 = srijeda; Press any key to continue . . .
9. cout<< " Sutra je "<<d2<<endl;
10. system("PAUSE");
11. return 0;
12. }
Da je grekom umjesto d2 = srijeda; upisano d2 = sijeda; ili bilo koji drugi pojam koji
nije naveden prilikom deklaracije enum varijable, prevoditelj bi javio greku.
U primjeru 2.1 prvi je put ispisana jedna varijabla. Vidi se da se ona ispisuje gotovo na
isti nain kao i konstanta s time da se ne navodi u navodnicima. Vidi se isto tako da se
jedna naredba cout moe koristiti za ispisivanje vie polja, s time da se za svako novo
polje navodi znak <<. Drugim rijeima, na primjer naredba:
34
Varijable koje se najee koriste su brojevi i slova, odnosno znakovi. Varijable koje
sadre brojeve zovu se numerike varijable. Za njih je bitno naglasiti da postoji
nekoliko tipova cjelobrojnih varijabli i nekoliko tipova varijabli s decimalnim brojevima.
Cijeli brojevi (integer), kako im sam naziv govori, su brojevi bez decimala . Decimalni
brojevi su u C++ brojevi s kliznim zarezom (floating point, s obzirom da Amerikanci
imaju decimalnu toku). Naziv klizni zarez je zbog toga to se brojevi pamte u
eksponencijalnom obliku, za razliku od fiksnog zareza na kojeg smo navikli u
svakodnevnom pisanju. Razlika izmeu prikaza broja u fiksnom i kliznom zarezu vidi se
iz slijedeih primjera:
U eksponencijalnom obliku, kao na primjer 972*10 -1, broj se sastoji od tri dijela: 972
naziva se mantisa, 10 je baza, a -1 eksponent. S obzirom da se podrazumijeva da je
baza uvijek 10, ona se ne pamti. Pamte se samo mantisa i eksponent.
Zbog toga se na primjer, broj 972*10-1 pamti u obliku koji se prikazuje kao 972e-1 (s
time da se ni e ne pamti, nego se pie kako bi itatelj mogao vidjeti gdje zavrava mantisa
i poinje eksponent). Dobro je primijetiti da tonost broja u eksponencijalnom obliku
ovisi od broja znamenki koje moe imati mantisa, dok su maksimalna, odnosno
minimalna veliina broja ovisne od broja znamenki koje moe imati eksponent.
Eksponencijalnim oblikom brojeva moe se sa manje znamenki zahvatiti puno vei
raspon brojeva. Ilustracije radi, na primjer: 5,68434*10-14 = 0,0000000000000568434 .
Ako se uzme u obzir da se baza 10 podrazumijeva i ne pamti u raunalu, kod
eksponencijalnog se oblika treba u konkretnom sluaju upamtiti 9 mjesta (6 za mantisu i
3 za eksponent s predznakom) dok se u fiksnom zarezu mora upamtiti 20 znamenki.
35
Tablica 2.1: Pregled tipova podataka
Tip Naziv Veliina Opis Granice vrijednosti
(broj bajtova) (Range)
Cijeli short 2 Integer (cjelobrojna v.) S predzn. -32768 do 32767
broj 16 bitova Bez predzn. od 0 do 65535
long 4 Integer 32 bita S predzn. -2147483648 do
2147483647
Bez predzn. od 0 do
4294967295
int * Duljina ovisi o tipu Vidjeti short, long
raunala
Realni float 4 Floating point 3,4e+/- 38 (7
(klizni zarez) znamenki)
double 8 Klizni zarez duple 1,7e+/- 308 (15
preciznosti znamenki)
long 10 Klizni zarez s 1,2e+/- 4932 (19
double poveanom duplom znamenki)
preciznosti
Znakovi char 1 8-bitni karakter S predznakom -128 do 127
Bez predzn. od 0 do 255
wchar_t 2 Wide character Wide character
(nedavno ubaeno)
Logiki bool 1 Elementi Bool-ove True ili false
algebre
* Vrijednosti ovise od tipa raunala
Primjer 2.2
1. // Primjer koritenja character varijabli
2. #include <iostream.h>
3. int main() {
4. char c = 'A'; // ovako deklariran c je lokalna varijabla
5. cout<< " c = " <<c<<", a c kao cijeli broj= " << int(c) <<endl;
6. c='t';
7. cout<< " c = " <<c<<", a c kao cijeli broj= " << int(c) <<endl;
8. c='!';
9. cout<< " c = " <<c<<", a c kao cijeli broj= " << int(c) <<endl;
10. system("PAUSE");
11. return 0;
12. }
36
c = A, a c kao cijeli broj= 65 5
c = t, a c kao cijeli broj= 116 7
c = !, a c kao cijeli broj= 33 9
Press any key to continue . . .
2.2.Konstante
Pod konstantom se podrazumijeva svaki izraz koji ima fiksnu vrijednost. Mogu se
podijeliti na cjelobrojne (integer) , brojeve s kliznim zarezom (floating-point), karaktere i
nizove (string). Prikaz konstanti je u naelu isti kao i za varijable, samo konstante ne
mogu mijenjati svoju vrijednost.
1335
303
-454
Osim decimalnih brojeva C++ raspoznaje i oktalne brojeve (s bazom 8) koje prepoznaje
po prvom znaku 0 (nula) i heksadecimalne (s bazom 16) koje prepoznaje s prvim
znakovima 0x (nula iks).
75 // decimalni broj
0113 // oktalni
0x4b // heksadecimalni
3.14159 // 3,14159
6.02e23 // 6,02x 1023
3.5e-12 // 3,5x 10-12
''z'' // znak
''Dobar dan'' // niz
37
prvi je primjer jednog karaktera (znak) a drugi je primjer niza karaktera (niz ili string). U
oba sluaja mora se konstanta staviti u navodnike. Oznaka z bez navodnika tretirala bi se
kao varijabla.
Kod koritenje navodnika moe doi do zabune, jer C++ koristi neke oznake s posebnim
znaenjem, kao na primjer:
'' \n'' - je oznaka za skok na novi red ili ''\t'' je tabulator. Tako na primjer ako se ispie
cout<<''jedan\ndva\ntri'';
cout<<''Lijevo \t Desno'';
Konstante mogu imati svoje ime, poput varijabli. Smisao je u tome da se moe
pojednostaviti njihova upotreba. Na primjer ako je potreban broj Pi na osam decimala
Pi=3.14159265 moe biti dosadno vie puta pisati ovaj broj, a postoji i mogunost
greke. Konstantama se moe pridruiti ime na dva naina:
#define PI 3.14159265
#define novired ''\n''
38
opseg = 2*PI*r;
cout <<novired;
Primjer2.3.
1. /* Ovaj program prikazuje razliite mogunosti
2. koritenja varijabli i konstanti. */ duljina x u bajtovima je: 4 9
3. #include <iostream.h> duljina long u bajtovima je: 4 10
4. int main() x= 6 11
5. { c= A 12
6. int x(5); int(c) = 65 13
7. x=x+1; c= ! 15
8. char c= 'A'; int(c) = 33 16
9. cout<< ''duljina x u bajtovima je: ''<< sizeof(x)<<endl;
10. cout<< " duljina long u bajtovima je: "<< sizeof(long)<<endl;
11. cout<< "x= "<<x<<endl;
12. cout<< "c= "<<c<<endl;
13. cout<< "int(c) = " <<int(c) <<endl;
14. c='!';
15. cout<< "c= "<<c<<endl;
16. cout<< "int(c) = " <<int(c) <<endl;
17. system("PAUSE");
18. return 0;
19. }
Primjer 2.4.
1. /* Ovaj program ispisuje maksimalne i
2. minimalne vrijednosti pojedinih varijabli */
3. #include <iostream.h>
4. #include <climits> // funkcije SHRT_MIN, itd.
5. #include <cfloat> // za float vrijednosti
6. int main()
7. {
8. cout<< "Najmanja vrijednost za short: "<<SHRT_MIN<<endl;
9. cout<< "Najvea vrijednost za short: "<<SHRT_MAX<<endl;
39
10. cout<< "Najvea vrijednost unsigned short: " <<USHRT_MAX<<endl;
11. cout<< "Najvea vrijednost int: " <<INT_MAX<<endl;
12. cout<< "Najvea vrijednost long: " <<LONG_MAX<<endl;
13. cout<< "Najvea vrijednost float: " <<FLT_MAX<<endl;
14. cout<< "Najmanja vrijednost float: " <<FLT_MIN<<endl;
15. return 0;
16. }
Izlaz je :
Najmanja vrijednost za short: -32768 8
Najveca vrijednost za short: 32767 9
Najveca vrijednost unsigned short: 65535 10
Najveca vrijednost int: 2147483647 11
Najveca vrijednost long: 2147483647 12
Najveca vrijednost float: 3.40282e+038 13
Najmanja vrijednost float: 1.17549e-038 14
Press any key to continue . . .
Primjer 2.5:
1. // Primjer koritenja character varijabli( pr2_5)
2. #include <iostream.h>
3. int main() {
4. char a=51, b='*', c=50, d='=', e=54;
5. cout<< a<<b<<c<<d<<e<<endl;
6. cin>>a; // ova naredba moze se koristiti umjesto: system ("PAUSE")
7. return 0;
8. }
40
Primjer 2.6:
1. // Primjer koritenja varijabli (pr2_6)
2. #include <iostream.h>
3. int main()
4. {
5. typedef unsigned int prirodni;
6. prirodni a=5, b=2; // a i b su prirodni brojevi s pocetnim vrijednostima 5 i 2
7. float c, d;
8. cout<<"Ispisi 5/2: "<<a/b<<endl;
9. cout<<"Sada ima decimale: "<<(float)a/b<<endl; //pazi: nije float (a/b)
10. c=a/b;
11. cout<<"Ispisuje se c: "<<c<<endl;
12. c=a;
13. d=c/b;
14. cout<<"Ispisuje se d: "<<d<<endl;
15. system("PAUSE");
16. return 0;
17. }
Ispisi 5/2: 2 8.
Sada ima decimale: 2.5 9.
Ispisuje se c: 2 11.
Ispisuje se d: 2.5 14.
Press any key to continue
41
cout<<7/2;
cout<<7./2;
Prva ce naredba ispisti vrijednost 3, a druga 3,5 jer se zbog decimalne toke iza 7
ukljuuje decimalna aritmetika.
3. Operatori
a=a+1;
a=b=c=5;
42
Znaenje ovih operatora je slijedee:
Operand Znaenje
+ zbrajanje
- oduzimanje
* mnoenje
/ dijeljenje
% modul
a=11%3 ; // a=2
k=8%5 ; // k=3
Primjer 3.1.
1. // primjer koritenja operatora (oper1.cpp)
2. #include <iostream.h>
3. int main() {
4. int m=54;
5. int n=20;
6. cout<< " m = " <<m<<", n= " << n <<endl; m = 54, n= 20 6
7. cout<< " m+n = " <<m+n<<endl; // m+n = 74 m+n = 74 7
8. cout<< " m-n = " <<m-n<<endl; // m-n = 34 m-n = 34 8
9. cout<< " m*n = " <<m*n<<endl; // m*n = 1080 m*n = 1080 9
10. cout<< " m/n = " <<m/n<<endl; // m/n = 2 m/n = 2 10
11. cout<< " m%n = " <<m%n<<endl; // m%n = 14 m%n = 14 11
12. cout<< " m-n*2 = " <<m-n*2<<endl; // m-n*2 = 14 m-n*2 = 14 12
13. cout<< " m/2*n = " <<m/2*n<<endl; // m/2*n = 540 m/2*n = 540 13
14. system("PAUSE"); Press any key to continue . . .
15. return 0;
16. }
Iz primjera 3.1 vidi se da se aritmetiki operatori mogu izravno upisivati u naredbu cout.
U posljednje dvije naredbe za ispisivanje po rezultatu se vidi da je izraz m-n*2 izraunat
tako da je najprije izvedena operacija mnoenja, a onda zbrajanja . Isto tako u izrazu
m/2*n operacije su izvedene s lijeva na desno tj. najprije dijeljenje pa onda mnoenje.
Utvreni redoslijed operacija moe se mijenjati pomou zagrada, na isti nain kao to je
uobiajeno u matematici.
43
m
Izraz n moe se napisati kao m/2*n ili (m/2)*n . Tu zagrade nita ne
2
mijenjaju.
m
Izraz mora se pisati m/(2*n)
2n
Svrha je ovih operatora skratiti pisanje. Znaenje je opisano kroz slijedee primjere:
Ovo se skraeno pisanje moe pisati na dva naina a++ (sufiks) ili ++a (prefiks), to
meutim nije uvijek ista stvar.
Na primjer:
b=3;
a=++b; // Rezultat e biti a=4 i b=4 (prefiks forma) jer je poveanje b izvedeno prije
prebacivanja u a.
b=3;
a=b++; // Rezultat e biti a=3 i b=4 (postfiks forma) jer je prebacivanje u a izvedeno
prije poveanja b.
Ako se u aritmetikom izrazu pojavljuje npr. b=++a, onda se taj izraz moe
interpretirati kao dvije naredbe na slijedei nain
a=a+1;
b=a;
najprije se a uvea za 1, a onda b poprimi vrijednost a. Znai moe se zamisliti da se taj
izraz ustvari sastoji on dva: prvog u kojem se a povea za 1 i drugog u kojem se koristi
takav uveani a.
Analogno, aritmetiki izraz u kojem se koristi operator a++, recimo b=a++ se moe
rastaviti na dvije naredbe:
b=a;
a=a+1;
Znai naprije b poprima vrijednost a, a zatim se a poveava za jedan. Ako se u nekom
aritmetikom izrazu koristi ++a, moe se zamisliti da se ispred tog izraza nalazi naredba
a=a+1, odnosno ako se u izrazu koristi naredna a++, moe se zamisliti da se poslije tog 44
izraza nalazi naredba a=a+1
Upotrebu kombiniranih operatora te sufiksa i prefiksa ilustrira primjer 3.2.
Primjer 3.2.
1. // primjer koritenja kombiniranih operatora
2. #include <iostream.h>
3. int main() {
4. int m, n=3; // m nema poetnu vrijednost, n=3
5. m=++n;
6. cout<< " m = " <<m<<", n= "<<n<<endl; // m=4, n=4
7. m=n++;
8. cout<< " m = " <<m<<", n= "<<n<<endl; // m=4, n=5
9. m+=9;
m = 4, n= 4 6
10. cout<< " m+=9 = " <<m<<endl; // m=13
m = 4, n= 5 8
11. n-=8;
m+=9 = 13 10
12. cout<< " n-=8 = " <<n<<endl; // n = -3 n-=8 = -3 12
13. system("PAUSE"); Press any key to continue . . .
14. return 0;
15. }
Operator Znaenje
< Strogo manje
<= Manje ili jednako
> Strogo vee
>= Vee ili jednako
== Jednako
!= Razliito
45
Posebno treba skrenuti pozornost na operator jednako = = , njega se nikako ne smije
pisati s jednim znakom = jer tada znai pridruivanje. To moe biti uzrok greke u
programu jer je recimo i= =2 bilo neistinito, a i=2 je uvijek istinito, jer se upravo
prebacilo 2 u i.
Opi mu je oblik
uvjet ? rezultat1:rezultat2
Ovaj operator ocjenjuje zadani uvjet i poprima vrijednost rezulata1 ili rezultat2 u
ovisnosti da li je uvjet ispunjen ili ne.
Na primjer matematiki izraz x = abs(x) (apsolutna vrijednost od x) moe se, pomou
uvjetnog operatora, napisati na slijedei nain:
x= (x<0) ? x : x; // x=abs(x)
Dakle ako je ispunjen uvjet x<0 u x se stavlja -x tj. x mijenja predznak, inae se uzima x
kakav je.
46
int n =22;
float x = 3.14159;
x +=n; // vrijednost 22 se automatski konvertira u 22,0
cout << x-2; // konstanta 2 se automatski konvertira na 2,0
Ako je T odreeni tip varijable, a v varijabla nekog drugog tipa, onda izraz T(v)
konvertira varijablu tipa v u tip T.
Ova se konverzija naziva cast.
int main() {
double v= 1234.56; v = 1234.56 , n = 1234
int n;
n= int(v); // isto bi bilo i bez int(v)
cout<<''v =''<<v<<'', n = ''<<n<<endl;
}
Ovaj tip konverzije podataka je C++ naslijedio od C. Isti bi rezultat bio da se umjesto
Naredbe:
n = int (v);
n = static_cast <int>(v);
U ovim sluajevima nije bilo neophodno pisati cast operator, jer se radi o konverziji s
nieg na vii tip.
Slijedei primjer prikazuje jednu zanimljivu mogunost konverzije podataka
char z1,z2;
z2='m';
z1=z2+('A' - 'a'); M
cout<<z1;
47
Rezultat izvoenja ovih naredbi je ispis velikog slova M. Ako se pogleda ASCII tablica
Dodatak A na kraju prirunika vidi se da je 'razmak' izmeu velikog i malog slova jednak
za sva slova. Dakle ako se bilo kojem malom slovu doda navedeni 'razmak' on se
'pretvara' u veliko slovo. Automatska konverzija omoguava da se izvre aritmetike
operacije sa znakovima (char).Dakle gornje naredbe predstavljaju 'recept' kako se mala
slova prevode u velika.
double dbroj;
int ibroj;
unsigned long ulbroj;
dbroj = ibroj * ulbroj; // ibroj se konvertira u unsigned long;
// rezultat mnoenja se konvertira u double.
Primjer 3.3.
1. // primjer programa za ilustraciju konverzije
2. #include <iostream.h>
3. int main() {
4. int m,n, x;
5. float p;
6. m= 3/2; // oekuje se da je rezultat 1 jer nema decimala
7. p= 3/2; // oekuje se rezultat 1,5
8. cout<< " m = " <<m<<", p= "<<p<<endl; // Oba su rezultata jednaka
1?
9. m=3.0/2;
10. p=3.0/2;
11. cout<< " m = " <<m<<", p= "<<p<<endl; // Sad su rezultati oekivani
12. // slijedi ilustracija rada uvjetnog operatora
13. x=-5;
14. x= (x<0) ? -x : x; // x=abs(x) m = 1, p= 1 8
15. cout<<"x = "<<x<<endl; m = 1, p= 1.5 11
16. x=7; x=5 15
17. x= (x<0) ? -x : x; // x=abs(x) x=7 18
18. cout<<"x = "<<x<<endl; Press any key to continue . .
19. system("PAUSE");
20. return 0;
21. }
48
broju. Zbog injenice da su s desne strane veliine razliitog tipa (3.0 je realni broj a 2
cijeli, aktivira se aritmetika realnih brojeva u kojoj se raunaju decimale). U sluaju
cjelobrojne varijable m decimale se odbacuju, dok se u sluaju realne varijable p one
zadravaju. Treba napomenuti da bi se izrazi ponaali na isti nain, kada bi s desne strane
umjesto konstanti, bile varijable odgovarajueg tipa. U nastavku primjera je ilustrirana
upotreba uvjetnog operatora za izraun apsolutne vrijednosti broja.
Overlow je tip greke koji nastaje kada se u polje eli pohraniti vrijednost koja je vea
od maksimalne vrijednosti za dotini tip podataka. Slijedei program pokazuje takav
primjer :
Primjer3.4.
1. // Primjer za ilustraciju overflow
2. #include <iostream.h>
3. int main()
4. {
5. int n=1000;
6. n*=1000;
7. cout<<n<<endl;
8. n*=1000;
9. cout<<n<<endl; 1000000 7
10. n*=1000; 1000000000 9
11. cout<<n<<endl; -727379968 11
12. n*=1000; -1530494976 13
13. cout<<n<<endl; Press any key to continue . . .
14. return 0;
15. }
Vidi se da je ve trei rezultat netoan, jer je nastao overflow. Meutim program nije
javio nikakvu greku. To pokazuje da o takvim grekama mora misliti programer. Za tu
su svrhu u C++ izraene posebne funkcije koje ispituju nastanak takvog uvjeta.
1e+006
1e+012
1e+024
1.#INF
Press any key to continue . . .
Dakle kod realnih varijabli rezultat upozorava da je nastao overflow.
5
Ovaj se rezultat dobije sa Dev-C++ prevoditeljem, isti program s Borland prevoditeljem nepredvieno
prekida rad ('puca').
49
3.9. Zaokruivanje rezultata
Primjer3.5.
1. // Primjer programa u C++
2. /* Ovaj program pokazuje probleme u zaokruivanju */
3. #include <iostream.h>
4. int main()
5. {
6. // najprije se varijabla dijeli s ,3 a nakon toga mnoi s 3
7. int i=1000.0;
8. int j=i/3; i=1000,j=333,k=999 10
9. int k=j*3; n=1000,p=333.333,r=1000 14
10. cout<<"i="<<i<<",j="<<j<<",k="<<k<<endl; p=0.333344,r=1.00003 17
11. float n=1000.0; Press any key to continue . . .
12. float p= n/3;
13. float r= p*3;
14. cout<<"n="<<n<<",p="<<p<<",r="<<r<<endl;
15. p=p-333;
16. r=3*p; //oekuje se rezultat 1
17. cout<<"p="<<p<<",r="<<r<<endl;
18. return 0;
19. }
Kod cjelobrojnih varijabli i,j,k razlika u rezultatu je oekivana. Kod realnih varijabli
n,p,r pokazuje se da 333.333 *3 zaokruuje na 1000 pa je rezultat toan. Meutim, u
naknadnim se operacijama pojavila greka u zaokruivanju, jer 3*0,333344 nije jednako
1.
U nastavku je dana tablica s prioritetima operatora i redoslijedom njihovog izvoenja od
lijeva na desno ili obrnuto. Taj se prioritet uvijek moe mijenjati sa zagradama.
50
Asocijativnost je redoslijed izvoenja takvih operatora, L-D s lijeva na desno ili D-L s
desna na lijevo.
Output (cout)
Opi oblik je
Na primjer:
Operator << naziva se operator insertiranja s obzirom da on insertira niz znakova ili
varijable koje ga slijede u izlazni niz podataka.
Na primjer:
cout << ''Dobar dan'' << '' ja sam student, imam '' << godine<<''godine'';
Drugi primjer:
ispisat e:
51
Ako se eli da se druga reenica pojavi u novom redu, treba napisati naredbu:
Input (cin)
int godine;
cin >>godine;
Slijedi primjer programa, kojemu zadajemo cijeli broj a on ispisuje taj broj i njegovu
dvostruku vrijednost.
Nakon ispisivanja : Molim upisite cijeli broj raunalo je ekalo na odgovor. Ukucano je
78 pa obvezno enter. Raunalo je nakon toga odgovorilo:
52
Upisali ste broj 78
i njegova je dvostruka vrijednost 156
Posljednje dvije naredbe nemaju na izgled nikakvog znaenja, jer nakon to se ukuca broj
program zavrava s radom. One su samo za ilustraciju da je na taj nain izbjegnuta
potreba za upisivanjem naredbe
system("PAUSE");
53
4. Naredbe za kontrolu toka programa
Slijed izvoenja naredbi u programu je jednak uobiajenom slijedu kojim itamo tekst,
dakle s lijeva na desno i od vrha stranice prema dnu. Postoje meutim naredne, kojima
se moe promijeniti opisani tijek izvoenja naredbi.
if (x>0)
cout<< ''x je pozitivan'';
else
cout <<''x nije pozitivan''; Tok if-else
na ekranu e se pojaviti samo jedna poruka
x je pozitivan
ili Tok if
x nije pozitivan
if (x>0)
?
True
cout<< ''x je pozitivan'';
cout <<''x nije pozitivan'';
False A
54
Tekst ''x nije pozitivan'' bi se uvijek ispisao na ekranu, ak i u sluaju kad je
zadovoljen uvjet x>0, samo to bi tada prije toga ispisao i tekst ''x je pozitivan''.
Dakle u konkretnom sluaju takav program ne bi bio korektan.
Slijedi primjer programa koji koristi naredbu if:
Primjer4.1.
1. /* Ovaj program provjerava djeljivost 2 broja */ 2
2. #include <iostream.h> m n
3. int main()
4. {
1 3
5. cout<<" Upisi dva prirodna broja"<<endl;
priv
6. int n,m, priv;
7. cin>>m>>n;
8. // Pretpostavka je m>n ako nije, mijenjaju mjesta
9. if (m<n) {
10. priv=n;
11. n=m;
12. m=priv;
13. }
14. if (m%n) cout<<m<<" nije djeljiv s "<<n<<endl;
15. else cout<<m<<" je djeljiv s "<<n<<endl;
16. system("PAUSE");
17. return 0;
18. }
Gornji primjer sadri dvije if naredbe, jednu bez else, drugu sa else. U prvoj if naredbi,
ako je uvjet zadovoljen, varijable m i n mijenjaju mjesta. To je za to to na primjer 8 je
djeljivi s 4, ali 4 nije djeljivo s 8. Ova se zamjena izvrava kroz tri naredbe, koje su
stavljene u vitiaste zagrade. Bez vitiastih zagrada izvrila bi se samo prva naredba
priv=n; dok bi se preostale dvije izvodile svaki put, neovisno da li je uvjet ispunjen.
Treba primijetiti da je naredba if (n%m) zadovoljena ako je izraz u zagradi razliit od 0.
Ako izraz nije 0 (false), onda je automatski true tj. m nije djeljiv s n.
int n;
cout<< '' upii cijeli broj ''<<endl;
cin>>n;
if (n=22) cout <<''n= ''<<n<<endl;
55
else cout<< ''n nije jednak 22 nego''<<n<<endl;
Iako izgleda sve u redu, gornji program sadri logiku greku. Naime, u naredbi
if (n=22). upotrijebljen je samo jedan znak jednakosti. Taj se znak interpretira kao znak
pridruivanja tj. vrijednost 22 prenosi se u varijablu n. Uvjet if e uvijek biti ispunjen jer
je vrijednost n razliita od nule (true). Dakle bez obzira koja se vrijednost unese, izlaz e
biti:
Primjer4.2.
1. // Primjer programa u C++ koji odreuje manji od dva zadana cijela broja
2. /* Ovaj program ilustrira upotrebu naredbe if */
3. #include <iostream.h>
4. int main()
5. {
6. cout<<" Upii dva cijela broja"<<endl;
7. int m,n;
8. cin>>m>>n;
9. if (m<n) cout<<m<<" je manji od "<<n<<endl;
10. else if (n<m) cout<<n<<" je manji od "<<m<<endl;
11. else cout<< m<<" je jednako "<<n<<endl;
12. return 0;
13. }
56
Primjer4.3.
1. // Primjer programa koji odreuje najmanji od tri zadana cijela broja
2. /* Ovaj program ilustrira upotrebu naredbe if */
3. #include <iostream.h>
4. int main()
5. {
6. cout<<" Upii tri cijela broja"<<endl;
7. int n1,n2,n3, min;
8. cin>>n1>>n2>>n3;
9. cout<<"Upisani brojevi su: "<<n1<<","<<n2<<","<<n3<<endl;
10. min=n1; // polazna je 'pretpostavka' da je n1 najmanji
11. if (n2<min) min=n2; // ako je pak n2 manji on e zamijeniti n1
12. if (n3<min) min=n3; // ako je n3 manji on e zamijeniti prethodnu vrijednost
13. cout<<"Najmanji je: "<<min<<endl;
14. return 0;
15. }
Petlje u programu ponavljaju odreeni skup naredbi dok je zadovoljen neki uvjet. Opi
oblik ove petlje je:
F
Vrh petlje
?
Povratni
Naredbe skok s
u petlji kraja A
na
poetak
while petlja
Dno petlje
57
Naredba se ponavlja toliko puta dok je uvjet istinit. Dakle, samo je po sebi razumljivo
da se unutar naredbe mora mijenjati neka veliina koja utjee na vrijednost uvjeta, jer bi
inae petlja bila beskonana.
Upotreba while petlje je ilustrirana na primjeru izrauna n! (N-faktorijela):
Primjer4.4.
1. // primjer za izraun faktorijela Neka je upisan n=6
2. #include <iostream.h> i<=n k i cout k
3. int main () 1 2
4. { 2<=6 true 2 3
5. int n; // zadani broj
3<=6 true 6 4
6. int i =2; //broj koji ide od 2 do n
4<=6 true 24 5
7. int k=1; //rezultat mnoenja
5<=6 true 120 6
8. cout << ''Unesi prirodni broj n'';
6<=6 true 720 7
9. cin >>n;
10. while (i<=n) 7<=6 false preskae n!=720
11. { k=k*i; Operacije unutar petlje su u tamnijim poljima. Ova je
12. i++; } tablica primjer za tzv. stolno testiranje programa. Prati se
13. cout << ''n!= ''<<k; logika naredbi i unose se redom vrijednosti pojedinih
14. return 0; varijabli.
15. }
Izlaz je slijedei:
...
Unesi prirodni broj n
15
n!= 2004310016
Press any key to continue . . .
4.3.Naredba do-while
Opi oblik
do while petlja
58
A
T
Kada bi prethodni zadatak za izraun faktorijela htjeli rijeiti s do-while petljom, onda
bi on na primjer mogao biti:
Primjer4.4a:
// primjer za izraun faktorijela Neka je upisan n=6
#include <iostream.h> i k i<=n cout k
int main () 1 1
{ 2 2 2<6 true
int n; 3 6 3<6 true
int i =1; 4 24 4<6 true
int k=1; 5 120 5<6 true
cout << ''Unesi prirodni broj n''; 6 720 6<6 false n!=720
cin >>n; Operacije unutar petlje su u tamnijim poljima.
do{ k=k*i; i++; } while (i<=n);
cout << ''n!= ''<<k;
return 0;
}
// druga varijanta
Unesi prirodni broj n
15 cout << ''Unesi prirodni broj n'';
n!= 2004310016 cin >>n;
Press any key to continue . . . k=n;
do { n- - ; k=k*n);} while (n=1);
cout << ''n!= ''<<k
Ova se petlja ponavlja sve dok je uvjet istinit slino kao u while petlji uz dodatak da for
petlja ukljuuje i poetnu vrijednost i korak poveanja.
59
Redoslijed izvoenja naredbi u petlji for je slijedei:
1. Postavlja vrijednost varijable na poetnu vrijednost (to radi samo prvi put)
2. Ispituje izraz uvjet, ako nije istinit (dakle false) naputa petlju, inae
3. Izvode se naredbe
4. izvede korak poveanja
5. Ponavlja naredbe 2-4
for petlja
i= poetna
vrijednost
Ne
Uvj
et
OK
Da ?
Naredbe
Korak
poveanja
Primjer4.4b.
1. // primjer za izraun faktorijela
2. #include <iostream.h>
U konkretnom sluaju program
3. int main () bi radio isto i bez vitiastih
zagrada. One su nune ako je
broj naredbi u petlji vei od 1.
4. {
5. int n;
6. int k=1;
60
7. cout << ''Unesi prirodni broj n''<<endl;
8. cin >>n;
Naredba break slui za nasilno naputanje petlje, ak i kad uvjeti petlje za njeno
naputanje nisu zadovoljeni.
break;
61
Primjer4.5.
1. // primjer za odbrojavanje
2. #include <iostream.h>
3. int main (){ 10,9,8,7,6,5,4,3,2,1,PALI!
4. int n; Press any key to continue . . .
5. for (n=10; n>0; n--)
6. {cout<<n<<",";}
7. cout<< "PALI!"<<endl;
8. system("PAUSE");
9. return 0;
10. }
Primjer4.6.
1. // primjer za odbrojavanje s break
2. #include <iostream.h>
3. int main (){
4. int n;
5. for (n=10; n>0; n--)
6. {
7. if (n==3)
8. {
9. cout<<"Preskacemo odbrojavanje,"; Ubaeno u odnosu Primjer4.5
10. break;
11. }
12. cout<<n<<",";
13. }
14. cout<< "PALI!"<<endl;
15. system("PAUSE");
16. return 0;
17. }
10,9,8,7,6,5,4,Preskacemo odbrojavanje,PALI!
Press any key to continue . . .
4.6.Naredba continue
62
Naredba continue radi slino kao break uz razliku da continue preskae samo tekuu
iteraciju. Dakle nakon naredbe continue program odmah prelazi na slijedeu iteraciju.
Ako na primjer u odbrojavanju elimo preskoiti broj 5, to se moe uiniti na slijedei
nain:
continue
10,9,8,7,6,5,4,Preskacemo odbrojavanje,2,1,PALI!
Press any key to continue . . .
goto labela;
63
labela: naredba;
Primjer4.7.
int main () {
int N =5;
for (int i=0; i<N;i++) {
for (int j = 0; j<N; j++) {
for (int k=0; k<N; k++) Petlja j Petlja i
if (i+j+k>N) goto van; Petlja k
else cout<<i+j+k<< '' '';
}
van: cout<<''. ''<<endl;
}
system("PAUSE"); Izvan petlje j, ali unutar petlje i
return 0;
}
0 1 2 3 4 1 2 3 4 5 2 3 4 5 .
1 2 3 4 5 2 3 4 5 .
2 3 4 5 .
3 4 5 .
4 5 .
Press any key to continue . . .
Da se je umjesto naredbe goto van upisala naredba break, ona bi izazvala izlazak iz
petlje k, ali ne i iz petlje j, pa bi izlaz bio:
0 1 2 3 4 1 2 3 4 5 2 3 4 5 3 4 5 4 5 .
1 2 3 4 5 2 3 4 5 3 4 5 4 5 5 .
2 3 4 5 3 4 5 4 5 5 .
3 4 5 4 5 5 .
4 5 5 .
Press any key to continue . . .
64
Postavlja se pitanje kako bi se problem mogao rijeiti bez upotrebe naredbe goto ? To se
moe rijeiti ubacivanjem jedne dodatne varijable tipa bool.
Ova se naredba koristi kada treba ispitati izraze koji mogu poprimiti vie razliitih
vrijednosti, a za svaku je vrijednost potrebna druga naredba.
switch ( izraz) {
case sluaj1: skup naredbi 1; break; switch
case sluaj2: skup naredbi 2; break;
. case 1 case 2 case3 default
.
. a b c d
default: skup naredbi;
}
Na primjer:
switch (x) {
case 1: cout<< ''x je jednak 1''; break;
case 2: cout<<''x je jednak 2''; break;
case 3: cout<<''x je jednak 3''; break;
default: cout<<'' x nije ni 1 ni 2 ni 3'';
}
65
Uz case se mogu usporeivati samo konstante, tj. ne mogu se pisati izrazi kao npr.
case (n*2).
Primjer 4.8:
// Upotreba naredbe switch
#include <iostream.h>
int main(){
int ocjena;
cout<<"Ukucati ocjenu"<<endl;
cin>>ocjena;
switch (ocjena){
case 1: {cout<< "Nedovoljan "; break;}
case 2: {cout<< "Dovoljan "; break;}
case 3: {cout<< "Dobar "; break;}
case 4: {cout<< "Vrlo dobar"; break;}
case 5: {cout<< "Izvrstan "; break;}
default: cout<<"Krivi unos";
}
system("PAUSE");
return 0;
}
Primjer4.9.
/* Ovaj program generira sluajne brojeve */
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
int main()
{
unsigned sjeme;
cout<<"Ukucati sjeme"<<endl;
cin>>sjeme;
srand(sjeme); // inicijalizira sjeme
66
for (int i=0; i<8; i++)
cout<<rand()<<endl // funkcija rand generira sluajne brojeve;
return 0;
}
Prve broj u svakom stupcu, nakon poruke 'Ukucati sjeme' je onaj koji je sjeme koje je
ukucano putem tipkovnice. Vidi se da je kod treeg prolaza upisano isto sjeme kao i za
prvi prolaz pa su i sve generirane 'sluajne' varijable bile iste.
Primjer4.9a.
/* Ovaj program generira sluajne brojeve iz time */
#include <iostream.h>
#include <stdlib.h>
#include <time.h> // ukljuuje se funkcija time()
int main()
{
unsigned sjeme=time(0) // dobiva trenutnu vrijednost vremena u raunalu;
cout<<"Sjeme je: "<<sjeme<<endl;
srand (sjeme); // generira sjeme za rand funkciju da se broj ne ponavlja
for (int i =0; i<8; i++)
cout<<rand()<<endl;
return 0;
}
67
Izlaz je: 1. prolaz 2. prolaz
Sjeme je: 1138462312 Sjeme je: 1138462405
12703 13007
2329 18891
12424 2624
16405 26069
4499 13482
10136 14874
25918 20464
3995 26670
S obzirom da funkcija time mjeri apsolutno vrijeme, odnosno broji sekunde od 1.1.1970.
ona se nikad ne ponavlja, pa s njom nije mogue ponoviti isti niz sluajnih brojeva.
Dakle za generiranje sluajnih brojeva izmeu 101 i 222 moe se koristiti program sa
slijedeim naredbama:
int n;
srand (time(0));
n=rand ()%122+101;
Slijedi primjer programa za igru protiv raunala. Raunalo generira sluajni broj izmeu
1 i 256 a igra ga treba pogoditi. Uz dobro izabranu taktiku, broj se moe pogoditi u
najvie 8 pokuaja.
68
Primjer 4.10.
1. // Igra pogaanja brojeva koje generira raunalo
2. /* Pravila igre: raunalo generira sluajni broj izmeu 1 i 256,
3. a igra ga pokuava pogoditi tako to unos po jedan broj. Raunalo odgovara
4. da li je broj koji se eli pogoditi manji jednak ili ve od upisanog broja */
5. #include <iostream.h> // tu su spremljene naredbe cout i cin
6. #include <cstdlib> // ukljuuje se biblioteka standardnih funkcija
7. #include <ctime> // ukljuuje se biblioteka s vremenom(sjeme sluajnih brojeva)
8. int n=1; // broj kojeg igra unosi u raunalo
9. int br; //sluajni broj kojeg generira raunalo
10. char odg;
11. int i=0; // Broj pokuaja da se pogodi zadani broj
12. int main (){
13. while (n!=0){
14. srand (time(0));
15. br=rand()%256+1;
16. // generirani sluajni broj u operaciji modul 256 daje ostatak djeljenja
17. // izmeu 0 i 255 pa mu se doda 1 da bi broj bio u traenim okvirima.
18. do {
19. cout<<" Ukucaj cijeli broj izmeu 1 i 256"<<endl;
20. cin>>n;
21. if (n<1||n>256) {cout<<" Ukucani broj je izvan dozvoljenih
granica"<<endl;
22. continue; }
23. i++;
24. if (n==br) cout<< " Cestitam pogodili ste u "<<i<<" koraka"<<endl;
25. if (n>br) cout<<"Trazeni broj je manji"<<endl;
26. if (n<br) cout<<"Trazeni broj je veci"<<endl;
27. } while (n!=br);
28. cout<<" Ako zelis nastaviti upisi bilo koji broj, inace upisi 0"<<endl;
29. cin>>n;
30. i=0;
31. }
32. system("PAUSE");
33. return 0;
34. }
Primjer4.10. sadri po jednu while i do while petlju. Prva petlja while ide izmeu
naredbi u 13. i 31. retku i izvodi se dok je ispunjen uvjet daje n razliit od 0. Kao to se
iz programa moe vidjeti, za izlazak iz navedene petlje treba ukucati vrijednost za n
jednaku 0.
Druga petlja do while nalazi se izmeu naredbi od 18. do 27. retka i ponavlja se sve dok
je ispunjen uvjet da je n razliit od broja kojeg treba pogoditi. Iz te petlje se moe izai
samo tako da se pogodi sluano generirani broj br, koji je generiran u 14. i 15. retku.
69
U nastavku je druga verzija programa. Sada igra zadaje broj izmeu 1- 256 a raunalo
ga pogaa. Moe se provjeriti da raunalo uvijek pogodi u najvie 8 pokuaja.
Metoda pogaanja broja koja je ugraena u program naziva se 'binarno pretraivanje' i
detaljno je pojanjena u poglavlju 6.5. Sutina je metode da se u svakom koraku interval
pretraivanja prepolovi, pa se u 8 koraka svede na jedan broj (256=28). Igra najprije
unosi broj, a za tim odgovara sa <,= ili > ovisno da li je zadani broj manji, jednak ili vei
od broja kojeg raunalo predlae.
Primjer4.11.
1. // Igra pogaanja brojeva
2. /* Pravila igre: upisati jedan cijeli broj izmeu 1 i 256.
3. Raunalo pogaa a na odgovor mora biti
4. <, = ili > ovisi o tome da li je upisani broj manji,
5. jednak ili veci od onog kojeg je racunalo prikazalo na ekranu*/
6. #include <iostream.h>
7. int n=1; // broj kojeg treba upisati i kojeg e raunalo pogaati
8. int lo=1, hi=256; //gornja i donja granica intervala u kojem se pogaa
9. int br; // broj kojeg raunalo generira da 'pogodi' n
10. char odg;
11. int i=1; // Broj pokuaja da se pogodi zadani broj
12. int main (){
13. while (n!=0) {
14. cout<<" Ukucaj cijeli broj izmeu 1 i 256"<<endl;
15. cin>>n;
16. if (n<1||n>256) {cout<<" Ukucani broj je izvan dozvoljenih granica"<<endl;
17. continue;}
18. br=(lo+hi)/2;
19. cout<<"Je li to broj "<<br<<" ?"<<endl;
20. cin>>odg;
21. while(odg!='=') {
22. if (odg=='<') hi=br;
23. if (odg=='>') lo=br;
24. if (odg=='>' && br>=n || odg=='<' && br<=n) {cout<<"Poceli smo
lagati?"<<endl;
25. goto kraj;}
26. br=(lo+hi)/2;
Koritena je
27. cout<<"Da li je to broj "<<br<<" ?"<<endl;
naredba goto,
28. cin>>odg;
koja se inae
29. i++; izbjegava.
30. }
31. cout <<"Pogodio u "<< i<<"koraka"<<endl;
32. kraj: lo=1; hi=256;
33. cout<<" Ako eli nastaviti upisi bilo koji broj, inae upisi 0"<<endl;
34. cin>>n;
35. }
70
36. return 0;
37. }
5.Funkcije
U poetnoj fazi razvoja tehnike programiranja, funkcije su nastale kao rjeenje nekoliko
problema.
Kada se na vie mjesta u nekom programu treba obaviti isti slijed naredbi mogua su
bila dva rjeenja, jedno je da se na svakom mjestu ponove iste naredbe. Drugo je
rjeenje da se te naredbe piu samo na jednom mjestu pa da se program grana na to
mjesto kada treba izvriti dotine naredbe. Prvo rjeenje trai dosadno ponavljanje
naredbi i poveanje programa, drugo rjeenje komplicira logiku programa.
Neki su se poslovi uporno ponavljali iz programa u program. Na primjer izraun drugog
korijena, logaritma ili vrjednosti trigonometrijskih funkcija u tehnikim programima ili
izraun kamate u komercijanm programima. Bili je logino da se ti zadaci rijee jednom
za uvijek, te da ih svi mogu koristiti kao gotovu i provjerenu stvar.
Programi u praktinoj primjeni su u pravilu puno veeg opsega od primjera koji su
prikazani u ovom priruniku. Zbog toga je est sluaj da na izradi jednog programa
sudjeluje vie osoba. Izrada i kasnije odravanje velikih i kompleksnih programa
nametnuli su potrebu da se oni razgrade na manje samostalne dijelove, koji se openito
nazivaju potprogramima.
Funkcije predstavljaju jednu vrstu potprograma unutar glavnog programa i njihovim se
koritenjem struktura programa moe znatno pojednostaviti. Nain izvoenja programa
koji sadri funkcije, ilustrirano je na slijedeoj slici:
71
Slika 5.1: Odnos glavnog programa i funkcija
Iako sama funkcija ima strukturu poput bilo kojeg programa, ona nema neredbu
int main () koja se smije pojaviti samo jedan put u svakom programu, kao oznaka odakle
poinje izvoenje dotinog programa.
Pozivom funkcije izvoenje se od glavnog programa (main) prenosi na naredbe funkcije.
Po zavretku izvoenja naredba funkcije, nastavlja se izvoenje glavnog programa od
naredbe koja slijedi iza naredbe s kojom je funkcija pozvana. Sama funkcija npr.
funkcija2, moe pozivati neku drugu funkciju3, po istoj logici koja vrijedi za odnos
glavnog programa i funkcije2.
Kada se u jednom programu isti postupak ponavlja na vie mjesta, onda se to moe
rijeiti na nain da se odgovarajue naredbe kopiraju. To meutim poveava opseg
programa i komplicira njegovo odravanje. Uvoenjem funkcije, taj se problem rjeava
njenim pozivanjem sa vie mjesta u programu. Pri tome se funkcije mogu prevoditi
zajedno s programom ili izdvojeno.
Jezik C++ ukljuuje u sebi niz funkcija koje su pohranjene u standardnim bibliotekama.
Ako se na primjer, eli izraunati drugi korijen zadanog broja to se moe uiniti
slijedeim programom:
Primjer5.1.
1. // Program za izraun drugog korijena brojeva od 0 do 5
2. #include <cmath.h> // ukljuuje matematike funkcije
3. // za izraun drugog korijena koristi se sqrt (square root)
4. #include <iostream.h>
5. using namespace std:
6. int main(){
7. for (int x=0; x<6; x++)
8. cout<<Drugi korijen od <<x<< = <<sqrt(x) <<endl;
9. } Drugi korijen od 0 = 0 8
Drugi korijen od 1 = 1 8
Drugi korijen od 2 = 1.41241 8
Drugi korijen od 3 = 1.73205 8
Svaki programer moe i sam napisati funkcju kada
Drugi za to od
korijen ima4 potrebu.
=2 Opi8oblik naredbi
za definiciju funkcije je: Drugi korijen od 5 = 2.23607 8
72
type ime (argument1,argument2,....) {naredbe}
povratni tip- definira tip podatka (int, float,...) kojeg funkcija vraa u glavni program.
ime je identifikator funkcije, tj. naziv prema pravilima za nazive varijabli, s kojim se
poziva.
Primjer5.2.
1. // program za zbrajanje dviju varijabli
2. #include <iostream.h>
3. int zbrajanje (int a, int b) // boldani dio teksta predstavlja funkciju
4. { int r;
5. r=a+b; Izlaz e biti:
6. return (r); }
Rezultat je 8
7. int main ()
8. {
9. int z;
10. z = zbrajanje (5,3);
11. cout << "Rezultat je " << z;
12. return 0;
13. }
Sada treba ponovo naglasiti da se program uvijek poinje izvoditi od naredbe main ().
Dakle, iako je funkcija smjetena ispred glavnog programa, prilikom izvoenja ona se
preskae i izvodi tek kada se poziva iz programa koji je oznaen sa main.
73
Unutar funkcije definirana je nova varijabla r. Naredba return r; uspostavlja
korespondenciju izmeu varijable r i varijable z, koja je navedena u naredbi s kojom se
poziva funkcija.
Zbog toga je vrijednost varijable z nakon zavretka rada funkcije zbrajanje jednaka 8.
Dakle:
cout << "Rezultat je " << r;
Odgovor je negativan jer je r prema nainu definicije lokalna varijabla, koja nije poznata
u main programu.
Isto tako unutar funkcije zbrajanje nije se mogla koristiti varijabla z, jer ona je
definirana unutar main vitiastih zagrada. Da se varijabla z definirala izvan vitiastih
zagrada, mogla bi se koristiti u cijelom programu.
z=zbrajanje (5 , 3);
Ako se prethodni program izmjeni tako da se deklaracija varijable r stavi izvan vitiastih
zagrada, ona e biti prepoznatljiva u cijelom programu, pa se u naredbi za ispisivanje
umjesto z moe staviti r.
74
Prilikom prevoenja prevoditelj (Borland) daje upozorenje da se varijabla z nigdje ne
koristi, ali program ipak daje isti rezultat kao i prije.
Primjer5.3.
1. // primjer funkcije 2. Prvi rezultat je 5 12
2. #include <iostream.h> Drugi rezultat je 5 13
3. int oduzimanje (int a, int b) Trei rezultat je 2 14
4. { etvrti rezultat je 6 16
5. int r;
6. r=a-b;
7. return (r);
8. }
9. int main () {
10. int x=5, y=3, z;
11. z = oduzimanje (7,2);
12. cout << "Prvi rezultat je " << z << '\n';
13. cout << "Drugi rezultat je " << oduzimanje (7,2) << '\n';
14. cout << "Trei rezultat je " << oduzimanje (x,y) << '\n';
15. z= 4 + oduzimanje (x,y);
16. cout << "etvrti rezultat je " << z << '\n';
17. return 0;
18. }
U ovom su primjeru prikazani razliiti naini pozivanja funkcije, no efekt je uvijek kao i
u prethodnom primjeru.
Postoje i funkcije koje ne trebaju vraati nikakvu vrijednost u glavni program. Tada se u
definiciji funkcije umjesto type( tj. int, float,...) navodi void.
75
5.1.Prijenos argumenata po vrijednosti i po referenci
int zbrajanje
5 (int a, int
3 b);
Primjer5.4.
1. // prijenos parametara po referenci , program udvostruuje vrijednost
varijabli
2. #include <iostream.h>
3. void duplicate (int& a, int& b, int& c)
4. {
5. a*=2; // a=a*2,
6. b*=2; // b=b*2
7. c*=2; // c=c*2 x=2, y=6, z=14
8. }
9. int main ()
10. {
11. int x=1, y=3, z=7;
12. duplicate (x, y, z);
13. cout << "x=" << x << ", y=" << y << ", z=" << z;
14. return 0;
15. }
Treba primijetiti da je funkcija duplicate tipa void jer ona ne navodi nikakav parametar
kojeg vraa u main program.
Kada se varijable prenose 'po referenci' prenose se same varijable i svaka promjena u
vrijednosti varijabli koja se izvri unutar funkcije ima neposredni utjecaj na samu
varijablu u main programu.
76
Dakle, varijabla x se prenosi na mjesto varijable a, na isti nain y na b i z na c.
Primjer5.5.
1. // default vrijednosti u n funkciji
2. #include <iostream>
5. {
6. float r;
7. r=a/b;
8. return (r);
9. }
11. {
77
15. system("PAUSE");
16. return 0;
17. }
78
5.3.Prenapregnute funkcije (overloaded)
Dvije funkcije mogu imati isto ime ako im se razlikuje broj argumenata ili tip
argumenata. Na primjer:
Primjer5.6.
1. // prenapregnute (overloaded) funkcije
2. #include <iostream.h>
3. int podijeli (int a, int b)
4. {return (a/b);} Prva funkcija
5. float podijeli (float a, float b)
6. {return (a/b);}
7. int main () Druga funkcija s istim nazivom
8. { 2
9. int x=5,y=2; 2.5
10. float n=5.0,m=2.0;
11. cout << podijeli (x,y); 2 11
12. cout << ''\n''; 2.5 13
13. cout << podijeli (n,m);
14. cout << ''\n'';
15. return 0;
16. }
Definirane su dvije funkcije s istim imenom ali razliitim argumentima. Prevoditelj bira
funkciju prema zadanim argumentima.
Ako se ispred definicije funkcije napie kljuna rije inline, prevoditelj e prevesti
izvorni kod funkcije na mjestu gdje se funkcije poziva. Na taj se nain izbjegava prijenos
parametara koji za neke, vrlo kratke funkcije, moe poveati vrijeme njihovog
izvoenja.
Rekurzivnost je svojstvo funkcije da moe pozvati samu sebe. To je vrlo korisno kod
rjeavanja nekih tipova zadataka. Navedimo primjer funkcije za izraun faktorijela.
Primjer5.7.
1. // izraun faktorijela-rekurzijom
2. #include <iostream>
3. using namespace std;
4. long faktorijela (long a)
5. {
6. if (a > 1) Ukucaj broj:
7. return (a * faktorijela (a-1)); 9! = 362880
79
8. else
9. return (1);
10. } Kako to radi ?
17. return 0;
18. }
Vidi se da je funkcija faktorijela pozivala samu sebe sve dok a nije poprimio vrijednost
1. Inae bi program uao u beskonanu petlju.
80
5.5. Postupka izrade programa -pseudokod
Do sada su obraeni neki osnovni elementi programskog jezika C++ na temelju kojih se
moe stvoriti predodba o postupku kodiranja programa. Kao to je ve reeno svaki
programski jezik predstavlja suelje za komunikaciju ovjeka sa raunalom. Vii
programski jezici, kakav je i C++, bolje su prilagoeni komunikaciji ovjekom. Dakle u
njih je ugraena logika bliska ljudskom razmiljanju. Program prevoditelj prevodi
naredbe pisane u C++ u strojni jezik koji je jedini 'razumljiv' raunalu.
Program sadri naredbe, varijable i konstante koje se za vrijeme izvoenja programa
nalaze u memoriji raunala. Naredbe su poredane jedna iza druge kao to su u programu
napisane i tim se redom i izvode. Izuzetak su one naredbe koje izazivaju skretanje
programa od slijednog izvoenja. Naredbe sadre adrese polja u kojima su smjetene
varijable i konstante te 'uputu' to s tim veliinama treba uiniti kao na primjer: zbrojiti
dvije veliine i rezultat pohraniti u neko polje (itaj adresu u memoriji), usporediti dvije
veliine i u ovisnosti od rezultata usporeivanja izvriti neku treu naredbu itd.
1. Definicija problema
to je prim broj? To je prirodni broj koji nije djeljiv ni s jednim drugim brojem osim s 1 i
sa samim sobom. Ni jedan parni broj (osim 2) nije prim broj, jer paran je onaj broj koji
je djeljiv s 2. Zato je onda 2 prim broj ? Zato to je u skladu s definicijom prim broja
djeljiv samo s jedan i sa samim sobom.
6
Broj 1 prema dananjem stanju stvari nije ni prim ni sloen broj. Nekad se smatrao prim brojem ali s
obzirom na neke njegove specifinosti danas je izbaen iz tog drutva.
81
Tako da ga pokuavamo dijeliti s brojevima koji su manji od njega (osim s 1), pa ako je
s nekim od njih djeljiv, taj broj oito nije prim broj. Na primjer 13 je prim broj jer nije
djeljiv ni s jednim brojem manjim od 13, dok 14 nije prim broj jer je djeljiv s 2 i sa 7.
Da li je nuno da se broj koji se ispituje dijeli sa svim brojevima od poevi od 2 pa do
broja koji je za 1 manji od njega?
Nije nuno, dovoljno je provjeravati djeljivost do prirodnog broja koji je jednak
cjelobrojnom korijenu zadanog broja .
Ilustrirajmo to na primjeru broja 64, koji se moe napisati kao produkt slijedea dva
broja:
8x8
4x16
2x32
Drugi korijen od 64 je 8, pa ako se broj 64 moe dobiti kao produkt dvaju brojeva koji
nisu njegov korijen, onda za njih mora vrijediti da je jedan vei od korijena, a drugi
mora biti manji7. Dakle ako broj nije djeljiv ni s jednim brojem do njegovog korijena, nije
djeljiv ni s jednim brojem veim od njegovog korijena.
7
Naime, kada bi se 64 mogao dobiti kao umnoak dva broja koji su oba vea od 8, onda bi se oni mogli
napisati kao 8+k i 8+ m, gdje su m, n >0.
slijedi
8*(m+k)+m*k=0
odnosno
mk
8
mk
S obzirom da su m i k brojevi vei od nule, razlomak s lijeve strane jednakosti ne moe nikad poprimiti
negativnu vrijednost. Prema tome je polazna pretpostavka nemogua.
82
1. zadatak: Napisati program kojemu se zadaje broj n i program ispituje da li je
taj n prim broj.
Vano je istaknuti!
Dovoljno je da se nae jedna vrijednost j za koju je (k%j) false, dakle 0, odnosno n je djeljiv
s j, pa da zakljuimo da n nije prim broj.
Iz injenice da je (k%j) true, dakle razliito od 0, tj. n nije djeljiv s j, ne moe se zakljuiti da
je n prim broj.
To se moe zakljuiti tek ako to svojstvo vrijedi za sve j vee od 1 i manje od korijena od n.
83
Primjer5.8.
1. // Program koji ispituje da li zadani broj prim ili ne
2. /* n- je broj koji upisujemo na konzoli
3. j- je broji ide od 2 do korijena od n, i s njime dijelimo n */
4. #include <iostream.h>
5. #include <cmath>
6. int j, k=1,n;
7. int main ()
8. {
9. cout << "Unesi prirodan broj vei od 2"<<endl;
10. cin >> n;
11. if (n<=2) cout<<"Upisani broj nije vei od 2";
12. else {
13. for (j=2; j<=sqrt(n); j++) {
14. k=n%j;
15. if (k==0) { cout<<n<< " nije prim broj, djeljiv je s " <<j;
16. break; }
17. }
18. if (k!=0) cout<< n <<" je prim broj";
19. }
20. return 0;
21. }
84
Usporedba pseudokoda i programa
U konkretnom programskom rjeenju izbjegnuta je upotreba naredbe goto nego je koritena naredba break. Zbog toga se prije pisanja
da je n prim broj moralo ispitati kako je program doao do te naredbe.
85
2 zadatak: Napisati program koji ispisuje sve prim brojeve koji su manji od zadanog
broja n
k =i%j;
Ako je k=0 (znai i je djeljiv s j) i nije prim broj pa naputamo j petlju i idemo
na kraj i petlje;
Kraj j petlje;
Ako je k!=0 pii i;
Kraj i petlje;
Kraj inae;
Kraj programa.
86
Pisano u C++ , prikazane su dvije verzije koda, sa i bez koritenja funkcije.
Primjer5.9.
1. // primbra.cpp- program za ispisivanje prim brojeva
2. /* n- je broj koji upisujemo na konzoli do kojeg trazimo prim brojeve
3. i- je broj koji se poveava od 3 do n, za kojega provjeravamo da li je d
4. brojem.
5. j- je broj kojeg mijenjamo od 2 do korijena od i, i s njime dijelimo i
6. #include <iostream.h>
7. #include <cmath>
8. int i,j,n;
9. int main () {
10. cout << "Unesi prirodan broj vei od 2"<<endl ;
11. cin >> n;
12. if (n<=2) cout<<"Upisani broj nije vei od 2";
13. else {
14. cout<< "2,"; Primjer5.9a.
15. for (i=3; i<=n; i=i+2) { // koristi funkciju
16. for (j=2; j<=sqrt(i); j++) #include <iostream.h>
17. if (i%j==0) break; #include <cmath>
18. if (i%j) cout<< i <<","; int i,k,n;
19. } /* slijedi funkcija - ona vraa vrijednost 0 ako
20. } ispitivani broj nije prim broj */
21. return 0; int primbroj (int i) {
22. } int a,c;
for (a=2; a<=sqrt(i); a++) {
c=i%a;
Lokiga glavnog programa je znatno if (c==0) break;
jednostavnija ako se koristi funkcija . }
Funkcija se moe odvojeno prevesti i return (c);
pohraniti. Bitno je znati da joj se predaje }
jedan cjelobrojni argument i da ona vraa int main () {
0 ako taj argument nije prim broj. cout << "Unesi prirodan broj vei od 2"<<endl ;
cin >> n;
if (n<=2) cout<<"Upisani broj nije vei od 2";
else {
cout<< "2,";
for (i=3; i<=n; i=i+2) {
k= primbroj(i);
if (k== 0) continue;
else cout<< i <<","; }
}
return 0;
}
87
I trei primjer programa za generiranje prim brojeva koji koristi funkciju i Boolove
varijable:
Primjer5.9b.
1. // Ispisivanje prim brojeva - koristi se funkcija i Boolova varijabla
2. #include <cmath> // radi upotrebe sqrt ()
3. #include <iostream.h>
4. bool jeprim (int); // vraa true ako n je prim broj, inae false
5. int main()
6. {
7. int x;
8. cout <<"Unesi cijeli broj vei od 2"<<endl;
9. cin>>x;
10. if (x<=2) cout<< "Broj nije vei od 2";
11. for (int i=0; i<=x; i++) U ovom je primjeru funkcija (od naredbe
12. if (jeprim(i)) cout<<i<<","; 15)smjetena nakon glavnog programa.
13. return 0; Kako bi glavni program prepoznao funkciju
14. } neophodno je prije programa (naredba 4.)
15. // slijedi opis funkcije staviti samo njenu deklaraciju.
16. bool jeprim (int n){
17. float sqrtn=sqrt(n);
18. if (n<2) return false; // 1 nije prim broj
19. if (n<4) return true; // zato to 2 i 3 jesu prim brojevi
20. if (n%2==0 )return false;
21. for (int d=3; d<=sqrtn; d+=2)
22. if (n%d==0) return false;
23. return 1; // to je ekvivalentno return true
24. }
88
6. Polja podataka (arrays)
float x[5];
4 bajta
20 bajta
Sadraj pojedinih elemenata ovako deklariranog polja nije predvidljiv, jer lanovi polja
nisu inicijalizirani..
Vidi se dakle da prvo polje nosi indeks nula (0), a posljednje duljinu polja 1.
89
float a[5] ={123.4, 5.6, 7., 12.2, -5. };
onda treba paziti da broj varijabli u vitiastim zagradama bude jednak navedenoj duljini
polja.
Ako je broj varijabli u vitiastim zagradama vei od duljine polja, prevoditelj e javiti
greku, npr:
U obrnutom sluaju ako je broj varijabli u vitiastim zagradama manji od duljine polja,
onda e se one 'puniti' navedenim redom a ostatak e biti iniciran s nulom.
1 2 0 0 0
daje rezultat
1 2 0 3 0
No moe se napisati i
ime e se zbrojiti sadraj prva etiri polja i rezultat smjestiti u x[4], pa e rezultat biti:
1 2 0 3 6
Ime polja se ne smije podudarati s imenom neke druge varijable sa ili bez indeksa.
Treba drati na umu da indeks polja poinje od nule, pa indeks 4 predstavlja peto po redu
polje u tablici itd.
90
Primjer inicijalizacije polja: a [0] = 22.2 8
a [1] = 44.4 8
Primjer6.1. a [2] = 66.6 8
1. // polja -arrays b [0] = 33.3 12
2. #include <iostream.h> b [1] = 44.4 12
3. int main ( ) { b [2] = 55.5 12
4. float a[ ] = {22.2, 44.4, 66.6}; b [3] = 66.6 12
5. // slijedi izraun broja elemenata u polju b [4] = 7.93931e+033 12
6. int brpolja = sizeof (a)/ sizeof (float); b [5] = 5.61501e-039 12
7. for (int i=0; i< brpolja; i++) b [6] = 5.60519e-045 12
8. cout<<"a [" <<i<<"] = " <<a[i] <<endl; Press any key to continue . . .
9. const int VELICINA=4; // ovo je konstanta !!!
10. float b[VELICINA ] = {33.3, 44.4, 55.5, 66.6};
11. for (int i=0; i< 7; i++) //GREKA!!! vrijednost indeksa izvan granica/
12. cout<<"b [" <<i<<"] = " <<b[i] <<endl;
13. system("PAUSE");
14. return 0;
15. }
Zadnje tri ispisane vrijednosti su sluajne, njihov sadraj ovisi o tome to je trenutno
pohranjeno u memoriji. Puno je opasnija greka kada se polje s 'promaenim' indeksom
pojavljuje s lijeve strane znaka pridruivanja, jer se tada nekontrolirano mijenja sadraj
na tim adresama, to moe izazvati nepredvidive posljedice.
Kada se polje deklarira kao na prinjer float a[]; program prevoditelj dobija uputu da e
elementi polja a biti tipa float, a sam simbol a predstavlja adresu polja. Program
prevoditelj ne zahtijeva da se definira broj elemenata u polju. Na isti nain je rijeen
prijenos polja nekoj funkciji.
Slijedi primjer funkcije koja zbraja elemente polja i vraa njihov zbroj:
91
Primjer6.2:
1. // polja i funkcije- zbraja vrijednosti u polju
2. #include <iostream.h>
3. int zbroj (int [], int);
4. int main ( ) {
5. int a[ ] = {11, 33, 55, 77};
6. int brpolja = sizeof (a)/ sizeof (int);
7. cout<<"Zbroj (a, broj polja) = " <<zbroj (a, brpolja)<<endl;
8. // funkcija u gornjoj naredbi ina isti uinak kao x= zbroj (a, brpolja);
9. // pa zatim cout<<x;
10. system("PAUSE");
11. return 0;
12. }
13. // gotov main program poinje funkcija Zbroj (a, broj polja) = 176
14. int zbroj (int a[], int n) { Press any key to continue . . .
15. int zbroj=0;
16. for (int i=0; i<n; i++)
17. zbroj += a[i]; // zbroj = zbroj + a[i];
18. return zbroj;
19. }
U gornjem primjeru je deklaracija funkcije data u prvom retku, prije main programa koju
je poziva.To je bilo neophodno kako bi prevoditelj 'znao' da zbroj predstavlja funkciju.
Sama funcija je opisana iza main programa.
Nazivi argumenata funkcije su u deklaraciji isputeni i navodi se samo njihov tip. Kada se
u main programu poziva funkcija zbroj (a, brpolja) onda se navode samo nazivi varijabli
bez da se navodi njihov tip, ali su tipovi istovjetni onima koji su navedeni u deklaraciji
funkcije.
Kada se ovako prenosi polje funkciji u stvari se prenosi samo adresa prvog polja koju
sadri varijabla naziv polja, u konkretnom sluaju zbroj.
Funkcija moe neposredno mijenjati sadraj tih polja jer je prijenos polja bez obzira na
formu, analogan prijenosu varijabli po referenci.
92
Metoda e se pojasniti na primjeru polja s 4 broja u redoslijedu 2,4,3,1. Sutina metode
je da se svaki element polja usporedi sa slijedeim, pa ako je vei od njega mijenjaju
mjesta. U prvom prolazu se tako najvei element u polju smjesti na posljednje mjesto,
nakon toga se u slijedeem koraku opet trai najvei od preostalih itd.
2 3 4 1 2 1 3 4 1 2 3 4
2 3 1 4
U prvom prolazu najprije su usporeeni 2 i 4 (prvi i drugi stupac) i kako 2 nije vei od 4
nije se uinilo nita. Nakon toga su usporeeni 4 i 3 (drugi i trei stupac) i s obzirom da
je 4>3, zamijenili su mjesta, pa je polje izgledalo kao u drugom retku. Nakon toga su
usporeeno 4 i 1 (3. i 4. stupac) pa kako je 4>1 ponovo su zamijenili mjesta i broj 4 je
postao posljednji element polja.
Trei korak ponovno zapoinje s usporedbom 1. i drugog stupca i kako je 2>1 oni
mijenjaju mjesto. Bitno je uoiti da savki korak poinje usporedbom 1. i 2. stupca ali
zavrava jedan korak prije prethodnog.
93
Primjer6.3.
1. // Bubble sort
2. // glavni program ima samo definiciju polja i tri naredbe pii, sortiraj i opet pii
3. #include <iostream.h>
9. print (a,8);
2.
10. sort (a,8);
13. return 0;
1.
14. } privr 3.
15. // funkcija swap
18. x=y;
19. y=privr;
20. }
94
24. for (int j=0; j<n-i; j++)// j je indeks tablice
27. }
31. cout<<endl;
32. }
Radi ilustracije rada programa, izvrit e se manje izmjene u funkciji bubble sort.
na utoj podlozi su dodatne naredbe:
95
// funkcija bubble sort
void sort (float a[ ], int n) {
cout<<" i "<<" j "<<" Tablica "<<endl; // prikazujem zaglavlje
for (int i=1; i<n; i++)
for (int j=0; j<n-i; j++){
if (a[j] > a[j+1]) swap (a[j], a[j+1]);
cout<<" "<<i<<" "<<j<<" "; // piu se vrijednosti indeksa petlji
print (a,8); // Ispisuju se elementi tablice
} Dodan je i par
} vitiastih zagrada
96
55.5 je bio ispred 22.5 ali su upravo zamijenili mjesta
55.5 22.5 99.9 66.6 44.4 88.8 33.3 77.7 - Ispis iz main programa, poetni sadraj
i j Tablica * polja
1 0 22.5 55.5 99.9 66.6 44.4 88.8 33.3 77.7
1 1 22.5 55.5 99.9 66.6 44.4 88.8 33.3 77.7
1 2 22.5 55.5 66.6 99.9 44.4 88.8 33.3 77.7
Broj 99.9 je najvei element u tablici
1 3 22.5 55.5 66.6 44.4 99.9 88.8 33.3 77.7
i on je u 1. koraku poput mjehuria
1 4 22.5 55.5 66.6 44.4 88.8 99.9 33.3 77.7
'isplivao' na zadnje mjesto. U drugom
1 5 22.5 55.5 66.6 44.4 88.8 33.3 99.9 77.7
je koraku broj 88.8 'isplivao' na
1 6 22.5 55.5 66.6 44.4 88.8 33.3 77.7 99.9
pretposljednje mjesto itd.
2 0 22.5 55.5 66.6 44.4 88.8 33.3 77.7 99.9
2 1 22.5 55.5 66.6 44.4 88.8 33.3 77.7 99.9
2 2 22.5 55.5 44.4 66.6 88.8 33.3 77.7 99.9
2 3 22.5 55.5 44.4 66.6 88.8 33.3 77.7 99.9 Ispis iz funkcije sort. Naredba za
2 4 22.5 55.5 44.4 66.6 33.3 88.8 77.7 99.9 ispis se nalazi iza pozivanja funkcije
2 5 22.5 55.5 44.4 66.6 33.3 77.7 88.8 99.9 swap, dakle nakon to su dva
3 0 22.5 55.5 44.4 66.6 33.3 77.7 88.8 99.9 elementa polja (eventualno)
3 1 22.5 44.4 55.5 66.6 33.3 77.7 88.8 99.9 zamijenila mjesto. Ako je element
3 2 22.5 44.4 55.5 66.6 33.3 77.7 88.8 99.9 upravo zamijenio mjesto nalazi se na
3 3 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 plavoj podlozi. Poredak elemenata
3 4 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 prije toga vidi se u retku iznad.
4 0 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 Na utoj je podlozi oznaen redak
4 1 22.5 44.4 55.5 33.3 66.6 77.7 88.8 99.9 kad poinje novi korak tj. promjena
4 2 22.5 44.4 33.3 55.5 66.6 77.7 88.8 99.9 vrijednosti varijable i.
4 3 22.5 44.4 33.3 55.5 66.6 77.7 88.8 99.9
5 0 22.5 44.4 33.3 55.5 66.6 77.7 88.8 99.9
5 1 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
5 2 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
6 0 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
6 1 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
7 0 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
Ispis iz main programa, konani
22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9 sadraj polja
Prethodni primjer je pokazao kako se sortiraju elementi polja u rastuem redoslijedu tj.
od manjeg elementa prema veem. Postavlja se pitanje kako bi izgledao program za
sortiranje elemenata u padajuem redoslijedu ?
97
Jednostavnije je ipak rjeenje da se u funkciji sort zamijeni naredba
Zadana je tablica
int p[]= { 22, 77, 33, 44, 11, 55, 66, 88};
Treba napisati programski kod funkcije koja provjerava da li se u tablici p nalazi neka
zadana vrijednost i na kojem je to mjestu.
98
gdje je x broj (konstanta) kojim pretraujemo tablicu, a [ ] je tablica a n broj elemenata u
tablici.
Primjer6.4.
1. // Funkcija za linearno pretraivanje tablice
2. #include <iostream.h>
3. int index (int, int [], int);
4. int main (){
5. int a[] = {22, 77, 33, 44, 55, 11, 66, 88 };
6. cout<<"index (44,a,8)= "<<index(44,a,8)<<endl;
7. cout<<"index (60,a,8)= "<<index(60,a,8)<<endl;
8. system("PAUSE");
9. return 0;
10. }
11. int index (int x, int a[], int n){
12. for (int i =0; i<n; i++)
13. if (x== a[i]) return i;
14. return n; // x nije pronadjen
15. }
Drugi nain pretraivanja polja je tzv. binarno pretraivanje. Kod linearnog pretraivanja
zadani se broj usporeuje sa svim elementima polja, odnosno dok ne naie na jednak
broj. Za polja s velikim brojem elemenata to moe usporavati program. Kod binarnog je
pretraivanja taj broj usporedbi daleko manji, no uvjet je da polje bude sortirano.
Postupak binarnog pretraivanja je ve prikazana u programu Primjer4.11.
99
Drugi ili trei korak tj. postupak 'raspolavljanja' dijelova polja a[ ] se nastavljaju dok se
segment polja ne svede na jedan element. Ako x nije jednak tom elementu znai da ga
nema u polju.
Ovaj postupak u svakom koraku (ako nije pronaen traeni broj) odbacuje pola segmenta
polja segmenta koji se razmatra. Prema tome, najvei broj koraka koji je neophodan da
bi se ispitalo neko polje, jednak je broju znamenaka koji broj elemenata toga polja ima u
binarnom obliku, umanjenom za 1.
Na primjer broj 256 ima binarni prikaz 100000000, dakle 9 znamenaka. Dijeljenjem 256
sa 2 dobija se redom 128, 64, 32, 16, 8, 4, 2,1. Dakle segment polja od 256 brojeva svodi
na jedan element u 8 koraka.
Primjer6.5.
1. Slijedi primjer programa za binarno pretraivanje:
2. #include <iostream.h>
6. ako x nije pronaen, odnosno indeks elementa polja u kojem se nalazi pronaeni x */
9. int a[] = {22, 33, 44, 55, 66, 77, 88}; // polje mora biti sortirano!!
12. system("PAUSE");
13. return 0;
14. }
100
18. while(lo<=hi){
23. }
25. }
26.
index (44, a, 7) = 2 10
index (60, a, 7) = 7 11
Press any key to continue . . .
Na primjer
101
tablica [0] [0] = 214;
tablica [2] [1] = 122;
tablica [1] [3] = 322;
1.stupac (0) 2.stupac (1) 3.stupac (2) 4.stupac (3) 5.stupac (4)
1.redak (0) 214
2.redak (1) 322
3.redak (2) 122
Dvodimenzionalno polje int tablica [3] [5] moemo shvatiti i kao tri
jednodimezionalna polja s pet elemenata.
ovom se naredbom iniciraju samo prva dva retka. Naime, svaki par unutarnjih vitiastih
zagrada predstavlja jedan redak. Na primjer
Primjer6.6.
1. // program za rad s tablicama
2. #include <iostream.h>
102
3. int mjeseci []={31,28,31,30,31,30,31,31,30,31,30,31};
5. int main () {
6. int i,j;
9. cout<<endl;
14. }
15. system("PAUSE");
16. return 0;
17. }
103
Izlaz iz prethodnog programa je:
Mjesec[1]=31 8
Mjesec[2]=28 8
Mjesec[3]=31 8
Mjesec[4]=30 8
Mjesec[5]=31 8
Mjesec[6]=30 8
Mjesec[7]=31 8
Mjesec[8]=31 8
Mjesec[9]=30 8
Mjesec[10]=31 8
Mjesec[11]=30 8
Mjesec[12]=31 8
9
Druga tablica 10
Dvodim [0,0]=1 13
Dvodim [0,1]=2 13
Dvodim [0,2]=3 13
Dvodim [0,3]=4 13
Dvodim [0,4]=5 13
Dvodim [1,0]=11 13
Dvodim [1,1]=12 13
Dvodim [1,2]=13 13
Dvodim [1,3]=0 13
Dvodim [1,4]=0 13
Dvodim [2,0]=21 13
Dvodim [2,1]=22 13
Dvodim [2,2]=0 13
Dvodim [2,3]=0 13
Dvodim [2,4]=0 13
Press any key to continue . . .
104
7. Znakovni nizovi
C niz se deklarira kao polje s znakovima tipa char. Prilikom inicijalizacije znakovnog
niza njegov se sadraj stavlja u navodnike, kao na primjer:
A u g u s t C e s a r e c \0
Znakovni niz uvijek zavrava s oznakom ''\0'' nul-znak (null-character). Njega nije
potrebno eksplicitno navoditi prilikom inicijalizacije, ali treba imati na umu da on
zauzima jedno znakovno mjesto.
Ako bi htjeli ispisati znakovni niz pisac program bi izgledao kako slijedi:
cout<<pisac[i]<<endl;
ispustilo endl itav bi tekst bio u istome retku.
cout<<pisac<<endl;
105
(uz dodatak da se izbaci i for petlja iz gornjeg primjera), bi ispisala cijeli sadraj niza
pisac u jednom retku kao i u prethodnom sluaju.
August Cesarec
Press any key to continue . . .
Naime, kada su u pitanju nizovi, znakovi se automatski prenose u cout dok ne naie
nul-znak. Na isti nain se ponaa i unos podataka sa cin.
Primjer7.2. s[0]=A
1. // ispis niza znakova s[1]=B
2. #include <iostream.h> s[2]=C
3. char s[] = "ABCD"; s[3]=D
4. int main () s[4]=
5. { Press any key to continue . . .
6. for (int i=0; i<5; i++)
7. cout<<"s["<<i<<"]="<<s[i]<<endl;
8. system("PAUSE");
9. return 0;
10. }
Iz ovako izmjenjenog programa vidi se da se niz s moe ispisati bez navoenja indeksa,
kao da je obina varijabla. Nakon toga je niz ispisan preko indeksa i pri tome je izvrena
i konverzija tipa iz char u int. Vidi se da je zadnji lan niza s[4] jednak 0, odnos nul
znak. Moe se dakle ponoviti: naredba cout ispisuje sve lanove niza dok ne naie na
nul znak.
106
U C++ postoji mogunost konverzje niza u broj, to je ilustrirano u primjeru 7.2b.
Primjer7.2b:
1. // Konverzija niza znakova u broj
2. #include <iostream.h>
3. #include <stdlib.h> // ukljuuje funkciju atoi
4. int main ()
5. {
6. char s[] = "5432";
7. int broj;
8. broj=atoi(s); // konverzija alfa to integer
9. cout<<broj<<endl;
10. system("PAUSE"); 5432
11. return 0; Press any key to continue
12. }
Pored funkcije atoi postoje i druge sline funkcije kao atol koja konvertira niz u long
format itd.
Zbog razliitih primjena nizova u ve su u C prevoditelju ukljuene razliite funkcije
za njihovu obradu, koje su ukljuene u biblioteku funkcija za obradu nizova <cstring>.
Primjer7.3.
1. // Rad s C nizovima u C++
2. #include <iostream.h>
3. #include <string.h>
4. int main()
5. {
6. char pisac []= "August Cesarec";// inicira se string pisac
7. char slikar []= "Edo Murtic ";// inicira se string slikar
8. char niz [50]; // polje za prebacivanje
9. cout<<"duljina niza pisac je "<<strlen(pisac)<<endl;
107
10. cout<<"duljina niza slikar je "<<strlen(slikar)<<endl;
11. strcpy (niz,slikar); // kopirati slikar u niz
12. cout<<"Niz: "<<niz<<endl; // da vidimo sto je preslo u niz
13. strcpy (slikar,pisac); //prebacuje sadraj iz pisac u slikar
14. cout<< slikar << " nakon strcpy(slikar,pisac)"<<endl;
15. strcpy (slikar,niz); // vraa pocetni sadraj
16. cout<<slikar<<"nakon vracanja vrijednosti" <<endl;
17. strcpy (niz, pisac);
18. cout <<niz<<endl;
19. strcat (niz, slikar);
20. cout<< niz << " nakon strcat"<<endl;
21. return 0;
duljina niza pisac je 14 9
22. }
duljina niza slikar je 10 10
Niz: Edo Murtic 12
August Cesarec nakon strcpy(slikar,pisac) 14
Edo Murtic nakon vracanja vrijednosti 16
August Cesarec 18
August CesarecEdo Murtic nakon strcat 20
#include <iostream.h>
#include <string.h>
int main()
{ Iako se u naredbi cout moe navesti
char pisac []= "August Cesarec"; niz slikar bez indeksa, to na primjer ne vrijedi
char slikar []= "Edo Murti "; za pridruivanje. Da se na primjer napisalo
char niz [50];
for (int i=0; i<16; i++) slikar= pisac;
slikar[i]=pisac[i];
cout<<slikar; prevoditelj bi javio greku.
return 0;
}
108
7.1. Uporaba nizova na primjeru obrade prijavnica
Podaci u utom redu pokazuju redni broj bajta u odnosu na poetak tj. prezime i ime je
smjeteno u prvih 15 bajtova, Matini broj je od 16 do 20, ifra predmeta od 23 do 25 i
ocjena u 31. bajtu.
Gornja se tablica moe smjestiti u dvodimenzionalno polje ocjene [] [40], gdje svaka
prijavnica predstavlja jedan redak, a unutar retka je niz od 40 bajta sa strukturom
prikazanoj u tablici 7.1. Treba izraditi program koji e izlistati navedenu tablicu i
izraunati prosjenu ocjenu po studentu.
Polje ocjene [] [] e u programu biti prikazano kao polje stringova koje je ve sortirano
po studentima. Ova je injenica bitna za definiciju algoritma, koji e se najprije
prikazati u pseudokodu.
Prosjena ocjena po studentu dobije se tako da se zbroje sve njegove ocjene i suma se
podijeli s brojem ocjena.
Na temelju tablice 7.1. mogu se definirati slijedei (pod)stringovi koje treba 'izvaditi'
iz polja ocjene [] []:
Sami nazivi navedenih stringove i njihove duljine govore koji e se podaci smjestiti u
njih. Potreno je jo definirati i slijedee varijable: n je broj elemenata u polju, odnosno
broj prijavnica, suma je polje u kojem se zbrajaju ocjene po studentu, i k- u kojem se
pamti broj ocjena po studentu, tako da bude:
suma
prosjek
k
Logika programa za prikaz podataka iz polja ocjene je jednostavna, treba redom oitavati
podatke iz polja i prikazivati ih na ekranu. Za izraun prosjene ocjene po studentu
109
potrebno je imati broj ocjena i njihov zbroj. Postavlja se pitanje kako znati da su za
pojedinog studenta prebrojene i zbrojene sve njegove ocjene?
110
Slika 7.1. Djelomini dijagram toka postupka obrade prijavnica
Start
Dijagram toka nije suma je polje u kojem se
potpun jer nema na zbrajaju ocjene za
primjer naznaen pojedinog studenta.
kraj programa. On suma=0; br je polje u kojem se
bi u realnoj situaciji br=0; broji broj ocjena (odnosno
nastao kad se prijavnica) po pojedinom
proita zadnji slog studentu.
u datoteci
prijavnica. prosjek=suma/br;
Prikazana logika Uzmi
nije dobra za prvi prijavnicu
slog, jer bi se kod
njega raunao i
pisao prosjek, a ni
za zadnji slog, za
kojeg se prosjek ne Da
Promje Raunaj
bi ni izraunao ni
na prosjek
pisao.
MBR ?
Pii MBRstari, A
prosjek
Ne
suma=0;
br=0;
Oznake A i B u
krugovima nemaju,
zasad, nikakvo
znaenje
B Kako provjeriti da li se
Pii redak za
promijenio MBR?
prijavnicu, MBR
111
Slijedi opis rjeenja pseudokodom:
Primjer7.4.
1. /* Ovaj program lista prijavnica i rauna prosjene ocjene po studentu */
2. #include <iostream.h>
3. #include <cstring>
4. int main()
5. {
112
14. "Aldo Burul 21446 P01 4",
19. int k=0; // k umjesto j pamti broj ocjena s obzirom da je j indeks petlje
21. int brocj; // brocj je numeriko polje za ocjenu koja je char varijabla
27. for (int j=15; j<20; j++) mbr[j-15]=podaci[i][j];// prenosi se mat. broj u mbr
28. for (int j=23; j<26; j++) sifra[j-23]=podaci[i][j]; //prenosi se sifra predmeta
31. // funkcija strcmp- string compare vraa 0 ako su dva niza jednaka
34. prosjek=suma/k;
36. suma=0;
113
37. k=0;
38. }
41. k++;
45. }
48. prosjek=suma/k;
50. system("PAUSE");
51. return 0;
52. }
Mbr Ime i prezime Sifra Ocjena Mbr Ime i prezime Sifra Ocjena
20616-Mario Kalac -P01- -3
Izlaz iz programa
20616-Mario je: -P02- -5
Kalac Ovakav bi izlaz
20616-Mario bio pregledniji:
Kalac -P01- -3
Prosjek za 20616 je 4 P02- -5
Prosjek = 4.00
20701-Tone Cvek -P01- -4
20701-Tone Cvek -P02- -4 20701-Tone Cvek -P01- -4
20701-Tone Cvek -P03- -3 P02- -4
Prosjek za 20701 je 3.66667 P03- -3
Prosjek = 3.67
20855-Mara Gruja -P01- -5
20855-Mara Gruja -P02- -3 20855-Mara Gruja -P01- -5
Prosjek za 20855 je 4 P02- -3
Prosjek = 4.00
21446-Aldo Burul -P01- -4
21446-Aldo Burul -P02- -5 21446-Aldo Burul -P01- -4
21446-Aldo Burul -P03- -2 P02- -5
Prosjek za 21446 3.66667 P03- -2114
Prosjek = 3.67
Press any key to continue . . . Press any key to continue . . .
Koje bi se izmjene u programu trebale uiniti pa da se dobije, ovaj pregledniji izlaz?
Namee se promjena logike ispisivanja. Ispisivanje cijelog retka treba napraviti samo
kada se student pojavljuje prvi put, a kad se on ponavlja ispisuje se samo Sifra i Ocjena.
Rjeenje se moe ilustrirati pozivom na logiku u dijagramu 7.1. Kod naredbe oznaene s
A u krugu, treba nakon ispisivanja MBrstari i prosjek 'skoiti' na novi red i ispisati MBR i
ime studenta. (Ostat e samo problem za prvog studenta, jer se za njega ta petlja ne
izvrava. U primjeru 7.4a u nastavku problem prve prijavnice je rijeen u naredbama
34,35 i 36). U naredbi oznaenoj s B umjesto ispisivanja itavog retka za prijavnicu treba
ispisati samo ifru predmeta i ocjenu.
Primjer 7.4a.
1. /* Ovaj program lista prijavnica i rauna prosjene ocjene po studentu */
2. #include <iostream.h>
3. #include <cstring>
6. int main()
7. {
115
14. "Mara Gruja 20855 P01 5",
21. int k=0; // k umjesto j pamti broj ocjena s obzirom da je j indeks petlje
23. int brocj; // brocj je numeriko polje za ocjenu koja je char varijabla
29. for (int j=15; j<20; j++) mbr[j-15]=podaci[i][j];// prenosi se mat. broj u mbr
30. for (int j=23; j<26; j++) sifra[j-23]=podaci[i][j]; //prenosi se sifra predmeta
33. // funkcija strcmp- string compare vraa 0 ako su dva niza jednaka
34. if (strcmp(mbrstari,"000000")==0) {// uitan je prvi slog, treba ispisati puni red
116
37. }
38. else {
41. suma=0;
42. k=0;
46. }
47.
49. }
52. k++;
53.
54. }
117
60. }
64. prosjek=zbroj/broj;
65. cout<<setw(30)<<"Prosjek =
"<<fixed<<setprecision(2)<<prosjek<<endl<<endl;
66. }
118
8. Pokazivai (pointers)
Memorija pojedinog raunala se moe predoiti kao jedno veliko polje (array), iji su
elementi bajtovi. Na primjer raunalo sa 256 MB RAM-a sadri 268.435.456 odnosno 2 8
bajtova. Zamiljeni kao polje ovi bajtovi imaju indekse od 0 do 268.435.455 ili
heksadecimalno pisano od 0x00000000 do 0x0fffffff.
Deklaracijom pojedine varijable pridodaju joj se tri bitna atributa: njen naziv, tip i
adresa u memoriji. Na primjer deklaracija
int n;
pridruuje nazivu n tip int (dakle 4 bajta) i neku adresu u memoriji na kojoj je pohranjena
vrijednost od n. Neka je to na primjer adresa 0x0064fdf4
0x0064fdf0
0x0064fdf1
0x0064fdf2
0x0064fdf3
0x0064fdf4
0x0064fdf5
0x0064fdf6
0x0064fdf7
0x0064fdf8
Kada se u programu eli pristupiti navedenoj adresi dovoljno je navesti naziv varijable,
no sadraju se moe pristupiti i tako da se umjesto naziva varijable, navede adresa na
kojoj je pohranjena dotina varijabla.
Pokazivai su varijable (objekti) koji sadre adrese i na taj nain 'pokazuju' na neke druge
varijable (objekte).
119
ted=&andy
Dakle im smo ispred varijable stavili znak & (ampersand), vie ne govorimo o sadraju
varijable nego o njenoj adresi u memoriji.
Neka je na primjer varijabla andy smjetena na adresi 1776 u memoriji, onda se to moe
ilustrirati na slijedei nain:
andy = 25;
fred = andy;
ted = &andy;
Koristei pokazivae moe se pojasniti to se dogaa kada se polju daje indeks koji
premauje granice polja:
Primjer8.1.
1. /* Ovaj program ilustrira rad s tablicama (array) */
2. #include <iostream.h>
3. int main()
4. {
5. int p [5], q [] = {22, 44, 11}, s[4]= {77, 88};
6. cout<<p[6]<< " "<<q[1]<<" " <<s[1]<<endl;
7. return 0;
8. }
izlaz je (kod Borland prevoditelja):
Oito je da je p[6] izvan dozvoljenih
44 44 88
granica, pa se postavlja pitanje zato je
ispisana vrijednost 44 ?
Pojanjenje daje slijedei program:
120
Primjer8.2:
1. /* Ovaj program ilustrira rad s tablicama (array) */
2. #include <iostream.h>
3. int main() Ovaj program najprije ispisuje adrese od
4. { polja p i q a tek nakon toga navedene
5. int p [5], q [] = {22, 44, 11}, s[4]= {77, 88}; vrijednosti.
6. cout << &p <<" "<<&q<<endl; Ispisane adrese su u heksadecimalnom
7. cout<<p[6]<< " "<<q[1]<<" " <<s[1]<<endl;obliku, odbije li se druga adresu od prve
8. return 0; dobije se 14 to prevedeno u dekadski
9. } sustav daje broj 20 (1*161 + 4*160 ).
Izlaz je : Tablica p zauzima u memoriji 20 bajtova
0012FF6C 0012FF80 (5*4) i nakon toga je smjetena tablica q.
44 44 88 Najvei indeks unutar polja p je 4 (5-1)
Zbog toga p[6] i q[1] predstavljaju istu
adresu u memoriji, to ilustrira slika.
Prekoraenje
p[5] p[6] p[7] p[8] p[9]
p[0] p[1] p[2] p[3] p[4] q[0] q[1] q[2] s[0] s[1]
? ? ? ? ? 22 44 11 77 88
Prva je razlika u pisanju heksadecimalnih adresa, jer se eksplicitno navodi '0x', zatim se
primjeuje da adrese u memoriji nisu iste, kao u sluaju kad se program prevede s
Borland prevoditeljem, ali najbitnije je to je polje p smjeteno da adresi veoj od polja
q, pa se s adresom p[6] ne zahvaa element polja q, nego neki drugi sadraj.
121
Oznaka & koristi se i za dodjeljivanje sinonima pojedinoj varijabli ili reference. Ako se
na primjer napie
int& moj_brat = fred;
onda je varijabla moj_brat sinonim za varijablu fred. Tip int se odnosi na varijablu fred.
U programu se naziv fred ili moj_brat koriste ravnopravno. Identifikator moj_brat ne
zauzima nikakvo mjesto u memoriji, odnosno zauzima isto mjesto koje i varijabla fred.
Ovaj operator itamo kao vrijednost koju pokazuje i ima slijedee znaenje. Napiemo li
naredbu
int med=*ted;
andy
med
Dakle sadraj varijable ted je 1776, ali *ted upuuje na sadraj polja na adresi 1776, a
to je 25.
Ponovimo dakle:
med =ted ; // sadraj polja med je 1776
med=*ted; // sadraj polja med je 25
andy == 25
Primjer: Sve su izjave &andy == 1776
istinite ted == 1776
andy = 25;
*ted == 25
ted = &andy;
*ted == andy;
122
8.3. Uporaba pokazivaa
Pokazivai su varijable koje sadre adresu drugih varijabli. Deklaracija pokazivaa ima
oblik
tip * ime_pokazivaa;
pri emu tip pokazuje na tip varijable (int, char, float) iju adresu pokaziva treba
prikazivati, dakle ne govori o tipu pokazivaa nego o tipu varijable koju on pokazuje. U
tom kontekstu zvjezdicu * treba shvatiti samo kao 'ovo je pokaziva' i ne treba je
mijeati s operatorom dereference.
Slijedei primjer ilustrira upotrebu pokazivaa:
Primjer8.3:
1. // primjer rada pokazivaima
2. #include <iostream.h> broj1 = 10 broj2 = 20
3. int main ()
4. {
5. int broj1 = 5, broj2 = 15;
6. int * pokazivac;
7. pokazivac = &broj1; // pokazivac sadri adresu od broj1
8. *pokazivac = 10; // na adresu broj1 staviti 10
9. pokazivac = &broj2; // piokazivac sadri adresu od broj2
10. *pokazivac = 20; // na adresu broj2 staviti 20
11. cout << "broj1=" << broj1 << "/broj2=" << broj2;
12. return 0;
13. }
Dakle pomou pokazivaa je izmjenjen sadraj varijabli broj1 i broj2, bez da se navode
nazivi dotinih varijabli. Slijedi jo jedan primjer rada s pokazivaima:
Primjer8.4:
1. // Primjer rada s pokazivaima
2. #include <iostream>
3. using namespace std;
4. int main()
5. {
6. int* ted, andy; &ted: 0x22ff74 9
7. ted=&andy; ted: 0x22ff70 10
8. andy=777; *ted: 777 11
9. cout<< "&ted: "<<&ted<<endl; andy: 777 12
10. cout << "ted: " <<ted << endl; andy: 555 14
11. cout << "*ted: " <<*ted<<endl; Press any key to continue . . .
12. cout << "andy: " << andy<<endl;
13. *ted=555;
14. cout << "andy: " << andy<<endl;
15. return 0;
16. }
123
U prethodnom je primjeru varijabla ted pokaziva, dok je andy obina varijabla tipa
int. Vidi se da je pokaziva ted (0x22ff74) smjeten neposredno nakon varijable andy
(0x22ff70). S obzirom da pokaziva ted sadri adresu od andy, vrijednosti *ted i andy su
identine.
*ted treba itati kao 'sadraj
Primjer8.5: polja na adresi ted '.
1. // primjer rada s pokazivaima
2. #include <iostream.h>
6. int main ()
7. {
8. p1=&m;
9. p2=&n;
11. *p2+=7;
12
12. cout<<endl; p1=0x43f000 13
*p1=15 m=15 14
13. cout<<"p1=" <<p1<<endl; p2=0x43f004 15
*p2=27 n=27 16
14. cout<<"*p1="<<*p1<<" m="<<m<<endl; povecavam p1 za 1 0x43f004 18
p2 bi trebao biti p1+1 0x43f008 20
15. cout<<"p2="<<p2<<endl; povecani p2=0x43f00c 22
a sto je tu ? 0 23
16. cout<<"*p2="<<*p2<<" n="<<n<<endl; Press any key to continue
17. p1++;
19. p2=p1+1;
124
21. p2++;
24. return 0;
25. }
Primjer8.6:
1. // primjer koritenja pokazivaa n = 44 5
&n = 0x22ff74 6
2. #include <iostream.h> pn = 0x22ff74 8
&pn = 0x22ff70 9
3. int main (){ *pn = 44 10
ppn = 0x22ff70 12
4. int n =44; &ppn = 0x22ff6c 13
*ppn = 0x22ff74 14
5. cout <<" n = " << n <<endl; **ppn = 44 15
Press any key to continue
125
6. cout <<" &n = " << &n <<endl;
16. system("PAUSE");
17. return 0;
18. }
126
pn=&n;
*ppn ppn=&pn;
ppn 0x22ff6c
Primjer8.7:
1. // odnos pokazivaa i polja
2. #include <iostream>
5. int brojevi[5];
9. p[1] = 20;
127
14. cout << brojevi[n] << ", ";
15. cout<<endl;
16. cout<<brojevi<<","<<brojevi+1<<","<<brojevi+2<<endl;
17. system("PAUSE");
18. return 0;
19. }
U primjeru 8.7. je naredbom 5. deklarirano polje brojevi koje ima 5 elemenata tipa int. U
naredbi 6. je deklariran pokaziva p za varijable tipa int. Naredba 7. je neuobiajena, jer
bi se oekivalo da pie p =&brojevi; Naime, kada varijabla brojevi ne bi bila polje (array)
prevoditelj bi javio greku. Naziv polja je u sutini pokaziva koji sadri adresu
prvog elementa u polju. Zbog toga se naredbom 8 u prvi element polja brojevi unosi
10. Iz slijedeih se naredbi (9,10,11 i 12) vidi da se varijabli p moe dodijeliti i indeks,
odnosno da se dodavanjem razliitih konstanti varijabli brojevi zapravo poveava adresa,
tj. dohvaaju se odgovarajui elementi polja. Ispis naredbom 16 pokazuje da se varijabla
naziva polja ponaa poput pokazivaa i kod raunskih operacija, tj. da se dodavanjem 1
ili 2 zapravo dodaju viekratnici duljine elemenata polja.
128
int x;
float* p;
u memoriji se rezervira mjesto za taj pokaziva, ali taj pokaziva ne pokazuje na neku
varijablu u memoriji tj. sadraj pokazivaa nije predvidljiv.
javio bi greku jer pokaziva ne pokazuje na nikakvu memoriju. Zbog toga je dobro
inicirati pokaziva prilikom deklaracije kao na primjer:
float* p=&x;
float* q;
q = new float;
*q =3.14159;
129
Operator new omoguava da memorija za pokaziva q alocira za vrijeme izvoenja
programa umjesto za vrijeme prevoenja. Naredbom q = new float; su se u memoriji
(zapravo u hrpi) zauzela 4 bajta za float varijablu, tako to je pokazivau q pridruena
odgovarajua adresa. Programera se u naelu ne tie koja je to adresa, mada je moe
doznati ispisivanjem sadraja pokazivaa q. Nakon toga je u odgovarajue float polje
unesen sadraj s naredbom : *q =3.14159;
Kada se se navedeno polje eli osloboditi za druge potrebe, ono se oslobaa s naredbom r
delete .
delete q;
delete pok;
Primjer8.8.
1. // primjer za dinamiko alociranje memorije
2. #include <iostream>
5. int * p1;
130
6. int * p;
9. cout<<"p = "<<p<<endl;
&p = 0x22ff70 &p1= 0x22ff74 8
10. *p = 10; p = 0x3d24d0 9
10, 19
11. p[1]= 20; 20, 19
30, 19
12. p[4]=50; 40, 19
50, 19
13. p=p+2; // preskace se p[1] p1= 0x3d2468, *p1= 19 23
1718356 26
14. *p=30; Press any key to continue . . .
15. p++;
16. *p=40;
17. p=p-3;
20. delete p;
22. *p1=19
24.
25. int a;
27. cout<<a<<endl;
28. system("PAUSE");
131
29. return 0;
30. }
Polja (arrays) mogu zauzimati puno mjesta u memoriji. Zbog toga ih je esto bolje
spremiti u hrpi, kako bi se memorija zauzela samo i tijeku izvoenja dijela programa koji
koristi navedena polja. Dakle ako se polje deklarira kao:
int * poktablice;
poktablice = new int[10] // tablica se smjeta u hrpu
poktablica [0]= 235; // prvi element tablice dobiva vrijednost 235
Uoiti razliku !
float pok*= &x;
*pok=10.234;
132
Kada se radi s pokazivaem na obinu varijablu mora se staviti *, a kod polja ne
Primjer8.9:
1. // primjer za dinamiko alociranje polja
2. #include <iostream>
6. cin>>n;
7. a=new double[n];
10. }
18. int n;
21. delete [] p;
22. system("PAUSE");
23. return 0;
24. }
134
Prijenos parametara po vrijednosti
int a, b, suma;
suma=zbroj (a,b);
int zbroj (int &x, int &y) { int zbroj (int *x, int *y) {
return x+y; } return *x+*y; }
.... ....
135
9. Ulazno izlazni tokovi
Umjesto ulazno izlaznih naredbi C++ koristi razrede8 koji su pohranjeni u standardnim
bibliotekama, kao na primjer iostream, koji omoguuju razliite ulazno izlazne operacije.
Prije pojanjenja samih ulazno izlaznih tokova neophodno je pojasniti neke osnovne
pojmove. Prvi je postupak meupohranjivanja podataka ili engleski buffering. Dva su
osnovna razloga zbog kojeg je uveden ovaj koncept prijenosa podataka. Prvi je u brzini
centralne jedinice u kojoj je brzina pristupa do pojedinog podatka reda veliine tisuu ili
vie puta vea nego kod najbrih vanjjskih jedinica kao to je magnetni disk. Drugi je
razlog u nainu pohranjvanja podataka na vanjskim jedinicama. Mali fiziki slogovi u
pravilu slabo iskoritavaju kapacitete vanjskih jedinica, pa se nekoliko slogova 'pakira' u
vee fiziki slog.
Pod pojmom blok, ili fiziki slog, se podrazumijeva odreeni broj logikih slogova koji
se sastoje od polja (field). Ti se blokovi spremaju (izmeu dva fizika prijenosa
podataka) u meuspremnik (buffer). Kod pisanja datoteke operativni sustav eka da se
taj meuspremnik napuni, kako bi se cijeli sadraj prenijeo na izlaznu jedinicu. Ovo
pranjenje meuspremnika se izvrava automatski i programer o tome ne mora voditi
rauna. Meutim, broj podataka ne mora biti viekratnik kapaciteta meuspremnika, pa
bi posljednji podaci kod zavretka programa, bez naknadne intervencije mogli ostati u
meuspremniku, ekajui da se ovaj popuni. Da bi se i ti podaci ispisali neophodno je
prisilno isprazniti meuspremnik (flush-isplahnuti). To se u pravilu ini automatski
prilikom zatvaranja toka, ali je ponekad, kada program prekine s radom na nepredvieni
nain, neophodno da to uini programer.
Kod itanja se u meuspremnik uita itav fiziki slog, koji se nakon toga prenosi u
memoriju programa slog po slog (kakav je deklariran u programu) u ulazno polje
definirano programom.
Za ulaz i izlaz podataka u C++ koriste se polja iz standardnog razreda string.
8
O razredima e biti govora kasnije. Za sada treba znati da je razred posebno definiran skup varijabli i
funkcija koje koriste te varijable koji se prema okolini ponaa kao zarvoreni objekt sa sueljem za
komunikaciju. Sutina U/I tokova je pojanjena bez oslanjanja na razrede.
136
9.1.Standardni razred string
Primjer9.1:
1. // Primjer rada s nizovima razreda string
2. #include <iostream>
3. #include <string> // mora se razred ukljuiti u program
4. using namespace std;
5. int main()
6. {
7. string S1;
8. string S2("Bog !");
9. string S3("To sam ja "); // stringovi S2 i S3 su inicirani kao i C-nizovi
10. string S4(S3);
11. // S4 je inicijaliziran s pomou drugog string objekta S3
12. S2: Bog ! 13
13. cout << "S2: " << S2 << endl; S3: To sam ja 14
14. cout << "S3: " << S3 << endl; S4: To sam ja 15
15. cout << "S4: " << S4 << endl; S1: Bog ! 19
16. S1: To sam ja 23
17. S1 = S2; // preoptereeni operator pridruivanja Press any key to continue . . .
18. // Pridruivanje jednog niza drugome
19. cout << "S1: " << S1 << endl;
20.
21. S1 = S3;
22. // S1 se sam podesio na potrebnu veliinu.
23. cout << "S1: " << S1 << endl;
24. system("PAUSE");
25. return 0;
26. }
U primjeru 9.1. deklarirana su 4 stringa S1, S2, S3 i S4 koji su tipa C++ od kojih S1
nema poetnu vrijednost, S2 i S3 su inicirani kao stringovi tipa C navodei niz karaktera
u navodnicima, dok je S4 iniciran pomou niza S3 to je mogunost koju nude C++
137
stringovi (naredbe 7-10). U naredbama 13-15 su ispisani sadraji tih stringova. Naredba
17. pokazuje da se C++ stringovi mogu pridruivati jedan drugome poput obinih
varijabli, pomou preoptereenog operatora pridruivanja. Isti je sluaj ponovljen u
naredbi 21, kada je S1 koji nije iniciran, pa nije mogao dobiti nikakvu duljinu, automatski
podesio svoju duljinu na duljinu niza S3 iji mu je sadraj pridruen.
Slijedei primjer ilustrira dodatne mogunosti rada s razredom string:
Primjer9.2:
1. // Primjer rada s razredom string dodatne mogunosti
2. #include <iostream>
3. #include <string>
5. int main()
6. {
7. string S1;
9. string S3("Mene");
11. if (S1.empty()) {
14. }
15. else
17. }
19. cout << "S1 ima sada duljinu " << S1.size() << endl;
138
20. if (S3 < S1) // Usporedna relacija-preoptereena
35. system("PAUSE");
36. return 0;
37. }
139
Nakon to se je u naredbi 7. deklarirao string S1 bez zadavanja poetne vrijednosti, u
naredbi 11 ispituje se da li je niz prazan. Oznaka S1.empty() treba samo shvatiti da se
ispituje S1, jer funkcija empty se odnosi openito na sve objekte na razreda string, oznaka
S1. specificira koji se objekt ispituje. Iz injenice da su se naredbe 12 i 13 izvodile to se
vidi iz ispisa, zakljuuje se da je uvjet S1.empty() bi zadovoljen.
U naredbi 18 je u S1 prenesen sadraj 'Pozdrav ' ukljuivi i prazno mjesto (blank) na
kraju, pa se iz ispisa u naredbi 19 vidi da je duljina S1 postala jednaka 8.
Poevi od naredbe 20 pa do 26 ilustrira se rad sa preotptereenim operatorima koji
omoguuju da se sa objektima tipa string radi kao s obinim varijablama.
U naredbi 20 usporeuju se stringovi S1 i S3. S obzirom da je u tom trenutku sadraj
stringa S1 jednak 'Pozdrav ak kojim sluajem ' a stringa S3 je ' Mene' zadovoljen je uvjet
S3<S1 jer je u ASCII tablici u prilogu A na kraju teksta znak M ispred znaka P. Zbog toga
je program i izvodio naredbu 21. Da su stringovi S1 i S3 imali na prvom mjestu isti znak,
usporeivao bi se slijedei itd. U naredbi 22 vidi se da se stringovi mogu 'zbrajati'. Ovo
se 'zbrajanje' zove konkatenacija (ulanavanje) a radi kao da se jedan string 'zalijepi' na
kraj prethodnog.
Rezultat se vidi u ispisu iz naredbe 23. Naredbe 24. 25 i ispis 26. takoer ilustriraju
mogunost konkatenacije. Konano naredbe od 28 do 34 pokazuju kako se pomou
ideksa mogu ispisivati podnizovi (ili im pristupiti). Objekti razreda string koriste se u
ulazno/izlaznim tokovima.
Ve je opisano kako se tokovi cin i cout koriste za rad s konzolom, odnosno ispisivanje
podataka na ekranu i upisivanje putem tipkovnice. U jeziku C++ su ulazno izlazni
tokovi rijeeni na nain da budu neovisni od tipa ulazno izlazne jedinice.
140
ios_base
ios
/\
/ \
/ \
istream ostream
/ | \ / | \
/ | | | \
/ / | \ \
/ / | \ \
/ / | \ \
istring ifstream iostream ofstream ostring
stream /\ stream
/ \
fstream stringstrea
Za dosege ove knjige dovoljno je znati da se razred ofstream koristi kada se eli pisati
podatke, dakle radi se s izlaznom datotekom, razred ifstream kada se podaci ele itati,tj.
kada se radi s ulaznom datotekom. Razred fstream se koristi kad se eli itati i pisati
podatke, odnosno aurirati datoteku.
Primjer9.3:
1. // primjer za kreiranje datoteke
5. int main(){
6. ofstream mojFile("primj1.txt");
10. { cout << " Greska u otvaranju izlazne datoteke" << endl;
141
12. char ch; // Ovo je polje za uitavanje elemenata stringa
13. // slijedi naredba za ispisivanje stringa, vidi se da umjesto cout stoji naziv datoteke
14. mojFile << "Evo malo mojeg niza podataka" << endl;
15. mojFile.close();
16. // Otvara istu datoteku kao input radi itanja i ispisivanja sadraja
19. {cout << " Nije otvorena ulazna datoteka"<< endl; return -1; }
20. while (mojFilei.get (ch)) cout<<ch;// opet se koristi cout za pisanje na ekran
21. system("PAUSE");
22. return 0;
23. }
Vid se da operator izluivanja >> preskae prazna polja. Naime, ne moe biti problem
u naredbi cout jer je ona ostala ista.
Izlazna datoteka mojFile otvorena je u naredbi 6. Postoje dva naina (mode) obrade
output datoteke truncated i append. Truncated znai da e nailaskom na otvorenu
142
datoteku u kojoj ve postoje neki podaci, oni biti izbrisani, a append da e se novi podaci
dodati iza postojeih. Ako se nita ne navede podrazumijeva se truncated.
Slog 'Evo malo mojeg niza podataka' je upisan u datoteku naredbom 14. Nakon toga
datoteka je naredbom 15 zatvorena. Naredbom 17 se ponovo otvara ista datoteka, ali ovaj
put kao ulazna. Vidi se da joj je u programu dano novo ime mojFilei (i na kraju) kako bi
je program prevoditelj razlikovao od prethodne.
Naredba 20. while (mojFilei.get (ch)) uitava podatke iz datoteke (bajt po bajt) i
pohranjuje u polje ch kojeg zatim naredba cout ispisuje. Ova se naredba ponavlja dok je
ispunjen uvjet da je mojFilei.get (ch) istinit ( true,) dakle do uitavanja kraja datoteke.
Kada se uita kraj datoteke, prestaju se izvoditit naredbe iz petlja while, tj. program ide
na naredbu system("PAUSE"); te na kraj programa.
Prilikom deklaracije datoteke nekad treba navesti i argumente tzv. mode, koji opisuje
nain pristupa podacima, kao n primjer:
ofstream mojFile("NekoImeDatoteke");
ofstream mojFile("NekoImeDatoteke",ios::out);
ofstream mojFile("NekoImeDatoteke",ios::out | ios::trunc);
U konkretnom sluaju sve tri deklaracije imaju isti uinak jer su out i trunc
podrazumijevani modovi za ofstream datoteku.
143
Tablica 9.1. Argumenti (mode) datoteka
Mode Znaenje
out Otvara se file ili stream za izlaz (default za ofstream datoteku)
in Otvara se file ili stream za ulaz ( default za ifstream datoteku)
app Svako insertiranje bit e ispisano iza postojeih podataka
trunc Izbrisati e postojee podatke (default )
ate Otvara datoteku i pozicionira se na kraj.
Podatke tretira binarno umjesto kao tekst. Na primjer float varijabla e se
binary
pohraniti u svom standardnom obliku od 4 bajta, a ne kao niz.
Neki operacijski sustavi pored tekstualnih, podravaju i binarne datoteke. U tablici 9.2.je
prikazana usporedba ovih dviju vrsta datoteka.
144
Primjer9.4:
1. // Primjer pisanja teksta u datoteku
2. #include <iostream> // za cout
3. #include <fstream>
4. using namespace std;
5. int main () {
6. ofstream primjerfile ("primjer9_4.txt"); // otvara se izlazna datoteka
7. if (primjerfile.is_open()) // ispituje se da li je datoteka otvorena
8. {
9. primjerfile << "To je prvi red.\n"; // ispisuju se redom 1. 2. i 3. red
10. primjerfile << "A ovo je drugi red.\n";
11. primjerfile << "Ne bi se reklo, ali sad su tri.\n";
12. primjerfile.close();
13. }
14. cout<<"Eto ja zavrsih"<<endl;
15. system("PAUSE");
16. return 0;
17. }
Eto ja zavrsih
Press any key to continue . . .
Gledajui na logiku primjer 9_4 ima nedostatak to u sluaju da datoteka nije otvorena
on e zavriti na potpuno isti nain, osim to nee ispisdati datoteku na disk. To se moe
provjeriti pretraivanjem i isitavajem datoteke 'primjer9_4' na lokalnom disku C u
folderu Borland\Bcc55\Bin gdje je upisana datoteka slijedeeg sadraja:
To je prvi red.
A ovo je drugi red.
Ne bi se reklo, ali sad su tri.
145
Slijedei program dodaje jedan slog na kraju datoteke 'primjer9_4.txt' iz prethodnog
primjera:
Primjer9.5:
1. // Primjer pisanja tekst file kojemu se dodaje sadraj na kraju
2. #include <fstream>
4. int main () {
7. {
9. primjerfile.close();
10. }
11. return 0;
12. }
Primjer9.6
1. // Citanje i ispis text file
2. #include <iostream>
3. #include <fstream>
4. using namespace std;
5. int main () {
6. char buffer[256];
146
7. ifstream primjerfile ("primjer9_4.txt");
8. if (! primjerfile.good())
9. { cout << "Greka u otvaranju datoteke"; exit (1); }
10. while (! primjerfile.eof())
To je prvi red. 13
11. {
A ovo je drugi red. 13
12. primjerfile.getline (buffer,100);
Ne bi se reklo, ali sad su tri. 13
13. cout << buffer << endl;
Je li to sad cetvrti red ? 13
14. }
Press any key to continue . . .
15. system("PAUSE");
16. return 0;
17. }
Kod ispitivanja stanja datoteka koriteni su izrazi good i eof. Postoje 4 funkcijska lana
tipa bool za oitavanjanja stanja
eof () vraa true ako je uitan znak za kraj datoteke (end of file)
bad () vraa true ako operacija nije uspjela zbog nepopravljivih greaka
fail () vraa true ako operacija nije uspjela zbog bilo kojeg razloga
good() vraa true, ako ni jedna prethodna nije true tj. operacija je uspjeno izvedena
147
U nastavku je prikazan program koji uitava taj tekst te broji broj znakova, broj praznih
mjesta (ili rjei) i broj reenica u njemu (otprilike kao to u MS Wordu radi Word
Count).
Primjer 9_7:
1. // Program koji ita tekst u broji znakove, rijei i reenice
2. #include <iostream>
3. #include <fstream>
4. using namespace std;
5. int main()
6. {
7. int blankbroj = 0; // broja praznih polja
8. int charbroj = 0; // broja znakova
9. int recenbroj = 0; // broja reenica
10. char ch;
11. ifstream iFile("tekst1.txt");
12. if (! iFile) // provjera da je datoteka otvorena
13. {
14. cout << " Greka u otvaranju ulazne datoteke" << endl;
15. return -1;
16. }
17. while (iFile.get(ch))
18. {
19. switch (ch) {
20. case ' ': // ako je blank poveaj broja za 1
21. blankbroj++;
22. break;
23. case '\n': break;
24. case '\t': break;
25. case '.': // Ako je toka dri da je to kraj reenice
26. recenbroj++;
27. break;
28. default: // ako nije nita od navedenog, to je karakter koji se broji.
29. charbroj++;
30. break;
31. }
32. }
33.
34. cout << "Ima " << blankbroj << " praznih mjesta" << endl;
35. cout << "Ima " << charbroj << " znakova" << endl;
36. cout << "Ima " << recenbroj << " recenica" << endl;
37. system("PAUSE");
38. return 0;
39. }
148
Ima 70 praznih mjesta 34
Ima 405 znakova 35
Ima 3 recenica 36
Press any key to continue . . .
Slijedi jo jedan primjer programa, koji ita sadraj jedne datoteke i pie ga u drugu.
Specifinost je ovog programa da moe posluiti za prijepis bilo koje datoteke, jer se
naziv datoteka definira u fazi izvoenja programa.
Primjer9.8
1. // Primjer opeg programa za prijepis datoteka
2. #include <iostream>
3. #include <fstream>
4. #include <string>
5. using namespace std;
6. int main(){
7. char ch;
8. string Ulazna;
9. string Izlazna;
10. cout << "Upisi naziv ulazne datoteke: ";
11. cin >> Ulazna;
12. cout << "Upisi naziv izlazne datoteke: ";
13. cin >> Izlazna;
14. cout<<"pocinje otvaranje"<<endl ;
15. ifstream iFile (Ulazna.c_str()); // Nazivi iFile i oFile su po izboru programera
16. ofstream oFile (Izlazna.c_str());
17. if (! iFile.good()) { cout<<"Greska u otvaranju ulazne datoteke"<<endl;
18. return -1; }
19. if (! oFile) { cout<<"Greska u otvaranju izlazne datoteke"<<endl;
20. //sa ili bez good() uinak je isti
21. return -1; }
22. while (! iFile.eof()){
23. iFile.get(ch);
24. oFile.put(ch);
25. cout<< ch; // samo da se vidi sto je prepisano
26. }
27.nazivsystem("PAUSE");
Upisi ulazne datoteke: tekst1.txt 10,11
28.naziv izlazne
Upisi return datoteke:
0; tekst2.txt 12,13
pocinje
29. }otvaranje 14
Za razliku od drugih programskih jezika C++ nema definirane naredbe za uitavan 25
je i ispis
Izlaz podataka. na
iz programa Naekranu,
taj se je nain
bio jehtjelo poveati fleksibilnost programsko
slijedei: 25
g jezika, jer programski jezici koji imaju takve naredbe su ogranieni na pojed 25
ine tipove ulazno izlaznih jedinica i organizacije podataka. 25
Umjesto ulazno izlaznih naredbi C++ koristi razrede koji su pohranjeni u standar 25
dnim bibliotekama, kao na primjer iostream, koji omoguuju razliite ulazno izl 25
azne operacije.\n 25
Press any key to continue . . . 149
Provjere radi moe se pogledati sadraj datoteke..\..\..\Borland\BCC55\Bin\tekst2.txt.
Razlika je u tome to operator izluivanja (extraction operator) '>>' isto kao i cin
odbacuju prazna polja.
150
7. char ocj;
8. ofstream stdev ("studenti.txt",ios::app);// u datoteku se mogu dodavati
slogovi
9. if (!stdev.is_open())
10. { cout<<"Greska u otvaraju datoteke "; exit (1);
11. }
12. cout<<"Upisi maticni broj student do 5 znamenaka, 99999 za kraj "<<endl;
13. cin>>mbr;
14. while (mbr!="99999") {
15. if (mbr!=stmbr) {
16. cout<<"Upisi ime te prezime studenta"<<endl;
17. cin>>ime>>prez;
18. stmbr=mbr; }
19. cout<<"Upisi sifru predmeta i ocjenu"<<endl;
20. cin>>pred>>ocj;
21. stdev <<setw(5)<<mbr<< setw(10)<<ime<<setw(15)<< prez<<
22. setw(3)<<pred<<ocj<<endl;
23. cout<<"Upisi maticni broj studenta, 99999 za kraj "<<endl;
24. cin>>mbr;
25. }
26. stdev.close();
27. system("PAUSE");
28. return 0;}
151
U nastavku je ispis s konzole za Primjer9.9.
Upisi maticni broj student do 5 znamenaka, 99999 za kraj 12
11111 13
Upisi ime te prezime studenta 16
Tone Tomac 17
Upisi sifru predmeta i ocjenu 19
p01 4 20
Upisi maticni broj studenta, 99999 za kraj 23
11111 24
Upisi sifru predmeta i ocjenu 19
p02 20
3 20
Upisi maticni broj studenta, 99999 za kraj 23
11111 24
Upisi sifru predmeta i ocjenu 19
p03 3 20
Upisi maticni broj studenta, 99999 za kraj 23
22222 24
Upisi ime te prezime studenta 16
Nina Mala 17
Upisi sifru predmeta i ocjenu 19
p01 5 20
Upisi maticni broj studenta, 99999 za kraj 23
22222 24
Upisi sifru predmeta i ocjenu 19
p02 4 20
Upisi maticni broj studenta, 99999 za kraj 23
99999 24
Press any key to continue . . .
152
scientific eksponencijalni prikaz brojeva
Primjer9.10:
1. /* Ovaj program ilustrira upotrebu manipulatora */
2. #include <iostream> To je x 128.457 8
3. #include <iomanip> xxxxoooooooooxoooo 9
4. using namespace std; 1. 128.4567- 13
5. int main() 2. 128.4567- 14
3. 128.4567- 15
6. {
4. 128.46 - 16
7. float x=128.4567; Press any key to continue . . .
8. cout<<"To je x "<<x<<endl;
9. cout<<"xxxxoooooooooxoooo"<<endl; // za brojanje mjesta na listi
10. cout<<fixed<<showpoint;//ova je neophodno za aktiviranje setprecision
11. // fixed aktivira prikaz brojki u obliku fiksnog zareza npr.12,34
12. // showpoint aktivira prikaz decimalne toke
13. cout<<"1. "<<setprecision(4)<<setw(12)<<x<<"-"<<endl;
14. cout<<"2. "<< x<<"-"<<endl;
15. cout<<"3. "<<setw(10)<<x<<"-"<<endl;
16. cout<<"4. "<<setprecision(2)<<setw(10)<<left<<x<<"-"<<endl;
17. return 0;
18. }
153
10. Koncept objektno orijentiranog programiranja
(Object-oriented Programming)
Tablica 10.1: Relativni trokovi otklanjanja greke u raznim fazama razvoja softvera
Relativni troak
Faza razvoja
otklanjanja
aplikacije
greke
Definiranje problema
(specifikacija 0.1 -- 0.2
zahtjeva)
Opis algoritma
0.5
-Modeliranje
Kodiranje 1
Pojedinano
2
testiranje programa
Testiranje cijele
5
aplikacije
Odravanje 20
Dakle, troak otklanjanja greaka u fazi odravanja aplikacije je 20 puta vei od troka
otklanjanja iste greke u fazi kodiranja. U fazi odravanja programa se 'ispravci'
programa ne rade samo zbog naknadno otkrivenih greaka. Neke promjene u programu
nastaju kao rezultat objektivnih promjena u realnom svijetu. To su na primjer promjene
zakona koji imaju utjecaja na nain voenja knjigovodstva, obrauna poreza itd. Razvoj
znanosti i tehnologije takoer mogu nametnuti neka nova rjeenja 'starih' problema itd.
Tako su se u tijeku razvoja tehnika programiranja prolo kroz slijedee 4 razvojne faze:
Nestrukturirano programiranje
Proceduralno programiranje
Modularno programiranje
Objektno orijentirano programiranje
9
A.M. Davis. Software Requirements, Analysis and Specification. Prentice-Hall, 1990.
154
10.1. Nestrukturirano programiranje
int main () {
gr0: int indgr= 0; // indikator grananja koji pokazuje odakle smo doli
.. // ostale naredbe u programu
..
goto kor; // neka je niz naredbi za izraun korijena identificiran s oznakom kor
..
gr1: indgr=1;
.. // nastavak naredbi
..
..
goto kor;
..
gr2: indgr=2;
.. // nastavak naredbi
..
goto kraj; // zato da se preskoi sekvencijlni izraun korijena
155
kor: // slijede naredbe za izraun korijena
..
..
if (indgr==0) goto gr0; // vraa se odakle je doao
if (indgr==1) goto gr1;
if (indgr==2) goto gr2;
if (indgr<0 || indgr>2) cout<< '' Odakle si stigao? ''<<endl;
kraj: return 0;
}
Zbog toga se ubrzo rodila ideja da se takav niz naredbi 'izvue' iz programa u posebne
procedure. Te su procedure poput dananjih funkcija izraerne tako da se prilikom
njihovog poziva automatski pohranjivala adresa povratka, koja pokazuje na naredbu
neposredno iza one kojom je dotina procedura (ili funkcija) pozvana. Tako je stvoren
koncept proceduralnog programiranja.
156
glavni program treba nastaviti izvoenje nakon to je procedura zavrila s radom. U
pravilu je to prva naredba koja slijedi iza naredbe kojom je pozvana procedura. Adrese
grananja i popvratka su u pravilu pohranjene u posebnim pokazivaima.
Na taj su se nain stvorili uvjeti da se sloeni program 'razgradi' na manje jednostavne
procedure ili potprograme iju logiku nije teko pratiti. Glavni program na taj nain
postaje bitno manjeg opsega, a zbog jednostavnosti naina poziva potprograma i povrata
kontrole izvoenja na glavni program, nije teko pratiti logiku njegovog izvoenja.
To se moe ilustrirati na primjeru programa Primjer6.3 za sortiranje (Buble sort):
#include <iostream.h>
void print (float [ ], int); // funkcija koja ispisuje polje
void sort (float [ ], int); // funkcija koja sortira elemente polja
void swap (float&, float&); // funkcija koja zamjenjuje vrijednost dviju varijabli
int main () {
float a[ ] ={55.5, 22.5, 99.9, 66.6, 44.4, 88.8, 33.3, 77.7};
print (a,8);
sort (a,8);
print (a,8);
}
Glavni program ima u sutini samo tri izvrne naredbe: ispisivanje tablice prije sortiranja,
sortiranje i ponovno ispisivanje.
Glavni program
Podaci
157
10.3. Modularno programiranje
Glavni program
Podaci
Modul 2
Modul 1
Podaci + podaci2
Podaci +podaci
1
Svaki modul moe sadravati vlastite podatke. Ti podaci omoguuju, da modul ima
odgovarajue stanje, koje se pozivom procedura moe modificirati.
158
10.4. Objektno orijentirano programiranje
Objekt
Objekt11 Objekt
Objekt44
Podaci
Podaci Podaci
Podaci
Objekt
Objekt33
Objekt
Objekt22 Podaci
Podaci
Podaci
Podaci
Iako ovo slii na malo bolje modularno programiranje, to ipak nije sluaj. Pored ovog
opisa objektno orijentirano programiranje mora zadovoljavati i niz drugih svojstava, kao
to su:
159
Za primjenu naela OOP (Objektno Orjentiranog Programiranja) u C++ jeziku
neophodno je uvesti pojam razreda (class).
dozvola pristupa-1:
lanovi_1;
....
Razredom se definira struktura objekta, dok se stvarni objekt definira njegovim nazivom,
koji moe biti naveden u samoj definiciji razreda ili posebnom naredbom.
Odnos iz meu razreda i objekta je isti kao odnos tipa varijable i same varijable. Na
primjer:
float broj;
class vektor {
public:
float ax, ay;
} vektor1;
160
Ovom se naredbom definira razred vektor koji sadri dva realna broja, koji predstavljaju
komponente vektora u ravnini. Razred vektor u ovom sluaju predstavlja tip podatka po
analogiji sa float iz prethodne deklaracije. Varijabla vektor1 pak predstavlja objekt po
analogiji s varijablom broj. Nakon to je u programu definiran razred vektor kao u
gornjem primjeru,objekt se moe i naknadno deklariratit:
vektor vektor2;
Nakon ovako definiranog razreda vektor, mogu se definirati i drugi objekti, na primjer:
Na taj smo nain definirali dva nova objekta sila i brzina koji pripadaju razredu vektor.
Deklaracijom razreda u programu, opisuje se samo novi tip varijabli, tj. njihova
struktura, dozvola pristupa i po potrebi funkcije za operacije meu njima i ne
zauzima se mjesto u memoriji.
Deklaraciju razreda treba shvatiti kao poopenje pojma tipa varijable (int, float) za koje
ne treba u programu nita dodatno navoditi jer su svojstva tih varijabli ve 'ugraena' u
C++. Na primjer ako se neka varijabla deklarira kao int, onda joj C++ dodijeli 4 bajta u
memoriji i interpretira kao cijeli broj. Razred je poopenje pojma tip, koji omoguuje
korisniku da definira nove tipove varijabli kojima dodjeljuje i neke funkcije.
Primjer razreda ilustrirat e se na primjeru razreda vektor kojim emo u C++ uvesti
elemente vektorske algebre.
161
Podsjetimo se:
Vektor se u ravnini prikazuje kao zbroj dva realna broja koji predstavljaju njegove
projekcije na koordinatne osi x i y:
a=ax+ay
5*a= 5*ax+5*ay
Zbroj dva vektora a=ax+ay i b=bx+by definiran je kao a+b = (ax+bx ) +(ay+by)
Skalarni vektora a=ax+ay i b=bx+by definiran je kao a*b = (ax*bx ) +(ay*by)
Kako je produkt jedininih vektora i*i odnosno j*j jednak 1, skalarni produkt vie nije
vektor nego skalar i otud mu i naziv.
class vektor {
public:
float ax, ay;
void mnoziskalarom (float skalar);
};
U ovoj je deklaraciji naveden samo prototip funkcije, tj. njen naziv i parametri, a opis
same funkcije bit e naveden kasnije. Funkcija je mogla biti opisana i unutar deklaracije
razreda, no ovo je odvajanje u skladu s uobiajenom praksom.
Nakon toga mnoenje konkretnog vektora, nazovimo ga (ax+bx ), sa skalarom, izvodi se:
vektor sila;
sila.mnoziskalarom(5.0);
162
Primjer 10.1:
1. // operacije s vektorima koritenjem razreda
2. #include <iostream.h>
3. class vektor {
4. public:
5. float ax, ay;
6. vektor zbrojvektora (vektor a, vektor b); // Opet se navode samo prototipovi
7. void mnoziskalarom (float skalar);
8. float skalprod (vektor a, vektor b);
9. };
10. // slijedi opis funkcije zbrajanja
11. vektor zbrojvektora (vektor a , vektor b) {
12. vektor c;
13. c.ax= a.ax + b.ax;
14. c.ay= a.ay + b.ay;
15. return c;
16. }
17. // slijedi opis skalarnog produkta
18. float skalprod (vektor a , vektor b) {
19. float c;
20. c= a.ax * b.ax+ a.ay * b.ay;
21. return c;
22. }
23. // slijedi mnoenje sa skalarom
24. void vektor::mnoziskalarom(float skalar){
25. ax *=skalar;
26. ay *=skalar;
27. }
163
28. // slijedi main program
29. int main() {
30. vektor v1, v2, v3;
31. char ch='a';
32. float m=0, skal;
33. while (ch!='k') {
34. cout<<" Ovo je program za raunanje s vektorima"<<endl;
35. cout<<" Ukucaj + ako eli zbrajati vektore"<<endl;
36. cout<<" * za mnoenje sa skalarom"<<endl;
37. cout<<" x za skalarni produkt vektora"<<endl;
38. cout<<" k za kraj"<<endl;
39. cin>>ch;
40. if (ch=='+'||ch=='x') {
41. cout<<" Unesi x i y komponentu 1. vektora " <<endl;
42. cin>>v1.ax>>v1.ay;
43. cout<<" Unesi x i y komponentu 2. vektora " <<endl;
44. cin>>v2.ax>>v2.ay;
45. if (ch=='+') {v3=zbrojvektora (v1,v2);
46. cout<<"v3= "<<v3.ax<<" + "<<v3.ay<<endl;
47. }
48. else {skal=skalprod (v1,v2);
49. cout <<''Skalarni produkt je ''<<skal<<endl;
50. }
51. }
52. if (ch=='*'){
53. cout<<" Unesi x i y komponentu vektora i skalar " <<endl;
54. cin>>v1.ax>>v1.ay>>m;
55. v1.mnoziskalarom(m);
56. cout<<"v1= "<<v1.ax<<" + "<<v1.ay<<endl;
57. }
58. }
59. return 0;
60. }
164
Primjer10.2:
1. // izraun povrine pravokutnika
2. #include <iostream.h>
3. class pravokutnik {
4. // Default dozvola pristupa je privat
5. int x, y;
6. public:
7. void zadaj_vrijednosti (int,int);
8. int povrsina (void) {return (x*y);}
9. };
10. void pravokutnik::zadaj_vrijednosti (int a, int b) {
11. x = a;
12. y = b; prvi= 12 17
13. } drugi= 30 19
14. int main () {
15. pravokutnik prvi, drugi;
16. prvi.zadaj_vrijednosti (3,4);
17. cout << "prvi= " << prvi.povrsina()<<endl;
18. drugi.zadaj_vrijednosti (5,6);
19. cout << "drugi= " << drugi.povrsina();
20. }
165
Primjer10.3:
1. // izraun povrine pravokutnika pomou pokazivaa this
2. #include <iostream.h>
3. class pravokutnik {
4. int a, b;
5. public:
6. void zadaj_vrijednosti (int,int);
7. int povrsina (void) {return (a*b);}
8. };
9. void pravokutnik::zadaj_vrijednosti (int a, int b) {
10. this->a = a;
11. this->b = b;
12. }
13. int main () {
14. pravokutnik prvi, drugi;
15. prvi.zadaj_vrijednosti (3,4);
16. cout << "prvi= " << prvi.povrsina()<<endl;
17. drugi.zadaj_vrijednosti (5,6);
18. cout << "drugi= " << drugi.povrsina();
19. }
Dozvolu pristupa u deklaraciji razreda moe biti: private:, public: ili protected.
private: odreuje da su lanovi koji slijede dostupni samo od lanova unutar istog
razreda ili prijateljskog razreda o emu e biti govora kasnije. Slino svojstvo ima i
oznaka protected:
public: lanovi su dostupni svugdje gdje je vidljiv sam razred. Varijable koje
predstavljaju suelje razreda, tj. preko kojih se komunicira s razredom imaju dozvolu
pristupa public.
166
10.6 . Konstruktor i destruktor
Dinamika alokacija memorije koristi se i kod razreda, o emu e biti rijei neto kasnije.
int main () {
pravokutnik prvi, drugi; 1. 2.
prvi.zadaj_vrijednosti (3,4);
cout << "prvi= " << prvi.povrsina()<<endl;
drugi.zadaj_vrijednosti (5,6); 1.
cout << "drugi= " << drugi.povrsina(); 2.
}
Naime deklaracijom razreda se opisuje samo 'tip varijable', a objekt (odnosno instanca ili
engleski instance) se stvara konkretnom deklaracijom objekta, u konkretnom sluaju
naredbom:
Radi izbjegavanja ovakvih problema razredi mogu ukljuiti specijalne funkcije koje se
nazivaju konstruktor i destruktor.
Konstruktor se poziva svaki put kada se formira novi objekt, a destruktor kada se taj
objekte eli izbrisati. Konstruktor omoguava da se s razredima postupa po istoj logici
kao i s varijablama, kada se na primjer navodi:
class pravokutnik {
int x, y;
public:
void zadaj_vrijednosti (int,int);
int povrsina (void) {return (x*y);}
};
Ako elimo u taj razred ukljuiti konstruktor on mora imati isto ime kao i razred i
koristi se za formiranje objekta, tj. za dodjeljivanje adrese u memoriji i davanja poetnih
vrijednosti varijablama. Jedan razred moe imati vie konstruktora.
167
Destruktor je funkcija koja poinje sa znakom ~ (tilda) i slijedi naziv razreda. Razred
moe imati samo jedan destruktor.
U nastavku je primjer konstruktora i destruktora za razred pravokutnik:
Primjer10.4:
1. // primjeri rada s razredima i konstruktorima
2. #include <iostream>
3. using namespace std;
4. class pravokutnik {
5. int x, y;
6. public:
7. pravokutnik(int, int); // ovo je konstruktor
8. ~pravokutnik (void); // ovo je destruktor
9. // slijede ostali podaci za razred
10. void zadaj_vrijednosti (int,int); // ona vienje neophodna
11. int povrsina (void) {return (x*y);}
12. } ;
13. // definicija konstruktora
14. pravokutnik::pravokutnik (int a, int b) {
15. x = a;
16. y = b;
17. }
18. // funkcija zadaj_vrijednost vie ne treba jer je to uinio konstruktor
19. // slijedi program
20. int main () {
21. pravokutnik prvi (3,4), drugi (5,6);
22. cout << "prvi= " << prvi.povrsina()<<endl;
23. cout << "drugi= " << drugi.povrsina()<<endl;
24. pravokutnik* treci;
25. treci = new pravokutnik (4,7);
26. cout <<"treci = " << treci->povrsina()<< endl;
27. cout <<&prvi <<" "<<&drugi<<" "<<treci;
28. }
prvi = 12 22
drugi = 30 23
treci = 28 26
0012FF5C 0012FF54 00913380 27
Objekti koji se koriste u programu mogu se smjestiti u stogu ili u hrpi. To ovisi o nainu
njihovog deklariranja.
168
Alokacija u stogu
pravokutnik prvi(3,4);
cout << "prvi= " << prvi.povrsina()<<endl;
Alokacija u hrpi
pravokutnik* treci;
treci=new pravokutnik(5,6);
cout << "treci = " << trecii->povrsina()<<endl;
169
konstruktor i destruktor, oni se stvaraju i pozivaju automatski. Slijedei primjer ilustrira
nain pozivanja konstruktora i destruktora:
Primjer10.6:
1. // Ovaj primjer ilustrira automatsko pozivanje konstruktora destruktora
2. class pravokutnik {
3. int x, y;
4. public:
5. // slijedii konstruktor
6. pravokutnik () {cout<< Objekt je roen<<endl;}
7. // slijedi destruktor
8. ~pravokutnik (void) {cout << Unitih ga<<endl;}
9. // definicija funkcije povrsina koja se u ovom primjeru ne koristi
10. int povrsina (void) {return (x*y);}
11. };
12. int main () { Objekt je roen 13,6
13. {pravokutnik x; // automatski se poziva konstruktor Sada x ivi 14
14. cout<< Sada x ivi<<endl; Unitih ga 15,8
15. } // automatski poziva destruktor Sada sam izmeu 16
16. cout <<Sada sam izmeu<<endl; Objekt je roen 17,6
17. {pravokutnik y; // opet poziva konstruktor Sada y ivi 18
18. cout<< Sada y ivi<<endl; Unitih ga 19,8
19. } // automatski poziva destruktor
20. }
Kada u programu ima potrebe da se pojedini objekt preslika (kopira) u drugi istog
sadraja, ako je u pitanju obina varijabla to se postie operarorom pridruivanja (na
primjer x=y;). Za kopiranje sadraja razreda postoje vie mogunosti.
Kod kopiranja objekata (razreda) koriste se pojmovi plitke (shallow) i duboke (deep)
kopije.
Plitka je kopija ona kod koje se preslikavaju samo vrijednosti elemenata objekta. Na
primjer, pokazivai se kopiraju, ali se ne kopiraju dijelovi dinamiki alocirane memorije
170
na koju su ti pokazivai usmjereni, to u nekim sluajevima moe stvarati probleme.
Takva se kopija dobija upotrebom operatora pridruivanja kao i za obine varijable.
Za duboku kopiju neophodan je konstruktor kopije (copy constructor), ali nije dovoljan.
Potrebno je ukljuiti destruktor i prenapregnuti operator pridruivanja koji kopira
dinamiki alociranu memoriju.
Taj se konstruktor razlikuje od ostalih po tome to ima samo jedan parametar i to
referencu na konstantni objekt istog razreda.
171
Na slijedeoj je slici prikazano hijerarhijsko stablo grafikih elemenata.
Grafobjekt
Krug Pravokutnik
Na vrhu stabla postoje neka zajednika svojstva svih elemenata a na niim razinama
postoje specifina svojstva.
class Grafobjekt {
private:
int Boja;
public:
void Postaviboju (int nova) { Boja=nova;}
int Citajboju () {return Boja;}
void Crtaj();
void Translatiraj (int, int) {}
void Rotiraj (int, int, int) {}
};
172
Ovom je deklaracijom reeno da e objekti razreda Linija sadravati sve elemente
(funkcijske i podatkovne ) razreda Grafobjekt. To je praktiki isti uinak kao da se je u
deklaraciji razreda Linija ukljuio sadraj osnovnog razreda Grafobjekt.
Iako je razred Linija naslijedio elemente iz razreda Grafobjekt, pa na taj nain ima pristup
svim njegovim elementima, on ima vlastito suelje. Pravo pristupa pojedinim
elementima koji se deklariraju u naslijeenom razredu se definira na isti nain kao i za
bilo koji drugi razred, dakle tako da se pojedinim elementima pridodaje atribut public,
protected ili private. Meutim pitanje je kakav je status naslijeenih elemenata ?
atributom public se odreuje da e svi elementi osnovnog razreda imati isto pravo
pristupa u naslijeenom razredu. Dakle Boja ima pravo pristupa privat, a ostali su public.
Onda bi svi elementi koji u osnovnom razredu imaju pravo pristupa public ili protected
(ovih u konkretnom sluaju nema), u naslijeenom razredu dobili pravo pristupa
protected. Dakle, Boja bi zadrala pravo pristupa privat a svi ostali elementi bi dobili
pravo pristupa protected.
svi bi elementi razreda Grafobjekt u razredu Linija dobili pravo pristupa private.
173
void Pristupi ();
};
void Izvedena::Pristupi {
i=8; // OK lan je preuzet kao protected
j=9; // OK lan je preuzet kao protected
k=10; // greka, lan je privatan
}
int main () {
Izvedena obj;
obj.i=7; // pogreka lan je protected
obj.j=6; // pogreka lan je protected
obj.k=5; // pogreka, lan je privat
return 0;
}
Iz primjera se vidi razlika izmeu prava pristupa protected i private. Izvedeni razredi
mogu pristupiti lanovima protected iz osnovnog razreda ali ne mogu pristupiti
lanovima private.
class Grafobjekt {
private:
int Boja;
public:
void Postaviboju (int nova) { Boja=nova;}
int Citajboju () { return Boja;}
void Crta j();
void Translatiraj (int, int) {}
void Rotiraj (int, int, int) {}
};
Naime, s obzirom da se na primjer postupak crtanja linije i kruga bitno razlikuju, nije
mogue opisati taj postupak na razini razreda Grafobjekt. Taj opis treba napraviti na
174
razini razreda Linija ili Krug, a program treba omoguiti da se funkcija Crtaj generira u
skladu s konkretnim sluajem.
To se ini pomou virtualnih funkcijskih lanova (virtual function members) .
Ilustracija upotrebe virtualnih lanova prikazana je u slijedeem primjeru:
class Grafobjekt {
private:
int Boja;
public:
void Postaviboju (int nova) { Boja=nova;}
int Citajboju () { return Boja;}
virtual void Crta j();
virtual void Translatiraj (int, int) {}
virtual void Rotiraj (int, int, int) {}
};
175
Objekt razreda Linija
vptr
Boja
x1 Konkretna funkcija
y1 Crtaj () Crtaj()
x2 Translatiraj ()
y2 Rotiraj ()
U sluaju da da mjesto trebaju zamijeniti dva objekta tipa string, kod funkcije je razliit:
176
Postavlja se pitanje, kako se mogu oba sluaja rijeiti s istim kodom ?
gdje se parametar tipa T koristi umjesto uobiajenih tipova koji se navode u definiciji
funkcije.
Koritenje predloka funkcije ilustrirat e se i na primjeru predloka za bubble sort:
Primjer11.1:
1. // predloak funkcije sortiranja
2. #include <iostream>
3. using namespace std;
4. template <class T>
5. void sort(T* v, int n) {
6. for (int i= 1; i < n; i++)
7. for (int j = 0; j< n-i; j++)
8. if (v[j] > v[j+1]) swap (v[j], v[j+1]);
9. }
10. // predloak funkcije za pisanje
11. template <class T>
12. void print (T* v, int n){
13. for (int i = 0; i< n; i++)
14. cout<<" " << v[i]<<endl;
15. }
16. int main ()
17. { int a[9]= {55, 33, 88, 11, 44, 99, 77, 22, 66};
18. print (a, 9);
19. cout<<" Sada ide sort"<<endl;
20. sort (a,9);
21. print(a,9);
22. cout<<" Sada idu string varijable"<<endl;
177
23. string s[7]={"Ivo", "Ana", "Bob", "Tom", "Edi", "Sue", "Dan" };
24. print (s,7);
25. cout<<" Sada ide sort"<<endl;
26. sort (s,7);
27. print(s,7);
28. system("PAUSE");
29. return 0;
30. }
55 33 88 11 44 99 77 22 66 18
Sada ide sort 19
11 22 33 44 55 66 77 88 99 21
Sada idu string varijable 22
Ivo Ana Bob Tom Edi Sue Dan 24
Sada ide sort 25
Ana Bob Dan Edi Ivo Sue Tom 27
Press any key to continue . . .
Prilikom instantacije predloka tj. kada ga se u programu poziva, navodi se tip varijabli s
kojima e se generirati razred. Za ilustraciju uzmimo primjer predloka za
template<class T>
class CCalculator
{
public:
CCalculator(const T &x, const T &y) : m_x(x), m_y(y){ } // konstruktor
~CCalculator(void){ } // destruktor
178
const T m_y;
};
179
Prilog A
ASCII znakovi
Hex Symbol ASCII Hex Symbol ASCII Hex Symbol ASCII Hex Symbol
ASCII
16 10 DLE 32 20 (space) 48 30 0
0 0 NUL
17 11 DC1 33 21 ! 49 31 1
1 1 SOH
18 12 DC2 34 22 " 50 32 2
2 2 STX
19 13 DC3 35 23 # 51 33 3
3 3 ETX
20 14 DC4 36 24 $ 52 34 4
4 4 EOT
21 15 NAK 37 25 % 53 35 5
5 5 ENQ
22 16 SYN 38 26 & 54 36 6
6 6 ACK
23 17 ETB 39 27 ' 55 37 7
7 7 BEL
24 18 CAN 40 28 ( 56 38 8
8 8 BS
25 19 EM 41 29 ) 57 39 9
9 9 TAB
26 1A SUB 42 2A * 58 3A :
10 A LF
27 1B ESC 43 2B + 59 3B ;
11 B VT
28 1C FS 44 2C , 60 3C <
12 C FF
29 1D GS 45 2D - 61 3D =
13 D CR
30 1E RS 46 2E . 62 3E >
14 E SO
31 1F US 47 2F / 63 3F ?
15 F SI
ASCII Hex Symbol ASCII Hex Symbol ASCII Hex Symbol ASCII Hex Symbol
64 40 @ 80 50 P 96 60 ` 112 70 p
65 41 A 81 51 Q 97 61 a 113 71 q
66 42 B 82 52 R 98 62 b 114 72 r
67 43 C 83 53 S 99 63 c 115 73 s
68 44 D 84 54 T 100 64 d 116 74 t
69 45 E 85 55 U 101 65 e 117 75 u
70 46 F 86 56 V 102 66 f 118 76 v
71 47 G 87 57 W 103 67 g 119 77 w
72 48 H 88 58 X 104 68 h 120 78 x
73 49 I 89 59 Y 105 69 i 121 79 y
74 4A J 90 5A Z 106 6A j 122 7A z
75 4B K 91 5B [ 107 6B k 123 7B {
76 4C L 92 5C \ 108 6C l 124 7C |
77 4D M 93 5D ] 109 6D m 125 7D }
78 4E N 94 5E ^ 110 6E n 126 7E ~
79 4F O 95 5F _ 111 6F o 127 7F
180
Dodatak B:
do looping construct
181
for looping construct
switch execute code based off of different possible values for a variable
182
template create generic functions
183