Sie sind auf Seite 1von 114

Univerzitet u Zenici

ER

ZITET U Z
E

N
I

UN

IC

SI

IC

AEN IS
S

UNIVER

ZE

ST

UDIORUM

Pedagoki fakultet
Katedra za matematiku i informatiku

Aleksandar Kara

Osnove programiranja u C++:


proceduralna paradigma

Zenica, 2009.

Uvodna rije ...


Ovaj udbenik je namijenjen studentima Pedagokog fakulteta Univerziteta
u Zenici za kurs Proceduralno programiranje, koji se slua na drugoj godini Odsjeka za Matematiku i Informatiku. Udbenik sadri osnove programiranja u
programskom jeziku C++ sa osvrtom na rjeavanje problema pomou proceduralnog pristupa. Oblasti koje karakteriu jezik C++ kao objektno-orijentisani
jezik, ostavljene su za kurseve Objektno-orijentisano programiranje I i II, koji
se sluaju na treoj, odnosno etvrtoj godini Pedagokog fakulteta Univerziteta
u Zenici.
Skriptu treba shvatiti kao izvor osnovnih pojmova i sintakse programskog
jezika C++ (specifinih za proceduralno programiranje), pri emu su za svaku
oblast dati i neki jednostavniji primjeri. Neto vei broj primjera, problema i
zadataka ostavljen je za diskusiju i izradu na predavanjima i vjebama. Svaka
cjelina skripte zavrava kviz pitanjima i zadacima, kako bi studenti na laki
nain provjerili svoje znanje.
Autor se zahvaljuje organizaciji WUS Austria i Austrian Development Cooperation na pomoi pri izradi poetnog materijala za ovaj udbenik.

A.Kara

Sadraj
Sadraj

1 Uvod
1.1 Kratki istorijat programskih jezika
1.2 O proceduralnom programiranju . .
1.3 Programski paket Dev-C++ . . . .
1.3.1 Instalacija . . . . . . . . . .
1.3.2 Kreiranje prvog programa .
1.3.3 Pokretanje izvrne datoteke
Kviz pitanja . . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

1
1
2
4
5
7
9
10

2 Osnove programiranja
2.1 Struktura programa . . . . . . .
2.2 Proces kompajliranja . . . . . .
2.3 Varijable . . . . . . . . . . . . .
2.4 Memorija . . . . . . . . . . . .
2.5 Ulazno/izlazni usmjerivai toka
2.6 Komentari . . . . . . . . . . . .
2.7 Imena (identifikatori) . . . . . .
2.8 Tipovi podataka . . . . . . . . .
2.8.1 Brojevi . . . . . . . . . .
2.8.2 Logiki tipovi . . . . . .
2.8.3 Karakteri (znakovi) . . .
Kviz pitanja . . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

11
11
13
14
15
16
17
18
19
19
22
23
24

3 Operatori
3.1 Aritmetiki operatori . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Relacijski operatori . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Logiki operatori . . . . . . . . . . . . . . . . . . . . . . . . . .

27
27
29
30

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

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

3.4
3.5
3.6
3.7
3.8
3.9
3.10
3.11

Bitovni operatori . . . . . . . . . . . . .
Inkrementalni i dekrementalni operatori
Operatori pridruivanja . . . . . . . . . .
Uslovni (ternarni) operator . . . . . . . .
Operator razdvajanja (zarez-operator) .
typedef imena . . . . . . . . . . . . . . .
sizeof operator . . . . . . . . . . . . . . .
Hijerarhija operatora . . . . . . . . . . .
Kviz pitanja . . . . . . . . . . . . . . . .
Zadaci za izradu . . . . . . . . . . . . . .

4 Naredbe
4.1 Jednostavne i sloene
4.2 Naredba if . . . . . .
4.3 Naredba switch . . .
4.4 Naredba while . . . .
4.5 Naredba do . . . . .
4.6 Naredba for . . . . .
Kviz pitanja . . . . .
Zadaci za izradu . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

30
31
32
32
33
33
34
34
35
37

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

39
39
40
41
42
43
44
45
46

5 Funkcije
5.1 Definicija . . . . . . . . . . . . .
5.2 Parametri i argumenti . . . . . .
5.3 Globalne i lokalne varijable . . . .
5.4 Rekurzivne funkcije . . . . . . . .
5.5 Optereene (overloaded ) funkcije .
Kviz pitanja . . . . . . . . . . . .
Zadaci za izradu . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

47
47
51
53
54
55
56
58

.
.
.
.

59
59
63
65
65

naredbe
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .

6 Polja (arrays)
6.1 Definisanje i inicijalizacija
6.2 Multidimenzionalna polja
Kviz pitanja . . . . . . . .
Zadaci za izradu . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

7 Pointeri
67
7.1 Osnovno o pointerima . . . . . . . . . . . . . . . . . . . . . . . 67
7.2 Dinamika memorija . . . . . . . . . . . . . . . . . . . . . . . . 68
7.3 Pointeri i polja . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
ii

7.4
7.5
7.6

Aritmetika sa pointerima
Funkcijski pointeri . . .
Reference . . . . . . . .
Kviz pitanja . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

71
73
75
77

8 Datoteke
8.1 Standardna biblioteka fstream . . . .
8.2 "ivotni" ciklus pristupa datotekama
8.2.1 Otvaranje datoteka . . . . . .
8.2.2 Zatvaranje datoteka . . . . . .
8.2.3 Pisanje na datoteke . . . . . .
8.2.4 itanje sa datoteka . . . . . .
Kviz pitanja . . . . . . . . . . . . . .
Zadaci za izradu . . . . . . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

79
79
80
80
85
85
87
90
91

9 O objektno-orijentisanom programiranju
9.1 Proceduralno i objektno-orijentisano programiranje
9.2 Prednosti objektno-orijentisanog programiranja . .
9.3 Karakteristike objektno-orijentisanih jezika . . . . .
9.3.1 Objekti . . . . . . . . . . . . . . . . . . . .
9.3.2 Klase . . . . . . . . . . . . . . . . . . . . . .
9.3.3 Nasljeivanje . . . . . . . . . . . . . . . . .
9.3.4 Ponovna iskoristivost . . . . . . . . . . . . .
9.3.5 Kreiranje novih tipova podataka . . . . . . .
9.3.6 Polimorfizam i optereivanje . . . . . . . . .
Kviz pitanja . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

93
93
96
97
97
98
99
99
100
100
101

Literatura

103

Popis pojmova

105

iii

Poglavlje 1

Uvod
1.1

Kratki istorijat programskih jezika

Jo od pronalaska diferentne maine 1882. godine, kompjuteri su zahtijevali


neko sredstvo koje e im dati instrukcije da obave odreeni zadatak. Ovo sredstvo je poznato kao programski jezik. Diferentna maina je obavljala odreene
operacije izmjenom njenih zupanika, tako da je prvi kompjuterski jezik, u
stvari, bilo fiziko kretanje. Naposljetku je ovo kretanje zamijenjeno elektrinim signalima kada je amerika vlada 1942. godine napravila ENIAC.
U toku 1945. godine, kao istraiva na Institute for Advanced Study, John
Von Neumann je razvio dva vana koncepta, koji su direktno utjecali na razvojni put programskih jezika: prvo, tzv. tehnika podjele programa (shareprogram tehnika), po kojoj kompjuterski hardver treba da bude jednostavan,
a da se za njegovu kontrolu trebaju koristiti kompleksne instrukcije, i drugo,
transfer uslovnom kontrolom (conditional control transfer ), koja daje prednost
podprogramima i malim blokovima koda koji se mogu koristiti bilo kojim redom, za razliku od pojedinanih hronoloki poredanih koraka (pretaa naredbi
IF ...THEN i FOR). Malo zatim (1949), izaao je prvi kompjuterski jezik za
elektronske sklopove, Short Code, koji je zahtijevao od programera da runo
unese nule i jedinice, a 1951. je napisan prvi kompajler, tako da je omogueno
pisanje programskih naredbi, koje bi kompajler preveo u niz nula i jedinica.
Godine 1957. je izaao prvi (glavni) kompjuterski jezik, Fortran (skraenica
engleskih rijei FORmula TRANslating system), koji je razvio IBM za naune
proraune. Ipak, Fortran nije bio najbolja opcija za manipulisanje ulaznim i
izlaznim podacima, pa je 1959. godine razvijen Cobol koji se esto naziva i
"jezik za biznismene".
U isto vrijeme razvio se i Lisp (LISt Processing), te Algol. Ovaj posljednji

Uvod

predstavlja korijen razvoja nekih danas veoma zastupljenih jezika, kao Pascal,
C, C++ i Java. Pascal je poeo sa upotrebom 1968. godine, a predstavljao
je, i jo uvijek predstavlja, veoma dobar edukacioni alat.
Jezik C je razvijen 1972. godine, kada se dogodio prelaz ka savremenim
programerskim jezicima. U osnovi, jezik C je nastavak jezika B i BCPL, ali
obuhvata mnogo karakteristika jezika Pascal.
Kasnih 70tih i poetkom 80tih razvija se nova programerska metoda
objektno-orijentisano programiranje (OOP). Bjarne Stroustoup je na osnovu
prvih OOP jezika (SIMULA, 1967. godina) uspio razviti nastavak jezika C
poznat pod nazivom "C sa klasama" (eng. C with classes), koji se kasnije
(1983) razvio u potpuni jezik. C++ se razvio kako bi se bolje organizovala
sirova snaga jezika C koristei OOP, a sauvala njegova brzina te mogunost
manipulisanja mnogobrojnim tipovima podataka.
Ranih 90tih interaktivna televizija postaje tehnologija budunosti, i kao
takva je zahtijevala specijalni jezik. Tako je Sun Microsystems razvio jezik
Java, koji se neto kasnije poeo koristiti za web dizajn, poto je projekat
interaktivne televizije (bar u tom periodu) propao.
Naravno, ovdje pria o programskim jezicima ne zavrava, i samo je pitanje
kakvi e se jo jezici razviti, naroito sa pojavom biolokih i kvantnih kompjutera. Ipak, injenica da je u samo 50 godina od razvitka prvog programskog
jezika do danas razvijeno vie od 4000 kompjuterskih jezika, govori sama za
sebe.

1.2

O proceduralnom programiranju

Za bilo koji problem vjerovatno postoji jednako puno naina da se isti analizira
i rijei kao to je ljudi i tehnologija da to urade. Tako se sa programerskog
aspekta, na primjer, problem moe podijeliti (dekompozirati) algoritamski ili
proceduralno, tj. u odnosu na sekvencu ili proceduru dogaaja koji se moraju
desiti. Alternatvno, problem se moe rijeiti pomou "objektno-orijentisanog"
pristupa, posmatrajui razne cjeline koje utjeu jedne na druge i uzimajui u
obzir njihovo meusobno djelovanje. Ova dva pristupa u dekompoziranju problema algoritamski i objektno-orijentisani su dva pristupa koji programeri
najee koriste. Pristupi su figurativno prikazani na Sl.1.1.
Algoritamski pristup poinje optim zadatkom koji treba izvriti (kao to
je "omoguiti korisniku da izvri opte bankarske funkcije"), zatim dijeli opti zadatak na naredne nivoe specificiranijih podzadataka (kao to je "proces
podizanja novca", te "proces stavljanja depozita"), te na dalje nivoe jo specifinijih zadataka (kao to su "upitaj korisnika na vrijednost depozita" ili

1.2. O proceduralnom programiranju

Slika 1.1: Dva pristupa u dekompoziranju problema

Slika 1.2: Algoritamska dekompozicija problema

Uvod

"verifikuj unesenu vrijednost kao vaeu"). Kada se zadatak prikae u obliku


dijagrama, najoptiji zadatak je obino na vrhu, a najspecifiniji zadaci se granaju prema dnu. Razni pravougaonici u takvom "stablu" odgovaraju raznim
procedurama i podprocedurama koje treba programirati, kao to je prikazano
na Sl.1.2.
Algoritamske ili proceduralne metode u dizajniranju softvera su razvijene u
kasnim 60tim kako bi se ukazalo na probleme u kojem se u to vrijeme nalazilo
opte stanje u razvijanju softvera. Poto su novi pristupi omoguili strukturni
pristup programiranju (u odnosu na haoticni "hack and run" pristup, koji
su koristili neki programeri), moe se naii i na podatak da se algoritamski
ili proceduralni pristup programiranju zove "strukturno programiranje". S
obzirom da ovaj pristup poinje na vrhu (opti zadatak koji treba izvriti) i
dijeli najvii zadatak na naredne nivoe specifinijih pod-zadataka prema dnu,
ovaj pristup se ponekad naziva i "top-down" pristup. Neki autori ga zovu i
proceduralni pristup, imajui u vidu da se algoritamski pristup fokusira na
procedure koje izvravaju zadatak. Dakle, ovaj pristup dizajniranju softvera
ima razliite nazive, i to:
Funkcionalna dekompozicija
Algoritamska dekompozicija
Strukturno programiranje
"top-down" programiranje
proceduralno programiranje
Bez obzira na naziv, ovaj pristup se fokusira na funkcionalnost programa,
poinjui sa vrha (najoptija funkcija), i idui prema dnu ka najspecifinijim
funkcijama. Mnogi programeri i danas koriste ovaj pristup, a jo uvijek je koristan za izradu kvalitetnih softvera - naroito za manje programe ili softverske
module. Bez obzira na injenicu da je C++ u osnovi OOP jezik, ovaj tekst
se bavi osnovama C++ sintakse u oblasti proceduralnog programiranja, kao
uvod u OOP paradigmu.

1.3

Programski paket Dev-C++

Da bismo napravili program koji treba da obavi neki zadatak, neophodna su


nam dva specijalizirana programa: jedan koji koristimo da napiemo izvornu
datoteku (editor), i drugi sa kojim dobijemo izvrnu datoteku (kompajler).
Ova dva programa se najee kombiniraju u jedinstven paket - tzv. razvojno

1.3. Programski paket Dev-C++

okruenje. Danas, najpoznatije C++ okruenje predstavlja Microsoftov proizvod Visual C++ .NET. Meutim, ovaj, kao i veina ovakvih programa, je
komercijalan i nije dostupan svim korisnicima. Ipak, mogue je nai veliki
broj besplatnih C++ okruenja. Jedno od takvih okruenja je i Dev-C++ .
Najnoviju verziju pomenutog programa mogue je nai na web stranici firme
BloodshedSoftware (http://bloodshed.net/download.html).

1.3.1

Instalacija

Instalacija Dev-C++ programa ni u emu se ne razlikuje od koritenja veine


instalacionih datoteka u Windows okruenjima. Dovoljno je dvostrukim klikom pokrenuti instalacionu datoteku (npr. devcpp-4.9.9.2 setup.exe) i pratiti
poruke na ekranu. Nakon zavretka ovog postupka, u traci sa alatima pojavljuje se ikona za pokretanje programa Dev-C++ , kao to je to prikazano na
slici 1.3.

Slika 1.3: Ikona aplikacije Dev-C++ u traci sa alatima (taskbar )

Program se pokree klikom na ikonu, nakon ega se na ekranu pojavljuje


prozor kao na slici 1.4.
Nakon instalacije je, takoer, preporuljivo podesiti neke opcije, mada to
nije od velike vanosti za programe koji su ogranieni na proceduralni pristup
programiranju. Ipak, u meniju Tools, i podmeniju Compiler options (slika
1.5), prvo treba izabrati opciju Code Generation. U prozoru koji se dobije
opciju Enable Exception Handling treba aktivirati (staviti na yes), kao to je
prikazano na slici 1.6a. Zatim treba izabrati opciju Linker i aktivirati Generate
Debugging Information (slika 1.6b).
Na ovaj nain instalacija je zavrena.

Uvod

Slika 1.4: Radno okruenje programa Dev-C++

Slika 1.5: Podmeni Compiler options u meniju Tools

1.3. Programski paket Dev-C++

a)

b)

Slika 1.6: Podeavanje opcija u podmeniju Compiler options

1.3.2

Kreiranje prvog programa

Upisivanje koda

Nakon pokretanja programa Dev-C++ , prvi korak u kreiranju koda je otvaranje novog zadatka. Dev-C++ prua vie opcija, ali se za sada moemo
ograniiti na jednostavne programe koji se mogu napisati u jednoj datoteci
opcija File/New/Source File, kao to je prikazano na slici 1.7. Nakon odabira
ove opcije, otvara se prozor u koji treba upisati kod, na primjer
#include <iostream>
using namespace std;
int main()
{
cout << "Vozdra, raja\n";
system("PAUSE");
return 0;
}

Nakon ispisivanja (dobija se prozor kao na slici 1.8), kod sauvamo negdje
na hard disku ili drugom nosiocu memorije, npr. pod imenom vozdra.cpp.
Generisanje izvrne datoteke

Nakon to se kod sauva, treba ga kompajlirati, tj. napraviti izvrnu mainsku


datoteku (o procesu kompajliranja e biti vie rijei u poglavlju 2.2). Ovo se

Uvod

Slika 1.7: Otvaranje novog programa

Slika 1.8: Upisivanje prvog programa

1.3. Programski paket Dev-C++

Slika 1.9: Proces kompajliranja bez greaka

izvodi koritenjem kombinacije tipki Ctrl i F9 na tastaturi, ili izborom opcije


Compile u meniju Execute, ili pritiskom na ikonu u nizu alata.
Nakon pokretanja procesa kompajliranja, pojavljuje se prozor sa porukama,
koje prate proces kompajliranja. Dev-C++ daje poruku u sluaju da nae
bilo kakvu greku u programu. U sluaju da nema greaka (slika 1.9), stvara
se izvrna datoteka koja ima ekstenziju exe (u naem sluaju vozdra.exe).
1.3.3

Pokretanje izvrne datoteke

Pokretanje izvrne datoteke, koju smo prethodno kompajlirali, izvodi se izborom opcije Run u meniju Execute, kombinacijom tipki Ctrl i F10 na tastaturi,
ili pritiskom na ikonu .
Prethodna dva procesa (kompajliranje i pokretanje) mogue je i objediniti
pritiskom na tipku F9 na tastaturi, izborom opcije Compile&Run u meniju
Execute, ili izborom ikone .
Program je mogue pokrenuti i van Dev-C++ okruenja, dvostrukim klikom na izvrnu datoteku (vozdra.exe) ili koristei MS-DOS terminal (Command Prompt) tako to se pozicioniramo u direktorij u kojem se nalazi izvrna
datoteka i ukucamo njeno ime..

10

Uvod

U svakom od ovih sluajeva otvorie se prozor sa izvrenim programom, kao


na slici 1.10.

Slika 1.10: Rezultat pokretanja programa vozdra.exe

Kviz pitanja
1. Programski jezik C++ pripada ........... jezicima.
2. ta je osnovna karakteristika proceduralnog programiranja?
3. Kako se jo naziva proceduralno programiranje i zbog ega?
4. Nabroj nekoliko programskih paketa koji omoguavaju pisanje i kompajliranje programa napisanih u C++ !

Poglavlje 2

Osnove programiranja
2.1

Struktura programa

C++ program se sastoji od jedne ili vie cjelina za prevoenje, pri emu ove
cjeline predstavljaju dio programa koji treba kompajlirati odvojeno od drugih
cjelina. Tanije, cjelina za prevoenje je rezultat primjene preliminarne faze
kompajliranja na izvornu datoteku (eng. source file). Ova faza se naziva i
predprocesiranje.
Izvorna datoteka obino poinje sa jednom ili vie (predprocesorskih) direktiva #include, pri emu svaka od njih navodi predprocesor da kopira deklaracije
entiteta (funkcija, globalnih varijabli, tipova, itd), koji su definisani u ostalim
cjelinama za prevoenje.
Posmatrajmo na prvi primjer iz prethodnog poglavlja:
1
2
3
4
5
6
7
8

#include <iostream>
using namespace std;
int main()
{
cout << "Vozdra, raja\n";
system("PAUSE");
return 0;
}

U liniji 1 pozvana je datoteka iostream. Prvi karakter, #, predstavlja simbol,


koji daje signal predprocesoru. Predprocesor ita kroz izvornu datoteku i trai
linije koje poinju sa ovim karakterom, tako da ih predprocesor proe prije nego
kompajler zapone sa radom. U stvari, svaki put kada pokrenemo kompajler,
predprocesor je ve pokrenut.

12

Osnove programiranja

Ukratko, linija 1 znai: Ono to slijedi je ime datoteke, nai tu datoteku


i odmah je proitaj. Uglaste zagrade (<>) daju naredbu predprocesoru da
nae zadatu datoteku koja je dio standardne biblioteke (u datom primjeru to
je datoteka koja sadri definicije za ispis i upis). U sluaju da elimo uvrstiti
neku drugu, nestandardnu datoteku, umjesto zagrada <> bismo koristili znake
dvostrukog navoda," ". Dakle, ova linija kae predprocesoru da nae datoteku
koja se zove iostream i da je odmah proita. Naravno, sadraj traene datoteke
bismo mogli u cijelosti upisati u izvornu datoteku bez koritenja direktive
#include.
Linija 2 omoguuje pristup standardnom entitetu, tzv. imeniku (namespace)
koji se naziva std. Bez ove linije, linija 5 bi se morala izvriti na drugaiji (dui)
nain, i to:
std::cout << "Vozdra, raja\n";

Linijom 3 poinje stvarni program sa funkcijom koja se naziva main(). Svaki


C++ program sadri samo jednu main funkciju. Inae, program moe da ima
proizvoljan broj funkcija, pri emu je funkcija main() specijalna; kada god se
program pokrene, ona se automatski poziva.
Glavni dio programa je linija 5, koja predstavlja neku naredbu, tj. raunarski korak koji daje neku vrijednost. Kraj naredbe uvijek zavrava takazarezom. Naredba u datom primjeru alje string1 "Vozdra raja" na tok cout
(output stream). Posljednji karakter u datom stringu (\n) je karakter koji oznaava novi red (vidi poglavlje 2.8.3). Za istu svrhu moe se koristiti i funkcija
endl2 , odnosno:
cout << "Vozdra, raja" << endl;

