Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 9

POKAZIVAI

-sve varijable u programu se nalaze na nekoj lokaciji u memoriji. Npr, sljedee dvije linije:
float x;
x=3.5;
zahtijevaju od kompajlera da odvoji etiri bajta memorije za realnu varijablu x, a da zatim tu smjesti
vrijednost 3.5. Lokaciju u memoriji (adresa prvog bajta) na kojoj je varijabla x smejtena je mogue
dobiti stavljajui operator & (adresa od) ispred naziva varijable. Tako &x oznaava adresu varijable x.
-pokaziva (pointer) je varijabla ija je vrijednost memorijska adresa neke druge varijable (odreenog tipa). Sintaksa
definisanja je:
<ime_tipa> * <naziv_pokazivake_varijable>;
-sadraj adrese na koju pointer pokazuje se moe dobiti pomou operatora * (tzv. derefenciranje pointera).
Primjer:
float x, y;
float* px;

x = 6.5;
px = &x;
y=*px;

Ovaj kod definie float varijable x i y, te pokaziva na float varijable px. Zatim u x stavlja vrijednost
6.5, a u px adresu varijable x. Potom u y stavlja sadraj adrese na koju px pokazuje (to je u ovom
sluaju 6.5).
-C omoguava vrenje aritmetikih operacija nad pointerima (+, -, ++, --). Meutim, treba shvatiti kako "jedinica
mjere" pri ovim raunanjima zavisi od tipa pointera. Npr, koristei prethodni primjer, izraz px+1 pokazuje ne na
naredni bajt, ve na prvu lokaciju iza varijable x (tj. 4 bajta iza lokacije na koju pokazuje px). Kada bi px bio tipa
double (ili char), tada bi px+1 pokazivao 8 bajtova (odnosno 1 bajt) iza lokacije na koju pokazuje px.

99
px
100
101
102
103
px+1 104
105
106
107
108

Primjer:
char* pc;
float* px;
float x;
x = 6.5;
px = &x;
pc = (char*) px;
Sada bi pc+1 pokazivao na lokaciju 101, zato to je pc pokaziva tipa char.
-treba shvatiti da, mada je vrijednost pointera obino neki veliki cijeli broj (koji se moe npr. odtampati sa printf),
pointeri i cjelobrojne promjenjive su dva potpuno razliita tipa podataka
-elementi nizova u C-u se smjetaju u susjedne memorijske lokacije. C tretira ime niza kao pointer na prvi element.
Npr, ako definiemo niz:
int a[10];
sada je a[0] isto to i *a, a[1] isto to i *(a+1) itd.
-pointeri omoguavaju dinamiku alokaciju memorije. Ovo je pogodno npr. ako elimo koristiti niz iju veliinu
neemo znati do vremena izvravanja programa. Za dinamiku alokaciju se koriste funkcije malloc i free,
slino kao new i dispose u Pascal-u. malloc alocira onoliko prostora koliko mu se to navede u argumentu.
-parametri funkcija u C-u se uvijek prenose po vrijednost. Prenos preko referenci se vri pomou pointera.
-mogue je definisati i pointer na pointer:
int **dupli;
pointer na pointer varijabla
pointer

PRIMJER 1:
#include <stdio.h>

