You are on page 1of 33

Programski jezici, C++

II Programiranje pomou programskog jezika C++


Da bismo napisali program, neophodna su nam dva specijalizovana programa: jedan koji koristimo da napiemo izvornu datoteku, i drugi (kompajler) sa kojim dobijamo izvrnu datoteku. Danas se ova dva prgrama najee kombinuju u jedinstven paket razvojno okruenje. Najpoznatije C++ okruenje predstavlja Microsoftov proizvod Visual C++.NET. Meutim, veina ovakvih programa je komercijalna i nije dostupna 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 tj. http://bloodshed.net/dev/devcpp.html ).

1 Programski paket Dev-C++


1.1 Instalacija Instalacija Dev-C++ programa ni u emu se ne razlikuje od 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 instalacije preporuljivo je podesiti neke opcije, mada to nije od velike vanosti za programe koji e se koristiti na ovom kursu. Ipak, u meniju Tools, i podmeniju Compiler options, prvo treba izabrati opciju Code Generation. U prozoru koji se dobije opciju Enable Exception Handling treba aktivirati (staviti na yes). Zatim treba izabrati opciju Linker i aktivirati Generate Debugging Information. Na ovaj nain instalacija je zavrena. 1.2 Kreiranje prvog programa 1.2.1 Upisivanje koda Nakon pokretanja programa Dev-C++, prvi korak u kreiranju koda je otvaranje novog zadatka. Dev-C++ prua vie opcija, ali e se u ovom kursu uglavnom raditi na jednostavnim datotekama sa izvrnim kodom (opcija File/New/Source File). Nakon odabira ove opcije, otvara se prozor u koji treba upisati kod, na primjer
#include <iostream> using namespace std; int main() { cout << Hello, world! << endl; system("PAUSE"); return 0; }

Nakon upisa kod sauvamo na nekom mjestu na hard disku, npr. pod imenom hello.cpp

Programski jezici, C++ 1.2.2 Generisanje izvrne datoteke Nakon to se sauva ovaj kod, treba ga kompajlirati, tj. proizvesti izvrnu mainsku datoteku. Ovo se izvodi koritenjem kombinacije tipki Ctrl+F9 na tastaturi, ili izborom opcije Compile u meniju Execute, ili pritiskom na ikonu u nizu alata. Nakon startanja 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, stvara se izvrna datoteka koja se naziva hello.exe. 1.3 Pokratanje programa Pokretanje programa, koji smo prethodno kompajlirali, u Dev-C++ okruenju izvodi se izborom opcije Run u meniju Execute, kombinacijom tipki Ctrl+F10 na tastaturi, ili pritiskom na ikonu Prethodna dva procesa (kompajliranje i pokretanje) mogue je 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 hello.exe.

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 kompilacije, koja se naziva predprocesiranje, na izvornu datoteku (source). 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 primjer iz prethodnog poglavlja:
1 2 3 4 5 6 7 8 #include <iostream> using namespace std; int main() { cout << Hello, world! << endl; system("PAUSE"); return 0; }