Tok (stream) je objekat koji izvrava ulazne i izlazne naredbe. Tok cout je
standardni izlazni tok (obino ekran) u C++ . Simbol << je izlazni operator
(usmjeriva toka) kojem je lijevi operand izlazni tok, a desni izraz. Ovaj
operator upuuje desni operand na lijevi. Dakle, u ovom sluaju string "Vozdra
raja \n" se alje na cout, tj. uzrokuje njegov ispis na ekranu i pomjeranje u
sljedei red.
Linija 6 zaustavlja izvrenje programa, kako bismo mogli vidjeti rezultat
njegovog rada. Bez ove linije program bi se nakon pokretanja izvrio, a konzola
bi se zatvorila veoma brzo, tako da bismo imali osjeaj kao da program nije
nita ni uradio.
1 String

je svaki niz karaktera koji se nalazi izmeu znaka navoda.


iz jezika C

2 naslijeeno

2.2. Proces kompajliranja

2.2

13

Proces kompajliranja

Kompajliranje C++ programa obuhvata nekoliko koraka, koji su veinom nevidljivi za korisnika:
Prvo, C++ predprocesor ide kroz program i izvodi instrukcije koje su
specificirane predprocesorskim direktivama (npr. #include). Rezultat
ovoga je modificirani tekst programa koji vie ne sadri nikakve direktive.
Zatim C++ kompajler prevodi programski kod. Kompajler moe biti
pravi C++ kompajler, koji pravi osnovni (asemblerski ili mainski) kod,
ili samo prevodilac, koji kod prevodi u C jezik. U drugom sluaju, rezultujui C kod se zatim prevodi kroz C kompajler kako bi se napravio
osnovni kod. U oba sluaja, rezultat moe biti nepotpun zbog toga to
program poziva podprogramske biblioteke koje nisu definisane u samom
programu.
Na kraju, linker zavrava objektni kod njegovim povezivanjem sa objektnim kodom bilo kojeg modula biblioteka, koji program moe pozvati.
Konaan rezultat je izvrna datoteka.
Slika 2.1 ilustruje prethodno navedene korake i za C++ prevodilac i za
C++ prirodni kompajler. U praksi su sve ove naredbe obino izvrene jednom naredbom (npr. CC), a korisnik ne vidi datoteke koje su se napravile u
meufazama.
C++
program

C++
prevodilac

C++
program

C++
prirodni
kompajler

C
kod

C
kompajler

Objektni
kod

linker

Slika 2.1: Proces kompajliranja u C++

Izvrna
datoteka

14

Osnove programiranja

2.3

Varijable

Varijabla je simboliko ime za memorijsku lokaciju u koju se mogu pohraniti podaci, koji se naknadno mogu pozvati. Varijable se koriste za uvanje
vrijednosti podataka tako da se iste mogu koristiti u raznim proraunima u
programu. Sve varijable imaju dvije vane osobine:
Tip, koji se postavlja kada se varijabla definie (npr. cijeli broj, realni
broj, karakter, ...). Kada se jednom definie, tip varijable u C++ se ne
moe promijeniti.
Vrijednost, koja se moe promijeniti davanjem nove vrijednosti varijabli.
Vrsta vrijednosti koja se moe pridruiti nekoj varijabli zavisi od njenog
tipa. Na primjer, cjelobrojna varijabla (int) moe uzeti samo vrijednosti
cijelih brojeva (npr. -5, 13, ...).
Kada se varijabla definie, njena vrijednost je nedefinisana sve dok joj se
ne pridrui neka. Pridruivanje vrijednosti nekoj varijabli po prvi put naziva se inicijalizacija. Neophodno je da se svaka varijabla inicijalizira prije
nego se koristi. C++ podrava dvije vrste inicijalizacije: (i) inicijalizaciju
kopiranjem (eng. copy-initialisation) i (ii) direktna inicijalizacija (eng. directinitialisation). Inicijalizacija kopiranjem koristi znak jednakosti, =, dok se
direktna inicijalizacija izvodi pomou malih zagrada, (), kao u sljedeim primjerima:
int broj(10); // direktna inicijalizacija
int broj = 10; // inicijalizacija kopiranjem

U oba sluaja varijabla broj je inicijalizirana na vrijednost 10. Treba napomenuti da inicijalizacija ne predstavlja pridruivanje (iako se u inicijalizaciji
kopiranjem koristi znak jednakosti), nego se deava onda kada se varijabla
definie i kada joj se da poetna vrijednost. S druge strane, pridruivanje
predstavlja ponitavanje trenutne vrijednosti varijable i zamjene novom.
Takoer je mogue da se varijabla definie i inicijalizira u isto vrijeme,
to je vrlo praktino. Naredni primjer pokazuje razliite naine definisanja i
inicijaliziranja varijabli.
1
2
3
4
5
6

#include <iostream>
using namespace std;
main()
{
int a,b,c;
float x = 4.32;

2.4. Memorija
int e,f,g;
char ime;
e = 4;
f = g = 12;
ime = C

7
8
9
10
11
12

15

Linije 5, 7 i 8 pokazuju primjere definisanja varijabli a, b, c, zatim e, f, g i


ime, respektivno. Varijable e, f i g su inicijalizirane linijama 9 i 10, a varijabla
ime u liniji 11. Istovremeno definisanje i inicijalizacija data je u liniji 6 za
varijablu x.
Na kraju, treba napomenuti da veina autora proces definisanja varijabli
poistovjeuje sa procesom deklarisanja. Meutim, neki autori prave razliku
izmeu ovih pojmova. Naime, zbog situacija u kojima se u vie datoteka jednog
te istog programa pristupa istoj varijabli, C++ razlikuje pojmove definisanja i
deklarisanja. Tako, definisanje varijable predstavlja alociranje prostora za nju,
te moguu inicijalizaciju. U jednom programu moe biti samo jedna definicija
varijable. S druge strane, deklaracija upoznaje program sa tipom i imenom
varijable. Definicija je time i deklaracija. Deklarisanje se izvrava na taj nain
da se ispred tipa doda kljuna rije extern. Sljedei primjer pokazuje razliku
izmeu definisanja i deklarisanja neke varijable:
extern int broj;
int broj;

// deklarise ali ne i definise broj


// deklarise i definise broj

Osnovna razlika je u tome da se sa extern, odnosno procecsom deklaracije,


ne alocira prostor za datu varijablu, nego samo upuuje na to da je varijabla
definisana negdje u programu.

2.4

Memorija

Za pohranjivanje izvrnog koda kao i podataka sa kojima program manipulira, kompjuter ima na raspolaganju RAM memoriju (eng. Random Access
Memory). Pri tome, memorija se moe zamisliti kao neprekidan niz bita, od
kojih svaki moe da pohrani binarni broj (0 ili 1). Memorija se obino dijeli na
grupe od 8 uzastopnih bita (ovo predstavlja bajt). Bajtovi su uzastopno adresirani, tako da je svaki bajt jedinstveno predstavljen svojom adresom (Sl.2.2).
C++ kompajler generie izvrni kod, koji mapira ulazne veliine na memorijske lokacije. Na primjer, definicija varijable
int zarada = 500;

16

Osnove programiranja
adresa

...

1211

1212

1213

1214

1215

1216

1217

bajt

bajt

bajt

bajt

bajt

bajt

bajt

...

Memorija

bit

Slika 2.2: Organizacija memorije u kompjuteru

navodi kompajler da alocira nekoliko bajta kako bi predstavio varijablu zarada.


Taan broj bajta koji je alociran i metoda koja se koristi za binarnu reprezentaciju cijelog broja zavisi od specifinosti C++ implementacije. Pretpostavimo,
na primjer, da se radi o 2 bajta. Kompajler koristi adresu prvog bajta na koju
se alocira zarada kako bi oznaio varijablu. Prethodna jednakost uzrokuje da
se vrijednost 500 pohrani u ova dva bajta koja su alocirana (Sl.2.3)

...

1211

1212

1213

bajt

bajt

bajt

1214

1215

10110011 10110011

1216

1217

bajt

bajt

...

Memorija

zarada

Slika 2.3: Reprezentacija cijelog broja u memoriji

Treba napomenuti da je organizacija memorije i koritenje adresa koji se


odnose na podatke veoma vano za programera, dok tana binarna reprezentacija podataka koje on koristi to nije.

2.5

Ulazno/izlazni usmjerivai toka

Najei nain na koji program komunicira sa vanjskim svijetom je preko jednostavnih ulazno/izlaznih (IO) operacija. C++ omoguuje dva korisna operatora za ovu svrhu: >> za ulaz, i << za izlaz. U ranijem tekstu pokazana je
upotreba operatora <<. Naredni primjer pokazuje upotrebu operatora >>.
1
2

#include <iostream>
using namespace std;

3
4

int main (void)

2.6. Komentari
5

17

{
int
radniDani = 22;
float radniSati = 7.5;
float satnica, plata;

6
7
8
9

cout << "Kolika je satnica? ";


cin >> satnica;

10
11
12

plata = radniDani * radniSati * satnica;


cout << "Plata = ";
cout << plata;
cout << \n;

13
14
15
16
17

Linija 11 ita ulaznu vrijednost, koju unosi korisnik i kopira je u varijablu


satnica. Ulazni operator >> uzima ulazni tok kao lijevi operand (cin je standardni C++ ulazni tok koji odgovara podacima unesenim pomou tastature),
a varijablu (na koju se kopira ulazni podatak) kao desni operand.

2.6

Komentari

Komentar je dio opisnog teksta koji objanjava neke aspekte programa. Kompajler u potpunosti ignorie komentare u programu, tako da je jedina svrha
koju komentar ima, da pomogne onome koji e itati program. C++ daje
dvije mogunosti pisanja komentara:
bilo ta napisano nakon //, pa do kraja date linije smatra se komentarom3 ,
i
bilo ta napisano izmeu /* i */ smatra se komentarom.
Sljedei primjer pokazuje upotrebu oba naina pisanja koemntara.
1
2

#include <iostream>
using namespace std;

3
4
5

/* Ovaj program racuna ukupnu platu radnika,


koja se zasniva na ukupnom broju radnih sati i satnici. */

6
7
8
9

int main (void)


{
int
radniDani = 22;

3 naslijeeno

iz jezika C

// Broj radnih dana u mjesecu

18

Osnove programiranja
float
float
float

10
11
12

radniSati = 7.5;
satnica = 33.50;
plata;

// Broj radnih sati u danu


// Satnica
// Ukupna mjesecna plata

13

// Racunanje i ispis plate

14
15

plata = radniDani * radniSati * satnica;


cout << "Plata = " << plata << \n;

16
17
18

Prvi nain se moe koristiti za komentar jedne i samo jedne linije (ili dijela
jedne linije), kao to je to demonstrirano u linijama 14 (cijeli red), te linijama
9-12 (dio reda). Drugim nainom se (koristei /* i */), pak, moe komentarisati
tekst upisan u vie linija (linije 4-5).

2.7

Imena (identifikatori)

Programski jezici koriste imena kako bi se oznaile razliite cjeline koje ine
program. Osim imena varijabli, ovdje spadaju i imena funkcija, tipova, te
makroa. C++ postavlja sljedea pravila za pravilno kreiranje imena (identifikatora):
ime treba da se sastoji od jednog ili vie karaktera, od kojih bilo koji moe
biti slovo (tj, slova engleske abecede a-z i A-Z), broj (0-9) i znak " ", pri
emu na prvom mjestu ne moe da bude broj.
velika i mala slova se razlikuju (zarada nije isto to i Zarada).
C++ ne postavlja nikakvo ogranienje na broj karaktera u nekom identifikatoru. Meutim, veina implementacija ima ovo ogranienje, ali je ono toliko
veliko da ne predstavlja nikakav problem (npr. i do 255 karaktera). Ipak, treba
imati na umu da postoje odreene rijei u C++ koje su rezervisane, tako da
identifikatori ne mogu uzimati njihova imena. Te rijei se nazivaju rezervisane
ili kljune rijei i neke od njih su date u Tabeli 2.1.
Pored navedenih pravila o davanju imena varijablama, postoji i veliki broj
prihvaenih konvencija, koje se uglavnom koriste radi lakeg praenja programa. Neke od vanijih su:
imena varijabli se obino piu malim slovima
za davanje imena se obino koriste mnemonika imena, tj. imena koja
poblie opisuju varijablu

2.8. Tipovi podataka

19

Tabela 2.1: Kljune (rezervisane) rijei u C++


asm
auto
break
case
catch
char
class
const

continue
default
delete
do
double
else
enum
extern

float
for
friend
goto
if
inline
int
long

new
operator
private
protected
public
register
return
short

signed
sizeof
static
struct
switch
template
this
throw

try
typedef
union
unsigned
virtual
void
volatile
while

ime moe da ima i vie rijei, koje su obino razdvojene donjom crtom,
ili su direktno povezane sa poetnim velikim slovom rijei koja se dodaje
imenu.
No, bez obzira na konvencije, opte je pravilo da se jedna odreena konvencija
konstantno koristi.

2.8

Tipovi podataka

U C++ jeziku ugraeni su neki osnovni tipovi podataka, kao to su brojevi,


logike vrijednosti i karakteri (znakovi). U ovom poglavlju su isti objanjeni,
a operacije nad njima su date u poglavlju 3.
2.8.1

Brojevi

U C++ su ugraena dva osnovna tipa brojeva, i to: cijeli i realni brojevi.
Cijeli brojevi

Cijeli broj (eng. integer ) se moe definisati pomou tipova short, int i long.
Jedina razlika je u tome to int koristi vie ili barem isto bajta kao short, a long
koristi vie ili barem isto bajta kao int . Ovo zavisi od kompjutera na kojem
se radi.
Konvencija je da cjelobrojne varijable uzimaju u obzir i pozitivne i negativne
brojeve (tada se kae da su oni tipa signed). Meutim, u sluaju kada se koriste
samo pozitivne vrijednosti, ukljuujui i 0, koriste se sa predznakom unsigned.
Ovo vrijedi i za realne brojeve.
Najee se pri definisanju cijelih brojeva koristi tip int, koji u kompjuteru
obino zauzima 4 bajta (mada kod nekih starijih kompjutera zauzima 2 bajta).
S obzirom da 4 bajta predstavlja 48 = 32 bita, i da prvi bit odreuje predznak

20

Osnove programiranja

broja, preostaje nam 31 bit da pohranimo vrijednost nekog broja. Na taj nain
se tipom int mogu pohraniti svi brojevi vei od najmanjeg negativnog broja
231 = 2147483648
i manji od najveeg mogueg pozitivnog broja
231 1 = 2147483647
Treba napomenuti da se cjelobrojne veliine u izvornom kodu mogu prikazati u jednom od tri brojna sistema, i to: dekadskom, oktalnom i heksadecimalnom. Pri tome, naravno, dekadski brojni sistem je sistem brojeva od 0-9,
oktalni 0-7, i heksadecimalni 0-9,A-F.
U jeziku C++ oktalne vrijednosti se piu tako da se ispred prve cifre broja
napie broj 0, nakon ega slijedi oktalni zapis broja, kao npr.
int broj = 010;

// broj 8 u dekadskom zapisu

U sluaju heksadecimalnog zapisa u C++ , ispred broja se pie 0x ili 0X,


tj.
int broj = 0x0C;

// broj 12 u dekadskom zapisu

Ipak, bez obzira koji od prikaza koristimo pri pridruivanju neke vrijednosti,
na ekranu se ispisuje broj u dekadskom brojnom sistemu. Tako u sljedeem
primjeru za svaki sluaj ispis je jednak broju 32:
int broj = 32;
cout << broj;

// broj 32 u dekadskom zapisu


// ispis 32

int broj = 040;


cout << broj;

// broj 32 u oktalnom zapisu


// ispis 32

int broj = 0x20;


cout << broj;

// broj 32 u heksadecimalnom zapisu


// ispis 32

Realni brojevi

Da bismo operisali sa realnim, tj. decimalnim, brojevima moemo koristiti


varijable tipa float i double. Tip double koristi vie bajta i time omoguuje vei
opseg i veu tanost pri predstavljanju realnih brojeva.
Naredni primjeri pokazuju upotrebu tipa float (analogno je za ostale tipove
koji predstavljaju realne brojeve):
float pi = 3.1415926;
float brzinaSvjetlosti = 2.997925e8;
float naboj = -1.6E-19;

2.8. Tipovi podataka

21

U prvom sluaju koristi se klasini nain prikaza broja sa decimalnim zarezom, dok je u drugom i treem sluaju koriteno nauno oznaavanje (eng.
scientific). Pri tome, u naunom oznaavanju je mogue koristiti i malo i veliko slovo "e", ali ne smije biti nikakvih praznina unutar broja (izmeu cifri i
slova e, te iza predznaka).
U sluaju da nam tanost na sedam decimala nije dovoljna, koristimo brojeve sa dvostrukom tanou, tj. brojeve tipa double. U principu, za prikaz
decimalnih brojeva najbolje je uvijek koristiti tip double, jer je brzina obavljanja operacija sa ovim tipovima na dananjim kompjuterima podjednako velika
kao i sa tipom float.
Ogranienja brojevnih tipova

Kao to je pokazano u dijelu o cijelim brojevima, na osnovu veliine memorije


koju neki brojevni tip zauzima, mogue je odrediti maksimalan i minimalan
broj koji se sa njim moe prikazati. O tome kako se odreuje veliina memorije
koju zauzima neki objekat ili tip, bie vie rijei u poglavlju 3.10 (operator
sizeof).
Ipak, koritenjem datoteka climits4 , za cjelobrojne, i cfloat, za decimalne
brojeve, mogue je nai ove vrijednosti. Na primjer, konstante INT_MIN i
INT_MAX daju najmanju i najveu vrijednost brojeva tipa int. Sline konstante postoje i za ostale tipove, a sljedei dio programa daje njihovu primjenu:
cout
cout
cout
cout
cout
cout

<<
<<
<<
<<
<<
<<

"Najmanji int: "


"Najveci int: "
"Najmanji long: "
"Najveci int: "
"Najveci float: "
"Najmanji double:"

<<
<<
<<
<<
<<
<<

INT_MIN
INT_MAX
LONG_MIN
LONG_MAX
FLT_MAX
DBL_MIN

<<
<<
<<
<<
<<
<<

endl;
endl;
endl;
endl;
endl;
endl;

Simbolike konstante

Prethodni brojevni tipovi se koriste za definisanje varijabli koje mijenjaju svoju


vrijednost u toku izvravanja programa. Meutim, u C++ je mogue definisati
i konstante, tj. veliine koje ne treba da mijenjaju svoju vrijednost u toku
izvrenja programa. Takve su na primjer, vrijednost , brzina svjetlosti, naboj
elektrona, itd.
Osnovni razlog zbog koritenja simbolikih konstanti je osiguranje od promjene njihove vrijednosti. Naime, moe se desiti da u toku pisanja programa
napiemo naredbu koja mijenja vrijednost konstante (npr. broja ) i na taj
nain napravimo veliku greku u daljem proraunu.
4 Datoteka

mora biti pozvana naredbom #include

22

Osnove programiranja

Kako bismo izbjegli ovakve probleme, na raspolaganju nam je kvalifikator


const, koji nam govori da se radi o varijabli koja ne mijenja svoju vrijednost.
Ovaj kvalifikator se koristi na taj nain da se postavlja ispred tipa varijable,
kao u primjeru:
const float pi = 3.1415926;

Ako bismo pokuali promijeniti vrijednost varijable pi (na primjer sa pi = 2*pi;)


kompajler bi prijavio greku.
Drugi nain definisanja neke konstante je pomou predprocesorske naredbe
#define, kao u:
#define PI 3.1415926

Jedina razlika u koritenju ova dva pristupa je u tome to varijanta sa const


omoguuje i simboliko lociranje pogreaka pri debagiranju, dok to nije mogue
sa drugom varijantom.
Takoer, bitno je napomenuti da se sve simbolike konstante moraju i inicijalizirati prilikom definisanja, tj. pogreno je napisati:
const float pi;

2.8.2

// greka!!!

Logiki tipovi

Logiki tipovi su vrlo kasno uvedeni u standardni jezik C++ . Prije nego se
uveo tip za ovu vrstu podataka, bool (od engleske rijei boolean, po matematiaru Booleu), u ovu svrhu su se koristili cijeli brojevi 0 i 1 (mada se umjesto
1 mogao koristiti bilo koji broj razliit od 0).
Osnovna karakteristika logikih tipova je da mogu imati dvije vrijednosti,
i to: tano i netano (eng. true i false)5 . Primjer definisanja logikih varijabli
je:
bool jaSamStudent = true;
bool autoLeti
= false;

Prilikom manipulisanja sa logikim varijablama (ispis, aritmetike operacije,


i sl.), oni se predstavljaju cjelobrojnim tipom int, i to: true se pretvara u 1,
a false u 0. No, logikim varijablama se mogu pridruiti i aritmetiki tipovi,
tako da se svim brojevima razliitim od nule pridruuje true, a jednakim nuli
false.
5 U ovu svrhu se moe koristiti bilo koja druga kombinacija suprotnih veliina kao istina i la, crno i bijelo,
i slino.

2.8. Tipovi podataka

2.8.3

23

Karakteri (znakovi)

Varijabla karakter (znak) se definie tipom char (od engleske rijei character karakter, znak) i uglavnom se pie kao samo jedan znak upisan izmeu jednostrukih znaka navoda . Ona obuhvata jedan jedini bajt koji sadri kod datog
karaktera. Ovaj broj je numerika vrijednost i zavisi od sistema kodiranja karaktera koji se koristi (to je zavisno od kompjutera). Najei sistem je ACSII
(eng. American Standard Code for Information Interchange). Na primjer,
karakter A ima ASCII kod 65, a karakter a 97.
Kao i cijeli broj i karakter moe da bude signed i unsigned. Tako, signed
karakter moe da sadri numerike vrijednosti izmeu -128 i 127, a unsigned 0
do 255.
Sljedei primjer pokazuje upotrebu tipa char za jednoznakovne varijable:
1
2
3
4
5
6
7
8
9
10

#include <iostream>
using namespace std;
main()
{
char ch;
do
{
cout << "Pritisnite K ili k za kraj,
a bilo koju tipku za nastavak \n";
cin >> ch;

11

if (ch != K && ch != k)
cout << "Zelite nastaviti?\n";
else
cout << "Kraj programa";
}while (ch != K && ch != k);

12
13
14
15
16
17

Pri pokretanju, ovaj program se nastavlja ako se unese bilo koji drugi karakter osim k ili K. Ako se, pak, unese k ili K, program se zaustavlja. Problem
nastaje ako korisnik programa pritisne samo tipku ENTER. U tom sluaju
objekat cin oekuje da se unese neka vrijednost, pa tek onda pritisne ENTER.
Osim klasinih karaktera (slova i sl.), postoje i karakteri koji imaju posebnu
namjenu (ne predstavljaju karaktere koji se ispisuju). Oni se predstavljaju
pomou tzv. escape-sekvenci, kao npr:
\n - novi red
\t - novi tabulator
\v - novi vertikalni tabulator

24

Osnove programiranja
\b
\
\"
\\
\a

backspace
znak navoda (apostrof)
dvostruki znak navoda
backslash (/)
zvuni signal

Znakovne varijable se, ipak, najee koriste kao nizovi karaktera (eng. string)
za ispis tekstova. O ovome e biti vie rijei u poglavlju 6 (polja).

Kviz pitanja
1. Koliko main funkcija moe biti u programu?
2. Koja je uloga include direktive?
3. ta radi predprocesor?
4. ta radi kompajler?
5. ta radi linker?
6. Koja je razlika izmeu tipova podataka unsigned int i int?
7. ta predstavlja varijabla?
8. Da li je mogue definisati vie varijabli jednom naredbom? Ako jeste,
dati primjer.
9. ta je od navedenog ispravna definicija varijable:
a)
b)
c)
d)

int n=-100;
unsigned int i =-100;
signed int = 2.9;
long m=2,p=4;

10. Koje od navedenih rijei predstavljaju pravilne nazive varijabli:


a)
b)
c)
d)
e)
f)

