You are on page 1of 49

POKAZIVAČI I FUNKCIJE

POKAZIVAČI I FUNKCIJE

Primjer metode za zamjenu vrijednosti dvije varijable:


SWAP1 - KRIVO
#include <stdio.h>

void swap1(int a, int b){


int tmp;
tmp = a;
a = b;
b = tmp;
return;
}

int main(){
int x = 1, y = 2;
swap1(x, y);
printf("%d %d\n", x, y);
return 0;
}
SWAP1 - KRIVO
#include <stdio.h>

void swap1(int a, int b){


int tmp;
tmp = a;
a = b;
b = tmp;
return;
}

int main(){
int x = 1, y = 2;
swap1(x, y);
printf("%d %d\n", x, y);
return 0;
}
SWAP1 - KRIVO
#include <stdio.h>

void swap1(int a, int b){


int tmp;
tmp = a;
a = b;
b = tmp;
return;
}

int main(){
int x = 1, y = 2;
swap1(x, y);
printf("%d %d\n", x, y);
return 0;
}
SWAP1 - KRIVO
#include <stdio.h>

void swap1(int a, int b){


int tmp;
tmp = a;
a = b;
b = tmp;
return;
}

int main(){
int x = 1, y = 2;
swap1(x, y);
printf("%d %d\n", x, y);
return 0;
}
SWAP1 - KRIVO
#include <stdio.h>

void swap1(int a, int b){


int tmp;
tmp = a;
a = b;
b = tmp;
return;
}

int main(){
int x = 1, y = 2;
swap1(x, y);
printf("%d %d\n", x, y);
return 0;
}
POKAZIVAČI I MEMORIJA
char *ptr;
Ime Vrijednost Adresa
varijable
ptr ? 0xDABA
POKAZIVAČI I MEMORIJA
char *ptr;
Ime Vrijednost Adresa
char c; varijable
ptr ? 0xDABA
c ? 0xDEE0
POKAZIVAČI I MEMORIJA
char *ptr;
Ime Vrijednost Adresa
char c; varijable
c = ‘9’; ptr ? 0xDABA
c 57 0xDEE0
POKAZIVAČI I MEMORIJA
char *ptr;
Ime Vrijednost Adresa
char c; varijable
c = ‘9’; ptr 0xDEE0 0xDABA

ptr = &c; c 57 0xDEE0


POKAZIVAČI – ARGUMENTI FUNKCIJA
void swap1(int* pA, int* pB){ Ime Vrijednost Adresa
... varijable
} x 1 0xAAC0
y 2 0xAAC4