U liniji 1 pozvana je datoteka iostream. Prvi karakter (#) predstavlja symbol, koji daje signal predprocesoru. Svaki put kada pokrenemo kompajler, predprocesor je ve pokrenut. U principu, predprocesor ita kroz izvornu datoteku i trai linije koje poinju sa ovim karakterom, tako da ih predprocesor proe prije nego kompajler starta sa radom. Ukratko ova linija znai: Ono to slijedi je 2

Programski jezici, C++ 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 kada bismo htjeli uvrstiti neku svoju datoteku, umjesto zagrada bismo koristili znake navoda. Dakle, ova linija kae predprocesoru da nae datoteku koja se zove iostream i da je odmah proita. Naravno, sadraj traene datoteke bismo mogli upisati u izvornu datoteku bez koritenja direktive #include. Linija 2 omoguuje pristup standardnom entitetu (namespace) koji se naziva std. Bez ove linije, linija 5 bi se morala izvriti na drugaiji nain (std::cout << ....) Linijom 3 poinje stvarni program sa funkcijom koja se naziva main(). Svaki C++ program sadri ovu funkciju. Funkcija predstavlja dio koda koji odrauje odreenu radnju. Inae, program moe da ima proizvoljan broj funkcija, pri emu je funkcija main() specijalna. Kada god se program starta, ona se automatski poziva. Sve funkcije poinju zagradom { i zavravaju zagradom }, a sve izmeu ovih zagrada predstavlja dio funkcije. Glavni dio programa je linija 5, koja predstavlja neku naredbu, tj. raunarski korak koji daje neku vrijednost. Kraj naredbe uvijek zavrava taka-zarezom. Naredba u datom primjeru alje string "Hello world \n" na tok cout (output stream). String je svaki niz karaktera koji se nalazi izmeu znaka navoda. Posljednji karakter u datom stringu (\n) je karakter koji oznaava novi red (vidi poglavlje II.2.10). Stream je objekat koji izvrava ulazne i izlazne naredbe. cout je standardni izlazni stream u C++ (standardni izlazni stream je obino ekran). Simbol << je izlazni operator (usmjeriva toka) kojem je lijevi operand izlazni stream, a desni izraz, i koji uzrokuje da se ovaj posljednji posalje na prvopomenuti. Dakle, u ovom sluaju string "Hello world \n" se alje na cout, tj. uzrokuje njegov ispis na ekranu. Linija 6 zaustavlja izvrenje programa, kako bismo bili u mogunosti vidjeti rezultat njegovog rada. Bez ove linije program bi se nakon pokretanja izvrio, a konzola bi se zatvorila tako brzo da bismo imali osjeaj da program nije nita ni uradio.

2.2 Proces kompajliranja


Kompajliranje C++ programa obuhvata nekoliko koraka, koji su veinom nevidljivi za korisnika: x prvo, C++ predprocecsor 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. x zatim, C++ kompajler prevodi programski kod. Kompajler moe biti pravi C++ kompajer koji pravi osnovni (asemblerski ili mainski) kod, ili samo prevodilac, koji kod prevodi u C jezik. U drugom sluaju, rezultujui C kod je zatim proveden 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. x 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 II.2.1 ilustruje prethodno navedene korake i za C++ prevodilac i za C++ prirodni kompajler. U praksi su sve ove komande obino izvrene jednom komandom (npr. CC), a korisnik ni ne vidi datoteke koje su se napravile u meufazama.

Programski jezici, C++


C++ program C++ prevodilac C kod C kompajler

C++ program

C++ prirodni kompajler

Objektni kod

linker

Izvrna datoteka

Slika II.2.1 C++ kompilacija 2.3 Varijable Varijabla je simboliko ime za memorijsku lokaciju u koju se mogu pohraniti podaci i naknadno ih 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: x 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. x Vrijednost, koja se moe promijeniti davanjem nove vrijednosti varijabli. Vrsta vrijednosti koja se moe pridruiti nekoj varijabli zavisi od njenog tipa. Na primjer, integer varijabla moe da uzima samo vrijednosti cijalih 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 obezbijediti da se svaka varijabla inicijalizira prije nego se koristi. Takoer je mogue da se varijabla definie i inicializira u isto vrijeme, to je vrlo praktino. Naredni primjer pokazuje razliite naine definisanja i inicijaliziranja varijabli.
#include <iostream> using namespace std; main() { int a,b,c; float x = 4.32; int e,f,g; char ime; e = 4; f = g = 12; ime = 'C' }

2.4 Memorija Za pohranjivanje izvrnog koda kao i podataka sa kojima progam manipulie, kompjuter ima na raspolaganju RAM memoriju (Read Access Memory). Memorija se moe zamisliti kao neprekidan 4

Programski jezici, C++ niz bita, od kojih svaki moe da pohrani binarni broj (0 ili 1). Obino je memorija podijeljena na grupe od 8 uzastopnih bita (ovo predstavlja bajt, byte). Bajtovi su uzastopno adresirani, tako da je svaki bajt jedinstveno predstavljen svojom adresom (Slika II.2.2).
adresa 1211 ... bajt 1212 bajt 1213 bajt 1214 bajt 1215 bajt 1216 bajt 1217 bajt ... Memorija

1 bit

Slika II.2.2 Bitovi i bajtovi u memoriji C++ kompajler generira izvrni kod, koji mapira ulazne veliine na memorijske lokacije. Na primjer, definicija varijable
int zarada = 500;

navodi kompajler da alocira nekoliko bajta kako bi predstavio varijablu zarada. Taan broj bajta koji je alociran i metod koji se koristi za binarnu reprezentaciju cijelog broja zavisi od specifinosti C++ implementacije, ali uzmimo 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 (Slika II.2.3)

1211 ... bajt

1212 bajt

1213 bajt

1214

1215

1216 bajt

1217 bajt ... Memorija

10110011 10110011 zarada

Slika II.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/izlazne naredbe 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 >>.

Programski jezici, C++


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

#include <iostream> using namespace std; int main (void) { int radniDani = 22; float radniSati = 7.5; float satnica, plata; cout << "Kolika je satnica? "; cin >> satnica; plata = cout << cout << cout << } radniDani * radniSati * satnica; "Plata = "; plata; '\n';

Linija 9 ita ulaznu vrijednost, koju unosi korisnik i kopira je u satnica. Ulazni operator >> uzima ulazni stream kao lijevi operand (cin je standardni C++ ulazni stream 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 pomognu onome koji e itati program. C++ daje dvije mogunosti pisanja komentara: x Bilo ta napisano nakon //, pa do kraja date linije smatra se komentarom x Bilo ta napisano izmeu /* i */ smatra se komentarom.
1 *1 2 3 4 5 6 7 8 9 10 11 12 13

#include <iostream> using namespace std; /* Ovaj program racina ukupnu platu radnika, koja se zasniva na ukupnom broju radnih sati i satnici. */ int main (void) { int radniDani = 22; float radniSati = 7.5; float satnica = 33.50; float plata;

// // // //

Broj radnih dana u mjesecu Broj radnih sati u danu Satnica Ukupna mjesecna plata

plata = radniDani * radniSati * satnica; cout << "Plata = " << plata << '\n'; }

Jasno da je da se prvi primjer moe koristiti za komentar jedne i samo jedne linije (ili dijela jedne linije), dok se posljednjim moe komentarisati tekts upisan u vie linija.

2.7 Imena 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 6

Programski jezici, C++ pravilno kreiranje imena (ili identifikatora). Ime traba 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. Uz to, velika i mala slova se razlikuju, tako da se, na primjer, varijable zarada i Zarada razlikuju. 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). 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 date su u tabeli Tabela II.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

2.8 Cijeli brojevi Cijeli broj (integer) se moe definisati pomou tipova short, int i long. Jedina razlika je u tome da int koristi vie ili barem isto bajta kao short, a long koristi vie ili barem isto bajta nego int. Ovo zavisi od raunara na kojem se radi. Konvencija je da cjelobrojne varijable uzimaju u obzir i pozitivne i negativne brojeve (kae se da su
signed). Meutim, u sluaju kada se koriste kao unsigned, onda mogu uzeti samo pozitivne vrijednosti (sa 0).