int main(){

float x, y; /* x i y su tipa float */


float *fp, *fp2; /* fp i fp2 su pointeri na float */
x = 6.5; /* x sada sadrzi vrijednost 6.5 */
printf("Vrijednost varijable x je %f, a adresa od x je %ld\n", x, &x);
fp = &x; /* fp sada pokazuje na adresu od x */
/* stampamo sadrzaj adrese na koju pokazuje fp *
printf("Vrijednost na memorijskoj adresi fp je %f\n", *fp);
/* mijenjamo sadrzaj memorijske adrese */
*fp = 9.2;
printf("Nova vrijednost x je %f = %f \n", *fp, x);
/* vrsimo aritmeticku operaciju nad sadrzajem fp */
*fp = *fp + 1.5;
printf("Krajnja vrijednost varijable x je %f = %f \n", *fp, x);
/* vrsimo dodjele */
y = *fp;
fp2 = fp;
printf("Dodijeljene vrijednosti: y = %f i fp2 = %f \n", y, *fp2);

PRIMJER 2:
#include <stdio.h>

int main()
{

int *niz, dniz, i;

scanf("%d", &dniz);
niz=(int *) malloc(dniz*sizeof(int));
for(i=0; i<dniz; i++)
scanf("%d", (niz+i));

for(i=0; i<dniz; i++)


printf("%d", *(niz+i));
}

Objanjenje: funkcija sizeof(tip) vraa broj bajtova koji u memoriji zauzima jedan podatak odgovarajueg
tipa. Npr, sizeof(int) vraa vrijednost 2. Funkcija malloc vraa pointer tipa void, koji se ne moe
dereferencirati, tj. pristupiti podatku na koji on pokazuje, poto se ne zna njegov tip. Zato se mora izvriti eksplicitna
konverzija u int pokaziva.

PRIMJER 3:
#include <stdio.h>

void zamjena1(int a, int b)


{
int temp;

temp = a;
a = b;
b = temp;
printf("Iz funkcije zamjena1:");
printf("a = %d, b = %d\n", a, b);
}

void zamjena2(int *a, int *b){


int temp;

temp = *a;
*a = *b;
*b = temp;
printf("Iz funkcije zamjena2: ");
printf("a = %d, b = %d\n", *a, *b);
}

int main()
{

int a, b;

a = 5;
b = 7;
printf("Iz funkcije main: a = %d, b = %d\n", a, b);

zamjena1(a, b);
printf("Iz funkcije main: a = %d, b = %d\n", a, b);
zamjena2(&a, &b);
printf("Iz funkcije main: a = %d, b = %d\n", a, b);
}

Objanjenje: C++ predaje argumente funkcijama pomou vrijednosti. Dakle, nema naina da se direktno promijeni
varijabla u funkciji iz koje je druga funkcija pozvana. Tako, potprogram za sortiranje zamjenjuje dva neporedana
elementa funkcijom sa imenom swap. Nije dovoljno napisati

swap(a, b);

gdje je funkcija definisana kao

void swap(int x, int y){ /* ovo je pogresno */


int temp;
temp=x;
x=y;
y=temp;
}

Zbog poziva preko vrijednosti, funkcija swap ne moe uticati na argumente a i b u funkciji koja ju je
pozvala. Ona samo zamjenjuje preslike (moda je ipak razumljivije rei kopije) varijabli a i b.
Da bi se dobio eljeni efekt, potrebno je pozivnim programom predati pokazivae do vrijednosti ovih
varijabli:
swap(&a, &b);
VEKTORI I ITERATORI

Vektor je objekat koji se koristi za skladitenje neogranieno mnogo objekata bilo kog tipa. Po tome je slian
dinamikoj listi, s tim to je obezbijeen pristup elementima po indeksu, dakle kao obian niz. Kada se kae
dinamiki, misli se da mu se veliina mijenja dinamiki, tj. da mu se memorija prazni automatski. Zbog ega je to
tako, to je ve neka druga pria, za vas trenutno nebitna.

moj_vektor[0] = 5;
int a = moj_vektor[5];

Da bi va program koristio vektore, potrebno je da sadri sljedee linije koda:

#include <vector>
using namespace std;

Kada predstavljate (deklariete, uvodite, pravite) objekat klase vektor, potrebno je da kaete kojeg tipa e biti objekti
u tom vektoru. Da ne bude zabune, kada se kae "vektor se koristi za skladitenje neogranieno mnogo objekata bilo
kog tipa", ne misli se da svaki element vektora moe biti proizvoljnog tipa, nego da moete napraviti vektor objekata
tipa "int", kao i vektor objekata tipa "double", ba kao i vektor objekata koji pripadaju proizvoljnoj klasi (vaoj ili
sistemskoj). To ukljuuje i da moete napraviti vektor objekata tipa vektor, kao i sve ostale akrobacije koje vam
padnu na pamet. Dakle, da se vratimo na temu. Kada predstavljate objekat klase vektor, potrebno je da kaete kojeg
tipa e biti objekti u tom vektoru. Deklaracija glasi:

vector<TIP> ime_vektora;

Umjesto rijei TIP unesite tip objekata koji e biti unutar vektora, npr. int, double, string, char *, MojaKlasa, itd.

vector<int> vektor_intova;
vector<char *> vektor_stringova;
vector<MojaKlasa> moj_vektor; //ovaj dio se odnosi na klase i za vas trenutno
nije bitan

Kada predstavite vektor na ovaj nain, on predstavlja prazan vektor, vektor bez ikakvih elemenata. Da biste ubacili
element odgovarajueg tipa u vektor, koristite njegovu metodu push_back(), na sljedei nain:

vektor_intova.push_back( 5 );
vektor_intova.push_back( 10 );
vektor_intova.push_back( 1 );
vektor_intova.push_back( 3 );

Pri ubacivanju elemenata u vektor, koristei metodu push_back, svaki sljedei element ide na kraj vektora, i pri
tome se on KOPIRA u vektor, tj. element unutar vektora NEMA nikakve VEZE sa elementom koji ste zadali kao
argument metoda push_back(). Nijedna izmjena elementa unutar vektora se ne odraava na element koji ste zadali
kao argument metoda push_back(). To je veoma vano za zapamtiti.

Nakon to ste kreirali vektor i ubacili u njega elemente koji vam u njemu trebaju, velika je vjerovatnoa da e vam
kasnije trebati da te elemente proitate ili izmijenite, tj. da im pristupite. Vektor, kao to je to reeno na poetku
ovog poglavlja, omoguava indeksni pristup svojim elementima, dakle moete da pristupite elementu vektora na
osnovu njegovog rednog broja. Prvi element koji ste ubacili u vektor ima redni broj 0, drugi koji ste ubacili ima
redni broj 1, ..., n-ti element koji ste ubacili ima redni broj n-1.
cout << vektor_intova[0] << endl; // 5
cout << vektor_intova[1] << endl; // 10
cout << vektor_intova[2] << endl; // 1
cout << vektor_intova[3] << endl; // 3
// ili:
for ( int i = 0; i < 4; i++ )
cout << vektor_intova[i] << endl; // isti rezultat

Ukoliko niste sigurni koliko vektor ima tano elemenata, moete koristiti njegovu ugraenu metodu size():

for ( int i = 0; i < vektor_intova.size(); i++ )


cout << vektor_intova[i] << endl;

Da biste ispraznili vektor, koristite njegovu metodu clear(), a da biste provjerili da li je ve prazan, koristite njegovu
metodu empty():

vektor_intova.clear();
moj_vektor.clear();
if ( ! vektor_intova.empty() || ! moj_vektor.empty() )
abort();

Naravno, postoji nain da se objekat ubaci u vektor na odgovarajue mjesto, kao i nain da izbacite pojedinane
elemente iz vektora, ali ta pria slijedi tek nakon zavrene prie o iteratorima.

ITERATORI

Iteratori predstavljaju posebnu vrstu objekata koji po mnogo emu lie na pokazivae. Prisutni su u skoro svim
klasama Standardne Biblioteke, sa malim meusobnim razlikama. Potreba za iteratorima je viestruka. Medjutim,
ono to je nama najbitnije je to da mnogo metoda klase vektor po svojoj definiciji trai iterator kao argument. Ono
to je nama takoe bitno je da se asistenti obraduju kad vide da koristite iteratore. Prema tome, hajde da vidimo kako
deklarisati iterator:

vector<TIP>::iterator i, j, k;

Nakon ovakve deklaracije, promjenjive i, j i k su spremne da pokazuju na objekte tipa TIP, a koji se nalaze u okviru
vektora takvih objekata. Nakon deklaracije, iteratori jo uvijek ne pokazuju ni na jedan objekat, pa ih je potrebno
inicijalizovati. Metoda begin() klase vektor, vraa iterator na prvi element vektora. Metoda end() klase vektor
vraa iterator na ELEMENT KOJI SE NALAZI IZA POSLJEDNJEG ELEMENTA VEKTORA. Ovo je jako bitno
za upamtiti. Dakle, metoda end() NE vraa iterator na posljednji element vektora, nego na jedan iza njega. Ovaj
element naravno ne postoji u vektoru, ali vidjeemo poslije zato je bitno da to bude ba tako.

vector<int>::iterator i, e;
i = vektor_intova.begin();
e = vektor_intova.end();

Kao to je ve reeno, iteratori po mnogo emu lie na pokazivae, ak moete slobodno da gledate ovako: iteratori
se razlikuju od pokazivaa samo po deklaraciji; u svim ostalim situacijama se koriste kao pokazivai. To ukljuuje
sljedee:

Iteratori se mogu dereferencirati


Na iteratorima se moe koristiti standardna pokazivaka aritmetika
Moe se deklarisati iterator na iterator (ba kao to moe i pokaziva na pokaziva)
Iteratori se mogu porediti
...

Evo nekoliko primjera koritenja iteratora:

vector<int> vektor_intova;
vector<int>::iterator i, e;
vektor_intova.push_back( 5 );
vektor_intova.push_back( 10 );
vektor_intova.push_back( 1 );
vektor_intova.push_back( 3 );
e = vektor_intova.end();
for ( i = vektor_intova.begin(); i != e; i++ )
cout << (*i) << endl;
i = vektor_intova.begin() + 2; // pokazuje na treci (tj. drugi) element
vektora, 1
i = vektor_intova.begin() + 3; // pokazuje na cetvrti (tj. treci) element
vektora, 3

cout << (*e) << endl; // GRESKA! Ne smije se dereferencirati iterator


koji pokazuje
// na element iza posljednjeg, jer on ne
postoji

Nakon to smo ovako predstavili iteratore, i ako ste to dosad dobro shvatili, moemo prei na onu priu koja se
ticala izbacivanja proizvoljnog elementa iz vektora, ili ubacivanje objekta u vektor, tako da ne dodje na kraj nego na
proizvoljnu poziciju.

Da biste izbrisali (zapravo izbacili) element iz vektora, koristite njegovu metodu erase(). Ona po definiciji
prihvata iterator na element koji elite da izbacite. Ukoliko znate da je to npr. element sa rednim brojem 3, onda ga
izbacujete na slijedei nain:

vektor_intova.erase( vektor_intova.begin() + 3 );
// ili:
vector<int>::iterator i = vektor_intova.begin() + 3;
vektor_intova.erase( i );

...a ukoliko elite da izbacite element koji ima vrijednost npr. 10, onda to radite ovako:

vector<int>::iterator i = vektor_intova.begin(), e = vektor_intova.end();


for ( ; i != e; i++ ) // nadam se da vam je jasan ovaj oblik petlje
if ( *i == 10 ) {
vektor_intova.erase( i );
break;
}

Slino, ako elite da ubacite novi objekat u vektor ali tako da dodje na proizvoljno mjesto u vektoru, onda koristite
njegovu metodu insert(). Ona takoe prihvata iterator kao svoj argument, i taj iterator treba da predstavlja
element PRIJE kojega elite da ubacite novi element. Na taj nain, ukoliko elite da ubacite novi objekat tako da on
ide na poetak vektora, radite neto ovako:

vektor_intova.insert( vektor_intova.begin(), 100 );

...a ako elite da ga dodate na kraj (bez da koristite push_back()), onda ovako:
vektor_intova.insert( vektor_intova.end(), 100 );

Ako elite da novi objekat zauzme takvo mjesto da mu je redni broj 3, onda:

vektor_intova.insert( vektor_intova.begin() + 3 );

NAPOMENE

Ukoliko budete intenzivno koristili iteratore, sigurno ete doi u situaciju da imate konstantan vektor (ili
koji sadri konstantne elemente), a elite proitati njegov sadraj koritenjem iteratora. Tada vam
kompajler nee dozvoliti da to uinite na do sada opisan nain. Sve zapravo ostaje isto, samo to ete
morati koristiti const_iterator umjesto dosadanjeg iterator. Dakle, deklaracija e morati
glasiti ovako:

int f( const vector<int> & vektor_intova )


{
vector<int>::const_iterator i = vektor_intova.begin();
// ...
}

Dvije stvari: vektor.push_back( 100 ) i vektor.insert( vektor.end(), 100 ) - su


sinonimi. Nemojte oekivati da e neka od te dvije da radi bre od druge.
Moete koristiti metodu vektora pop_back(), koja izbacuje posljednji element vektora i predstavlja
sinonim za erase( vektor.end() - 1 );
Metoda clear() svakako radi bre nego izbacivanje jednog po jednog elementa.
Metoda size() zapravo vraa unsigned, a ne int, tako da se kompajler moe buniti kada poredite
neku promjenjivu tipa int i vektor.size(). Npr. najispravnije bi bilo:

vector<int> vektor_intova;
for ( unsigned i = 0; i < vektor_intova.size(); i++ )
cout << vektor_intova[i] << endl;
// a NE:
for ( int i = 0; i < vektor_intova.size(); i++ )
cout << vektor_intova[i] << endl;

Moram pri tome da vas upozorim da je esta zamka neto ovakvo:

for ( unsigned i = vektor.size() - 1; i >= 0; --i )


cout << vektor_intova[i] << endl;

... jer e se i smanjivati do nule, a onda kada bude trebalo da postane jednako -1, budui da je tipa
unsigned, dobie neku bezveze pozitivnu vrijednost, i zapaete u beskonanu petlju, i mogue je da e
vam pui program.

Link ka vectorima i njegovim ugraenim funkcijama: http://www.cplusplus.com/reference/vector/vector/


PRIMJERI

1. Zadaci 1a i 1b.
Trivijalan primjer gdje vector moe obraditi milion lanova dok obian niz crashuje.

2. Zadatak 2.
Trivijalan primjer raunanja aritmetike sredine koristei vectore.

3. Zadatak 3.
Tu je prikazano korienje permutacija, tj funkcije next_permutation(pocetak, kraj);Na
poetku se uitavavaju brojevi u vektor, a nakon toga se ispisuju pomou iteratora. Funkcija kao
parametar uzima poetnu i krajnju vrijednost vektora koje su predstavljene iteratorima.

You might also like