identifier
dva 15
ukupna-plata
ukupna_plata
default
proc.program

2.8. Tipovi podataka

25

11. Definii varijable koje predstavljaju sljedee veliine:


a) visina neke osobe
b) zarada neke osobe
c) broj rijei u rjeniku
d) slovo u abecedi
12. Dati primjer starog (jedan red) i novog naina pisanja komentara.
13. Koju datoteku (header file) moramo pozvati u izvornoj datoteci da bi se
koristile cout i cin?
14. Napisati naredbu koja dobiva numeriku vrijednost sa tastature i pridruuje je varijabli temp.
15. Kako se definiu brojevi u C++ ?
16. Kako se definiu znakovi u C++ ?
17. Dati primjer definisanja konstante koja predstavlja brzinu svjetlosti (c =
2.997925 108 m/s)
18. Kako se u C++ definiu logike varijable?

Poglavlje 3

Operatori
U ovom poglavlju su obraeni ugraeni C++ operatori, koji se koriste za stvaranje izraza, pri emu izraz predstavlja bilo kakav proraun koji daje neku
vrijednost. C++ nudi operatore za izvravanje aritmetikih, relacijskih, logikih, bitovnih i uslovnih izraza. Takoer, tu su i veoma korisne "popratne
pojave" (eng. side-effect) kao to su pridruivanje, inkrement i dekrement.

3.1

Aritmetiki operatori

C++ nudi pet osnovnih operatora, koji su sumirani u Tabeli 3.1.


Tabela 3.1: Aritmetiki operatori
Operator
+
*
/
%

Ime
Sabiranje
Oduzimanje
Mnoenje
Dijeljenje
Ostatak pri dijeljenju

Primjer
12+4.9
3.98-4
2*3.4
9/2.0
13%3

Rezultat
16.9
-0.02
6.8
4.5
1

Osim ostatka pri dijeljenju (%) svi aritmetiki operatori prihvataju mijeanje cijelih i realnih brojeva. Openito, ako su oba operanda cijeli brojevi, i
rezultat je cijeli broj. Meutim, ako je jedan od operanada realan, onda je i
rezultat realan (na primjer, tipa double)1 .
Kada su oba operanda pri dijeljenju cijeli brojevi, rezultat je takoer cijeli
broj (tzv. cjelobrojno dijeljenje). U tom sluaju rezultat se zaokruuje na
donju vrijednost, tj.
1 Ovakav

nain konverzije u C++ naziva se implicitna konverzija

28

Operatori
9/2
-9/2

daje 4, a ne 4.5!
daje -5, a ne -4.5!

ak i u sluaju kada je rezultat dijeljenja definisan kao realan broj, kao u


sljedeem primjeru
int cijena = 100; int volumen = 80;
double jedinicnaCijena = cijena/volumen;

// daje 1

rezultat dijeljenja je cjelobrojan, s obzirom da dijeljenje ima vei prioritet od


pridruivanja.
Cjelobrojno dijeljenje predstavlja jednu od najeih greki u programiranju, pa je neophodno upoznati naine na koje se moe zaobii. Ovo se moe
ostvariti pomou tzv. eksplicitne konverzije, ili dodjele tipa (eng. cast). U tu
svrhu se mogu koristiti sljedei operatori (eng. cast operators): static_cast,
dynamic_cast, const_cast i reinterpret_cast, ali je za na sluaj vaan
operator static_cast (koristi se u sluajevima kada se manjem aritmetikom tipu pridruuje vei; na primjer tipu int pridruuje tip double). Sljedei
primjer pokazuje njegovu primjenu:
int cijena = 100;
int volumen = 80;
double jedinicnaCijena = static_cast<double>(cijena)/volumen; //
daje 1.25

Operator static_cast moe se koristiti i na varijabli volumen, ali i na obje


varijable u koliniku.
Prije nego se poeo koristiti ovaj C++ nain pisanja, u upotrebi je bio stari
nain (eng. old-style cast), koji se daje ili u tzv. funkcijskom obliku (varijabla
meu zagradama):
double jedinicnaCijena = double(cijena)/volumen; // daje 1.25

ili u tzv. starom nainu pisanja u jeziku C (sa tipom meu zagradama):
double jedinicnaCijena = (double)cijena/volumen; // daje 1.25

Ipak, stari nain pisanja se ne preporuuje u pisanju programa koji e se kompajlirati na C++ kompajlerima.
Operator % daje ostatak pri dijeljenju dva cijela broja (oba operanda moraju biti cijeli brojevi!!!), npr.
13%3 daje 1

3.2. Relacijski operatori

29

Prilikom koritenja aritmetikih operatora veoma vano mjesto zauzima pojam preljeva. Naime, u sluaju da zbir brojeva prelazi maksimalno dozvoljenu
vrijednost, koja je navedena u poglavlju 2.8.1, dobivena vrijednost moe biti
negativna. Ovaj fenomen se lako moe pokazati na slici 3.1 ako se za tip int
pretpostavi da ima 2 bajta, tj. 16 bita (to znai da je maksimalan pozitivan
broj jednak 215 = 32767)

oduzimanje
-2

-1

sabiranje
1

int

-32767
-32768

32766
32767

Slika 3.1: Preljev pri koritenju aritmetikih operatora

Dakle, ukoliko neku varijablu koja ima vrijednost 32767 uveamo za samo
1, vrijednost koju dobivamo je -32768 (!!!), odnosno za jedan vea od najvee
mogue u smjeru kazaljke na satu na slici 3.1.

3.2

Relacijski operatori

C++ nudi est relacijskih operatora za raunanje brojnih veliina (Tabela 3.2)
Pri tome, treba zapamtiti da se operatori <= i >= mogu koristiti samo u
tom obliku, a da =< i => ne znae nita u ovom kontekstu.
Operandi nekog relacijskog operatora moraju biti brojevi. No, i karakteri
su ispravni operandi poto predstavljaju brojnu vrijednost (sjetimo se ASCII
tabele).
Relacijski operatori se ne smiju korisiti za poreenje stringova, poto se u
tom sluaju porede njihove adrese, a ne sadraj. U tom sluaju, rezultat je

30

Operatori

Tabela 3.2: Relacijski operatori


Operator
==
!=
<
<=
>
>=

Ime
Jednakost
Nejednakost
Manje od
Manje ili jednako
Vee od
Vee ili jednako

Primjer
5==5
5!=5
5<5.5
5<=5
5>=5.5
5.5>=5

Rezlutat
1
0
1
1
0
1

neodreen. Ipak, postoje funkcije koje mogu porediti i leksikografsku razliku


dva stringa.

3.3

Logiki operatori

Za kombinovanje logikih izraza C++ nudi tri logika operatora (Tabela 3.3).
Slino relacijskim operatorima, rezultat pri koritenju logikih operatora je 0
(false) ili 1 (true).
Tabela 3.3: Logiki operatori
Operator
!
&&
||

Ime
Logika negacija
Logiko i
Logiko ili

Primjer
!(5==5)
5<6 && 6<6
5<6 || 6<5

Rezlutat
0
1
1

Za razliku od logikog i i logikog ili operatora, koji su binarni operatori,


logika negacija je unarni operator, tj. ima samo jedan operand kojem daje
negaciju vrijednosti koju posjeduje.

3.4

Bitovni operatori

C++ obezbijeuje est bitovnih (eng. bitwise) operatora koji se koriste za


manipulisanje pojedinanim bitovima cjelobrojnih podataka. Isti su dati u
Tabeli 3.4.
Bitovni operatori su definisani samo za cjelobrojne (int, long int) operande
i tretiraju ih kao sekvence bita. Tako, binarna negacija ( - tilda) predstavlja
unarni operator koji mijenja stanje bita operanda, tj. svi bitovi koji su jednaki
0 postavlja u 1, a sve bitove koji su jednaki 1 u 0. Binarno i uporeuje
odgovarajue bitove svojih operanada i kao rezultat daje 1 ako su oba bita 1,
a 0 u ostalim sluajevima. Binarno ili uporeuje odgovarajue bitove svojih

3.5. Inkrementalni i dekrementalni operatori

31

Tabela 3.4: Bitovni operatori


Operator

&
|

>>
>>

Ime
Binarna negacija
Binarno i
Binarno ili
Iskljuivo ili
Pomaknuti desno
Pomaknuti lijevo

Primjer
\011
\011 & \027
\011 | \027
\011 \027
\011>>2
\011<<2

Rezlutat
\366
\001
\037
\036
\002
\044

Tabela 3.5: Inkrement i dekrement operatori


Operator
++
++

Ime
Inkrement prefiks
Inkrement postfiks
Dekrement prefiks
Dekrement postfiks

Primjer
++k+10
k++ +10
k+10
k +10

Rezlutat
16
15
14
15

operanada i kao rezultat daje 0 ako su oba bita 0, a 1 u ostalim sluajevima.


Binarno iskljuivo ili uporeuje odgovarajue bitove svojih operanada i kao
rezultat daje 1 ako su oba bita razliita, a 0 u ostalim sluajevima.
Operatori pomaknuti lijevo i pomaknuti desno kao lijevi operand uzimaju
sekvencu bitova, a kao desni neki cijeli broj n. Prvi operator daje kao rezultat sekvencu bita koja je jednaka lijevom operandu, ali koja je pomjerena n
bitovnih pozicija ulijevo. Drugi operator ima istu funkciju, s tom razlikom to
pomjera sekvencu bita za n pozicija udesno.

3.5

Inkrementalni i dekrementalni operatori

Takozvani auto inkrementalni (++) i auto dekrementalni () operatori obezbijeuju prigodan nain za poveavanje, odnosno smanjivanje brojne varijable
za 1. Upotreba ovih operatora je sumirana u Tabeli 3.5, pri emu se pretpostavlja da je
int

k = 5;

Kao to se vidi, oba operatora se mogu koristiti u prefiksnom i postfiksnom


obliku. Razlika je velika, jer kada se operator koristi u prefiksnom obliku prvo
se primjenjuje operator, a onda se u izrazu koristi rezultat. Kada se koristi u
postfiksnom obliku, prvo se rauna izraz, a onda se primjenjuje operator.
Oba operatora se mogu primijeniti kako na cjelobrojne, tako i na realne
brojeve, iako se ova karakteristika veoma rijetko koristi na realnim brojevima.

32

3.6

Operatori

Operatori pridruivanja

Operator pridruivanja (=) se koristi za pohranjivanje vrijednosti na neku memorijsku lokaciju (koja je obino pridruena nekoj varijabli). Lijevi operand
operatora treba biti neka vrijednost, npr. lijevaVrijednost, dok desni operand
moe biti proizvoljni izraz. Desni operand se izrauna i pridrui lijevoj strani.
Pri tome lijevaVrijednost predstavlja bilo ta to zauzima neku memorijsku lokaciju na koju se moe pohraniti neka veliina; moe biti varijabla, te zasnovana
na pointerima i referencama.
Operator pridruivanja moe imati mnogo varijanti, koje se dobivaju njegovim kombinovanjem sa aritmetikim operatorima (mogua je kombinacija i
sa bitovnim operatorima). Ove varijante su date u tabeli 3.6.
Kako operator pridruivanja sam po sebi predstavlja izraz ija se vrijednost
pohranjuje u lijevi operand, on se moe koristiti kao desni operand za narednu
operaciju pridruivanja, odnosno moe se napisati:
int m, n, p; m = n = p = 5; // isto kao: m = (n = (p = 100));
m =(n= p = 100) + 2;
// isto kao: m = (n = (p = 5)) + 2;

ili
m = 100; m += n = p = 5;

3.7

// isto kao: m = m + (n = p = 5);}

Uslovni (ternarni) operator

Uslovni operator treba tri operanda (odatle ime ternarni). On ima optu formulu:
operand1 ? operand2 : operand3;

Operand operand1 se izraunava, i tretira kao logiki uslov. Ako je rezultat


razliit od nule, tada se izraunava operand2. U suprotnom, izraunava se
operand3. Na primjer, u sljedeem primjeru
int m = 1, n = 2;
int min = (m < n ? m : n);

// min dobija vrijednost 1

U samo jednoj liniji odreujemo manji od dva broja (u naem sluaju to je


broj 1).

3.8. Operator razdvajanja (zarez-operator)

3.8

33

Operator razdvajanja (zarez-operator)

Operator razdvajanja, ili zarez-operator (eng. comma operator ) koristimo kada


mnogostruke izraze elimo kombinovati u jedan izraz. Ovaj operator ima dva
operanda, pri emu prvo izraunava lijevi operand, a zatim desni, pa tak nakon
toga vraa vrijednost posljednjeg kao konaan rezultat. Na primjer:
int m, n, min;
int mBroji =0, nBroji=0;
......
min = (m < n ? mBroji++, m : nBroji++, n);

U ovom primjeru, kada je m < n, izraunava se mBroji++, a zatim se


vrijednost m pohranjuje u min. U suprotnom, izraunava se nBroji++, a zatim
se vrijednost n pohranjuje u min.

3.9

typedef imena

Kljuna rije typedef omoguava definisanje novih imena (sinonima) za postojee tipove podataka. Opta formula ima oblik:
typedef tip novo_ime_tipa;

Dakle, typedef definicija poinje kljunom rijei typedef, nakon ega se ispisuje tip podatka i identifikator. Pri tome, identifikator ne uvodi novi tip
podatka, nego samo sinonim (nadimak) za postojei tip. Ovaj identifikator se
moe koristiti bilo gdje u programu u kojem bi se mogao koristiti i sam tip.
Na primjer, sljedei primjer pokazuje koritenje sinonima prirodni, za prirodne, tj. nenegativne cijele brojeve.
typedef unsigned int prirodni;

Ukoliko bismo eljeli definisati prirodni broj N koritenjem imena prirodni,


piemo:
prirodni N;

Treba napomenuti da se u posljednjem primjeru identifikator prirodni moe


koristiti kao tip u nekoj drugoj typedef deklaraciji. Inae, typedef imena se
koriste kako bi se smanjila kompleksnost ispisivanja pojedinih tipova, kao to su
kompleksne deklaracije imenika, pointera na funkcije, te pointera na funkcijske
lanove klasa.

34

Operatori

3.10

sizeof operator

sizeof operator slui za raunanje veliine bilo kojeg podatka ili tipa. To je
unarni operator, koji za operand moe imati tip (npr. int, char, . . . ) ili izraz,
a kao rezultat daje broj bajtova koji operand zauzima u memoriji raunara.
Ovaj rezultat je u potpunosti zavisan od raunara na kojem se radi. Naredni
primjer ilustruje koritenje ovog operatora za raunanje veliine osnovnih tipova podataka.
1
2

#include <iostream>
using namespace std;

3
4
5
6
7
8
9
10
11
12
13
14

int main (void)


{
cout << "char size = "
cout << "short size = "
cout << "int size =
"
cout << "long size = "
cout << "float size = "
cout << "double size ="
cout << "HELLO size = "
system("pause");
}

<<
<<
<<
<<
<<
<<
<<

sizeof(char)
sizeof(short)
sizeof(int)
sizeof(long)
sizeof(float)
sizeof(double)
sizeof("HELLO")

<<
<<
<<
<<
<<
<<
<<

"
"
"
"
"
"
"

bytes\n";
bytes\n";
bytes\n";
bytes\n";
bytes\n";
bytes\n";
bytes\n";

Na laptopu Dell Inspiron 9100 dobivaju se sljedei rezultati:


char size
short size
int size
long size
float size
double size
HELLO size

3.11

=
=
=
=
=
=
=

1
2
4
4
4
8
6

bytes
bytes
bytes
bytes
bytes
bytes
bytes

Hijerarhija operatora

Slino pravilima u matematici o redoslijedu izvoenja pojedinih raunskih operacija, i redoslijed koritenja pojedinih operatora u nekom izrazu u C++ je veoma bitan. Stoga se operatori dijele na razliite hijerarhijske nivoe, pri emu
operatori na viim nivoima imaju prednost nad onim koji su nie. Tabela 3.7
daje prikaz hijerarhije nekih od operatora operatora u C++ , od onih sa najveim prema onim sa najmanjim prioritetom. Pri tome su operatori sa istim
prioritetom smjeteni u isti blok (odvojen horizontalnim linijama).

3.11. Hijerarhija operatora

35

Na primjer, u izrazu
a=b+c*d;

prvo se rauna c*d, jer znak mnoenja * ima vei prioritet od znaka sabiranja
+ i znaka pridruivanja =. Rezultat mnoenja se zatim dodaje varijabli b, jer
operacija sabiranja ima vei prioritet od operacije pridruivanja.
Ovakav nain definisanja hijerarhije je neophodan, jer se pojedini operatori
koriste za vie namjena. Takav primjer je znak plus, +, koji se moe koristiti
kao binarni operator za sabiranje, unarni operator za promjenu znaka nekog
broja, ali i kao operator za uveavanje (postfiks i prefiks inkrement). Ako, na
primjer, elimo sabrati dva broja, pri emu je drugi broj prethodno uvean za
jedan, imamo izraz:
c=a+ ++b;

No, moe se desiti da umjesto prethodnog izraza napiemo:


c=a+++b;

to bi, imajui na umu hijerarhiju operatora, kompajler razumio kao:


c=a++ +b;

U ovom sluaju, prvo se izvrava sabiranje brojeva a i b, a zatim se broj a


povea za jedan, to naravno nismo eljeli uraditi.
Treba napomenuti da u sluaju dvoumljenja oko prioriteta operatora, najbolje je koristiti zagrade, i na taj nain zaobii ugraenu hijerarhiju. Tako bi
ranije primjere mogli napisati u obliku:
a=b+(c*d);

odnosno
c=a+(++b);

Kviz pitanja
1. Koji od logikih operatora su unarni, a koji su binarni?
2. ta radi inkrement operator?
3. ta radi dekrement operator?
4. Objasni ta radi sljedea naredba:
cout >> --broj!

36

Operatori

5. Dodati zagrade sljedeim izrazima tako da se pokae kojim redom se izraunavaju pojedini operatori:
a)
b)
c)
d)

(n <= p + q && n >= p - q || n == 0)


(++n * q / ++p - q)
(n | p & q p 2 + q)
(p < q ? n < p ? q * n - 2 : q / n + 1 : q - n)

6. ta e biti vrijednost sljedeih varijabli nakon inicijalizacije:


a)
b)
c)
d)

double d = 2 * int(3.14);
long k = 3.14 - 3;
char c = a + 2;
char c = p + A - a;

7. Tano ili netano: u naredbi pridruivanja, vrijednost sa lijeve strane od


znaka jednako je uvijek jednako vrijednosti na desnoj strani.
8. Tano ili netano: potpuno je normalno koristiti razliite tipove podataka
u istom aritmetikom izrazu.
9. Objasniti pojam preljeva!
10. Napisati naredbu koja pomou operatora pridruivanja poveava vrijednost varijable temp za 23. Napisati istu naredbu bez operatora pridruivanja.
11. Relacijski operator
a)
b)
c)
d)

Pridruuje jedan operator drugom


Daje Boolean rezultat
Poredi dva operanda
Logiki kombinuje dva operanda

12. Napisati izraz koji koristi relacijski operator koji ima vrijednost true ako
varijabla var1 nije jednaka varijabli var2.
13. Operatori && i ||:
a) Porede dvije numerike vrijednosti
b) Kombinuju dvije numerike vrijednosti
c) Porede dvije Boolean vrijednosti

3.11. Hijerarhija operatora

37

d) Kombinuju dvije Boolean vrijednosti


14. Provjeriti ta je rezultat sljedee upotrebe uslovnog operatora, ako je
m=5.1, n=7.2:
int min = (m < n ? m++ : n++);

Zadaci za izradu
1. Napisati program kojim se unosi oitavanje temperature u Farenhajtima,
te daje ekvivalentna temperatura u Celzijima, koristei formulu:
tempC = 5/9*(tempF - 32)

(Primjer: 104 F = 40 C)
2. Napisati program koji unosi oktalne brojeve, i daje rezultat u decimalnom
obliku. Na primjer,
Unesi oktalni broj: 214 Oktalni(214) = Decimalni(140)

3. Napisati program koji vri konverziju izmeu proizvoljnih brojnih sistema.

38

Operatori

Tabela 3.6: Operatori pridruivanja


Operator
=
+=
=
*=
/=
%=
&=
|=
=
<<==
>>==

Primjer
n=25
n+=25
n =25
n*=25
n/=25
n%=25
n &= 0xF2F2
n |= 0xF2F2
n = 0xF2F2
n <<= 6
n >>= 6

Ekvivalentno sa
n=n+25
n=n25
n=n*25
n=n/25
n=n%25
n = n & 0xF2F2
n = n | 0xF2F2
n = n 0xF2F2
n = n << 6
n = n >> 6

Tabela 3.7: Hijerarhija operatora


Operator
::
.
->
[]
()
++

sizeof
sizeof
++

+-!
*/%
+
> < >= <=
== !=
&

|
&&
||
? :
= *= /= += -= &=
= |= %= >>= <<=
,