2.9 Realni brojevi Realni broj se moe definisati sa tipom float i double. double koristi vie bajta i time omoguuje veu opseg i veu tanost pri predstavljanju realnih brojeva. 2.10 Karakteri Varijabla karakter se definie tipom char. 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 maine). Najei sistem je ACSII (Amercan Standard Code for Information Interchange). Na primjer, karakter A ima ASCII kod 65, a karakter a 97. Kao i interger 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.

Programski jezici, C++ Karakteri koji imaju posebnu namjenu (ne predstavljaju karaktere koji se ispisuju) predstavljaju se pomou escape sekvenci, kao npr:
\n novi red \t novi tabulator \v novi vertikalni tabulator \b backspace \ znak navoda (apostrof) \ dvostruki znak navoda \\ backslash (/) \a zvuni signal

2.11 Stringovi String je uzastopni niz karaktera koji se zavravaju nultim karakterom. Tako je, barem, bilo u jeziku C. Ipak, u C++ uveden je novi tip podataka koji se naziva C++ string klasa, pa je mogue na mnogo prirodniji nain manipulisati varijablama sa vie karaktera. Sljedei primjer pokazuje njenu upotrebu.
#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; if (ch != 'K' && ch != 'k') cout << "Zelite nastaviti?\n"; else cout << "Kraj programa"; } while (ch != 'K' && ch != 'k'); }

Ovaj primjer dobro funkcionie jer zavrava program ako se unese "k" ili "K", odnosno program se nastavlja ako se unese bilo koji drugi karakter. 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.

3. Operatori
Ovo poglavlje obrauje ugraene C++ operatore koji se koriste za stvaranje izraza, pri emu izraz predstavlja bilo kakav proraun koji daje neku vrijednost. C++ nudi operatore za izvravanje aritmetikih, ralacijskih, logikih, bitwise i uslovnih izraza. Takoer nudi veoma korisne popratne efekte (side-effect) kao to su pridruivanje, inkrement i dekrement. 3.1 Aritmetiki operatori C++ nudi pet osnovnih operatora, koji su sumirani u Tabeli II.3.1. 8

Programski jezici, C++ Tabela II.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

// // // // //

daje daje daje daje daje

16.9 -0.02 6.8 4.5 1

Osim ostatka pri djeljenju (%) 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 rezulat realan (tipa double). 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.
9 / 2 -9 / 2 // daje 4, a ne 4.5! // daje -5,a ne -4.5!

S obzirom da neeljeno cjelobrojno dijeljenje predstavlja jednu od najeih greki u programiranju, neophodno je da promijenimo jedan od operanada da bude realan broj, kao npr.
int int double cijena = 100; volumen = 80; jedinicnaCijena = cijena / (double) volumen;

// daje 1.25

Operator % daje ostatak pri dijeljenju dva cijela broja (oba operanda moraju biti cijeli brojevi), npr.
13%3 daje 1

3.2 Relacijski operatori C++ nudi 6 relacijskih operatora za raunanje brojnih veliina (Tabela II.3.2) Tabela II.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 6.3 >= 5

// // // // // //

daje daje daje daje daje daje

1 0 1 1 0 1

Treba zapamtiti da se operatori <= i >= mogu korisiti 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 operaotri se ne smiju korisiti ze poreenje stringova, poto se u tom sluaju porede njihove adrese, a ne sadraj. U tom sluaju, rezlutat je neodreen. Ipak, postoje funkcije koje mogu porediti i leksikografsku razliku dva stringa. 9

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

! && ||

Ime Logika negacija Logiko i Logiko ili

Primjer

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

// daje 0 // daje 1 // daje 1

Logika negacija je unarni opearator, tj. ima samo jedan operand kojem daje negativnu vrijednost. 3.4 Inkrementalni i dekrementalni operatori Takozvani auto inkremetalni (++) i auto dekrementalni (--) operatori obezbijeuju prigodan nain za poveavanje, odnosno smanjivanje brojne varijable za 1. Upotreba ovih operatora je sumirana u Tabeli II.3.4., pri emu se predpostavlja da je
int k = 5;

Tabela II.3.4 Inkrement i dekrement operatori.


Operator

++ ++ ---

Ime Inkrement (prefiks) Inkrement (postfiks) Dekrement (prefiks) Dekrement (postfiks)

Primjer

++k k++ --k k--

+ + + +

10 10 10 10

// // // //

daje daje daje daje

16 15 14 15

Kao to se vidi, oba operatora se mogu korisiti u prefiksnom ili postfiksnom obliku. Razlika je velika, jer kada se operator koristi u prefiksnom obliku prvo se primijenjuje operator, a onda se u izrazu koristi rezultat. Kada se koristi u postfiksnom obliku, prvo se rauna izraz, a onda se primijenjuje operator. Oba operatora se mogu primijeniti kako na cjelobrojne, tako i na realne brojeve, iako se ova karakteristika veoma rijetko koristi na realnim brojevima. 3.5 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 lijeva_vrijednost, dok desni operand moe biti proizvoljni izraz. Desni operand se izrauna i pridrui lijevoj strani. Pri tome lijeva_vrijednost 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 dobijaju njegovim kombinovanjem sa aritmetikim i bitwise operatorima. Ove varijante su date u sljedeoj tabeli.

10

Programski jezici, C++ Tabela 2.3.5 Operatori pridruivanja