int main(){
int x = 1, y = 2;
swap1(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
POKAZIVAČI – ARGUMENTI FUNKCIJA
void swap1(int* pA, int* pB){ Ime Vrijednost Adresa
... varijable
} x 1 0xAAC0
y 2 0xAAC4
pA 0xAAC0 0xDD00
int main(){
pB 0xAAC4 0xDD04
int x = 1, y = 2;
swap1(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
POKAZIVAČI – ARGUMENTI FUNKCIJA
void swap1(int* pA, int* pB){ Ime Vrijednost Adresa
int t = *pA; varijable
*pA = *pB; x 1 0xAAC0
*pB = t; y 2 0xAAC4
} pA 0xAAC0 0xDD00
pB 0xAAC4 0xDD04
t 1 0xEEEE
int main(){
int x = 1, y = 2;
swap1(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
POKAZIVAČI – ARGUMENTI FUNKCIJA
void swap1(int* pA, int* pB){ Ime Vrijednost Adresa
int t = *pA; varijable
*pA = *pB; x 2 0xAAC0
*pB = t; y 2 0xAAC4
} pA 0xAAC0 0xDD00
pB 0xAAC4 0xDD04
t 1 0xEEEE
int main(){
int x = 1, y = 2;
swap1(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
POKAZIVAČI – ARGUMENTI FUNKCIJA
void swap1(int* pA, int* pB){ Ime Vrijednost Adresa
int t = *pA; varijable
*pA = *pB; x 2 0xAAC0
*pB = t; y 1 0xAAC4
} pA 0xAAC0 0xDD00
pB 0xAAC4 0xDD04
t 1 0xEEEE
int main(){
int x = 1, y = 2;
swap1(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
POKAZIVAČI – ARGUMENTI FUNKCIJA
void swap1(int* pA, int* pB){ Ime Vrijednost Adresa
int t = *pA; varijable
*pA = *pB; x 2 0xAAC0
*pB = t; y 1 0xAAC4
}

int main(){
int x = 1, y = 2;
swap1(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
DEMISTIFICIRANI SCANF

Funkciji scanf se proslijeđuju adrese varijabli u kojih


želimo učitati vrijednost s ulaza:

char ch;
int numx;
float numy;
scanf("%c %d %f", &ch, &numx, &numy);
ADRESE I POZIVI FUNKCIJA

U programskom jeziku C ne postoji pravilo za


redoslijed poziva funkcija u izrazima:

x = funk1(&a,b) + funk2(&a,b);

Ukoliko neka od funkcija mijenja vrijednost varijable a,


mi ne znamo koja funkcija će to prva napraviti.
ADRESE I POZIVI FUNKCIJA
#include <stdio.h>
#define STOPA 0.08

float kamate(float *iznos) {


float kamate_iznos = *iznos * STOPA;
*iznos += kamate_iznos;
return( kamate_iznos );
}
float uplata(float rata, float *iznos){
*iznos -= rata;
return *iznos;
return (*iznos -= rata)
}
ADRESE I POZIVI FUNKCIJA
int main() {
float iznos = 10000, rata = 100;
float novi_iznos;
novi_iznos = kamate(&iznos) + uplata(rata,&iznos);
printf("Novi iznos: %.2f\n", novi_iznos);
printf("Iznos : %.2f\n", iznos);
return 0;
}
ADRESE I POZIVI FUNKCIJA
int main() {
float iznos = 10000, rata = 100;
float novi_iznos;
novi_iznos = kamate(&iznos) + uplata(rata,&iznos);
printf("Novi iznos: %.2f\n", novi_iznos);
printf("Iznos : %.2f\n", iznos);
return 0;
}
Ukoliko se prvo poziva
Ukoliko se prvo poziva
funkcija kamate(&iznos),
funkcija uplata(rata,
ispis je:
&iznos), ispis je:
Novi iznos: 11500.00
Novi iznos: 10692.00
Iznos: 10700.00
Iznos: 10692.00
PRISJETIMO SE...
• Pridruživanje:

int num = 5;
int *p1num = &num;
int *p2num = NULL;

p2num = p1num;
*p2num = 7;
printf("%d\n", num);

• Oba pokazivača sadrže istu adresu – adresu varijable num.


PRISJETIMO SE...
Aritmetika: ptr++;
Adresa se uvećava za broj bajtova koji odgovara veličini
podatkovnog tipa na koji pokazuje ptr.

char c;
char *pc = &c;
printf("%p\n", pc);
pc++;
printf("%p\n", pc);

Ako je adresa od varijable c 0x0000FF00, nakon uvećavanja


pokazivača pc s naredbom pc++, u pc je spremljena adresa
0x0000FF01.
POKAZIVAČI I POLJA
Polja i pokazivači u C-u su usko povezani
• Ime polja je konstantni pokazivač
• S pokazivačima se može raditi kao i s poljima preko
indeksa
Definirajmo polje b[5] i pokazivač bPtr:
int b[5], *bPtr;
Da bi ih izjednačili možemo pisati:
bPtr = b; ili bPtr = &b[0];
(Ime polja (b) je u stvari adresa prvog elementa polja)
(Eksplicitno pridružujemo pokazivaču bPtr adresu
prvog elementa)
POKAZIVAČI I POLJA

Element b[3]
• Može mu se pristupiti kao *( bPtr + 3 )
• Može mu se pristupiti i kao bPtr[ 3 ]
– Pokazivač/indeks notacija: bPtr[ 3 ] isto kao i b[ 3 ]
• Budući je ime polja pokazivač, aritmetika pokazivača
može se primijeniti i na samo polje: *( b + 3 )
POKAZIVAČI I POLJA
Ime svakog deklariranog polja jest konst.
pokazivač

Svaki pokazivač se može koristiti kao polje


POKAZIVAČI I POLJA
int a[10];
int b[5]; Izraz Ekvivalentni
int *bPtr; izraz
int *aPtr; &b[0] b
aPtr = &a[0]; &b[1] b+1
bPtr = b; b[0] = 4 *(b+0) = 4
b[2] = 8 *(b+2) = 8
NIJE DOPUŠTENO! b b++ bPtr++
i a moraju ostati
nepromijenjeni, tj -
a=b aPtr = bPtr
konstantni
POLJE KAO ARGUMENT FUNKCIJE
void ucitajPolje(int p[], int n)
int main () { {
int polje[10]; int i;
for(i = 0; i < n; i++)
int n, i; scanf("%d", &p[i]);
scanf("%d", &n); }

ucitajPolje(polje, n); • Polje predano kao stvarni


argument koristeći
for(i = 0; i < n; i++)
činjenicu da je naziv polja
printf("%d ", polje[i]);
adresa prvog elementa
• Polje p[] kao formalni
argument
return;
• Pristup elementima na isti
}
način kao i „običnom” polju
POLJE KAO ARGUMENT FUNKCIJE
void ucitajPolje(int *p, int n)
int main () { {
int polje[10]; int i;
for(i = 0; i < n; i++)
int n, i; scanf("%d", &p[i]);
scanf("%d", &n); }

ucitajPolje(polje, n); • Pokazivač int* p kao


formalni argument
for(i = 0; i < n; i++)
• Pristup elementima na isti
printf("%d ", polje[i]);
način kao i „običnom” polju

return;
}
POLJE KAO ARGUMENT FUNKCIJE
void ucitajPolje(int *p, int n)
int main () { {
int polje[10]; int i;
for(i = 0; i < n; i++)
int n, i; scanf("%d", p+i);
scanf("%d", &n); }

ucitajPolje(polje, n); • Pristup elementima


koristeći svojstvo da je
for(i = 0; i < n; i++)
polje zapravo niz
printf("%d ", polje[i]);
elemenata u memoriji
jedan za drugim
return;
}
POLJE KAO ARGUMENT FUNKCIJE
void ucitajPolje(int p[], int n)
int main () { {
int polje[10]; int i;
for(i = 0; i < n; i++)
int n, i; scanf("%d", p+i);
scanf("%d", &n); }

ucitajPolje(polje, n); • Polje p[] kao formalni


argument
for(i = 0; i < n; i++)
• Pristup elementima
printf("%d ", polje[i]);
koristeći svojstvo da je
polje zapravo niz
elemenata u memoriji
return;
jedan za drugim
}
POLJE KAO ARGUMENT FUNKCIJE
void ucitajPolje(int p[], int n)
int main () { {
int polje[10]; int i;
for(i = 0; i < n; i++)
int n, i; scanf("%d", &p[i]);
scanf("%d", &n); }

ucitajPolje(&polje[0], n); • Polje predano kao adresa


prvog elementa
for(i = 0; i < n; i++)
printf("%d ", polje[i]);

return;
}
POLJE KAO ARGUMENT FUNKCIJE
Postoje 2 načina pisanja prototipa funkcije sa
poljem kao argumentom:
povratna_vrijednost funkcija(tip_polja x[])
Ili koristeći pokazivače:
povratna_vrijednost funkcija(tip_polja *x)

U oba slučaja x je pokazivač na polje tipa „tip_polja”.


VELIČINA POLJA U FUNKCIJI
Kako da funkcija zna veličinu polja?
void funkcija(int x[])
Ili koristeći pokazivače:
void funkcija(int *x)

Možemo funkciji proslijediti veličinu polja s kojim


raspolaže:
void funkcija(int x[], int n)
...
for(i = 0; i < n; i++ )
x[i]++;
VELIČINA POLJA U FUNKCIJI
Kako da funkcija zna veličinu polja?
void funkcija(int x[])
Ili koristeći pokazivače:
void funkcija(int *x)

Ili možemo označiti zadnji element polja nekom


specijalnom vrijednosti (npr., 0):
void funkcija(int x[])
...
for(i = 0; x[i] != 0; i++ )
x[i]++;
POLJE KAO ARGUMENT FUNKCIJE
• Da bi mogla koristiti neko polje, funkciji se uvijek
prosljeđuje adresa početka polja kojemu se onda
pristupa preko operatora * i [].
• Ukoliko želimo naglasiti da nije dopuštena izmjena
polja u funkciji, koristiti ključnu riječ const:
int nadji(const int x[], int n)
Ili koristeći pokazivače:
int nadji(const int *x, int n)
U oba slučaja x je pokazivač na polje tipa „tip_polja”.
POLJE KAO ARGUMENT FUNKCIJE
• Kako proslijediti samo dio polja?
• Funkcija ostaje ista:
int nadji(const int x[], int n)
• Mijenja se poziv:
int polje[20] = {1,2,3,4,5,6,7,8,9,10,11};
rez = nadji(&polje[3], 3);
NA OVAJ NAČIN
PROSLJEĐUJEMO U
FUNKCIJU DIO POLJA

rez = nadji(polje + 3, 3);


ENDIAN
#include <stdio.h>
Vrijednost 511 binarno:
int main () { 00000000 00000000 00000001 11111111
int a=511; 00 00 01 FF
unsigned char *p;
p = (char *) &a;
printf ("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));
return 0;
} ISPIS:
255 1 0 0
LITTLE ENDIAN / BIG ENDIAN
• Memorija se sastoji od niza bajtova
• Kako pohraniti char vijednost?
– 1 bajt – jednostavno je
• Kako pohraniti integer vrijednost?
– 4 bajta – jedan po jedan, jedan za drugim
0x200080FA
...

...

...

0x200080FD

...
0x200080FB

0x200080FC
... ... ... 0x20 0x00 0x20 0x00 ...
BIG ENDIAN
• Prvo najznačajniji bajt
• Na kraju najmanje značajni bajt
• BIG ENDIAN

1. bajt 2. bajt 3. bajt 4. bajt


0x200080FA
...

...

...

0x200080FD

...
0x200080FB

0x200080FC
... ... ... 0x20 0x00 0x20 0x00 ...
BIG ENDIAN
• Vrijednost 511 pohranjena BIG ENDIAN
mehanizmom (00 00 01 FF)

1. bajt 2. bajt 3. bajt 4. bajt


0x200080FA
...

...

...

0x200080FD

...
0x200080FB

0x200080FC
... ... ... 0x00 0x00 0x01 0xFF ...
LITTLE ENDIAN
• Prvo najmanje značajni bajt
• Na kraju najznačajniji bajt
• LITTLE ENDIAN

4. bajt 3. bajt 2. bajt 1. bajt


0x200080FA
...

...

...

0x200080FD

...
0x200080FB

0x200080FC
... ... ... 0x20 0x00 0x20 0x00 ...
LITTLE ENDIAN
• Vrijednost 511 pohranjena LITTLE ENDIAN
mehanizmom (00 00 01 FF)

4. bajt 3. bajt 2. bajt 1. bajt


0x200080FA
...

...

...

0x200080FD

...
0x200080FB

0x200080FC
... ... ... 0xFF 0x01 0x00 0x00 ...
REKURZIJA
• Pogodan način za rješavanje nekih problema: svojstvo
algoritma da poziva samog sebe sa promjenjenim
argumentima ≈ indukcija.
• Funkcija mora moći pozvati samu sebe: moguće je ako
programski jezik to dopušta (u C-u su moguće rekurzivne
funkcije).
• Funkciju treba napisati kao rekurzivnu.
• Broj poziva nije neograničen i zavisi od veličine stoga (OS,
prevodioc)
REKURZIJA
void incrementAndPrint(int n)
{
n++;
printf("%d ", n);

if(n < 10)


incrementAndPrint(n);
}

int main()
{
incrementAndPrint(5);

return 0;
}
REKURZIJA - PRIMJER
n !=n⋅(n−1)!
0!=1
• Faktorijel od n se dobije tako da se n pomnoži sa faktorijelom
od n-1 (ne moramo ga znati izračunati već možemo ponovo
pozvati funkciju = rekurzija).
• U svakom koraku tj. pozivu funkcije n se smanji za 1 i na kraju
dolazimo do 0 za koju je prema definiciji 0! = 1.
• Vraćamo se unatrag odakle su funkcije pozvane i svaki puta
množimo rezultat sa brojem više
REKURZIJA - PRIMJER
double fakt(int n)
{
double rez = 1; Primjer izračuna faktorijela bez
for(i = 1; i <= n; i++) rekurzije
rez *= i;
return rez;
}

int main()
{
printf("%g\n", fakt(5));

return 0;
}
REKURZIJA - PRIMJER
double fakt(int n)
{
if (n==0)
return 1;
else
return n * fakt(n-1);
}

int main()
{
printf("%g\n", fakt(5));

return 0;
}

You might also like