znaenje
globalno podruje
izbor lana
izbor lana
indeksiranje
poziv funkcije
uveaj nakon
umanji nakon
veliina objekta
veliina tipa
uveaj prije
umanji prije
unarni operatori
mnoenja
sabiranja
bitovni pomaci
poredbeni operatori
operatori jednakosti
bitovni i
bitovni ili
bitovno iskljuivo ili
logiko i
logiko ili
logiko i
pridruivanja

Primjer
::ime
objekat.clan
pointer->clan
varijabla[indeks]
funkcija(argumenti)
broj++
broj
sizeof izraz
sizeof(tip)
++broj
broj
!broj
izraz % izraz
izraz + izraz
izraz izraz
izraz <= izraz
izraz == izraz
izraz & izraz
izraz izraz
izraz | izraz
izraz && izraz
izraz || izraz
izraz ? izraz : izraz
vrijednost *= izraz

razdvajanje

izraz,izraz

Poglavlje 4

Naredbe
Ovo poglavlje opisuje razne oblike C++ naredbi koje slue za pisanje programa. Kao i veina ostalih programskih jezika, C++ nudi razliite vrste
naredbi koje se koriste u razliite svrhe. Tako se deklaracione naredbe koriste
za definisanje varijabli, naredbe pridruivanja za jednostavne proraune, itd.
U narednim poglavljima bie objanjene neke od njih.

4.1

Jednostavne i sloene naredbe

Jednostavna naredba je svaka naredba koja zavrava taka-zarezom (;). Definicije varijabli i izrazi koji zavravaju sa taka-zarezom su samo neki od primjera,
kao u sljedeim sluajevima:
int
i;
//
++i;
//
double d = 10.5; //
d + 5;
//

deklaraciona naredba
naredba sa popratnom pojavom
deklaraciona naredba
beskorisna naredba

Najjednostavniji oblik naredbe je linija koja sadri samo taka-zarez, tzv.


null -naredba. No, i ovakva naredba ponekad ima smisla, to e se pokazati u
kasnijem tekstu (vidi poglavlje 4.4)
Mnogostruke naredbe se mogu kombinovati u sloene naredbe kada se grupiu izmeu velikih zagrada ({}), kao na primjer
{ int min, i = 10, j = 20;
min = (i < j ? i : j);
cout << min << \n;
}

Ovakve naredbe su korisne iz dva razloga: a) omoguuju da se mnogostruka


naredba postavi tamo gdje bi inae mogla da se postavi samo jedna, i b) omo-

40

Naredbe

guuju da se u program uvede podruje definisanosti varijable (eng. scope).


Podruje varijable predstavlja dio programa unutar kojeg varijabla ostaje definisana. Izvan tog podruja ona to vie nije. Ovo je veoma vana osobina o
kojoj e vie biti rijei u poglavlje 5 o funkcijama.

4.2

Naredba if

Ponekad je poeljno da se izvri odreena naredba koja zavisi od ispunjenja


nekog uslova. Upravo tu mogunost prua if naredba, iji je opti oblik:
if (izraz)
naredba;

Prvo se izvrava izraz, i ako je rezultat razliit od nule izvrava se naredba. U


suprotnom, nita se ne deava.
Na primjer, ako elimo provjeriti da li je pri dijeljenju djelilac razliit od
nule i izvriti dijeljenje, upotreba naredbe if ima oblik:
if (djelilac != 0)
Kolicnik=djelitelj/djelilac;

U sluaju da elimo izvriti vie naredbi koje ovise o nekom istom uslovu,
koristimo sloenu naredbu, tj. sve naredbe stavljamo izmeu velikih zagrada.
Varijanta if naredbe koja omoguuje da se specificiraju dvije alternativne
naredbe, jedna koja se izvrava kada je uslov ispunjen i druga kada nije, naziva
se if-else naredba i ima oblik:
if (izraz)
naredba1;
else
naredba2;

Ovdje se najprije izvrava izraz, i ako je rezultat razliit od nule, izvrava se


naredba1. U suprotnom, izvrava se naredba2, to pokazuje i primjer provjere
da li je broj paran ili ne:
1
2

#include <iostream>
using namespace std;

3
4
5
6

main()
{
int x;

4.3. Naredba switch


cout << "Unesite neki broj";
cin >> x;
if (x % 2 == 0)
cout << "Broj je paran" << endl;
else
cout << "Broj je neparan" << endl;

7
8
9
10
11
12
13

41

Pored prethodno navedenih varijanti, postoji i ugnijedena if naredba, u


kojoj se javlja vie od dvije alternative. Primjer takve varijante je, recimo,
izraunavanje cijene telefonskog rauna:
if (vrijemePoziva > 7 && vrijemePoziva < 19) {
if (duzinaPoziva <= 60)
cijena = duzinaPoziva * tarifa1;
else
cijena = 60 * tarifa + (duzinaPoziva - 60) * tarifa2;
} else
cijena = osnovnaCijena;

Kao to se vidi unutar prve if naredbe, koja provjerava uslov da li je poziv


izvren u periodu 7.00-19.00 sati, nalazi se jo jedna if naredba. Ova naredba
ima za cilj da provjerava duinu poziva, i na osnovu toga formira cijenu istog.
U sluaju da je poziv izvren izvan perioda 7.00-19.00, cijena se formira na
osnovu osnovne cijene poziva.

4.3

Naredba switch

switch naredba omoguuje izbor izmeu vie alternativa, koje su zasnovane na


vrijednosti nekog izraza. Opti oblik switch naredbe je:
switch (izraz) {
case konstanta_1:
naredbe;
break;
...
case konstanta_n:
naredbe;
break;
default:
naredbe;
}

42

Naredbe

Prvo se rauna izraz (switch tag), a zatim se rezultat poredi sa svakom


od numerikih konstanti (labele), po redu kako se javljaju, dok se ne poklopi
sa jednom od komponenti. Nakon toga se izvravaju naredbe koje slijede.
Izvravanje se izvodi sve dok se ne naie na naredbu break ili dok se ne izvre
sve naknadne naredbe. Posljednji sluaj (default) moe, a i ne mora da se
koristi, i pokree se ako nijedna od prethodnih konstanti nije zadovoljena.
Koritenje ove naredbe dat je u sljedeem primjeru, koji odreuje opseg
osvojenih bodova na ispitu na osnovu dobijene ocjene.
#include <iostream>
using namespace std;
main()
{
int ocj;
cout << "Unesite ocjenu: ";
cin >> ocj;
switch (ocj)
{
case 5:
cout << "Imate 90 100 bodova" << endl;
break;
case 4:
cout << "Imate 80 89 bodova" << endl;
break;
case 3:
cout << "Imate 70 79 bodova" << endl;
break;
case 2:
cout << "Imate 60 69 bodova" << endl;
break;
default:
cout << "Imate ispod 60 bodova" << endl;
}
}

4.4

Naredba while

Naredba while (naziva se i while petlja) omoguuje ponavljanje neke naredbe


sve dok je ispunjen neki uslov. Opti oblik ove naredbe je:
while (izraz)
naredba;

4.5. Naredba do

43

Prvo se izraunava izraz (naziva se i uslov petlje). Ako je rezultat razliit on


nule tada se izvrava naredba (naziva se i tijelo petlje) i cijeli proces se ponavlja.
U suprotnom, proces se zaustavlja.
Na primjer, ako elimo izraunati zbir svih brojeva od 1 do n, upotreba
while naredbe ima oblik:
i = 1;
sum = 0;
while (i <= n)
sum += i++; \\ili {sum = sum + i; i = i + 1;}

Tijelo petlje while moe biti prazno, tj. sa null -naredbom, ali to nije uobiajeno. Ipak, sljedei primjer, problem nalaenja najveeg neparnog faktora
nekog broja, pokazuje i jedan takav sluaj.
while (n % 2 == 0 && n /= 2)

Ovdje uslov petlje izvrava sve neophodne kalkulacije, tako da nema potrebe
za tijelom.

4.5

Naredba do

Naredba do (naziva se i do petlja) je slina naredbi while, osim to se prvo


izvrava tijelo petlje, a zatim se provjerava uslov. Opti oblik naredbe je:
do
naredba;
while (izraz);

Prvo se izvrava naredba, a zatim provjerava izraz. Ako je izraz razliit od


nule cijeli proces se ponavlja. U suprotnom, petlja se zaustavlja.
Naredba do se manje koristi nego while petlja. Obino se koristi kada se tijelo
petlje mora izvriti najmanje jedanput bez obzira na ispunjenje uslova. Takav
primjer je, recimo, ponovljeno unoenje nekog broja u primjeru izraunavanja
njegovog kvadrata sve dok se ne unese broj 0:
do {
cin >> n;
cout << "Kvadrat broja " << n << " je" << n * n << "\n";
} while (n != 0);

Za razliku od while petlje, do petlja se nikada ne koristi sa praznim tijelom


prvenstveno zbog jasnoe.

44

4.6

Naredbe

Naredba for

Naredba for (for petlja) je slina naredbi while, ali ima dvije dodatne komponente: (i) izraz koji se izraunava samo jednom prije nekog prorauna koji se
ponavlja, i (ii) izraz koji se izraunava jednom na kraju svake iteracije. Opti
oblik naredbe for je:
for (izraz1; izraz2; izraz3)
naredba;

Prvo se izraunava izraz1. Svakim prolaskom kroz petlju se izraunava izraz2.


Ako je rezultat razliit od nule izraunava se izraz3. U suprotnom petlja se
zaustavlja. Oblik while petlje koja je ekvivalentna do petlji je:
izraz1;
while (izraz2) {
naredba;
izraz3;
}

Naredba for se najee koristi u situacijama kada se neka varijabla poveava


ili smanjuje za neku veliinu u svakoj iteraciji, odnosno kada je broj iteracija
unaprijed poznat. Sljedei primjer rauna zbir svih brojeva od 1 do n:
sum = 0;
for (int i = 1; i <= n; ++i)
sum += i;

Prvo se vrijednost zbira inicijalizira na vrijednost nula (sum=0;). Prvi izraz


u petlji for predstavlja poetnu vrijednost brojaa i, koja je jednaka 1. Nakon
toga, provjerava se uslov i <= n. Ako je uslov ispunjen, izraunava se naredba.
U ovom sluaju, radi se o jednostavnoj naredbi (sum += i;), tako da nema
potrebe za koritenjem velikih zagrada. Nakon izvrenja naredbe, izraunava
se trei izraz, ++i, i postupak nastavlja sve dok se ne ispuni uslov i <= n.
Treba naglasiti da se umjesto prefiks inkrementa, kao trei izraz mogao staviti
i postfiks inkrement (i++).
Bilo koja od komponenti u petlji moe biti prazna. Na primjer, ako se
uklone prvi i trei izraz, onda je do petlja
for (; i != 0;)
bilo-sta;

ekvivalentna sa while petljom

4.6. Naredba for

45

while (i != 0)
bilo-sta;

Uklanjanje svih izraza u petlji daje beskonanu petlju:


for (;;)
bilo-sta;

// beskonana petlja

Poto petlje predstavljaju naredbe, mogu se pojaviti unutar drugih petlji


(tzv. ugnijedene petlje). Klasini primjer je koritenje dvostruke petlje pri
ispisu tablice mnoenja brojeva do 10:
for (int i = 1; i <= 10; ++i){
for (int j = 1; j <= 10; ++j)
cout << setw(5)<< i*j;
cout << endl;
}

U liniji sa ispisom (cout << setw(5)<< i*j;) koriten je operator za manipulisanje setw(), koji se koristi za formatirano ispisivanje. Naime, brojka
unutar zagrada (u gornjem primjeru to je broj 5) predstavlja najmanji prostor
predvien za ispis podataka u izlaznom toku.

Kviz pitanja
1. Koja od petlji (for, while, do) se izvrava barem jednom?
2. Koja od petlji je najbolji izbor kada je broj iteracija poznat?
3. Napii naredbe za sljedee:
a) provjera da li je broj neparan,
b) provjera da li je broj neparan i negativan,
c) dati apsolutnu vrijednost nekog broja.
4. Pretpostavljajui da je n = 20, ta e biti rezultat sljedeeg koda:
if (n >= 0)
if (n < 10)
cout << "n je malo\n";
else
cout << "n je negativno\n";

5. Opii svrhu tri naredbe unutar for petlje.

46

Naredbe

6. Tano ili netano: inkrementalni izraz unutar for petlje moe smanjiti
varijablu petlje.
7. Blok nekog koda je odvojen .....
8. Koliko puta se izvrava tijelo do petlje?
9. Dati sintaksu naredbe switch!

Zadaci za izradu
1. Napisati program koji daje najmanji zajedniki sadrilac dva cijela broja!
2. Napisati program koji daje najvei zajedniki djelilac dva cijela broja!
3. Napisati program koji daje sve proste brojeve izmeu 2 i nekog broja N.
4. Savreni broj je broj koji je jednak zbiru svojih djelilaca. Napisati program koji daje prvih N savrenih brojeva!
5. Napisati program koji daje sve savrene brojeve manje od 10000!
6. Jedna od metoda za rjeavanje nelinearnih jednaina je metoda polovljenja intervala. Napisati program koji daje rjeenje nelinearne jednaine
pomou ove metode, pri emu su ulazni podaci interval u kojem se nalazi
rjeenje, te tanost (razlika izmeu dvije uzastopne iteracije).
7. Napisati program koji rjeava nelinearne jednaine pomou metode tangente, tj. Newton-Raphsonove metode!

Poglavlje 5

Funkcije
Ovo poglavlje opisuje funkcije koje definie korisnik, kao jedan od glavnih
"graevinskih" blokova u C++ programiranju. Funkcije obezbijeuju prikladan nain pakovanja nekog numerikog "recepta", koji se moe koristiti koliko
god je to puta potrebno, i predstavljaju okosnicu tehnike proceduralnog programiranja.

5.1

Definicija

Definicija funkcije se sastoji od dva glavna dijela: zaglavlja ili interfejsa, i


tijela funkcije. Interfejs (neki autori ga nazivaju i prototip) definie kako se
funkcija moe koristiti. On se sastoji od tri dijela:
Imena. Ovo je, u stvari, jedinstveni identifikator funkcije.
Parametara (ili potpisa). Ovo je niz od nula ili vie identifikatora nekog
tipa koji se koriste za prosljeivanje vrijednosti u i iz funkcije.
Tipa. Ovo specificira tip vrijednosti koji funkcija vraa. Funkcija koja ne
vraa nijednu vrijednost bi trebala da ima tip void.
Tijelo funkcije sadri raunske korake (naredbe) koji ine samu funkciju.
Koritenje funkcije se izvodi njenim pozivanjem. Poziv funkcije se sastoji od
imena funkcije, praenim zagradama za pozivanje (). Unutar ovih zagrada se
pojavljuje nula ili vie argumenata koji se odvajaju zarezom. Broj argumenata
treba odgovarati broju parametara funkcije. Svaki argument je izraz iji tip
treba odgovarati tipu odgovarajueg parametra u interfejsu funkcije.
Kada se izvrava poziv funkcije, prvo se raunaju argumenti i njihove rezultujue vrijednosti se pridruuju odgovarajuim parametrima. Nakon toga

48

Funkcije

se izvrava tijelo funkcije. Na kraju, funkcija vraa vrijednost poziva (ako isti
postoji).
Sljedei primjer ilustrativno pokazuje definiciju jednostavne funkcije koja
izraunava vrijednost stepena cijelog broja na neki cijeli broj.
1
2
3
4
5
6
7

int Stepen (int baza, unsigned int eksponent)


{
int
rezultat = 1;
for (int i = 0; i < eksponent; ++i)
rezultat *= baza;
return rezultat;
}

Linija 1 definie interfejs funkcije. Ona poinje tipom funkcije koji se vraa;
u ovom sluaju radi se o cjelobrojnoj vrijednosti, int . Nakon toga je dato ime
funkcije, Stepen, a zatim lista njenih parametara. Funkcija Stepen ima dva
parametra (baza i eksponent) koji su tipa int. Pri tome, uzeto je da varijabla
eksponent ima samo pozitivne vrijednosti (unsigned int), jer je i funkcija Stepen
cjelobrojnog tipa int1 . Sintaksa parametara je slina sintaksi definisanja varijabli, tj. nakon tipa daje se ime parametra, osim to se parametri ne odvajaju
zarezom, kao u
int Stepen (int baza, eksponent)

// Ovo je pogreno!

Zagrada { u liniji 2 predstavlja poetak tijela funkcije. U liniji 3 definisana je


lokalna varijablu rezultat. Stepen varijable baza na varijablu eksponent pomou
for petlje se rauna u linijama 4 i 5. Rezultat se pohranjuje u varijablu rezultat
(linija 5). U liniji 6 vraa se vrijednost rezultat kao rezultat funkcije. Zagrada
} u liniji 7 predstavlja kraj tijela funkcije.
Naredni primjer pokazuje kako se funkcija poziva (bez definicije funkcije).
Posljedica poziva funkcije je da se vrijednosti argumenata 2 i 8 pridruuju
parametrima baza i eksponent, respektivno, a zatim se rauna tijelo funkcije.
1
2

#include <iostream>
using namespace std;

3
4