Operator Primjer Ekivalentno sa

= += -= *= /= %=

n n n n n n

= 25 += 25 -= 25 *= 25 /= 25 %= 25

n n n n n

= = = = =

n n n n n

+ * / %

25 25 25 25 25

Kako operator pridruivanja sam po sebi predstavlja izraz ija se vrijednost pohranjuje u lijevi operand, on se moe korisititi kao desni operand za narednu operaciju pridruivanja, odnosno moe se napisati:
int m, n, p; m = n = p = 100; m = (n = p = 100) + 2; // znai: n = (m = (p = 100)); // znai: m = (n = (p = 100)) + 2;

ili
m = 100; m += n = p = 10; // znai: m = m + (n = p = 10);

2.6 Uslovni (ternarni) operator Uslovni operator treba tri operanda (odatle ime ternarni). On ima optu formulu:
operand1 ? operand2 : operand3 operand1 se izraunava, i tretira se kao logiki uslov. Ako je rezultat razliit od nule, tada se izraunava operand2. U suprotnom, izraunava se operand3. Na primjer: int m = 1, n = 2; int min = (m < n ? m : n);

// min dobija vrijednost 1

Provjeriti ta je rezultat sljedee upotrebe uslovnog operatora:


int min = (m < n ? m++ : n++);

Postoji jo nekoliko vrsta operatora (npr. zarez operator, sizeof operator), ali o njema nee biti rijei u ovom kursu.

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 narednom teksu bie objanjene neke od njih.

11

Programski jezici, C++ 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 neki primjeri:
int i; ++i; double d = 10.5; d + 5; // // // // deklaraciona naredba naredba sa popratnim efektom deklaraciona naredba beskorisna naredba

Posljednji primjer pokazuje beskorisnu naredbu, jer nema nikakvih popratnih efekata. 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. 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) omoguuju da se u program uvede scope ( prostor). Scope predstavlja dio programa unutar kojeg varijabla ostaje definisana. Izvan scope-a ona to vie to nije. Ovo je veoma vana osobina o kojoj e vie biti rijei kada se budu objanjavale funkcije. 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 bismo eljeli provjeriti da li je pri djeljenju djelilac razliit od nule, imali bismo:
if (djelilac != 0) Kolicnik=djelitelj/djelilac;

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

12

Programski jezici, C++ Ovdje se najprije izvrava izraz, i ako je rezultat razliit od nule, izvrava se naredba1. U suprotnom, izvrava se naredba2, to pokazuje i sljedei primjer:
#include <iostream> using namespace std; main() { int x; cout << "Unesite neki broj"; cin >> x; if (x % 2 == 0) cout << "Broj je paran" << endl; else cout << "Broj je neparan" << endl; }

Pored prethodno navedenih varijanti, postoji i ugnijedena if naredba, u kojoj se javljaju vie od dvije alternative. Primjer takve varijente je:
if (callHour > 6) { if (duzinaPoziva <= 5) cijena = duzinaPoziva * tarifa1; else cijena = 5 * tarifa + (duzinaPoziva - 5) * tarifa2; } else cijena = osnovnaCijena;

4.3 Naredba switch


switch naredba omoguuje izbor izmeu vie alternativa, koje su zasnovane na vrijednosti izraza. Opti oblik switch naredbe je: switch (izraz) { case konstanta_1: naredbe; ... case konstanta_n: naredbe; default: naredbe; }

Prvo se rauna izraz (koji se naziva switch tag), a zatim se rezultat poredi sa svakom od numerikih konstanti (koje se nazivaju 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. Klasini primjer ocijenjivanja nekog rada na osnovu osvojenih bodova dat je u daljem teksu: 13

Programski jezici, C++


#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;

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 bismo eljeli izraunati zbir svih brojeva od 1 do n, upotreba while naredbe bi izgledala kao:
i = 1; sum = 0; while (i <= n) sum += i++;

Interesantno je da nije neuobiajeno za while naredbu da ima prazno tijelo petlje, tj. null-naredbu. Takav primjer je problem nalaenja najveeg neparnog faktora nekog broja
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: 14

Programski jezici, C++


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.
do petlja 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 ponovljeno unoenje nekog broja i izraunavanje njegovog kvadrata dok se ne unese 0:
do { cin >> n; cout << n * n << '\n'; } while (n != 0);

Za razliku od while petlje, do petlja se nikada ne koristi sa praznim tijelom prvenstveno zbog jasnoe. 4.6 Naredba for Naredba for (for petlja) je slina naredbi while, ali ima dvije dodatne komponente: izraz koji se izraunava samo jednom prije svega, i izraz koji se izraunava jednom na kraju svake iteracije. Opti oblik naredbe for je:
for (izraz1; izraz2; izraz3) naredba;

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

for petlja se najee koristi u situacijama kada se neka promjenljiva 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 (i = 1; i <= n; ++i) sum += i;

Bilo koja od komponenti u petlji moe biti prazna. Na primjer, ako se uklone prvi i trei izraz, onda do petlja lii na while petlju: 15

Programski jezici, C++


for (; i != 0;) bilo-sta; // je ekvivalentno sa: 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). Na primjer:
for (int i = 1; i <= 3; ++i) for (int j = 1; j <= 3; ++j) cout << '(' << i << ',' << j << ")\n";

daje parove skupa {1,2,3}

5 Funkcije
Ovo poglavlje opisuje funkcije, koje definie korisnik, kao jedan od glavnih graevinskih blokova u C++ programiranju. Funkcije obezbijeuju prikladan nain upakivanja nekog numerikog recepta, koji se moe koristiti koliko god je to puta potrebno. 5.1 Definicija funkcije Definicija funkcije se sastoji od dva glavna dijela: zaglavlja ili interfejsa, i tijela funkcije. Interfejs (neki ga nazivaju i prototip) definie kako se funkcija moe koristiti. On se sastoji od tri dijela: x Imena. Ovo je, u stvari, jedinstveni identifikator. x Parametara (ili potpisa funkcije). Ovo je niz od nula ili vie identifikatora nekog tipa koji se koriste za proslijeivanje vrijednosti u i iz funkcije. x Tipa funkcije. 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 neku 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 bi trebao odgovarati broju parametara funkcije. Svaki argument je izraz iji tip bi trebao 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 se izvrava tijelo funkcije. Na kraju, funkcija vraa vrijednost (ako ista postoji) pozivu. Sljedei primjer ilustrativno pokazuje definiciju jednostavne funkcije koja izraunava vrijednost stepen cijelog broja na neki cijeli broj.

16

Programski jezici, C++


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 int). Nakon toga je dato ime funkcije (Stepen), a zatim njena lista parametara. Funkcija Stepen ima dva parametra (baza i eksponent) koji su tipa int. Sintaksa parametara je slina sintaksi definisanja varijabli, tj. nakon tipa daje se ime parametra. Meutim, nije mogue nakon tipa dati niz parametara odvojenih zarezom, kao u
int Stepen (int baza, eksponent) // Ovo je pogreno!

Zagrada { u liniji 2 predstavlja poetak tijela funkcije. Linija 3 definie lokalnu varijablu. Linije 4 i 5 raunaju stepen varijable baza na varijablu eksponent pomou for petlje. Rezultat se pohranjuje u varijablu rezultat. 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. Posljedica poziva funkcije je da se vrijednosti argumenata 2 i 8 pridruuju parametrima baza i eksponent, respektivno, a zatim se rauna tijelo funkcije.
#include <iostream> using namespace std; main (void) { cout << "2 ^ 8 = " << Stepen(2,8) << '\n'; }

Kada se program pokrene daje sljedei izlaz:


2 ^ 8 = 256

Openito, funkcija se treba definisati prije nego se koristi. To se moe uraditi na vie naina, kao to je pokazano u narednim primjerima. Primjer 1.
#include <iostream> using namespace std; double Stepen (int baza, int eksponent) { double rezultat = 1; for (int i = 0; i < eksponent; ++i) rezultat *= baza;

17

Programski jezici, C++


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

Primjer 2. Treba napomenuti da se deklaracija funkcije sastoji od njenog prototipa, tako da je za deklarisanje 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 deklaraciji, ali to nije preporuljivo.
#include <iostream> using namespace std; double Stepen (int baza, int eksponent); // deklarisanje funkcije

/* moguce je funkciju daklarisati i na sljedeci nacin double Stepen (int, int); */ main () { int a,b; cout << "Unesi bazu:"; cin >> a; cout << "\nUnesi eksponent:"; cin >> b; cout << a<<"^" <<b<<" = " << Stepen(a,b) << '\n'; system("PAUSE"); } double Stepen (int baza, int eksponent) { double rezultat = 1; for (int i = 0; i < eksponent; ++i) rezultat *= baza; return rezultat; }

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, onda bi prehodni program bio:
#include <iostream> #include StepenInt.h using namespace std; main () { int a,b;

18

Programski jezici, C++


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 taan (relativni ili apsolutni) poloaj (path) iste. 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 posljedica toga, ako funkcija napravi bilo kakvu promjenu na parametrima, ovo nee promijeniti vrijednosti argumenta. Na primjer,
#include <iostream> using namespace std; void Foo (int broj) { broj = 0; cout << "broj = " << broj << '\n'; } int main () { int x = 10; Foo(x); cout << "x = " << x << '\n'; system("PAUSE"); return 0; }

parametar broj u funkciji Foo 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 num 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. 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 & iza tipa parametra u interfejsu funkcije, tj. u predhodnom primjeru interfejs funkcije Foo bio bi
void Foo (int& num)

U kontekstu pozivanja funkcija, a na osnovu prethodno iznesenog, razlikujemo dvije vrste pridruivanja: priduivanje prema vrijednosti i pridruivanje prema referenci. U praksi (u pogledu funkcija) se mnogo vie koristi priduivanje prema vrijednosti. 19

Programski jezici, C++ 5.3 Globalne i lokalne varijable (globalni i lokalni scope) Za sve to se definie izvan programskog scope-a se kae da ima globalni scope. Tako, sve funkcije koje smo do sada koristili imaju globalni scope, i predstavljaju globalne funkcije. No, i varijable se mogu defnisati u globalnom scope-u, tj. izvan svih funkcija koje se koriste u programu. Na primjer:
int godina = 1994; int Maksimum (int, int); int main (void) { //... } // globalna varijabla // globalna funkcija // globalna funkcija

Treba zapamtiti da su globalne varijable automatski inicijalizirane na vrijednost nula. Poto su globalni entiteti vidljivi na svim programskim novoima, oni moraju biti jedinstveni na nivu programa. To znai da se globalne varijable ili funkcije na globalnom scope-u ne mogu definisati vie nego jedanput, iako se ime funkcije moe definisati vie puta sve dok su im parametri (njen potpis) jedinstveni. Globalni entiteti su openito pristupani bilo gdje u programu. Svaki blok u programu definie lokalni scope. Na taj nain, tijelo funkcije predstavlja lokalni scope. Parametri funkcije imaju isti scope kao i tijelo funkcije. Varijable koje su definisane unutar lokalnog scope-a su vidljive samo u tom scope-u. Lokalni scope moe da bude ugnijeden, pri emu unutranji scope ponitava vanjski. Na primjer, u
int xyz; // xyz je globalna varijabla void Foo (int xyz) // xyz je lokalna varijabla u tijelu funkcije Foo { if (xyz > 0) { double xyz; // xyz je lokalna varijabla u ovom bloku //... } }

Imamo tri razliita scope-a, od kojih svaki ima razliitu varijablu xyz. Openito, ivotni vijek varijable je ogranien na njen scope. Tako, na primjer, globalne varijable traju svo vrijeme izvrenja programa, dok se lokalne varijable kreiraju kada se ue u njihov scope, a unitavaju kada se izlazi iz njihovog scope-a. Memorijski prostor za lokalne varijable je rezervisan prije izrvrenja programa, dok je memorijski prostor za lokalne varijable alociran u hodu u toku izvrenja programa. Poto lokalni scope ponitava globalni, to lokalne varijable sa istim imenom kao globalne varijable onemoguavaju pristup globalnim varijablama unutar lokalnog scope-a. Na primjer, u
int greska; void Greska (int greska) { //... }

globalna varijabla greska je nepristupana unutar funkcije Greska, poto je ponitena lokalnim parametrom greska. Ovaj problem se moe prevazii koritenjem unarnog operatora :: (unary scope operator), koji globalni entitet uzima kao argument, kao u primjeru 20

Programski jezici, C++


int greska; void Greska (int greska) { //... if (::greska != 0) //... }

// odnosi se na globalnu varijablu error

5.4 Rekurzivne funkcije Za funkciju koja poziva samu sebe kaemo da je rekurzivna. Rekurzija je opta programska metoda koja se primijenjuje na probleme koji se definiu u odnosu na same sebe. Na primjer, problem raunanja faktorijela je primjer rekurzivne funkcije. Faktorijel je definisan sa: x Faktorijel od 0 je 1. x Faktorijel pozitivnog broja n je n puta faktorijel od 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, iterativna opcija je bolja, pa bi funkcija imala oblik:
int Factorijel (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 OOP. Ako bismo eljeli da naa funkcija Stepen ima mogunost koritenja realnih brojeva umjesto cijelih, ili ak 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) {

21

Programski jezici, C++


int rezultat = 1;

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 parametrom za izraunavanje stepena broja 2 { return Stepen(2.0,eksponent); } Stepen sa jednim

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, ali razliite tipove, a u drugom sluaju i razliit broj parametara. Treba paziti da pri pozivu pojedinih funkcija svi tipovi argumenata odgovaraju tipovima parametara (broj 2 je cijeli broj, dok je 2.0 realan!!!)

6. Polja
Ovo poglavlje objanjava polja i ilustruje njihovu upotrebu pri definisanju varijabli. Polje se sastoji od niza objekata (nazivaju se i elementi niza), koji su istog tipa i zauzimaju neprekidan memorijski prostor. Openito, samo polje ima simboliko ime, a ne njegovi elementi. Svaki elemenat je identificiran njegovim indeksom, koji pokazuje poloaj nekog elementa u nizu. Broj elemenata u nizu 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. 6.1 Definisanje i inicializacija polja 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:
int visina[10];

Pristup individualnim elementima nekog niza vri se indeksiranjem niza. Prvi elemenat niza uvijek ima indeks 0. Na taj nain, visina[0] i visina[9] oznaavaju prvi i posljednji elemenat niza 22

Programski jezici, C++


visina, respektivno. Svaki elemenat niza se moe tretirati kao varijabla tipa cijeli broj. Tako, na primjer, da bi smo treem elementu ovog niza pridruili vrijednost 177, pisali bismo: visina[2] = 177;

Pokuaj pristupa nepostojeem elementu nekog niza (na primjer visina[-1] ili visina[10]) moe uzrokovati ozbiljnu greku (tzv. runtime greka, ili greka 'indeks izvan granica). Procesiranje bilo kojeg niza obino ukljuuje koritenje petlje, koja ide kroz niz od elementa do elementa. Sljedei primjer pokazuje funkciju koja rauna srednju vrijednost nekog niza:
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 niza se mogu inicijalizirati. U tu svrhu koriste se zagrade{}, izmeu kojih se specificira lista poetnih vrijednosti elemenata niza koje su odvojene zarezom. Na primjer,
int broj[3] = {5, 10, 15};

definie niz broj, i inicijalizira tri elementa ovog niza na vrijednosti 5, 10, 15, respektivno. Ovo je tzv. eksplicitno inicijaliziranje. Kada je broj vrijednosti u inicijalizatoru manji od dimenzije niza, 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 niza), dimenzija niza postaje suvina i moe se izostaviti, tj. broj elemenata je implicitan u inicijalizatoru (implicitna inicijalizacija). U ovom sluaju inicijalizacija niza broj se moe izvriti i na sljedei nain:
int broj[] = {5, 10, 15}; // dimenzija nije potrebna

Jo jedan primjer u kojem se dimenzija niza moe izostaviti je kada je niz parametar u nekoj funkciji. Na primjer, funkcija Average iz ranijeg primjera se moe napisati na bolji nain, ako se postavi da dimenzija niza nije fiksirana na neku konstantnu vrijednost, nego se dodaje jo jedan parametar, tj.
double Srednja (int broj[], int velicina) { double srednja = 0; for (int i = 0; i < velicina; ++i) srednja += broj[i]; return srednja/velicina; }

Kompletan program bi, u tom sluaju, bio:

23

Programski jezici, C++


#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.
#include <iostream> using namespace std; int main () { // DEKLARACIJA int x[10]; int y[10]; int i, j, n; // UNOSENJE cout << "Unesite broj clanova polja: "; 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; } }

24

Programski jezici, C++


Interesantno je napomenuti da je i C++ string niz karaktera. Tako
char str[] = "HELLO";

definie varijablu str kao niz est (6) karaktera: pet slova i prazan karakter (null-character). Zavrni prazan karakter postavlja kompajler. Za razliku od toga,
char str[] = {'H', 'E', 'L', 'L', 'O'};

definie varijablu str kao niz od 5 elemenata. 6.2 Multidimenzionalni nizovi Niz moe da ima i vie nego jednu dimenziju (dvije, tri, i vie). Ipak, organizacija niza u memoriji je ista kao i prije, tj. neprekidna sekvenca elemenata. Percepcija programera, pak, je drugaija. Na primjer, pretpostavimo da je srednja vrijednost temperatura po godinjim dobima za tri australijska grada data sljedeom tabelom
Tabela II.6.1 Srednje temperature gradova Proljee Sidnej Melburn Brizbejn 26 24 28 Ljeto 34 32 38 Jesen 22 19 25 Zima 17 13 20

Ovo se moe predstaviti dvodimenzionalnim nizom cijelih brojeva:


int godDobTemp[3][4];

Ovo je u memoriji predstavljeno kao neprekidan niz od 12 elemenata tipa cijeli broj. Programer, meutim, moe to zamisliti kao tri reda od po 4 elementa u svakom, kao na Sl. II.6.1.
...

26

34 First row

22

17

24

32

19

13

28

38

25

20

...

Prvi red

Second row

Drugi red

Third row

Trei red

Slika II.6.1 Organizacija varijable godDobTemp u memoriji Kao i kod jednodimezionalnih nizova, elementima nizova se pristupa preko indeksa. No, neophodan je dodatni indeks za svaku dimenziju. Na primjer, srednja temperatura u Sidneju u toku ljeta, data je elementom godDobTemp[0][1]. Inicijalizacija niza se moe obaviti pomou ugnijedenog inicijalizatora, kao:
int godDobTemp[3][4] {26, 34, 22, {24, 32, 19, {28, 38, 25, }; = { 17}, 13}, 20}

Poto se ovaj dvodimenzionalni niz mapira kao jednodimenzionalni niz od 12 elemenata, mogue je koristiti i:
int godDobTemp[3][4] = {

25

Programski jezici, C++


26, 34, 22, 17, 24, 32, 19, 13, 28, 38, 25, 20 };

Ipak, bolja opcija je koritenje ugnijedenog inicijalizatora, poto ne samo da je pregledniji, nego daje i dodatne mogunosti. Na primjer, ako nam je samo prvi elemenat svakog reda razliit od nule, a ostali su jednaki nuli, mogli bismo koristiti:
int godDobTemp[3][4] = {{26}, {24}, {28}};

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


int godDobTemp[][4] = { {26, 34, 22, 17}, {24, 32, 19, 13}, {28, 38, 25, 20} };

Procesiranje multidimenzionalnih nizova je slino jednodimenzionalnim, s tim da se moraju korisiti ugnijedene petlje. Sljedei primjer pokazuje pronalaenje maksimalnog elementa u dvodimenzionalnom nizu iz prethodnih primjera.
#include <iostream> using namespace std; const int redovi const int kolone = 3; = 4;

int godDobTemp[redovi][kolone] = { {26, 34, 22, 17}, {24, 32, 19, 13}, {28, 38, 25, 20} }; int najvecaTemp (int temp[redovi][kolone]) { int najveca = 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 << najvecaTemp(godDobTemp) << "\n"; system("PAUSE"); }

Napomena: Treba paziti kako se inicijalizira vrijednost kontrolne varijable najveca u prethodnom primjeru. Ovdje se koristila vrijednost nula. Meutim, najbolje bi bilo kada bi se inicijalizirala na vrijednost prvog elementa niza, jer u sluaju svih negativnih elemenata niza, nula bi rezultat funkcije bez obzira da li je lan niza ili ne.

7. Datoteke
Ovo poglavlje pokazuje kako se podaci dobiveni pokretanjem nekog programa mogu sauvati njihovim pohranjivanjem 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. 26

Programski jezici, C++ Datoteka, pri tome, predstavlja skup podataka koji su snimljeni na neku formu trajne memorije (hard disk, CD-ROM, floppy disk, ...). 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++ izvrnu 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 e se primjeri u ovom poglavlju odnositi samo na njih. 7.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 fstream sa:
#include <fstream>

Datoteka fstream definie tri nova tipa podataka: x ofstream. Ovaj tip podataka predstavlja stream 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. x ifstream. Ovaj tip podataka predstavlja stream 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. x fstream. Ovaj tip podataka predstavlja openito stream za datoteke, ima karateristike i ofstream i ifstream. On moe kreirati datoteke, pisati na njih i itati sa njih.

7.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: x Datoteka prvo mora da se otvori. Ovo otvara put u komunikaciji izmeu datoteke i stream objekta u programu (fstream, ifstream, ofstream), koji se koristi u pristupu datoteci. x Nakon otvaranja program ita sa datoteke, pie na nju, ili ini oboje. x Na kraju, program zatvara datoteku. Ovo je bitan korak, poto odravanje komunikacije izmeu datoteke i stream objekta 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 nije zatvorena prije prethodnog pristupa. 7.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. 27

Programski jezici, C++ Otvaranje datoteke za pisanje Datoteke sa pisanje se mogu otvoriti pomou fstream i ofstream objekata na dva naina: (i) pomou metode (member function) open, ili (ii) pomou konstruktora (constructor). Otvaranje pomou funkcije open Prvi argument funkcije open je ime i lokacija datoteke koja se treba otvoriti. Meutim, mogue je dodati i drugi argument zavisno od toga da li se fstream i ofstream poziva funkciju open, ili se eli neki drugi modul od onog koji se daje. 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) i apsolutna (absolute path). Pri tome, relativni put predstavlja lokaciju u odnosu na na program, tj. datoteka se stvara u direktoriju u kojem se nalazi i na program. Ovo postiemo na sljedei nain:
ofstream izlaz; izlaz.open("studenti.txt");

Za razliku od relativnog puta, apsolutni put predstavlja lokaciju koja zapoinje slovom drajva, sadrei sve direktorije i poddirektorije dok se ne doe do datoteke. Na primjer, ako je datoteka studenti.txt u direktoriju Pedagoski, a ovaj je podirektorij 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 II.2.10). 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);

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 raunaru (sa drugaijim direktorijima). 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 II.7.1.
Tabela II.7.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. Infomacija e se itati sa datoteke. Datoteka se ne kreira ako ne postoji. Informacija e se zapisati u datoteku. Postojei sadraj datoteke je poniten.

28

Programski jezici, C++ Ako za otvaranje datoteke koristimo ofstream objekat, onda ne moramo koristiti dodatne argumente, ali treba zapamtiti da u tom sluaju moemo samo upisivati informaciju da datoteku, ali ne i itati sa nje. Ako bismo, na primjer, eljeli da pratimo greke izazvane pokretanjem nekog programa i eljeli sauvati sve zapise o tome, koristili bismo opciju ios::app, tj.
ofstream izlaz; izlaz.open("studenti.txt", ios::app);

Meutim, ako se za otvaranje datoteke za pisanje koristi fstream objekat, treba se dodati jo jedan argument, tj. opcija za pisanje (ios::in). U ovom sluaju bi bilo:
fstream izaz; izlaz.open("studenti.txt", ios::out);

Otvaranje pomou konstruktora Konstruktori su funkcije koje se automatski pozivaju kada se pokuava kreirati primjerak (instanca) nekog objekta (instanca prema objektu je isto to i varijabla prema tipu podatka). Oni mogu biti optereeni (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:
ofstream izaz("studenti.txt"); fstream izaz("studenti.txt",ios::out);

Primjena konstruktora, u stvari, omoguava deklarisanje i inicijalizaciju primjerka nekog objekta. Kao i u sluaju deklarisanja 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 iostream objekat. Uz to, datoteka sa koje se ita mora postojati, jer se pokretanjem jednog od prethodnih objekata ne kreira datoteka. Stoga, otvaranje datoteke za itanje se moe otvoriti na jedan od sljedeih naina:
ifstream ulaz; ulaz.open("studenti.txt"); fstream ulaz; ulaz.open("studenti.txt", ios::in); //obavezno dodati argument ios::in ifstream ulaz("studenti.txt"); fstream ulaz("studenti.txt", ios::in);

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: 29

Programski jezici, C++


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 tzv. bitwise operator (|), koji ima isto znaenje kao logiki operator || (ili). 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 bi, na primjer, bio:


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

Pri emu 0x22fed4 predstavlja memorijsku lokaciju (adresu) ifstream varijable ulaz. 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, dobiemo negativan odgovor o njenom postojanju (vrijednost iostream objekta je NULL, a funkcije fail je true, tj. 1). 7.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 kojima se ne 'manipulie'. Zatvranje datoteka se vri pomou funkcije close. Sljedei primjeri pokazuju njenu upotrebu pri zatvaranju datoteka za pisanje i itanje: 30

Programski jezici, C++


ofstream izlaz; izlaz.open("studenti.txt"); // skup naredbi outfile.close(); ifstream ulaz; ulaz.open("studenti.txt"); // skup naredbi ulaz.close();

7.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 iostrem objekat, a ne cout objekat. Sljedei program pokazuje primjer upisivanja podataka na datoteku studenti.txt:
#include <fstream> #include <iostream> using namespace std; int main (){ char podaci[80]; 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; }

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 () { string x; ofstream izlaz; izlaz.open("podaci.txt", ios::app); while (x != "***") { cout << "Unesite neki tekst (za kraj unesite ***):" << endl; cin >> x; izlaz << x << endl; } izlaz.close(); }

31

Programski jezici, C++ 7.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 poglavlja, tj. nakon to korisnik upisuje informacije na datoteku, program ita iste podatke i ispisuje ih na ekran.
#include <fstream> #include <iostream> using namespace std; int main (){ string podaci; 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(); 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; }

Meutim, vidimo da je u ovom sluaju koritena C++ string klasa umjesto varijable podaci tipa char. Na taj nain se pomou funkcije getline moe ispisati ime razreda koje ima vie od jedne rijei. 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 (){ string podaci; bool status; ofstream izlaz; status = upisiDatoteku(izlaz, "studenti.txt"); if (!status) { cout << "Datoteka za ispisivanje otvoriti\n"; cout << "Program se zavrsava\n"; system("PAUSE");

se

ne

moze

32

Programski jezici, C++

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; 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; }

33

You might also like