main(void){

1U

sluaju da se funkcija eli proiriti i na stepenovanje na negativne cijele brojeve, imala bi realni tip,
a linija 5 prethodnog primjera imala bi oblik:
rezultat*=1./baza
pri emu varijabla rezultat mora biti realna.

5.1. Definicija
cout << "2 ^ 8= " << Stepen(2,8) << \n;

5
6

49

Kada se program pokrene daje sljedei izlaz:


2 ^ 8 = 256

Definisanje gore pomenute funkcije moe se izvriti na vie naina, kao to je


pokazano u narednim primjerima.
Primjer 1.
1
2

#include <iostream>
using namespace std;

3
4
5
6

double Stepen (int baza, int eksponent)


{
double
rezultat = 1;

for (int i = 0; i < eksponent; ++i)


rezultat *= baza;
return rezultat;

8
9
10
11

12
13
14
15
16
17
18
19
20
21
22

main ()
{
int a,b;
cout << "Unesi bazu:";
cin >> a;
cout << "\nUnesi eksponent:";
cin >> b;
cout << a<<"^" <<b<<" = " << Stepen(a,b) << \n;
system("PAUSE");
}

Vidi se da je funkcija Stepen definisana prije glavnog programa (sve funkcije, koje se koriste u nekom programu, moraju se definisati prije glavnog
programa, dakle prije funkcije main). U ovom sluaju, funkcija ima tip double,
tako da moe da "pokrije" vie mogunosti (vee rezultate, decimalne brojeve
kao rezultat). Poziv funkcije, linija 20, vri se pomou Stepen(a,b), pri emu
tipovi oba argumenta a i b, odgovaraju tipovima parametara funkcije baza i
eksponent, respektivno.

50

Funkcije

Primjer 2.
Treba napomenuti da se definicija funkcije sastoji od njenog prototipa, tako
da je za definisanje dovoljno ispisati samo njen prototip. Na taj nain, kompletna definicija funkcije se moe dati kasnije, kao to je pokazano u narednom
primjeru. Takoer je mogue izostaviti nazive parametara u definiciji, ali to
nije preporuljivo.
1
2

#include <iostream>
using namespace std;

3
4
5

double Stepen (int baza, int eksponent);


// deklarisanje funkcije

6
7
8
9

/* moguce je funkciju daklarisati i na sljedeci nacin


double Stepen (int, int);
*/

10
11
12
13
14
15
16
17
18
19
20

main ()
{
int a,b;
cout << "Unesi bazu:";
cin >> a;
cout << "\nUnesi eksponent:";
cin >> b;
cout << a<<"^" <<b<<" = " << Stepen(a,b) << \n;
system("PAUSE");
}

21
22
23
24

double Stepen (int baza, int eksponent)


{
double rezultat = 1;

25

for (int i = 0; i < eksponent; ++i)


rezultat *= baza;
return rezultat;

26
27
28
29

Dakle, funkcija je definisana u liniji 4, koristei njen potpis. Vano je napomenuti da je u ovom sluaju neophodno staviti taka-zarez (;) nakon definisanja, jer linija 4 predstavlja naredbu. Sjetimo se da se nakon definisanja
funkcije ne stavlja taka-zarez nakon zagrade }, koja zatvara tijelo funkcije.
itava definicija funkcije data je linijama 22-29.

5.2. Parametri i argumenti

51

Primjer 3.
Radi preglednosti veoma je korisno sakupiti sve funkcije u posebne datoteke,
i umjesto njihovog definisanja u sklopu izvrne datoteke, treba samo proitati
tu datoteku. Na primjer, ako je definicija funkcije Stepen data u datoteci
StepenInt.h,tj.
\\ sadrzaj datoteke StepenInt.h
int Stepen (int baza, int eksponent)
{
int rezultat = 1;
for (int i = 0; i < eksponent; ++i)
rezultat *= baza;
return rezultat;
}

onda prethodni program ima oblik:


#include <iostream>
#include StepenInt.h
using namespace std;
main ()
{
int a,b;
cout << "Unesi bazu:";
cin >> a;
cout << "\nUnesi eksponent:";
cin >> b;
cout << a<<"^" <<b<<" = " << Stepen(a,b) << \n;
system("PAUSE");
}

Ovdje treba paziti gdje se datoteka StepenInt.h nalazi. U primjeru koji je


dat, ona se nalazi u istom direktoriju kao i izvrna datoteka. U suprotnom,
treba dati tanu lokaciju iste (eng. path).

5.2

Parametri i argumenti

C++ podrava dva oblika parametara: vrijednost i referencu. Parametar po


vrijednosti prima kopiju vrijednosti argumenata koja im se prenosi. Kao po-

52

Funkcije

sljedica toga, ako funkcija napravi bilo kakvu promjenu na parametrima, ovo
nee promijeniti vrijednosti argumenata. Na primjer, u programu
#include <iostream>
using namespace std;
void Funkcija (int broj)
{
broj = 0;
cout << "broj = " << broj << \n;
}
int main ()
{
int x = 10;
Funkcija(x);
cout << "x = " << x << \n;
system("PAUSE");
return 0;
}

parametar broj u funkciji Funkcija je parametar po vrijednosti. On se ponaa


kao lokalna varijabla u funkciji. Kada se funkcija pozove i vrijednost x se prenese, varijabla broj primi kopiju vrijednosti varijable x. Kao rezultat toga, iako
varijabla broj u funkciji mijenja vrijednost na 0, to nee utjecati na varijablu
x. Program e dati sljedei izlaz:
broj = 0;
x = 10;

Za razliku od parametra po vrijednosti, parametar po referenci prima argument koji se prenosi i sve obavlja direktno na njemu (vie o referencama u
poglavlju 7.6). Bilo koja promjena parametra po referenci u samoj funkciji,
direktno se odnosi i na argument, tj. i on se mijenja. Da bismo definisali parametar po referenci, potrebno je dodati simbol & (ampersand) ispred varijable
koja je parametar u interfejsu funkcije, tj. u prethodnom primjeru interfejs
funkcije Funkcija ima oblik:
void Funkcija (int &broj)

Mogue je simbol & staviti i iza tipa varijable broj, kao u


void Funkcija (int& broj)

5.3. Globalne i lokalne varijable

53

i na programeru je da odabere nain koji mu vie odgovara. U principu, vano


se uvijek drati istog pravila, ako ni zbog ega drugog onda zbog preglednosti
programa.
U kontekstu pozivanja funkcija, a na osnovu prethodno iznesenog, razlikujemo dvije vrste pridruivanja: pridruivanje prema vrijednosti i pridruivanje
prema referenci. U praksi (u pogledu funkcija) se mnogo vie koristi pridruivanje prema vrijednosti.

5.3

Globalne i lokalne varijable

Za sve to se definie izvan programskog podruja (scope) se kae da ima


globalni karakter. Tako, sve funkcije koje smo do sada koristili predstavljaju
globalne funkcije. No, i varijable se mogu definisati u globalnom podruju, tj.
izvan svih funkcija koje se koriste u programu, ukljuujui i funkciju main. Na
primjer:
int godina = 1994;
// globalna varijabla
int Maksimum (int,int); // globalna funkcija
int main (void){
// globalna funkcija
//...
}

Treba zapamtiti da su globalne varijable automatski inicijalizirane na vrijednost nula.


Poto su globalni entiteti "vidljivi" na svim programskim nivoima, oni moraju biti jedinstveni na nivou programa. To znai da se globalne varijable ili
funkcije na globalnom podruju ne mogu definisati vie nego jedanput, iako se
ime funkcije moe definisati vie puta sve dok su im parametri (njen potpis)
jedinstveni (o optereenju funkcija bit e vie govora u dijelu 5.5). Globalni
entiteti su openito pristupani bilo gdje u programu.
Svaki blok u programu definie lokalno podruje. Na taj nain, tijelo funkcije predstavlja lokalno podruje. Parametri funkcije imaju isto podruje kao
i tijelo funkcije. Varijable koje su definisane unutar lokalnog podruja su vidljive samo u tom podruju. Lokalno podruje moe da bude ugnijedeno, pri
emu unutranje podruje ponitava vanjsko. Na primjer, u
int xyz;
// xyz je globalna varijabla
void Funkc (int xyz) // xyz je lokalna varijabla
// u tijelu funkcije
Funkc {
if (xyz > 0) {
double xyz; // xyz je lokalna varijabla u ovom bloku

54

Funkcije
//...
}
}

imamo tri razliita podruja, od kojih svaki ima razliitu varijablu xyz.
Openito, ivotni vijek varijable je ogranien na podruje iste. Tako, na
primjer, globalne varijable traju svo vrijeme izvrenja programa, dok se lokalne
varijable kreiraju kada se ue u njihovo podruje, a unitavaju kada se iz njega
izae. Memorijski prostor za lokalne varijable je rezervisan prije izvrenja
programa, dok je memorijski prostor za lokalne varijable alociran "u hodu" u
toku izvrenja programa.
Poto lokalno podruje ponitava globalno, to lokalne varijable sa istim
imenom kao globalne varijable onemoguavaju pristup globalnim varijablama
unutar lokalnog podruja. Na primjer, u
int greska; \\globalna varijabla
void Greska (int greska) { \\lokalna varijabla
//...
}

globalna varijabla greska je, kao to se i oekuje, nepristupana unutar funkcije


Greska, poto je ponitena lokalnim parametrom greska.
Ovaj problem se moe prevazii koritenjem unarnog operatora podruja
:: (unary scope operator ), koji globalni entitet uzima kao argument, kao u
primjeru
int greska;
void Greska (int greska) {
//...
if (::greska != 0) // odnosi se na globalnu varijablu
// greska
//...
}

5.4

Rekurzivne funkcije

Za funkciju koja poziva samu sebe kaemo da je rekurzivna. Rekurzija je opta


programska metoda koja se primjenjuje na probleme koji se definiu u odnosu
na same sebe.
Na primjer, problem raunanja faktorijela je primjer rekurzivne funkcije.
Faktorijel je definisan sa:
Faktorijel od 0 je 1.

5.5. Optereene (overloaded ) funkcije

55

Faktorijel pozitivnog broja n je n puta faktorijel od n-1, tj. n!=n(n-1)!


Posljednji dio definicije jasno pokazuje da je faktorijel definisan u odnosu
na samog sebe, te se stoga moe predstaviti rekurzivnom funkcijom, npr.
int Faktorijel (unsigned int n) {
return n == 0 ? 1 : n * Faktorijel(n-1);
}

U principu, sve rekurzivne funkcije se mogu napisati koristei iteracije. Naime, treba imati u vidu da u sluaju velikog broja poziva funkcija (u primjeru
faktorijela je to veliki broj n), dolazi do zauzimanja velikog memorijskog prostora (tzv. runtime stack ), pa je upotreba iteracija bolje rjeenje. No, u nekim
sluajevima elegantno i jednostavno rekurzivno rjeenje moe da bude bolja
opcija.
U sluaju faktorijela, na primjer, iterativna opcija je bolja, pa bi funkcija
imala oblik:
int Faktorijel (unsigned int n) {
int rezultat = 1;
while (n > 0) rezultat *= n--;
return rezultat;
}

5.5

Optereene (overloaded ) funkcije

U prethodnim poglavljima je pomenuto da je mogue definisati vie funkcija


sa istim imenom, pri emu njen potpis mora biti drugaiji. Ovaj postupak se
naziva optereivanje (overloading, specijalni oblik polimorfizma) i predstavlja
jednu od osnovnih karakteristika objektno-orijentisanog programiranja.
Ako bismo eljeli da naa funkcija Stepen ima mogunost koritenja realnih
brojeva umjesto cijelih, ili, pak, da izraunava vrijednost stepena broja 2 na
neki realan broj, onda bismo definisali dvije dodatne funkcije sa istim imenom,
ali razliitim potpisom. Sljedei primjer pokazuje koritenje ovakvih funkcija.
#include <iostream>
#include <cmath>
using namespace std;
int Stepen (int baza, int eksponent)
{
int rezultat = 1;

56

Funkcije

for (int i = 0; i < eksponent; ++i)


rezultat *= baza;
return rezultat;
}
double Stepen (double baza, double eksponent)
// funkcija Stepen sa realnim parametrima
{
return exp(eksponent*log(baza));
}
double Stepen (double eksponent)
/* funkcija Stepen sa jednim
parametrom za izracunavanje stepena broja 2*/
{
return Stepen(2.0,eksponent);
}
main (void)
{
double a,b;
cout << "Unesi bazu:";
cin >> a;
cout << "\nUnesi eksponent:";
cin >> b;
cout << a<<"^" <<b<<"= " << Stepen(a,b) << \n;
cout << "2^" <<b<<"= " << Stepen(b) << \n;
system("PAUSE");
}

Iz primjera se vidi da sve funkcije imaju isto ime; prva i druga imaju razliite tipove, dok trei oblik funkcije Stepen ima razliit broj parametara. Treba
paziti da pri pozivu pojedinih funkcija svi tipovi argumenata odgovaraju tipovima parametara (broj 2 se tretira kao cijeli broj, ali 2.0 kao realan!!!)

Kviz pitanja
1. Da li funkcija moe imati vie od jednog argumenta?
2. Da li funkcija mora imati return vrijednost?
3. Da li funkcija moe imati vie od jedne return vrijednosti?
4. Da li je mogue da funkcija nema ni argumente ni return vrijednost?

5.5. Optereene (overloaded ) funkcije

57

5. Da li funkcija moe imati i argumente i return vrijednosti?


6. Nakon imena funkcije slijedi .....
7. Tijelo funkcije je odvojeno ....
8. Skup naredbi koji obavlja radnje neke funkcije predstavlja ..... funkcije.
9. Opis funkcije dat jednom naredbom, koja zapoinje definiciju funkcije,
naziva se ....
10. Tano ili netano: kada se argumenti funkcije prenose po vrijednosti,
funkcija radi sa originalnim argumentima iz programa koji poziva funkciju.
11. Varijabla definisana unutar bloka je vidljiva:
a) od take definisanja nadalje u programu,
b) od take definisanja nadalje u funkciji,
c) od take definisanja nadalje u bloku,
d) u cijeloj funkciji.
12. ta znai kada se koriste prazne zagrade () u definiciji funkcije?
13. Koliko vrijednosti se moe vratiti iz funkcije?
14. Tano ili netano: kada funkcija vraa vrijednost, cijeli poziv funkcije
se moe pojaviti na desnoj strani znaka jednakosti i pridruiti drugoj
varijabli.
15. Gdje se specificira tip vrijednosti koji se vraa nekom funkcijom?
16. Kada se argument prenosi po referenci:
a) kreira se varijabla u funkciji da pohrani vrijednost argumenta,
b) funkcija ne moe pristupiti vrijednosti argumenta,
c) kreira se privremena varijabla u programu koji poziva funkciju da pohrani vrijednost argumenta,
d) funkcija pristupa originalnoj vrijednosti argumenta u programu koji je
poziva.

58

Funkcije

Zadaci za izradu
1. Zadatke 1, 2 i 3 iz Poglavlja 3 rijeiti koritenjem funkcija.
2. Napisati funkciju koja daje sve proste brojeve izmeu brojeva 2 i nekog
broja N. Funkcija treba da ima jedan argument.
3. Napisati funkciju bisekcija, sa argumentima a i b za granice intervala, te
epsilon za tanost i funk za funkciju f(x), koja rjeava nelienarnu jednainu pomou metode bisekcije; funkcija treba da vraa rjeenje jednaine
f (x) = 0. Definisati funkciju funk, koja daje vrijednost traene funkcije
f (x).
4. Prethodni zadatak rijeiti za Newton-Raphsonovu metodu!
5. Napisati program koji sadri funkciju NZS, koja kao rezultat daje najmanji zajedniki sadrilac dva broja.
6. Napisati program koji sadri funkciju NZD, koja kao rezultat daje najvei
zajedniki djelilac dva broja.
7. Napisati funkciju koja provjerava da li su dva broja brojevi prijatelji.
Brojevi prijatelji su oni brojevi kod kojih vrijedi da je svaki od njih jednak
zbiru djelilaca drugog.
8. Dati funkciju koja kao rezultat daje traeni broj parova brojeva prijatelja.
Kao argument dati broj traenih parova.

Poglavlje 6

Polja (arrays)
Ovo poglavlje objanjava polja (neki autori upotrebljavaju i izraz niz) i ilustruje njihovu upotrebu pri definisanju varijabli. Polje se sastoji od niza objekata (nazivaju se i elementi polja), koji su istog tipa i zauzimaju neprekidan
memorijski prostor. Openito, samo polje ima simboliko ime, a ne njegovi
elementi. Svaki element je identificiran njegovim indeksom, koji pokazuje poloaj nekog elementa u polju. Broj elemenata u polju naziva se dimenzija polja.
Dimenzija polja je fiksirana i prethodno odreena, i ne moe se promijeniti u
toku izvrenja programa.
Polja su pogodna za predstavljanje podataka koji se sastoje od mnogo slinih, individualnih objekata. Primjeri za to su lista imena, tabela gradova i
njihovih sezonskih temperatura, i slino.

6.1

Definisanje i inicijalizacija

Varijabla polje je definisana specificiranjem njegove dimenzije i tipa njegovih


elemenata. Na primjer, polje koje obuhvata 10 mjerenja visine (od kojih je
svaka cijeli broj) moe se definisati na sljedei nain (broj se ispisuje izmeu
uglastih zagrada, []):
int visina[10];

Pristup individualnim elementima polja (u ovom sluaju radi se o nizu


elemenata) vri se indeksiranjem tog polja. Prvi element polja uvijek ima
indeks 0. Na taj nain, visina[0] i visina[9] oznaavaju prvi i posljednji element
polja visina, respektivno. U ovom sluaju, svaki element polja se moe tretirati
kao varijabla tipa cijeli broj, tj. int . Tako, na primjer, da bi smo treem
elementu polja visina pridruili vrijednost 177, piemo:

60

Polja (arrays)
visina[2] = 177;

Pokuaj pristupa nepostojeem elementu nekog polja (na primjer visina[-1]


ili visina[10]) moe uzrokovati ozbiljnu greku (tzv. runtime greka, ili greka
"indeks izvan granica").
Procesiranje bilo kojeg polja obino ukljuuje koritenje petlje, koja ide kroz
polje od elementa do elementa. Sljedei primjer pokazuje funkciju koja rauna
srednju vrijednost elemenata nekog polja od tri cjelobrojna elementa:
const int velicina = 3;
double Srednja (int broj[velicina]) {
double srednja = 0;
for (int i = 0; i < velicina; ++i)
srednja += broj[i];
return srednja/velicina;
}

Kao i kod ostalih varijabli, vrijednosti elemenata polja se mogu inicijalizirati. U tu svrhu koriste se zagrade {}, izmeu kojih se specificira lista poetnih
vrijednosti elemenata polja koje su odvojene zarezom. Na primjer,
int broj[3] = {5, 10, 15};

definie polje broj, i inicijalizira tri elementa ovog polja na vrijednosti 5, 10, 15,
respektivno. Ovo je tzv. eksplicitno inicijaliziranje. Kada je broj vrijednosti
u inicijalizatoru manji od dimenzije polja, ostali elementi su inicijalizirani na
nulu, kao u sluaju:
int broj[3] = {5, 10}; // broj[2] je inicijaliziran na 0

Kada se koristi potpuni inicijalizator (broj poetnih vrijednosti odgovara


dimenziji polja), dimenzija polja postaje suvina i moe se izostaviti, tj. broj
elemenata je implicitan u inicijalizatoru implicitna inicijalizacija. U ovom
sluaju inicijalizacija polja broj se moe izvriti i na sljedei nain:
int broj[] = {5, 10, 15}; // dimenzija nije potrebna

Jo jedan primjer u kojem se dimenzija polja moe izostaviti je kada je


neko polje parametar u nekoj funkciji. Na primjer, funkcija Srednja iz ranijeg
primjera se moe napisati na bolji nain, ako se postavi da dimenzija polja nije
fiksirana na neku konstantnu vrijednost, nego se doda jo jedan parametar, tj.
double Srednja (int broj[], int velicina) {
double srednja = 0;

6.1. Definisanje i inicijalizacija

61

for (int i = 0; i < velicina; ++i)


srednja += broj[i];
return srednja/velicina;
}

Vidi se da se pomou definicije int broj[] omoguava vea fleksibilnost dimenzije polja, pa je kompletan program u tom sluaju:
#include <iostream>
using namespace std;
double Srednja (int broj[],int velicina)
{
double srednja = 0;
for (int i = 0; i < velicina; ++i)
srednja += broj[i];
return srednja/velicina;
}
main ()
{
int velicina;
cout <<"Broj elemenata ....";
cin >> velicina;
int n[velicina];
for(int i=0;i<velicina;i++){
cout<<"n["<<i<<"]= ";
cin>>n[i];
}
cout << "Srednja vrijednost je .... "
<< Srednja(n,velicina) << "\n";
system("PAUSE");
}

Sljedei program predstavlja primjer pomou kojeg se unosi, sortira i ispisuje neki niz. Pri tome, sortiranje je izvedeno od najveeg prema najmanjem
elementu niza.
1
2
3
4
5

#include <iostream>
using namespace std;
int main ()
{
// DEFINISANJE

62

Polja (arrays)
int x[10];
int y[10];
int i, j, n;
// UNOSENJE
cout << "Unesite broj clanova polja (<10): ";
cin >> n;
for (i = 0; i < n; i++)
{
cout << "Unesite clan br. " << i << ": ";
cin >> x[i];
y[i] = x[i];
}
// SORTIRANJE
for (i = 0; i < n-1; i++)
{
for (j = i+1; j < n; j++)
{
if (y[i] < y[j]) swap(y[i],y[j]);
}
}
// STAMPANJE
cout << "x:" << \t << "y:" << endl;
for (i = 0; i < n; i++)
{
cout << x[i] << \t << y[i] << endl;
}

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

U ovom primjeru je za zamjenu vrijednosti varijabli koritena funkcija swap


(linija 23), mada programer sam moe definisati slinu funkciju.
Kao to je ranije reeno, za pohranjivanje testova se koriste znakovna polja
(eng. string). To su, u stvari, polja iji elementi imaju tip char. Prilikom
inicijalizacije ovakvih polja, sadraj se stavlja izmeu znaka dvostrukih navoda
". Na primjer:
char

str[] = "VOZDRA";

definie varijablu str kao niz od sedam (7) karaktera: est slova i jedan prazan
karakter (null -karakter). Zavrni prazan karakter postavlja kompajler. Za
razliku od toga,
char

str[] = {V, O, Z, D, R, A};

definie varijablu str kao niz od 6 elemenata. Treba naglasiti da prethodni primjer nije ispravan, jer svaki pravilno inicijalizirani niz karaktera mora obavezno

6.2. Multidimenzionalna polja

63

da zavri null -karakterom. Takoer, ovakav nain inicijaliziranja je neefikasan


u odnosu na prvi.
Osim ovakvog predstavljanja rijei, tj. znakovnih polja, u C++ je ugraen
i tip string, koji manipulie sa znakovnim poljima. S obzirom da se radi o
specijalnoj klasi u C++ , to pripada objektno-orijentisanoj paradigmi, ovdje
o tome nee biti rijei.

6.2

Multidimenzionalna polja

Polje moe da ima i vie nego jednu dimenziju (dvije, tri, i vie). Ipak, organizacija polja u memoriji je ista kao i prije, tj. neprekidna sekvenca elemenata,
pa je percepcija programera neto drugaija od one koja se namee na prvi
pogled (kao multidimenzionalna). Na primjer, pretpostavimo da je srednja vrijednost temperatura po godinjim dobima za tri bosanskohercegovaka grada
data tabelom 6.1.
Tabela 6.1: Srednje godinje temperature gradova
Ime grada
Sarajevo
Tuzla
Zenica

Proljee
10
13
14

Ljeto
20
21
23

Jesen
10
12
11

Zima
1
3
4

Ovo se moe predstaviti dvodimenzionalnim poljem cijelih brojeva:


int godDobTemp[3][4];

Ovo je u memoriji predstavljeno kao neprekidan niz od 12 elemenata tipa


int . Programer, meutim, moe to zamisliti kao tri reda od po 4 elementa u
svakom, kao na Sl.6.1.
...

10

20
First row

10

Prvi red

13

21
Second row

12

Drugi red

14

23

11

...

Third row

Trei red

Slika 6.1: Organizacija varijable godDobTemp u memoriji

Kao i kod jednodimenzionalnih polja (nizova), i ovdje se elementima pristupa preko indeksa. No, neophodan je dodatni indeks za svaku dimenziju.
Na primjer, srednja temperatura u Zenici u toku ljeta, data je elementom
godDobTemp[2][1].
Inicijalizacija polja se moe obaviti pomou ugnijedenog inicijalizatora, kao
u:

64

Polja (arrays)
int godDobTemp[3][4] = {
{10, 20, 10, 1},
{13, 21, 12, 3},
{14, 23, 11, 4}
};

Poto se ovo dvodimenzionalno polje mapira kao jednodimenzionalni niz od


12 elemenata, mogue je koristiti i sljedei nain:
int godDobTemp[3][4] = {
10, 20, 10, 1, 13, 21, 12, 3, 14, 23, 11, 4
};

Ipak, bolja opcija je koritenje ugnijedenog inicijalizatora, poto ne samo


da je pregledniji, nego daje i dodatne mogunosti. Na primjer, ako je samo
prvi element svakog reda razliit od nule, a ostali su jednaki nuli, moemo
koristiti:
int godDobTemp[3][4] = {{26}, {24}, {28}};

Takoer je mogue izostaviti prvu dimenziju (implicitna inicijalizacija), kao


u:
int godDobTemp[][4] = {
{10, 20, 10, 1},
{13, 21, 12, 3},
{14, 23, 11, 4}
};

Procesiranje multidimenzionalnih polja je slino jednodimenzionalnim, s


tim da se moraju koristiti ugnijedene petlje. Sljedei primjer pokazuje pronalaenje maksimalnog elementa u dvodimenzionalnom polju iz prethodnih
primjera.
#include <iostream>
using namespace std;
const int redovi
const int kolone

= 3;
= 4;

int godDobTemp[redovi][kolone] = {
{10, 20, 10, 1},
{13, 21, 12, 3},
{14, 23, 11, 4}
};

6.2. Multidimenzionalna polja

65

int najTemp (int temp[redovi][kolone])


{
int najveca = temp[0][0];
for (int i = 0; i < redovi; ++i)
for (int j = 0; j < kolone; ++j)
if (temp[i][j] > najveca)
najveca = temp[i][j];
return najveca;
}
main ()
{
cout << najTemp(godDobTemp) << "\n";
system("PAUSE");
}

Napomena: Treba paziti kako se inicijalizira vrijednost kontrolne varijable najveca u prethodnom primjeru; pravilno je postaviti na prvi lan polja,
umjesto pretpostaviti neku konanu vrijednost (na primjer 0).

Kviz pitanja
1. Da li neko polje moe sadravati i cijele brojeve, realne brojeve i karaktere?
2. Koji je indeks prvog elementa u nizu?
3. Koji je indeks posljednjeg elementa u nizu?
4. Koja je razlika izmeu inicijalizacije i pridruivanja?
5. Koja su dva naina inicijalizacije polja?

Zadaci za izradu
1. Napisati program koji rjeava sistem od N (treba unijeti ovu vrijednost)
linearnih jednaina pomou Gaussove metode eliminacije.
2. Prethodni zadatak uraditi pomou Gaussove metode eliminacije sa djeliminim izborom glavnog elementa.
3. Prethodne zadatke rijeiti koristei funkciju Gauss, odnosno GaussIzbor,
koje kao argumente uzimaju matricu sistema A, te vektor b.

66

Polja (arrays)

4. Napisati program koji daje koeficijente polinoma n-tog reda koji aproksimiraju proizvoljan broj taaka, na primjer m, pomou metode najmanjih
kvadrata.
5. Prethodni primjer napisati koristei funkciju MNKpolinom, koja kao argumente ima koordinate taaka (x,y), broj tih taaka m, te stepen traenog
aproksimacionog polinoma n, a njena vrijednost je niz koeficijenata polinoma.

Poglavlje 7

Pointeri
7.1

Osnovno o pointerima

Pointeri (pokazivai) predstavljaju adresu neke memorijske lokacije i omoguuju indirektni nain pristupa podacima u memoriji. Pointer varijabla se definie pokazivanjem na podatak odreenog tipa. Na primjer,
int *ptr1;
char *prt2;

// pointer cijelog broja


// pointer karaktera

Vrijednost pointera varijable je adresa na koju pokazuje. Na primjer, ako


se uzme da je:
int num;

moemo pisati:
ptr1 = &num;

Simbol & (ampersand, znak i) je adresni operator; on uzima varijablu kao


argument i vraa memorijsku adresu te varijable. Efekt prethodnog pridruivanja je da je adresa varijable num pridruena pointeru ptr1. Na taj nain,
kaemo da ptr1 pokazuje na num. Dijagramski prikaz ovog pridruivanja dat
je na slici 7.1.
prt1

broj

Slika 7.1: Jednostavan cjelobrojni pointer

Uzimajui da ptr1 pokazuje na num. Izraz:

68

Pointeri
*ptr1

dereferencira ptr1 da bi se dobilo ono na ta on pokazuje, pa je time ekvivalentan num. Simbol * je operator dereferenciranja; on uzima pointer kao
argument i vraa sadraj memorijske lokacije na koju pokazuje.
Openito, tip pointera mora odgovarati tipu podatka na koji taj pointer
pokazuje. Meutim, pointer tipa void odgovara bilo kojem tipu. Ovo je veoma
korisno pri definisanju pointera koji mogu pokazivati na podatke razliitih
tipova, ili one podatke kojima tip u poetku nije poznat.
Pointer se moe konvertovati (pomou cast) u neki drugi tip. Na primjer,
ptr2 = (char*) ptr1;

konvertuje ptr1 u pointer karaktera prije nego se pridrui pointeru ptr2.


Bez obzira na tip, pointeru se moe pridruiti vrijednost 0. Ovakav pointer
se naziva null -pointer. Null -pointer se koristi za inicijalizaciju pointera, i za
obiljeavanje kraja struktura sa podacima koji se zasnivaju na pointerima (na
primjer, linkovane liste i sl.).

7.2

Dinamika memorija

Pored programskog stoga (eng. stack ), koji se koristi za pohranjivanje globalnih varijabli, te blokova stogova za pozivanje funkcija, na raspolaganju je
i drugi vid memorije, koji se naziva hrpa (eng. heap). Ova memorija se koristi za dinamiko alociranje memorijskih blokova u toku izvrenja programa.
Zbog toga se ova memorija esto naziva i dinamika memorija. S druge strane,
programski stog se esto naziva statika memorija.
Za alociranje i dealociranje memorijskih blokova u hrpi (jo se naziva i javna
memorija) koriste se dva operatora. Operator new kao argument uzima tip i
alocira memorijski prostor za objekat tog tipa. On vraa pointer na alocirani
prostor. Na primjer,
int *ptr = new int;
char *str = new char[10];

alociraju prostor za jedan cijeli broj i prostor koji je dovoljno velik da pohrani
niz od deset karaktera, respektivno.
Memorija koja se alocira iz hrpe ne ispunjava ista pravila podruja definisanosti (eng. scope rules) kao normalne varijable. Na primjer, kada funkcija
Funkcija
void Funkcija (void) {
char *str = new char[10];

7.2. Dinamika memorija

69

//...
}

vraa vrijednost, lokalna varijabla str je unitena, ali memorijski prostor koji
pokazuje na str nije. Ovo posljednje ostaje alocirano sve dok ga programer
eksplicitno ne oslobodi.
Operator delete se koristi za oslobaanje memorijskog prostora koji se alocira pomou new. On uzima pointer kao argument i oslobaa memorijski
prostor na koji taj pointer pokazuje. Na primjer,
delete ptr;
delete [] str;

// brie neki objekat


// brie niz objekata

Ukoliko bi se na niz podataka, koristio prvi pristup, oslobaa se prostor samo


jednog elementa niza, tako da je u sluaju nizova uvijek neophodno dodati
zagrade [ ], koje treba da to i pokau. Ako se operator delete treba primijeniti
na pointer koji pokazuje ni na ta drugo no dinamiki alocirani objekat (na
primjer varijabla u stogu), moe doi do ozbiljne greke (tipa runtime). S
druge strane, potpuno je bezazleno primijeniti ovaj operator na null -pointer.
Dinamiki objekti su veoma korisni za kreiranje podataka koji traju due od
poziva funkcija koje ih kreiraju. Sljedei primjer pokazuje jedan takav sluaj,
gdje se koristi funkcija koja uzima string parametar i vraa kopiju stringa.
1
2
3
4
5
6
7

#include <string>
char* CopyOf (const char *str)
{
char *copy = new char[strlen(str) + 1];
strcpy(copy, str);
return copy;
}

U linija 1, kao to je ve poznato, poziva se standardna biblioteka string


koja definie mnotvo funkcija za manipulisanje sa stringovima. Funkcija strlen (definisana u string), u liniji 4, daje broj karaktera njenog argumenta (koji
je tipa string) do posljednjeg null -karaktera, koji nije uzet u obzir. Kako null karakter nije ukljuen u brojanje, treba dodati jo jedan karakter i alocirati
niz karaktera te veliine (sa tim brojem karaktera). Funkcija strcpy, koja je takoer definisana u string, kopira drugi argument na prvi, karakter po karakter,
ukljuujui i posljednji null -karakter.
Zbog ogranienih memorijskih resursa, uvijek postoji mogunost da se dinamika memorija "potroi" u toku izvrenja programa, naroito ako se alocira
veliki prostor, ali se i ne oslobodi. U sluaju da operator new ne moe da alocira prostor potrebne veliine, vratie vrijednost nula. Na programeru je da se

70

Pointeri

bavi ovakvim problemima. Jedna od osnovnih karakteristika jezika C++ , rad


sa iznimkama, daje praktian primjer ta i kako raditi sa ovim problemima,
ali to nije jedna od tema u ovom tekstu.

7.3

Pointeri i polja

Pointeri i polja su u jeziku C++ povezani. Naime, lanovima polja se pristupa


preko pointera. Tako na primjer, naredbom
int cijeliBroj[10];

definiemo jednodimenzionalno polje cijelih brojeva tipa int sa deset lanova.


Ime varijable cijeliBroj ima smisao pointera na prvi elemenat polja cijeliBroj[0].
Prilikom pristupa elementima polja, kompajler vrijednost indeksa dodaje pointeru na prvi elemenat, tako da se naredba
int broj = cijeliBroj[3];

prevodi kao
int broj = *(cijeliBroj+3);

Posljednja naredba se moe shvatiti kao: uzmi adresu prvog elementa polja,
poveaj je za 3, pogledaj ta se nalazi na toj adresi, te pridrui tu vrijednost
varijabli broj. Dakle, ako imamo definisano polje
int cijeliBroj[] = {1,2,3};

onda imamo sljedea znaenja:


cout << cijeliBroj << endl;
// adresa poetnog elementa
cout << *cijeliBroj << endl;
// vrijednost poetnog elementa polja
cout << &(cijeliBroj[1]) << endl;
// adresa elementa cijeliBroj[1]
cout << (cijeliBroj + 1) << endl;
// adresa elementa cijeliBroj[1]

Stoga se elementima polja moe pristupati i preko pointera i preko indeksa, i na


programeru je koji e pristup koristiti. Ipak, treba naglasiti da se definicijom
int cijeliBroj[10];

ne stvara pointer na varijablu cijeliBroj koji pokazuje na polje, nego je cijeliBroj


samo sinonim za pointer na prvi elemenat polja. Vrlo slina diskusija se moe
primijeniti i na viedimenzionalna polja, s obzirom da su u memoriji raunara
ista predstavljena jednodimenzionalnim poljima.

7.4. Aritmetika sa pointerima

7.4

71

Aritmetika sa pointerima

U C++ je mogue neku cjelobrojnu vrijednost dodati i oduzeti od pointera.


Programeri esto koriste ovu mogunost, koja se jo naziva i aritmetika sa
pointerima. Ova aritmetika, pak, nije ista kao ona sa cjelobrojnim vrijednostima, jer rezultat zavisi od veliine objekta na koji se pokazuje. Na primjer,
pretpostavimo da je int predstavljen sa 4 bajta. Ako se uzme da je
char *str = "VOZDRA";
int broj[] = {10, 20, 30, 40};
int *ptr =&broj[0];

str++ e "napredovati" str za jedan karakter char, tj. za jedan bajt, tako da
pokazuje na drugi karakter niza karaktera "VOZDRA", dok e ptr++ "napredovati" ptr za jedan int, tj. 4 bajta, tako da pokazuje na drugi elemenat niza
broj. Slika 7.2 pokazuje ovo shematski.
V O Z D R A \0

str
str++

10

20

30

40

ptr
ptr++

Slika 7.2: Aritmetika sa pointerima

Na osnovu prethodno reenog slijedi da se elementi niza "VOZDRA" mogu


predstaviti i sa *str, *(str+1), *(str+2), itd.. Na slian nain, elementi niza
broj se mogu predstaviti sa *ptr, *(ptr+1), *(ptr+2) i *(ptr+3).
Jo jedan vid aritmetike sa pointerima koji je dozvoljen u C++ je oduzimanje pointera istog tipa. Na primjer,
int *ptr1 = &broj[1];
int *ptr2 = &broj[3];
int n = ptr2 - ptr1; // n postaje 2

Aritmetika sa pointerima je veoma korisna kada se pristupa elementima


nekog niza. Sljedei primjer pokazuje funkciju za kopiranje rijei slinu funkciji
strcpy.
1
2
3

void CopyString (char *dest, char *src)


{
while (*dest++ = *src++)

72

Pointeri
;

4
5

U liniji 3, uslov petlje pridruuje sadraj src sadraju dest, a zatim inkrementalno poveava oba pointera. Ovaj uslov postaje jednak nuli kada je
posljednji null -karakter pointera src kopiran u dest.
Pokazuje se da je varijabla koja predstavlja niz, kao to je to sluaj sa broj
sama po sebi adresa prvog elementa niza koji predstavlja. Stoga se elementima varijable broj moe pristupiti i preko aritmetike sa pointerima na broj, tj.
broj[i] je ekvivalentno *(broj+i). Razlika izmeu broj i ptr je u tome to je broj
konstanta, tako da ne moe pokazivati ni na ta, dok je ptr varijabla i moe se
iskoristiti da pokazuje na bilo koji drugi cijeli broj.
Sljedei primjer pokazuje kako funkcija najTemp, koja je pokazana u prethodnom poglavlju moe da se pobolja koritenjem aritmetike sa pointerima.
1
2
3
4
5
6
7
8
9
10

int najTemp (const int *temp, const int redovi,


const int kolone)
{
int
najveca = 0;
for (int i = 0; i < redovi; ++i)
for (int j = 0; j < kolone; ++j)
if (*(temp + i * kolone + j) > najveca)
najveca = *(temp + i * kolone + j);
return najveca;
}

U ovom sluaju, umjesto da se na funkciju prenosi niz (linija 1), prenosi se


int pointer i dva dodatna parametra koja specificiraju dimenzije niza. Na ovaj
nain, funkcija nije ograniena na niz odreene duine. Izraz *(temp+i * kolone+j) u liniji 8, je ekvivalentan izrazu temp[i][j] koji je koriten u prethodnom
poglavlju.
Funkcija najTemp se moe dalje pojednostaviti, ako se temp tretira kao
jednodimenzionalni niz od redovi*kolone cijelih brojeva. Ovo je pokazano u
sljedeem primjeru.
1
2
3
4
5
6
7

int najTemp (const int *temp, const int redovi,


const int kolone)
{
int
najveca = 0;
for (int i = 0; i < redovi * kolone; ++i)
if (*(temp + i) > najveca)
najveca = *(temp + i);

7.5. Funkcijski pointeri


return najveca;

8
9

7.5

73

Funkcijski pointeri

Pored svega do sada reenog o pointerima, mogue je uzeti i adresu funkcije i


pohraniti je kao pointer funkcije. Tada se pointer moe koristiti da indirektno
pozove funkciju. Na primjer,
int (*Uporedi)(const char*, const char*);

definie pointer funkciju koja se naziva Uporedi koja moe zadrati adresu bilo
koje funkcije koja kao argumente uzima dva konstantna pointera tipa char i
vraa cjelobrojnu vrijednost. Takva je, na primjer, funkcija strcmp, koja slui
za uporeivanje stringova. Na taj nain imamo:
Uporedi = &strcmp;

//
//

funkcija Uporedi pokazuje na strcmp


funkciju

Operator & nije neophodan i moe se izostaviti:


Uporedi = strcmp;

//
//

funkcija Uporedi pokazuje na strcmp


funkciju

Kao alternativa, mogue je definisati i inicijalizirati pointer odjednom, kao


int (*Uporedi)(const char*, const char*) = strcmp;

Kada se adresa funkcije pridruuje pointeru funkcije, dva tipa se moraju


poklapati. Prethodna definicija je ispravna jer se prototip funkcije strcmp
poklapa
int strcmp(const char*, const char*);

Sa definicijom funkcije Uporedi datom prethodno, strcmp se moe koristiti


direktno, ili indirektno preko Uporedi. Sljedea tri poziva su ekvivalentna:
strcmp("Suljo","Mujo");
(*Uporedi)("Suljo","Mujo");
Uporedi("Suljo","Mujo");

//
//
//

direktni poziv
indirektni poziv
indirektni poziv (skraeno)

est sluaj koritenja pointer funkcije je da se prenese kao argument nekoj


drugoj funkciji; obino zbog toga to posljednja trai razliite oblike prve u
razliitim okolnostima. Dobar primjer je binarna pretraivaka funkcija koja
pretrauje kroz ureeni niz stringova. Ova funkcija moe koristiti funkciju
uporeivanja (kao to je strcmp) radi uporeivanja stringa koji se trai i niza

74

Pointeri

stringova. No, ovo ne mora da bude prigodno za sve sluajeve. Na primjer,


strcmp razlikuje mala i velika slova. Ako bismo eljeli da izvrimo pretraivanje bez razlikovanja malih i velikih slova, onda bismo trebali koristiti drugu
funkciju za uporeivanje.
Kao to je pokazano u sljedeem primjeru, postavljajui funkciju uporeivanja kao parametar funkcije pretraivanja, imamo mogunost da ih postavimo
nezavisno jednu od druge.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

int BinTrazi (char *podatak, char *tabela[], int n,


int (*Uporedi)(const char*, const char*))
{
int dole = 0;
int gore = n - 1;
int sred, cmp;
while (dole <= gore) {
sred = (dole + gore) / 2;
if ((cmp = Uporedi(podatak,tabela[sred])) == 0)
return sred; // return item index
else if (cmp < 0)
gore = sred - 1; // pretrazi donji dio
else
dole = sred + 1; // pretrazi gornji dio
}
return -1; // nije pronadjeno
}

Linije 1 i 2 predstavljaju potpis funkcije BinTrazi, koja predstavlja poznati


algoritam za traenje kroz sortiranu listu podataka. Lista traenja je, u ovom
sluaju, tabela koja predstavlja polje stringova sa dimenzijom n. Podatak koji
se trai je pod imenom podatak. Linija 2 predstavlja pointer funkciju koja
treba da se koristi za uporeivanje podatka podatak sa elementima polja.
Algoritam za pretraivanje zapoinje u liniji 7 koristei while petlju, i u
svakom koraku opseg pretraivanja polovi. Postupak se zaustavlja kada se
granice opsega, oznaene sa dole i gore, poklope, ili dok se podatak ne nae.
Podatak se poredi sa srednjim elementom polja (linija 9), i ako se sa njim
poklapa, vraa se indeks istog (linija 10). Ako je, pak, podatak manji od
srednjeg podatka, pretraivanje se ograniava na donju polovinu polja (linija
11-12). U suprotnom, pretraivanje se ograniava na gornju polovinu polja
(linija 13-14).
U sluaju da nije pronaen podatak koji se poklapa sa traenim, funkcija
vraa vrijednost 1.

7.6. Reference

75

Sljedei primjer pokazuje kako se funkcija BinTrazi moe pozvati sa strcmp,


koji se prenosi kao funkcija za uporeivanje.
char *gradovi[] = {"Doboj","Kakanj","Sarajevo","Zenica"}
cout << BinTrazi("Zenica", gradovi, 4, strcmp) << endl;

Rezultat posljednje naredbe bio bi, naravno, 3.

7.6

Reference

Referencama se uvodi pojam nadimka (drugog imena, eng. alias) za neki


objekat. One predstavljaju poseban tip podataka, i djeluju slino pointerima.
Takoer, nain definisanja referenci je slian onom kod pointera, osim to se
umjesto simbola * koristi simbol &. Na primjer,
double broj1 = 3.14;
double &broj2 = broj1;

definie broj1, te broj2 kao referencu za broj1. Nakon ovakve definicije i broj1
i broj2 se odnose na isti objekat, kao da su ista varijabla. Treba naglasiti da
referenca ne kreira kopiju objekta, nego je nita drugo no simbolini nadimak
za isti. Na taj nain, nakon naredbe
broj1 = 0.16;

i broj1 i broj2 imae vrijednost 0.16.


Kada se definiu, reference se uvijek moraju inicijalizirati, tj. referenca mora
biti nadimak za neto to je ve definisano. Nepravilno je referencu definisati,
a kasnije inicijalizirati, kao u
double &broj3;

// nepravilno: referenca je bez


// inicijalizatora

broj3 = broj1;

Takoer je mogue definisati referencu koja je konstantna (eng. const reference)1 . U tom sluaju, konstantna referenca mora odgovarati konstantnom
objektu. Sljedei primjeri pokazuju neke od primjena:
const int broj = 13;
const int &refbroj = broj; // u redu: i referenca i objekat su
// const
int &refBroj2 = broj;
// greska
1 C++ programeri ipak koriste ovaj pojam, iako on u stvari znai referencu konstante (eng. reference to
const)

76

Pointeri

Referenca refBroj u gornjem primjeru se moe proitati, ali se ne moe promijeniti.


Najee koritenje referenci je u sluaju parametara funkcija (vidi poglavlje
5.2). Parametri koji se prosljeuju preko referenci olakavaju prosljeivanje
argumenata po referenci. Sljedei primjer, funkcija zamjene vrijednosti dvije
varijable, ponovno pokazuje osnovne razlike izmeu prosljeivanja po referenci,
i po vrijednosti.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

void Zamijeni1 (int x, int y) // po vrijednosti (objekti)


{
int temp = x;
x = y;
y = temp;
}
void Zamijeni2 (int *x, int *y) // po vrijednosti (pointeri)
{
int temp = *x;
*x = *y;
*y = temp;
}
void Zamijeni3 (int &x, int &y) // po referenci
{
int temp = x;
x = y;
y = temp;
}

Iako funkcija Zamijeni1 (linija 1), zamjenjuje x i y, ovo nema nikakvog efekta
na argumente koji se prosljeuju funkciji, jer Zamijeni1 dobija kopiju argumenata. Ono to se deava kopiji ne utjee na original. Za razliku od ovog sluaja,
funkcija Zamijeni2 (linija 7) prevazilazi problem koji ima funkcija Zamijeni1 koritenjem parametara pointera. Dereferenciranjem pointera, Zamijeni2 dolazi
do originalnih veliina i zamjenjuje ih.
Funkcija Zamjeni3 (linija 13) prevazilazi problem funkcije Zamijeni1 pomou
parametara referenci. Parametri postaju nadimci za argumente koji se prosljeuju funkciji i na taj nain ih zamjenjuju.
Osnovna prednost funkcije Zamijeni3 nad funkcijom Zamijeni2 je to je sintaksa poziva funkcije ista kao za Zamijeni1, te nema adresiranja ili dereferencranja. Sljedea funkcija main ilustrira razliku:
1
2

int main (void)


{

7.6. Reference
int i = 10, j = 20;
Zamijeni1(i, j); cout << i << ", " << j << \n;
Zamijeni2(&i, &j); cout << i << ", " << j << \n;
Zamijeni3(i, j); cout << i << ", " << j << \n;

3
4
5
6
7

77

Kada se pokrene prethodni program, dobija se ispis:


10, 20
20, 10
10, 20

Kviz pitanja
1. ta su pointeri ili pokazivai?
2. Koja je razlika u definisanju cjelobrojne varijable i cjelobrojne pointer
varijable?
3. Koje je znaenje tipa podatka u definiciji pointera?
4. ta je to null -pointer?
5. Koji operator se koristi da bi se pointer pridruio adresi neke druge varijable ili konstante?
6. Da li pointer moe pokazivati na razliitu memorijsku lokaciju u razliitim
vremenskim periodima u programu?
7. Da li na istu memorijsku lokaciju moe da pokazuje vie od jednog pointera?
8. ta je rezultat inkrementiranja pointer varijable?
9. ta je to dinamika memorija?
10. Koja je veza pointera i polja?
11. ta predstavljaju aritmetike operacije sa pointerima?
12. Objasni pojam funkcijskih pointera?
13. ta su to reference i gdje se najee upotrebljavaju?

Poglavlje 8

Datoteke
Ovo poglavlje pokazuje kako se podaci dobiveni pokretanjem nekog programa
mogu sauvati (pohraniti) na neku datoteku. S obzirom da uvanje podataka
nema svrhu ako tim podacima ne moemo da pristupamo, bie objanjeno i
kako proitati podatke sa neke datoteke.
Datoteka, pri tome, predstavlja skup podataka koji su snimljeni na neku
formu trajne memorije (hard disk, CD-ROM, floppy disk, itd.). Datoteci se
pristupa preko njenog imena (filename), u ijem sastavu se obino nalazi ekstenzija (dio imena iza take), koja oznaava tip podataka u datoteci (npr. .doc
za Microsoft Word, .xls Microsoft Excel, .cpp za C++ izvornu datoteku, itd.).
U osnovi, postoje dvije vrste datoteka: tekstualne i binarne. Tekstualne
datoteke sadre tekst, dok binarne mogu sadravati i kompleksnije vrste podataka, kao to su slike, izvrni programi, baze podataka, itd. Tekstualnim
datotekama je neto jednostavnije pristupiti, pisati podatke u njih, te itati sa
njih. Upravo to je i razlog zbog ega ce se primjeri u ovom poglavlju odnositi
samo na njih.

8.1

Standardna biblioteka fstream

U ranijim poglavljima koristili smo standardnu biblioteku iostream (io se odnosi


na input/output), koja pored ostalog, daje mogunost ispisivanja na standardni
izlaz (ekran, monitor) pomou cout, te itanje sa standardnog upisa (tastatura)
pomou cin. Meutim, ova datoteka nam ne omoguava da podatke trajno
sauvamo. U tu svrhu se koristi standardna biblioteka fstream (f se odnosi na
datoteku, tj. file), koja omoguava pisanje na i itanje sa datoteka. Ovo se
postie pozivanjem sadraja datoteke fstream sa:
#include <fstream>

80

Datoteke

Biblioteka fstream definie tri nova tipa podataka:


ofstream. Ovaj tip podataka predstavlja tok za izlazne datoteke (o se
odnosi na output). Pravac izlaza je sa programa na datoteku. Ovaj tip
podataka se koristi za kreiranje datoteka i pisanje informacija na njih. Ne
moe se koristiti za itanje datoteka.
ifstream. Ovaj tip podataka predstavlja tok za ulazne datoteke (i se odnosi
na input). Pravac ulaza je sa datoteke prema programu. Ovaj tip podataka se koristi za itanje informacija sa datoteka. Ne moe se koristiti za
kreiranje datoteka i pisanje na njih.
fstream. Ovaj tip podataka predstavlja openito tok za datoteke, ima
karakteristike i ofstream i ifstream objekata. Pomou ovog tipa, datoteke
se mogu kreirati, moe se pisati na njih ali i itati sa njih.

8.2

"ivotni" ciklus pristupa datotekama

Kada program pristupa datotekama, bez obzira da li ih ita, ili na njih pie,
ili ini oboje, on prolazi kroz sljedee korake:
Datoteka prvo mora da se otvori. Ovo otvara put u komunikaciji izmeu
datoteke i objekta toka u programu (fstream, ifstream, ofstream), koji se
koristi u pristupu datoteci.
Nakon otvaranja, program ita sa datoteke, pie na nju, ili ini oboje.
Na kraju, program zatvara datoteku. Ovo je bitan korak, poto odravanje komunikacije izmeu datoteke i objekta toka zahtijeva resurse, tako da
zatvaranje datoteke oslobaa ove resurse kada vie nisu potrebni. Uz to,
postoji mogunost da se kasnije u programu ne moe pristupiti datoteci
ako prethodno nije zatvorena.
8.2.1

Otvaranje datoteka

Bez obzira da li se sadraj datoteke treba proitati ili se na datoteku trebaju ispisati neki podaci, datoteka prvo treba da se otvori. Naredna poglavlja
pokazuju kako se to obavlja.

8.2. "ivotni" ciklus pristupa datotekama

81

Otvaranje datoteke za pisanje

Datoteke za pisanje se mogu otvoriti pomou fstream i ofstream objekata na dva


naina: (i) pomou metode open, ili (ii) pomou konstruktora (constructor 1 ).
Otvaranje pomou funkcije open

Ovaj nain otvaranja datoteke postiemo na

sljedei nain:
1
2

ofstream izlaz;
izlaz.open("studenti.txt");

Prvom linijom je kreiran objekat izlaz tipa ofstream, dok se u drugoj liniji
kreira datoteka studenti.txt. Kao to se vidi, argument funkcije open je ime i
lokacija datoteke koja se treba otvoriti. Meutim, mogue je dodati i drugi argument zavisno od toga da li je funkcija open lan objekta fstream ili ofstream,
ili se eli neki drugi modul od onog koji se daje (vidi tabelu 8.1).
Datoteka u koju elimo pisati podatke ne mora postojati. U sluaju da ne
postoji, ona e se automatski kreirati pod imenom i na lokaciji koju smo upisali.
Lokacija se moe dati kao relativna (relative path) ili apsolutna (absolute path).
Pri tome, relativni put predstavlja lokaciju u odnosu na lokaciju programa, tj.
direktorij u kojem se nalazi izvorna datoteka.
Za razliku od relativnog puta, apsolutni put predstavlja lokaciju koja zapoinje slovom drajva, sadravajui sve direktorije i poddirektorije, dok se ne
doe do datoteke. Na primjer, ako je datoteka studenti.txt u direktoriju Pedagoski, a ovaj je poddirektorij direktorija UNZE, a sve se nalazi na tvrdom
disku sa slovom C, onda bi se datoteka otvorila na sljedei nain:
ofstream izlaz;
izlaz.open("C:\\MFZE\\Pedagoski\\studenti.txt");

Vidimo da se u tom sluaju koriste po dva znaka \, jer samo jedan izmeu
navodnika predstavlja escape-sekvencu (poglavlje 2.8.3).
Bez obzira da li koristimo relativni ili apsolutni put, argument za funkciju
open ne mora da bude neko ime (rije), nego i (string) varijabla, kao to je to
u sljedeem primjeru:
ofstream izlaz;
char imeDatoteke[80];
cout << "Unesite ime datoteke: ";
cin >> imeDatoteke;
izlaz.open(imeDatoteke);
1 Oba ova pojma, metode (eng. member function) i konstruktori, odnose se na klase, tj. dio su objektnoorijentisane paradigme

82

Datoteke

Vano je zapamtiti da je koritenje relativnog puta bolja opcija, jer se moe


desiti da neki direktorij u apsolutnom putu ne postoji, naroito ako se program
koristi na nekom drugom kompjuteru (sa drugaijim rasporedom direktorija).
Koritenje drugog argumenta u funkciji open definie modul u kojem se
datoteka treba otvoriti. Neke od opcija (tzv. file mode flag), koje se mogu
koristiti date su u Tabeli 8.1.
Tabela 8.1
Opcija (file mode flag)
ios::app
ios::binary
ios::in
ios::out

Opis
Postojei sadraj datoteke je ouvan i sav izlaz
se ispisuje na kraj datoteke.
Informacija se na datoteku pie u binarnom
obliku.
Informacija e se itati sa datoteke. Datoteka
se ne kreira ako ne postoji.
Informacija e se zapisati u datoteku. Postojei
sadraj datoteke je poniten.

Ako, na primjer, elimo da konstantno dodajemo neke podatke u datoteku


log, koristimo opciju ios::app, tj.
ofstream izlaz;
izlaz.open("log", ios::app);

Kada za otvaranje datoteke koristimo ofstream objekat, onda ne moramo


koristiti dodatne argumente, ali treba zapamtiti da u tom sluaju moemo
samo upisivati informaciju na datoteku, ali ne i itati sa nje.
Meutim, ako se za otvaranje datoteke za pisanje koristi fstream objekat,
treba dodati jo jedan argument, tj. opcija za pisanje ios::out. U ovom sluaju
imamo:
fstream izlaz;
izlaz.open("studenti.txt", ios::out);
Otvaranje pomou konstruktora Konstruktori su funkcije koje se automatski
pozivaju kada se pokuava kreirati primjerak (eng. instance) nekog objekta
(primjerak je prema objektu isto to i varijabla prema tipu podatka). Oni mogu
biti optereeni (eng. overloaded ), tako da isti objekat moe imati konstruktor sa nijednim, jednim, dva, ili vie argumenata. U prethodnim primjerima
(npr. fstream izlaz;) koritene su naredbe sa konstruktorima bez argumenata.
Naredni primjeri pokazuju upotrebu konstruktora sa jednim i dva argumenta,
respektivno:

8.2. "ivotni" ciklus pristupa datotekama

83

ofstream izlaz("studenti.txt");
fstream izlaz("studenti.txt",ios::out);

Prvi sluaj zamijenjuje izraz


ofstream izlaz;
izlaz.open("studenti.txt");

a drugi
fstream izlaz;
izlaz.open("studenti.txt", ios::out);

Primjena konstruktora, u stvari, omoguava definisanje i inicijalizaciju primjerka nekog objekta. Kao i u sluaju definisanja (deklaarisanja) i inicijalizacije varijabli, koritenje jednog od naina otvaranja datoteke zavisi od samog
programa i naih potreba.
Otvaranje datoteka za itanje

Sve to je reeno u prethodnom poglavlju moe se primijeniti i na otvaranje


datoteka za itanje. Jedina razlika je to se, uz koritenje objekta fstream,
umjesto objekta ofstream koristi ifstream objekat. Uz to, datoteka sa koje se
ita mora postojati, jer se pokretanjem jednog od prethodnih objekata datoteka ne kreira.
Analogno diskusiji o otvaranju datoteka za pisanje, otvaranje datoteke za
itanje se moe otvoriti na jedan od sljedeih naina:
1) pomou ifstream objekta
ifstream ulaz;
ulaz.open("studenti.txt");

2) pomou fstream objekta


fstream ulaz;
ulaz.open("studenti.txt", ios::in);
//obavezno dodati argument ios::in

3) pomou konstruktora
ifstream ulaz("studenti.txt");
fstream ulaz("studenti.txt", ios::in);

84

Datoteke

Otvaranje datoteka za itanje i pisanje

Kao to je ranije reeno, objekat fstream se moe koristiti za otvaranje datoteka


i za pisanje i za itanje. U tu svrhu koristi se sljedea sintaksa:
fstream izlazUlaz;
izlazUlaz.open("studenti.txt", ios::in | ios::out);

ili pomou konstruktora:


fstream izlazUlaz("studenti.txt", ios::in | ios::out);

U oba primjera koriten je bitovni operator i, |, (poglavlje 3.4).


Provjera da li je datoteka otvorena

Prije nego ponemo itati podatke sa neke datoteke, korisno je znati da li ona
uopte postoji. Provjera se moe izvriti na dva naina. Ako se datoteka ne
moe otvoriti za itanje, onda je: (i) vrijednost ifstream objekta jednaka NULL
(nula), (ii) vrijednost funkcije fail objekta ifstream je true(1). Sljedei primjer
ilustruje koritenje oba naina.
#include <fstream>
#include <iostream>
using namespace std;
int main (){
ifstream ulaz;
ulaz.open("studenti.txt");
cout << "(ulaz) = " << ulaz << endl;
cout << "(ulaz.fail()) = " << ulaz.fail() << endl;
return 0;
}

Ako datoteka studenti.txt ne postoji nakon izvrenja programa dobijamo:


(ulaz) = 0
(ulaz.fail()) = 1

U sluaju da postoji, izlaz je, na primjer:


(ulaz) = 0x22fed4
(ulaz.fail()) = 0

pri emu 0x22fed4 predstavlja memorijsku lokaciju (adresu) ifstream varijable


ulaz.

8.2. "ivotni" ciklus pristupa datotekama

85

Za razliku od ifstream objekta, ofstream objekat koji pokuava otvoriti datoteku koja ne jo postoji nije NULL, a njegova fail funkcija ima vrijednost
false(0). To je zbog toga to operativni sistem kreira datoteku, ako ona ne
postoji. Ipak, i u ovom sluaju je korisno provjeriti da li datoteka postoji.
Naime, ako datoteka postoji, ali ima osobinu read-only 2 , dobiemo negativan
odgovor o njenom postojanju (vrijednost iostream objekta je NULL, a funkcije
fail je true, tj. 1).
8.2.2

Zatvaranje datoteka

Svaka otvorena datoteka se treba zatvoriti prije nego se napusti program. To


je zbog toga to svaka otvorena datoteka zahtijeva sistemske resurse. Osim
toga, neki operativni sistemi imaju ogranienje na broj otvorenih datoteka sa
kojima se ne "manipulie".
Zatvranje datoteka se vri pomou funkcije close. Sljedei primjeri pokazuju
njenu upotrebu pri zatvaranju datoteka za pisanje i itanje:
ofstream izlaz;
izlaz.open("studenti.txt");
// skup naredbi
outfile.close();
ifstream ulaz;
ulaz.open("studenti.txt");
// skup naredbi
ulaz.close();

8.2.3

Pisanje na datoteke

Pisanje podataka na datoteku se izvodi pomou operatora za ispisivanje (<<),


kao to je to bio sluaj sa ispisivanjem na ekran (cout<<). Jedina razlika je u
tome to se ovdje koristi fstream ili ofstrem objekat, a ne cout objekat.
Sljedei program pokazuje primjer upisivanja podataka na datoteku studenti.txt:
1
2
3

#include <fstream>
#include <iostream>
using namespace std;

4
5
6

int main (){


char podaci[80];

2 Datoteke

sa atributom read-only ne mogu mijenjati sadraj.

86

Datoteke
ofstream izlaz;
izlaz.open("studenti.txt");
cout << "Zapisivanje u datoteku" << endl;
cout << "=======================" << endl;
cout << "Upisite razred: ";
cin.getline(podaci, 80);
izlaz << podaci << endl;
cout << "Unesite broj studenata: ";
cin >> podaci;
cin.ignore();
izlaz << podaci << endl;
izlaz.close();
return 0;

7
8
9
10
11
12
13
14
15
16
17
18
19
20

U ovom primjeru upis teksta sa tastature je obavljen pomou funkcijskog


lana objekta cin getline() (linija 12), koji kao prvi argument uzima znakovni
niz, a kao drugi duinu istog. Ovim se tekst koji je upisan preko tastature,
pridruuje varijabli podaci, koja je data kao niz od 80 elemenata. U liniji
16 koritena je funkcija ignore() (i ovo je funkcijski lan klase iostream), koja
u ovom obliku (bez argumenata) ima za cilj da proita sljedei karakter pri
upisu, ali ga ne pridrui nijednoj varijabli. To je zbog toga to nema potrebe
za pridruivanjem karaktera, koji oznaava novu liniju, koji je ostao pri itanju
u ulaznom meuspremniku (eng. input buffer ) nekoj varijabli.
Upotrebom drugog argumenta pri otvaranju datoteke za pisanje (ios::app)
moemo dodavati sadraj na postojeu datoteku kao to to pokazuje sljedei
primjer. U ovom primjeru zapisivanje se prekida nakon unosa znakova ***.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main ()
{
char x[100];
ofstream izlaz;
izlaz.open("podaci.txt", ios::app);
while (x != "***")
{
cout << "Unesite neki tekst
(za kraj unesite ***):" << endl;
cin >> x;
izlaz << x << endl;

8.2. "ivotni" ciklus pristupa datotekama

87

}
izlaz.close();
}

8.2.4

itanje sa datoteka

Analogno prethodnom poglavlju, itanje podataka sa datoteka obavlja se pomou operatora za itanje (>>) kao to je to sluaj sa ispisivanjem sa tastature
(cin>>). Sljedei primjer nadopunjava onaj iz prethodnog dijela, tj. nakon to
korisnik upie informacije na datoteku, program ita iste podatke sa datoteke
i ispisuje ih na ekran.

1
2
3

#include <fstream>
#include <iostream>
using namespace std;

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

int main (){


char podaci[100];
ofstream izlaz;
izlaz.open("studenti.txt");
cout << "Upisivanje u datoteku" << endl;
cout << "=====================" << endl;
cout << "Unesite razred: ";
getline(cin,podaci);
izlaz << podaci << endl;
cout << "Unesite broj studenata: ";
cin >> podaci;
cin.ignore();
izlaz << podaci << endl;
izlaz.close();

19

ifstream ulaz;
cout << "Citanje sa datoteke" << endl;
cout << "===================" << endl;
ulaz.open("studenti.txt");
getline(ulaz,podaci);
cout << podaci << endl;
getline(ulaz,podaci);
cout << podaci << endl;
ulaz.close();
return 0;

20
21
22
23
24
25
26
27
28
29
30

88

Datoteke

Slino primjeru iz prethodnog dijela, podaci se unose pomou funkcije getline (linija 13) sa neto drugaijom sintaksom. Ovdje pomenuta funkcija (definisana je kao funkcija, a ne funkcijski lan) ima dva argumenta: prvi tipa
iostream (cin), a drugi varijabla podaci. Na slian nain se pomou iste
funkcije podaci itaju sa datoteke (linije 23 i 25), pri emu je prvi lan objekat
ulaz tipa ifstream.
Prethodni primjer se moe napisati i na programerski adekvatniji nain
upotrebom funkcija za itanje i pisanje na datoteku.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
bool upisiDatoteku (ofstream&, char*);
bool citajDatoteku (ifstream&, char*);
int main (){
char podaci[100];
bool status;
ofstream izlaz;
status = upisiDatoteku(izlaz, "studenti.txt");
if (!status)
{
cout << "Datoteka za ispisivanje se ne
moze otvoriti\n";
cout << "Program se zavrsava\n";
system("PAUSE");
return 0;
}
else
{
cout << "Pisanje u datoteku" << endl;
cout << "==================" << endl;
cout << "Upisite razred: ";
getline(cin, podaci);
izlaz << podaci<< endl;
cout << "Unesite broj studenata: ";
cin >> podaci;
cin.ignore();
izlaz << podaci<< endl;
izlaz.close();
}
ifstream ulaz;

8.2. "ivotni" ciklus pristupa datotekama

89

status = citajDatoteku(ulaz, "studenti.txt");


if (!status)
{
cout << "Datoteka za citanje se ne
moze otvoriti\n";
cout << "Program se zavrsava\n";
system("PAUSE");
return 0;
}
else
{
cout << "Citanje se datoteke" << endl;
cout << "===================" << endl;
getline(ulaz, podaci);
while(!ulaz.fail()) {
cout << podaci << endl;
getline(ulaz, podaci);
}
ulaz.close();
}
system("PAUSE");
return 0;
}

bool upisiDatoteku (ofstream& datoteka, char* strDatoteka)


{
datoteka.open(strDatoteka);
if (datoteka.fail())
return false;
else return true;
}
bool citajDatoteku (ifstream& datoteka, char* strDatoteka)
{
datoteka.open(strDatoteka);
if (datoteka.fail())
return false;
else return true;
}

Iz ovog primjera se vidi da se ifstream i ofstream objekti u funkcijama


upisiDatoteku i citajDatoteku prosljeuju po referenci, iako nije dna od
ovih funkcija ne mijenja sadraj datoteke. Razlog lei u injenici da unutranje
stanje objekta toka moe promijeniti koritenjem open funkcije, iako se sadraj

90

Datoteke

ne mijenja.
Sukcesivno itanje

esto puta je potrebno proitati sve podatke sa neke datoteke, pri emu unaprijed ne poznajemo konaan broj informacija (na primjer, proizvoljan broj
vrijednosti neke varijable). U tu svrhu se koristi funkcija eof (od engleske rijei end of file), koja je tana ukoliko se proe posljednja linija u kojoj postoji
neka informacija. Sljedei primjer pokazuje upotrebu ove funkcije u problemu
itanja nizova karaktera (rijei).
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
char podaci[80];
ifstream saDat;
saDat.open("podaci.txt");
while(!saDat.eof()) {
saDat >> podaci;
cout << podaci << endl;
}
saDat.close();
system("PAUSE");
}

Linije 12-15, petlja while, omoguavaju sukcesivno itanje podataka sa datoteke podaci.txt. Kada se doe do posljednje linije sa nekom informacijom,
funkcija eof vraa vrijednost true i automatski se izlazi iz petlje. Na analogan
nain se mogu itati podaci rasporeeni u kolone.

Kviz pitanja
1. Nabrojati formate datoteka u kojima se mogu pohraniti podaci!
2. Koja standardna datoteka treba da se pozove kada program pie na datoteku ili ita sa nje?

8.2. "ivotni" ciklus pristupa datotekama

91

3. Koji od tri objekta iostream, ifstream, fstream, moe sluiti i za upis i za


ispis na datoteke?
4. U emu se sutina zatvaranja datoteke?
5. ta je konstruktor?
6. Da li se stream objekti trebaju proslijediti po vrijednosti ili referenci, i
zato?

Zadaci za izradu
1. Zadatke iz poglavlja 6, rijeiti tako da se unos podataka vri iz datoteke
ulaz.txt, a rezultati ispisuju u datoteci rezultat.txt!

Poglavlje 9

O objektno-orijentisanom
programiranju
Jo u uvodnom dijelu je reeno da C++ predstavlja jedan od najrairenijih
objektno-orijentisanih jezika. Stoga su u ovom poglavlju date neke od osnova
objektno-orijentisanog pristupa i razlika u odnosu na proceduralno.

9.1

Proceduralno i objektno-orijentisano programiranje

Umjesto da se fokusira na procedure koje su ukljuene u izvravanju zadatka,


objektno-orijentisani pristup se fokusira na razne objekte. Na primjer, na ATM
(eng. Automatic Teller Machine) bankomatima, objekti koji su ukljueni u
analizu mogu biti:
korisnik
raun
transakcija
tipka
ekran
izvjetaj
Objektno-orijentisani pristup sagledava problem kao kolekciju nezavisnih
objekata koji rade zajedno da bi se izvrila grupa zadataka. Paljivom analizom i dizajnom, mogu se kreirati softverski objekti koji su korisni i izvan

94

O objektno-orijentisanom programiranju

programa za koji su prvobitno kreirani. Na primjer, objekat prozor (koji predstavlja prozor aplikacije u Windowsu, X Windowsu, MacOS, itd.) je neto to
programer moe koristiti u gotovo svakom programu koji razvija.
Objektno-orijentisano

MONITOR
Sve stvari i
radnje povezane
sa monitorom

RAUN
Sve stvari i
radnje povezane
sa raunom

Transakcija
Sve stvari i radnje
povezane sa
transaksijama

Proceduralno

TASTATURA
Sve stvari i
radnje povezane
sa tastaturom

Stvar 1 (Trenutni broj rauna korisnika)


Stvar 2 (Trenutni izvje taj korisnika)
Stvar 3 (Trenutni meni)

Radnja 1 (Ispisni meni)


Broj rauna
Sve stvari i radnje
povezane sa
brojem rauna

Radnja 2 (Upitati korsnika za


koliinu novca)
Radnja 3 (Podizanje novca)
Radnja 4 (.....)

Klijent
Sve stvari i radnje
povezane sa
klijentom

Slika 9.1: Poreenje organizacije stvari i radnji u dva pristupa

Razlike izmeu objektno-orijentisanog i proceduralnog pristupa date su na


slici 9.1. U principu, i objektno-orijentisani i algoritamski (proceduralni) pristup pokuavaju da rijee neki problem dijelei ga na sve manje i manje cjeline
- proces koji se zove apstrakcija. Razlika je u tome kako je izvrena ta
apstrakcija. Algoritamski pristup se fokusira na procedure, dok se objektnoorijentisani pristup fokusira na objekte koji su ukljueni u izvravanju koraka.
Podsjetimo se iz gramatike da svaka reenica sadri subjekat i predikat.
I pored ovog pojednostavljivanja, moe se reci da i kompjuterski programi
takoer ukljuuju slino sparivanje informacija stvar/radnja. Kompjuterski
programi moraju nekako predstaviti podatak (kao to je "balans rauna", "broj
korisnikog rauna", ...) i procedure (kao to su "oduzeti podignuti novac od
balansa rauna" i "prikazati broj korisnikog rauna na ekran"). Nain na
koji su podaci i procedure predstavljeni je jo jedna razlika izmeu objektnoorijentisanog i algoritamskog pristupa.
Kod algoritamskog pristupa, "strukture" podataka se kreiraju da bi se zadrale vrijednosti kojima e se operisati pomou procedura. Ovaj podatak
moe biti "globalni" - na raspolaganju svim procedurama unutar programa, ili

9.1. Proceduralno i objektno-orijentisano programiranje

95

"lokalni" - na raspolaganju samo odreenoj proceduri. Pored toga, podatak


se obino predstavlja odvojeno od procedure koja sa njim operie, i smatra
se odvojenom cjelinom. Kada se pokrene, proceduralni program moe postaviti ogroman blok strukture podataka koja sadri raznolike podatke kao to su
"broj rauna", "adresa boravka", i "trenutni tip transakcije". Tada "glavna"
procedura moe korisniku prikazati meni. Kako korisnik izabere odreenu
stavku u meniju, tako se pozivaju razne procedure za manipulaciju vrijednostima, koje su sadrane unutar raznih struktura podataka.
Kod objektno-orijentisanog pristupa (slika 9.2), s druge strane, i podaci i
procedure su ugraeni unutar nekog objekta na koji se direktno odnose. Na
primjer, objekat korisnik moe imati osobine (podatke koji su dio, ili lanovi
objekta) kao to je "ime" ili "lista rauna". Ove osobine sadre podatke koji
se odnose na specifinog korisnika. No, dobar dizajn bi vjerovatno onemoguio
da objekat korisnik ima osobinu kao to je "tip transakcije". Ta osobina bi vie
odgovarala kao osobina objekta transakcija.

Slika 9.2: Objektno-orijentisana dekompozicija problema

Na slian nain, objekat korisnik moe imati metode (procedure koje su dio,
ili lanovi objekta), kao to su "prikazati listu korisnikih rauna" ili "promijeniti adresu". Ove metode su procedure koje se odnose na objekat korisnik.
Procedura "procesiraj podizanje novca" ne bi postojala kao odvojena cjelina
unutar objektno-orijentisanog modela, nego bi se funkcionalnost, koja je sadr-

96

O objektno-orijentisanom programiranju

ana unutar te procedure, implementirala pomou metoda ili osobina raznih


objekata koji su ukljueni u transakciji. Na primjer, objekat transakcija moe
imati osobinu "tip" (type), koji specificira tip transakcije ("podizanje novca"
u ovom primjeru). Objekat transakcija moe pozvati objekat raun da bi se
podigla odreena svota novca.
Jo jedna osobina, koja se esto povezuje sa objektno-orijentisa-nim programima je event-driven dizajn. Objekti mogu imati odreene dogaaje (eng.
event) sa kojima su povezani, kao to su "tipka na miu je pritisnuta" ili "objekat e se sakriti". Objekti se mogu programirati da odgovore na takve dogaaje. U prozorskom okruenju (Windows, X, MacOS, ...), gotovo samo se
koristi event-driven dizajn.

9.2

Prednosti objektno-orijentisanog programiranja

U mnogim sluajevima, dananje generacije programera su izloene samo objektno-orijentisanim i objektno-zasnovanim alatima i jezicima za razvijanje.
Upravo zbog toga, mnogi novi programeri prednosti objektno-orijentisanog
programiranja mogu uzeti zdravo-za-gotovo. Suprotno tome, programeri koji
su odrasli sa jezicima kao to su BASIC, COBOL i C ponekad imaju problema u tranziciji na objektno-orijentisano programiranje. Upravo iz razloga
to su kreirali mnogo korisnih i velikih programa koristei strukturno (a ne
objektno-orijentisano) programiranje, oni ne mogu odmah prepoznati prednosti objektno-orijentisanog programiranja. Kada ih okolnosti prisile da koriste objektno-orijentisane jezike i alate za razvoj, kao to su C++ i Visual
Basic, oni mogu ignorisati osobine ovih programa, i koristiti proceduralni ili
strukturni pristup.
Poto postoji mnogo prednosti objektno-orijentisanog programiranja, ne
samo da je vano kako koristiti objektno-orijentisane ili objektno-zasnovane
alate za razvoj, nego i kako ih korisiti na nain objektnog orijentisanja. Neki jezici (kao to su SmallTalk i Java) oteavaju mogunost nekoritenja objektnoorijentisanog pristupa. Ipak, ak i kod ovih jezika programeri treba da razviju
objektno-orijentisano razmiljanje da bi dobili punu korist od prednosti koje
su na raspolaganju.
Neke od prednosti objektno-orijentisanog programiranja ukljuuju:
sposobnost jednostavnog koritenja dijelova koda u razliitim programima,
tedei vrijeme u analizi, dizajnu, razvoju, testiranju, i debagiranju,
mogunost kupovine dijelova postojeeg, testiranog koda da bi se u razvoju omoguio komponentno-zasnovani pristup,

9.3. Karakteristike objektno-orijentisanih jezika

97

smanjeni trokovi razvoja,


sposobnost jednostavne podjele velikih programerskih projekata izmeu
razvojnih timova,
poboljane karakteristike debagiranja i testiranja,
vii kvalitet softvera,
sposobnost da se programski zadaci, koji su preveliki da bi se rijeili u
jednom kratkom raunu, podijele i rijee,
sposobnost kreiranja jednostavnih i konzistentnih sredstava za meudjelovanje razliitih tipova objekata, pri emu se skriva kompleksnost razlika
koje postoje.
U ovom trenutku, ove prednosti mogu izgledati kao marketinka pria, jer
uistinu, i dobro neobjektno-orijentisano programiranje moe imati neke od ovih
prednosti. Uz to, koritenje objektno-orijentisanog pristupa ne garantuje prednosti koje su spomenute, ali u mnogome poveava anse da se date prednosti
ostvare. Postoje specifine karakteristike objektno-orijentisanog programiranja koje dolaze sa kriptiranim imenima kao to su skrivanje informacije (eng.
data hiding), enkapsulacija (eng. encapsulation), i nasljeivanje (eng. inheritance) koje su u vezi sa pojedinim prednostima. to se vie naui o ovim
osobinama, to e se vie razumjeti prednosti koje one donose.

9.3

Karakteristike objektno-orijentisanih jezika

U narednim dijelovima dati su glavni elementi objektno-orijentisanih jezika, i


to: objekti, klase, nasljeivanje, ponovna iskoristivost, kreiranje novih tipova
podataka, polimorfizam, te optereivanje
9.3.1

Objekti

Za razliku od proceduralnog programiranja, u kojem razmiljamo o tome kako


problem podijeliti na funkcije/procedure, u objektno-orijentisanom programiranju razmiljamo o tome kako problem podijeliti na objekte. Na taj nain
programiranje postaje mnogo jednostavnije, prvenstveno zbog slinosti izmeu
objekata u programerskom smislu i objekata u stvarnom svijetu. Logino je
onda postaviti pitanje kakvi to objekti mogu da budu objekti u objektnoorijentisanom programu. Odgovor na ovo pitanje je ogranien samo imaginacijom programera. Ipak, evo nekih tipinih kategorija koje mogu predstavljati
objekte u objektno-orijentisanom programiranju:

98

O objektno-orijentisanom programiranju

Fiziki objekti: automobili u simulaciji saobraaja, komponente u elektrinim kolima, zemlje u ekonomskim modelima, avioni u simulaciji zranog saobraaja,. . .
Elementi u kompjuterskom okruenju: prozori, meniji, grafiki objekti
(linije, pravougaonici, krugovi), mi, tastatura, printer, . . .
Konstruktori za pohranjivanje podataka: polja, stakovi, linkovane liste,
binarna stabla, . . .
Ljudski entiteti: zaposlenici, studenti, kupci, prodavai, . . .
Kolekcije podataka: inventar, lini podaci, rjenik, tabela geografske irine i duine za gradove svijeta, . . .
Tipovi podataka koje definie korisnik: vrijeme, uglovi, kompleksni brojevi, take u ravni, . . .
Komponente u kompjuterskim igrama: automobili u utrci, pozicije u raznim igrama (ah, mica, ...), ivotinje u eko-simulaciji, suparnici i prijatelji
u avanturistikim igrama, . . .
Slinost izmeu programskog objekta i objekta iz stvarnog svijeta je rezultat spajanja podataka i funkcija: rezultujui objekat nudi revoluciju u programskom dizajnu. Ovakva slinost nije bila mogua izmeu programskih
konstrukcija i modeliranih stvari u proceduralnom programiranju.
9.3.2

Klase

U OOP kaemo da su objekti lanovi klasa. Na primjer, gotovo svi kompjuterski jezici imaju ugraene tipove podataka. Tako, tip int , koji predstavlja cijeli
broj, je definisan u C++. Pomou njega moemo deklarisati koliko god hoemo varijabli tipa int . Na slian nain, mogue je definisati mnogo objekata
iste klase. Neka klasa slui kao plan, ili templejt. Ona specificira koji podaci
i koje funkcije e biti ukljuene u objekte te klase. Definisanje klase ne kreira
nijedan objekat, kao to ni postojanje tipa int ne kreira nijednu varijablu.
Klasa je, na taj nain, opis mnogih slinih objekata. Ovo je u saglasnosti
sa ne-tehnikim znaenjem rijei klasa. Na primjer, Pink Floyd, Dire Straits,
Led Zepellin i Bijelo Dugme su lanovi klase rok grupa, ali ne postoji nijedna
grupa koja se zove rok grupa, nego su odreene grupe sa njihovim imenima,
koji posjeduju odreene karakteristike, lanovi ove klase.

9.3. Karakteristike objektno-orijentisanih jezika

9.3.3

99

Nasljeivanje

Ideja klasa dovodi direktno do ideje nasljeivanja. U svakodnevnom ivotu


koristimo koncept klasa koji se dijeli na podklase. Znamo, na primjer, da je
klasa (ili carstvo) ivotinja podijeljeno na sisare, vodozemce, insekte, ptice,
itd. Klasa vozila je podijeljena na automobile, kamione, autobuse, motocikle,
itd .
Princip u ovakvoj podjeli je da podklasa dijeli neke zajednike karakteristike
sa klasom iz koje je dobijena, tj. kojoj pripada. Automobili, kamioni, autobusi
i motocikli svi imaju tokove i motor; ovo su osnovne karakteristike vozila.
Pored karakteristika koje dijele sa ostalim lanovima klase, svaka podklasa ima
i karakteristike svojstvene njoj samoj: autobusi, na primjer, imaju sjedita za
mnogo putnika, dok kamioni imaju prostor za prenoenje tekih materijala.
Na slian nain, neka OOP klasa se moe podijeliti na podklase. U C++
originalna (poetna) klasa se naziva osnova klasa; mogu se definisati i ostale
klase koje dijele njene karakteristike, ali mogu se dodati i neke njene karakteristike. Ove klase se nazivaju izvedene klase.
No, ne treba nas zbuniti relacija objekata i klasa, s jedne strane, sa relacijom
osnovne klase i izvedene klase, sa druge strane. Svi objekti, koji postoje u
kompjuterskoj memoriji, imaju karakteristike koje su iste za tu klase, koja
im slui kao templejt. Dobivene klase nasljeuju neke osobine od njihovih
osnovnih klasa, ali imaju i neke svoje.
Nasljeivanje je donekle analogno koritenju funkcija kako bi se pojednostavilo tradicionalno proceduralno programiranje. Na primjer, ako primijetimo
da nekoliko dijelova u proceduralnom programiranju obavlja gotovo istu radnju, napisaemo jedinstvenu funkciju koja e zamijeniti one radnje koje su iste.
Svaki od tih dijelova se tako moe obaviti pozivom te funkcije, uz izvrenje onih
zadataka koji su bili karakteristini za te dijelove. Na slian nain, osnovna
klasa sadri elemente koji su zajedniki za grupu dobivenih klasa. Kao to to
funkcije rade u proceduralnom programiranju, tako isto nasljeivanje skrauje
objektno-orijentisani program i pojanjava odnos izmeu elemenata programa.
9.3.4

Ponovna iskoristivost

Nakon to se klasa napie, kreira, i debagira, moe se distribuirati ostalim


programerima da je koriste u njihovim programima. Ovo se naziva ponovna
iskoristivost (eng. reusability). Ovo je slino nainu na koji se biblioteka
funkcija u proceduralnom programiranju moe uklopiti u razliite programe.
Meutim, kod OOP, koncept nasljeivanja proiruje ideju ponovne iskoristivosti. Programer moe uzeti neku postojeu klasu i, bez njenog modifikovanja,

100

O objektno-orijentisanom programiranju

dodati joj neke osobine i mogunosti. Ovo se obavlja izvoenjem nove klase iz
postojee. Nova klasa e naslijediti mogunosti stare, sa mogunou dodavanja novih.
Na primjer, mogli smo napisati (ili kupiti od nekoga) klasu koja kreira
sistem menija, kao to je onaj koji se koristi u Windowsu ili nekom drugom
grafikom interfejsu. Ova klasa radi, i nema potrebe da je mijenjamo, ali
je mogue dodati neke karakteristike menijima na primjer, da svijetle ili
dodavanjem nekih drugih efekata. Da bismo ovo uradili, jednostavno bismo
kreirali novu klasu koja nasljeuje sve karakteristike postojee uz dodatak
svijetleih menija. Jednostavnost sa kojom se postojei softver moe ponovno
iskoristiti je vana prednost OOP. Mnoge kompanije su shvatile da mogunost
ponovnog koritenja klasa na novim projektima obezbijeuje poveani povrat
uloenog kapitala u originalni softver.
9.3.5

Kreiranje novih tipova podataka

Jedna od prednosti objekata je da programeru daju pogodan nain za konstruisanje novih tipova podataka. Pretpostavimo da u naem programu radimo sa
dvodimenzionalnim poloajima (x,y koordinate, ili geografska irina i duina),
i eljeli bismo da operacije sa ovim poloajnim vrijednostima izrazimo normalnim aritmetikim operacijama, kao to je
pozicija1 = pozicija2 + koordinatniPocetak

gdje varijable pozicija1, pozicija2 i koordinatniPocetak predstavljaju par nezavisnih numerikih vrijednosti. Kreiranjem klase koja obuhvata ove dvije vrijednosti, i deklarisanjem da pozicija1, pozicija2 i koordinatniPocetak budu objekti
te klase, moemo, u principu, kreirati novi tip podataka. Mnoge karakteristike
C++ su usmjerene ka olakavanju kreiranja novih tipova podataka na ovaj
nain.
9.3.6

Polimorfizam i optereivanje

Treba zapamtiti da operacije = i + kao u prethodno navedenom primjeru ne


rade isto kao kada rade sa ugraenim tipovima kao to je int . Objekti pozicija1
i ostali nisu prethodno definisani u C++ , nego su objekti klase pozicija koju
je definisao programer. Postavlja se pitanje: Kako operatori = i + znaju kako
da operiu nad objektima? Odgovor glasi: Mogue je definisati nove operacije
za ove operatore. Ove operacije e biti metode (eng. member functions) klase
pozicija.

9.3. Karakteristike objektno-orijentisanih jezika

101

Koritenje operatora ili metoda na razliite naine, zavisno od toga sa im


operiemo, se naziva polimorfizam (laiki reeno, jedna te ista stvar sa razliitim oblicima). Kada se jednom postojeem operatoru, kao to je = ili + da
sposobnost da operie na novim tipovima podataka, kae se da je taj operator
optereen (eng. overloaded ). Optereivanje je tip polimorfizma i predstavlja
jo jednu vanu karakteristiku OOP. Ova karakteristika OOP je pokazana na
primjeru funkcija u poglavlju 5.5.

Kviz pitanja
1. Koje su razlike izmeu proceduralnog i objektno-orijentisanog programiranja?
2. Koje su karakteristike OOP jezika?
3. ta su to objekti?
4. Po emu se karakteriu klase?
5. ta je to nasljeivanje?
6. ta je to polimorfizam, a ta optereivanje?

LITERATURA
[1] C++ standard - ISO/IEC 14882
[2] Davis, R. C++ for Dummies. Wiley-Publisher Inc., 5. izdanje edition,
2004.
[3] Eckel, B. Thinking in C++, volume I-II. Prentice Hall, 2000.
[4] Hekmat, S. C++ Programming. Pragmatix Software Pty. Ltd., 2005.
[5] Kent, J. C++ demystified: A self-teaching guide. McGraw-Hill/Osborne,
2004.
[6] Liberty, J. Sams Teach Yourself C++ in 21 days. Prentice Hall, 1997.
[7] Lippman, B. C++ Essentials. Addison Wesley, 2002.
[8] Lippman, S. and Lajoie, J. C++ Primer. Prentice Hall, 2005.
[9] Motik, B. and ribar, J. Demistificirani C++. Element, Zagreb, 2. izdanje
edition, 2001.
[10] Press, W.H. Numerical Recipes in C++. Cambridge University Press,
1997.
[11] Schildt, H. C++: The Complete Reference. Osborne McGray-Hill, 1998.
[12] Stroustrup, B. The C++ Programming Language. Addison-Wesley, 3.
izdanje edition, 2000.
Osim navedene literature, koja je koritena u toku pisanja ovog udbenika,
itaoci se upuuju i na sljedee izvore, koji po svom sadraju ne samo da
zadovoljavaju potrebe kursa, nego daju i primjenu jezika C++ u oblasti numerike analize, to moe biti od velike koristi za studente odsjeka Matematika
i Informatika.
[1] http://www.alglib.net/
103

104

LITERATURA

[2] http://cliodhna.cop.uop.edu/ hetrick/c-sources.html


[3] http://www.cplusplus.com/doc/tutorial/
[4] http://pagesperso-orange.fr/jean-pierre.moreau/links.html
[5] http://www.nr.com/
[6] S. Salleh, A. Zomaya, and S. Bakar. Computing for Numerical Methods
Using Visual C++. John Wiley & Sons, Inc., 2008. ISBN 978-0-47012795-7.
[7] L. Shampine, R. Allen Jr., and P. S. Fundamentals of Numerical Computing. John Wiley & Sons, Inc., 1997.

Indeks
!, 30
++, vidi inkrement
, vidi dekrement
<<, vidi usmjerivai toka, 30
>>, vidi usmjerivai toka, 30
*, 27, 68
+, 27
-, 27
/, 27
/*...*/, vidi komentar
//, vidi komentar
<, 29
<=, 29
=, 32
==, 29
>, 29
>=, 29
%, 27
&, 30, 52, 67, 75
&&, 30
, vidi operator razdvajanja
, 30
[ ], 59, 69
, 30
|, 30
||, 30

char, 23
cin, 17
close, 85
const, 21
cout, 12
datoteke, 79
ciklus, 80
otvaranje, 80
za itanje, 87
za pisanje, 85
zatvaranje, 85
define, 22
definicija, 14
funkcije, 47
polja, 59
varijable, 14
deklaracija, 15
dekrement, 31
delete, 69
dereferenciranje, 68
Dev C++, 4
instalacija, 5
izvrna datoteka, 7
pokretanje, 9
prvi program, 7
do, 43
double, 20

adresni operator, vidi &


aritmetiki operatori, 27
konverzija, vidi konverzija
preljev, vidi preljev

eof, 90
escape-sekvence, 23
fail, 84
float, 20
for, 44
fstream, 79
funkcije, 47
argumenti, 51
definicija, 47
optereene, vidi optereivanje
parametri, 51

bitovni operatori, 30
bool, 22
brojevi
cijeli, 19
decimalni, 20
heksadecimalni, 20
ogranienja, 21
oktalni, 20
realni, 20

105

106
rekurzivne, vidi rekurzija
funkcijski pointeri, 73
globalno podruje, 53
hijerarhija operatora, 34
hrpa, 68
identifikatori, vidi imena
if, 40
ifstream, 80
imena, 18
include, 11
inicijalizacija, 14, 59
inkrement, 31
int, 19
ios, 82
iostream, 11
karakteri, 23
kljune rijei, 18
komentar, 17
kompajliranje, 13
konstante, 21
konstruktor, 81
konverzija, 27
eksplicitna, vidi static_cast
implicitna, 27
linker, 13
logiki operatori, 30
logiki tipovi, 22
lokalno podruje, 53
long, 19
main(), 12
memorija, 15
dinamika, 68
naredbe
jednostavna, 39
sloena, 39
new, 69
niz, vidi polja
ofstream, 80
open, 81
operator razdvajanja, 33
operatori, 27
aritmetiki, vidi aritmetiki operatori
bitovni, vidi bitovni operatori

Indeks
logiki, vidi logiki operatori
pridruivanje, vidi operatori pridruivanja
razdvajanje, vidi operator razdvajanja
relacijski, vidi relacijski operatori
uslovni, vidi uslovni operator
operatori pridruivanja, 32
overloading, vidi optereenje
petlja
do, vidi do
for, vidi for
while, vidi while
pointeri, 67
aritmetika, 71
funkcijski, vidi funkcijski pointeri
i polja, 70
pokazivai, vidi pointeri
polja, 59
multidimenzionalna, 63
preljev, 29
proceduralno programiranje, 2
reference, 75
rekurzija, 54
relacijski operatori, 29
short, 19
simbolike konstante, vidi konstante
sizeof, 34
static_cast, 28
std, 12
stog, 68
struktura programa, 11
switch, 41
ternatni, vidi uslovni operator
tijelo, vidi funkcije
tip, 19
brojni, vidi brojevi
karakteri, vidi karakteri
logiki, vidi logiki tipovi
typedef, 33
uslovni operatori, 32
usmjerivai toka, 16
varijabla, 14
while, 42
zaglavlje, vidi funkcije

Das könnte Ihnen auch gefallen