UNIVERZITET EDUKONS NOVI SAD – SREMSKA · PDF file1 Dr DušanT.Malbaški 1...

97
UNIVERZITET EDUKONS NOVI SAD – SREMSKA KAMENICA PREZENTACIJA Dr Dušan T. Malbaški 2014.

Transcript of UNIVERZITET EDUKONS NOVI SAD – SREMSKA · PDF file1 Dr DušanT.Malbaški 1...

UNIVERZITET EDUKONS NOVI SAD – SREMSKA KAMENICA

PREZENTACIJA

Dr Dušan T. Malbaški

2014.

1

Dr Dušan T. Malbaški

1 UVOD

2

3

Programski jezik C

• 1972. Dennis Ritchie (Bell Laboratories)

• viši programski jezik koji se po brzini i iskorišćenju memorijskog prostora može približiti asemblerskom jeziku

• nastao kao zamena za asemblerski jezik u svrhu izrade sistemskih programa

• funkcija cilja: mali i brzi programi

2

4

Osnovne osobine jezika C

1. operatorski jezik (preko 40 operatora, 15 nivoa prioriteta, oba smera grupisanja)

2. slabo tipiziran jezik, tj.

• dozvoljava mešovite izraze

• na poseban način realizuje logički tip

1

2 ELEMENTI PROGRAMSKOG JEZIKA C

22

Sadržaj

• alfabet programskog jezika C

• format izvornog koda

• komentarisanje izvornog koda

• identifikatori

• globalna struktura programa

• primer

33

Izučiti procedurni programski jezik znači:

1. proučiti tipove podataka kojima raspolaže

2. proučiti kakvim naredbama raspolaže

3. proučiti kako je realizovan ulaz-izlaz

4. proučiti kako su realizovani potprogrami

2

4

Alfabet programskog jezika C

• Mala i velika slova engleske abecede (znak _ tretira se kao slovo). C pravi razliku između malih i velikih slova, dakle

a≠A!

• Cifre 0 1 2 3 4 5 6 7 8 9

• Specijalni znaci + - * ! != += <<= itd.

4

5

• slobodan format (elementi izvornog koda se slobodno raspoređuju po ekranu)

while(x--) {y+=x; z*=y;}

while(x--) {y+=x;z*=y;

}

while(x--){y+=x;z*=y;

}

Format izvornog koda

isto!

6

Terminatori

• naredbe se razdvajaju tzv. belim znakom (razmaknica, blanko, novi red)

• za razliku od paskala, znak ; nije znak za razdvajanje naredbi nego deo nekih naredbi. Zove se terminator.

x = 1;

y = z+5; while(a<3) b--;

naredbe

3

7

Rečnik

• mora da postoji zbog slobodnog formata

• sadrži rezervisane reči (koje programer ne sme da upotrebi po volji)

• primeri: double while do int return

8

Komentarisanje izvornog koda

• duži komentar/*

t

e

k

s

t

*/

/*

Program za racunanje snage

Verzija 2.5

Datum: 12.07.2012.

*/

• kraći komentar// tekst

x++; // uvecaj x za 1

y+=x; // nadodaj x na y

9

Identifikatori

• identifikator je reč koja se jednoznačno pridružuje nekim elementima izvornog koda (promenljiva, tip, imenovana konstanta, potprogram)

• pravila:1. može sadržati samo slova i cifre

2. prvi simbol mora biti slovo

x123 myAge MAXD _m

a+b 236pq 128 +k

da

ne

4

10

• postoji više konvencija vezanih za oblik identifikatora; najvažnije:

identifikator koji ima semantiku mora biti mnemonički

sila napon2 masa power myFile

11

Globalna struktura programa

potprogram (funkcija)

potprogram (funkcija)

potprogram (funkcija)

globalna promenljiva

tip

direktiva

ime_dat.ekst (obično: ime_dat.c)

12

Domet identifikatora

• je oblast izvornog koda u kojoj se on može upotrebiti

• počinje definicijom

• proteže se do kraja izvornog koda ili do krajapotprograma ako je identifikator lokalan za potprogram

• može se proširiti deklarisanjem (dakle, u programskom jeziku C definisanje i deklarisanje nisu sinonimi)

• definicija je jedna, a deklaracija može biti proizvoljan broj, uključujući i nijednu

5

13

double f(double x) {. . . . .. . . g(a,b) . . .

}

void g(int i, double y) {int j;. . . . . .

. . f(t) √. . .

. . . . . .}

const double PI = 3.1415926;

f

PI

j

14

Primer: računanje obima kruga

#include <stdio.h>

const double PI = 3.1415926;

double obimKruga(double r) {

return 2*r*PI;

}

int main() {

double poluprecnik, obim;

printf(“Uneti poluprecnik: “);

scanf(“%lf”,&poluprecnik);

obim = obimKruga(poluprecnik);

printf(“Obim kruga je %f“,obim);

return 0;

}

obim.c

globalna promenljiva

funkcija

lokalne promenljive

zaglavlje biblioteke

algoritam glavnog programa

parametar

argument

ime funkcije

15

• izvorni program smešten je u datoteku obim.c

• posle prevođenja u folderu se pojavljuje izvršni program obim.exe

• dijalog izgleda ovako:

Uneti poluprecnik: 1.5<Enter>

Obim kruga je 9.424778

programkorisnik

6

1616

Rezime

• alfabet programskog jezika C: slova, cifre, specijalni znaci

• format izvornog koda: slobodan

• komentarisanje izvornog koda: dve vrste komentara

• identifikatori: semantika zahteva mnemoniku

• globalna struktura programa: labava

• domet identifikatora: oblast važenja

• primer: obim kruga

3 TIPOVI PODATAKA

222

Sadržaj

• klasifikacija tipova podataka

• standardni tipovi podataka

• iskaz typedef

• promenljive

• elementarni ulaz-izlaz

• znakovni, celobrojni i realni tipovi

• enumeracija

• logički tip

• simboličke konstante

33

klasifikacija tipova podataka

tip podataka

bazni izvedeni

standardni enumeracija

- znakovni

-celobrojni

- realni

- tip void

- niz

- slog (struktura)

- unija

- pokazivač

- datotečni tip

-programerski definisani tipovi

44

• familija znakovnih tipova: char

• familija celobrojnih tipova: int

• familija realnih tipova: double i float

Modifikatori:

− dužine short, long

− predznaka signed, unsigned

55

standardni bazni tipovi

• char

• unsigned char

• signed char

• short [int]

• unsigned short [int]

• [signed] short [int]

• int

• unsigned [int]

• signed [int]

• long [int]

• unsigned log [int]

• [signed] long [int]

• double

• float

• long double

[xxx] znači da xxx nije obavezno navesti

celobrojni realni

66

Iskaz typedef

• konstruisanje programerski definisanih tipova

typedef opis_tipa Ime_tipa;

gde Ime_tipa po konvenciji počinje velikim slovom

typedef double Rastojanje;

77

Promenljive

• definicijom se zadaju tip i ime (identifikator), a kompajler na osnovu tipa rezerviše memorijsku lokaciju

• moraju se definisati tačno jedanput

• domet promenljive počinje definicijom

tip ime1[=pv1], ime2[=pv2], … imen[=pvn];

gde su pv1,…,pvn (neobavezne) početne vrednosti

(inicijalizacija)

88

• promenljiva se može inicijalizovati samo konstantnim izrazom

int i, j=0, k=-1; //i nije inicijalizovana j i k jesu

double x=0.5, y; //x je inicijalizovana, y nije

double z=x; //ne moze! x nije konstanta

99

Modifikatori pristupa

• const: promenljiva je zaključana (ne može menjati vrednost)

const double PI = 3.1415926; //uociti velika slova

• volatile: promenljivoj se može pristupati izvan programa

1010

Elementarni ulaz-izlaz

• jeste ulaz sa tastature odn. izlaz na ekran

• obavlja se posredstvom posebnih funkcija iz zaglavlja stdio.h

• ulaz: funkcija scanf

• izlaz: funkcija printf

1111

Funkcija scanf

scanf("formatni string", &p1,...,&pn)

• formatnim stringom zadaje se način interpretacije znakova koji pristižu sa tastature

• &p1,...,&pn su adrese promenljivih p1, ..., pnčije vrednosti se učitavaju

• konverziona specifikacija:

%[*][širina][h|l|L]tip_konverzije

gde | znači "ili"

1212

Funkcija printf

printf("formatni string", iz1,...,izn)

• formatnim stringom zadaje se način interpretacije i raspored vrednosti koje će biti prikazane na ekranu

• iz1,...,izn su izrazi čije vrednosti se prikazuju na ekranu

• slobodni tekst se prenosi bez izmena

• konverziona specifikacija:

%[flegovi][širina][.preciznost][h|l|L]tip_konverzije

1313

Znakovni tip

• predstavlja pojedinačne simbole iz datog kodnog sistema (ASCII, UNICODE)

• identifikator familije: char uz modifikatore signed i unsigned

• konverziona specifikacija: %c

• u izvornom kodu, konstante se predstavljaju na tri načina i to iz tehničkih razloga

1414

pravi simboli kojih ima na tastaturi

'a' '+' '0' '5' 'X'

osim simbola ? ' " \

1515

upravljački simboli

• prikazuju se pomoću tzv. "eskejp sekvenci"

• počinju znakovima '\ i završavaju se znakom '

'\0' znak sa kodom 0

'\n' novi red

'\b' backspace

'\f' form feed

'\r' carriage return

'\t' tab

1616

• eskejp sekvencom prikazuju se znaci ? \ ' "

'\?' '\\' '\'' '\"'

• kada se nalaze unutar znakova navoda eskejp sekvence pišu se bez apostrofa

"ovo je neka linija\n"

1717

simboli kojih nema na tastaturi

1. preko dekadne vrednosti koda

2. preko eskejp sekvence oblika

'\oktalne cifre'

'\heksadecimalne cifre‘

Inače, na ovaj način mogu se predstaviti sviznaci.

1818

znakovni tip je član familije celobrojnih tipova!

• znakovna promenljiva ima istovremeno i celobrojnu vrednost jednaku njenom kodu

char x,y;

. . . . .

x = 'M';

x = 67;

y = x + 1; //y dobija vrednost 68 odnosno 'N'

isto

1919

char ch='+';

printf("%c",ch); //na ekranu se pojavljuje +

printf("%d",ch); //na ekranu se pojavljuje 43

2020

Celobrojni tip

• podskup skupa celih brojeva

• identifikator familije: int

• prikaz konstanata u izvornom kodu:

– dekadni: 1 1567 -23 +6 0 0234

– oktalni: 0234 077 -0325

– heksadecimalni: 0x32a 0xDB3 -0X2e

• sufiksi: U ili u za unsigned i L ili l za long

256U -0x78abL 126LU

2121

Konverzione specifikacije

• %d dekadna konverzija signed

• %u isto za unsigned

• %o oktalna konverzija

• %x heksadecimalna konverzija

• %i na ulazu: prepoznaje se oblik konstante

na izlazu: isto što i %d

2222

Realni tip

• podskup skupa realnih brojeva

• identifikatori: double float long double

• osnovni realni tip je double

• prikaz konstanata u izvornom kodu:

– decimalni: 6.2 +0.7 -9.9 0.0 .8 23.

– eksponencijalni: 1e6 -0.8E12 2.7e-9

• sufiksi: F ili f za float, L ili l za long double

1235.8F -0.6L 1e8L

2323

Konverzione specifikacije za ulaz

• %lf %le %lg za tip double

• %f %e %g za tip float

• %Lf %Le %Lg za tip long double

sva tri oblika se ponašaju jednako

2424

Konverzione specifikacije za izlaz

• %f izlaz je decimalni

• %e izlaz je eksponencijalni

• %g izlazni oblik bira se prema veličini broja

• za long double %Lf %Le %Lg

double i float

long double

2525

Tip enumeracije

• vrednosti su imenovane konstante koje su definisane u programu

• svrha: povećanje čitljivosti (razumljivosti) izvornog koda, tj. povećanje pouzdanosti

• obično se označavaju velikim slovima:

PONEDELJAK UTORAK SREDA itd.

JANUAR FEBRUAR MART APRIL itd.

• identifikator familije: enum

• definiše se na tri osnovna načina

26

1) direktno

enum {V1,…,Vn} p1,…,pm;

• V1,…,Vn vrednosti enumeracije

• p1,…,pm promenljive tipa enumeracije

enum {NE,DA} log1,log2;

• promenljive se moraju definisati zajedno sa enumeracijom, tj. ne mogu se definisati naknadno

26

27

2) putem taga (priveska)

enum tag {V1,…,Vn};

• gde je tag kratak identifikator, jedinstven za svaku enumeraciju

enum RGB {CRVENA,ZELENA,PLAVA};

• promenljive se ne moraju definisati zajedno sa enumeracijom

enum RGB b1,b2; //bilo gde iza definicije

• puno ime enumeracije je sada enum tag

27

puno ime enumeracije

28

3) primenom typedef

typedef enum {V1,…,Vn} ImeEnumeracije;

• gde je sada ImeEnumeracije identifikator pridružen enumeraciji

enum {CRVENA,ZELENA,PLAVA} OsnBoja;

• promenljive se ne moraju definisati zajedno sa enumeracijom

OsnBoja b1,b2; //bilo gde iza definicije

• ImeEnumeracije se sada koristi kao njen identifikator

28

ime enumeracije

29

Vrednosti enumeracije

• vrednosti enumeracije su istovremeno i celobrojne (kao i kod znakovnog tipa)

• implicitno: prva vrednost je 0, a svaka ostala je za 1 veća od prethodneenum dan {PONEDELJAK,UTORAK,SREDA,CETVRTAK,PETAK,SUBOTA,NEDELJA};

enum dan d1, d2;

d1 = UTORAK; //vrednost d1 je istovremeno jednaka 1

d2 = d1 + 3; //d2 je istovremeno PETAK i 4

29

=0 =1 =2

30

• Vrednosti enumeracije mogu se zadati eksplicitno, putem inicijalizacije

enum xyz {V1=10,V2,V3,V4=20,V5=30,V6};

• primer:typedef enum {PLUS='+',MINUS='-',PUTA='*'} ZnakOper;

. . . . . . .

ZnakOper op=PLUS; //vrednost op je istovremeno PLUS, '+' i 43!

30

=10 =11 =30 =31=12

31

Realizacija logičkog tipa

• Logički tip, kao tip, obuhvata logičke (Bulove) konstante (T i F),kao i odgovarajuće operacije (Λ V ¬)

• Realizacija logičkog tipa u programskom jeziku C je specifična:

logički tip realizuje se preko baznih tipova!

31

32

• kada je logički tip rezultat operacije tada se u ulozi F pojavljuje celobrojna vrednost 0, a u ulozi T (celobrojna) vrednost 1

• kada je operand logičkog tipa tada se u ulozi F pojavljuje 0, a u ulozi T bilo koja vrednost različita od 0

• primer (α i β su izrazi baznog tipa, && u C-u označava konjunkciju)

α && β

32

=0 (F)

=1 (T)=0 (F)≠0 (T)

33

Simboličke konstante

• predstavljaju još jedan način za efektivno imenovanje konstanti

• zaključane promenljive imaju status promenljive, a imenovane konstante su konstante u pravom smislu reči

• realizuju se pogodnom primenom tzv. pretprocesorske direktive #define

• ne stižu do kompajlera

34

• definicija:

#define IME vrednost

• primer:

#define TRUE 1

• pre prelaska na prevođenje, modul sa imenom pretprocesor skenira izvorni kod i gde god pronađe ime simboličke konstante zameni ga vrednošću (osim ako je ime unutar znakova " ".

35

#define TRUE 1

TRUE

TRUE"...TRUE..."

TRUE

1

1"...TRUE..."

1

briše se iz izvornog koda

363636

Rezime

• klasifikacija tipova podataka• iskaz typedef: konstruisanje novih tipova

kombinovanjem postojećih• promenljive: pre prve upotrebe moraju se definisati;

modifikatorom const mogu se zaključati, te se ponašaju kao imenovane konstante (iako ostaju promenljive)

• elementarni ulaz-izlaz: funkcije scanf i printf• standardni bazni tipovi: znakovni, celobrojni i realni tip• enumeracija: povećanje čitljivosti izvornog koda• znakovni tip i enumeracija su istovremeno i celobrojni• logički tip realizuje se na poseban način, preko baznih

tipova• simboličke konstante su imenovane konstante u pravom

smislu reči

4 IZVEDENI TIPOVI

222

Sadržaj

• tip niza

• tip stringa

• tip sloga (strukture)

• tip unije

3

Tip niza

• tip niza predstavlja sredstvo za grupisanje više vrednosti istog tipa, tako da im se pristupa na osnovu pozicije, tzv. indeksiranjem

• same vrednosti mogu biti proizvoljnog tipa (baznog ili izvedenog)

• nizovi baznih tipova zovu se jednodimenzioni nizovi ili vektori, a nizovi takvih nizova nose naziv matrice

• memoriju za niz zauzima kompajler u fazi prevođenja i ona se ne može menjati u toku izvršenja programa

4

Definisanje niza

• Niz se definiše iskazom

tip imeNiza[duzina];

gde je tip tip elemenata niza, a konstantni izraz duzina predstavlja najveći mogućibroj elemenata niza.

• primer: iskazom

int vek[50];

definiše se niz vek čiji su elementi tipa int i ne može ih biti više od 50.

5

Smeštanje niza u memoriju

• Na osnovu dužine i veličine u bajtovima svakog elementa (određuje se iz tipa elementa), kompajler rezerviše memoriju za niz. Niz se smešta u jedinstvenu zonu operativne memorije.

• Dakle, za niz vek biće rezervisan memorijski prostor veličine

50 * l(int)

gde je l(int) veličina podataka tipa int u

bajtovima5

6

• tokom izvršenja programa, memorija ne može da se menja

• dakle, broj aktuelnih elemenata niza vek može biti manji od 50, ali veći ne!

• zaključak: niz treba tretirati kao rezervisani memorijski prostor u kojem su (ređe) svi ili (najčešće) samo neki elementi aktuelni

6

prvi elementposlednji element

........

aktuelni elementi

neaktuelni elementi

7

Nizovi i simboličke konstante

• Za zadavanje dužine niza (naročito ako se koristi više nizova iste dužine) koriste se simboličke konstante:

#define MAX_EL 100

…………………

int niz1[MAX_EL];

• za zadavanje dužine niza ne mogu se koristiti zaključane promenljive, jer one po prirodi nisu konstante nego – promenljive.

7

8

Pristup elementima niza

• nizom se može rukovati isključivo preko pojedinačnih elemenata; dodela niza nizu nije dozvoljena ni u jednom procedurnom programskom jeziku, pa ni u C-u

• elementima niza pristupa se operacijom koja nosi naziv indeksiranje

• operator indeksiranja je binaran, sa nizom kao levim operandom, a indeksom kao desnim. Oznaka operatora je [], a ispisuje se oko desnog operanda

8

9

imeNiza[indeks]

• najmanja vrednost indeksa je 0; najveća vrednost indeksa je duzina-1

0 ≤ indeks ≤ duzina-1

• indeks je unsigned izraz; u praksi se najčešće koriste int izrazi (kompatibilni su sa unsigned)

• kompajler računa adresu elementa po formuli

adr(imeNiza[indeks]) = adr(imeNiza[0]) + indeks*l (tip)

• u toku izvršenja programa "proboj" indeksa (izlazak iz opsega) se ne proverava, što znatno ubrzava indeksiranje, ali ako dođe do proboja posledice su nepredvidive!

9

levi operanddesni operand

10

int vek[50], vek1[50], i, j;

………………

vek[15]

vek1[0]

vek[i]

vek1[2*i-j+1]

vek[50] //greska, ali nece biti prijavljena

vek = vek1; //dodela nije dozvoljena

10

11

Inicijalizacija niza

• niz se može inicijalizovati inicijalizatorom

={vr1,vr2,…,vrn}

gde su vr1,vr2,…,vrn konstantne vrednosti koje se dodeljuju elementima niza pri kompilaciji

• primeri:int iNiz[4] = {3,-1,10,20}; //iNiz[0]=3,iNiz[1]=-1,iNiz[2]=10,iNiz[3]=20

double db[10] = {1.3,-0.5}; //db[0]=1.3, db[1]=-0.5, ostali nedefinisani

int in[] = {10,25,2,8,19} ; //in dobija duzinu 5

11

sic!

12

Multiindeksni tipovi

• niz baznih tipova nosi naziv vektor; nizovi čiji su elementi nizovi, nizovi nizova itd. zovu se multiindeksni ili multidimenzionalni tipovi

• najpoznatiji multiindeksni tip je niz vektora koji nosi naziv matrica (nizovi sa više od 2 dimenzije se retko koriste)

• definicija multiindeksnog tipa:tip ime[duzina1][duzina2]…[duzinak];• indeksiranje:• ime[indeks1][indeks2]…[indeksk]

12

13

Matrica• definicija:

tip imeMatrice[duzina1][duzina2];

• indeksiranje

imeMatrice[indeks1][indeks2]

• pošto je matrica niz nizova, izraz oblika

imeMatrice[indeks]

je dozvoljen i po tipu je niz (predstavlja vrstu matrice)

13

14

smeštanje matrice u memoriju

• kompajler pakuje matricu, tj. seče je po vrstama i smešta sukcesivno u memoriju

• ako je definisana matricadouble m[MAXV][MAXK]; //MAXV I MAXK su simbolicke konstante

adresa elementa sa indeksima i i j računa seformulom

adr(m[i][j]) = adr(m[0][0])+(i*MAXK+j)*l(double)

14

vrsta vrstavrsta .......

nulta vrstaposlednja vrsta

uočiti: prva dimenzija MAXV se ne koristi u formuli

15

inicijalizacija matrice• matrica se inicijalizuje kao i svaki drugi niz,

uzimajući u obzir to da je svaki član takvog niza takođe niz

• primer:

int mtr[2][3]={{2,6,-1},{3,8,2}};

15

283

162

16

Tip stringa

• tip stringa, kao takav, jeste tekstuelni tip, tj. tip čije su konstante tekstovi

• u C-u, tip stringa realizuje se kao specijalni znakovni niz

• dakle, znakovni niz u C-u pojavljuje se u dve uloge:

– u ulozi (običnog) niza čiji su elementi znakovnog tipa i

– u ulozi stringa

17

String-konstante

• Specifičnost znakovnog niza u ulozi stringa. Oblik:

"sadrzaj stringa"

Na primer,

"Jovan Jovic"

• Mogu se upotrebiti za inicijalizaciju

char ime[] = "Jovan Jovic";

18

Memorisanje stringa

• Kada je znakovni niz u ulozi stringa, iza poslednjeg aktuelnog znaka umeće se znak '\0'.

char ime[12]="Ana Peric";

char ime[12]={'A','n','a',' ','P','e','r','i','c'};

'A' 'a' ' ' 'P' 'e' 'r' 'i' 'c' '\0''n'

'A' 'a' ' ' 'P' 'e' 'r' 'i' 'c''n'

char niz kao string

običan char niz

19

• za ulaz-izlaz stringova postoji posebna konverziona specifikacija

%s

• operacije nad stringovima (spajanje ili konkatenacija, kopiranje, brisanje podstringa, dodavanje podstringa, određivanje dužine stringa itd.) izvedene su kao funkcije i nalaze se u biblioteci čije je zaglavlje

<string.h>

20

Tip sloga (strukture)

• tip sloga ili zapisa generalno predstavlja sredstvo za grupisanje više vrednosti različitog tipa, sa svrhom da posluži za opis entiteta; u C-u se za tip sloga (iz nejasnih razloga) koristi termin struktura

• elementi su semantički nesamostalni; da bi se to podvuklo, umesto termina "element" koristi se termin polje

• polja strukture mogu biti proizvoljnog tipa (baznog ili izvedenog)

• memoriju za strukturu zauzima kompajler u fazi prevođenja i ona se ne može menjati u toku izvršenja programa

21

Definisanje strukture

• ključna reč struct zajednička je za sve strukture (kao kod enumeracije reč enum)

• shodno tome, postoje ista tri načina za definisanje sloga:

– direktno

– primenom taga

– primenom typedef

21

22

Opšta šema (sa npr. tagom):

struct tag {

tip1 p1, p2 ,…, pk;

tip2 q1, q2 ,…, qm;

tip3 r1, r2 ,…, rn;

…………..

};

gde su tip1,... tipovi polja, a p1,… q1,… r1,…njihovi nazivi

22

polja tipa tip1

polja tipa tip2

polja tipa tip3

23

• direktno

struct {int i; double a,b; char ch;} s1,s2;

• sa tagom

struct tck {

char oznaka; //polje tipa char

double x,y; //dva polja tipa double

};

……………….

struct tck t1,t2; //definisanje promenljivih

23

24

• sa typedef

typedef

struct {

char ime[15];

char prezime[30];

unsigned godrodj;

} Osoba;

……………………

Osoba pers1,pers2;

24

25

Rukovanje strukturama

• pristup poljima: pomoću operatora koji se zove selektor i predstavlja simbolom . (tačka)

imeSloga.imePolja

• primer:

pers1.godrodj

pers2.ime

pers2.prezime[5]

25

26

• operator dodele = jeste definisan za strukture

struct tck t1,t2;

t2.oznaka='a'; t2.x=4.2; t2.y=-0.5;

t1 = t2; //polja t2 se kopiraju u odgovarajuca polja t1

26

'a'

4.2

-0.5

t1

'a'

4.2

-0.5

t2

27

• struktura se može inicijalizovati, istim konstruktom kao i niz

={vr1,vr2,...,vrn}

gde su vr1,vr2,...,vrn konstantne vrednosti koje se dodeljuju poljima redom kojim su polja definisana

• primer:

struct tck t = {'b',0.8,-2.4};

gde će biti: t.oznaka='b' t.x=0.8 t.y=-2.4.

27

28

Tip unije

• u formalnom smislu (sintaksno) definiše se i koristi isto kao i struktura; razlika je samo u ključnoj reči koja je kod unije union (umesto struct), sve ostalo je isto

• po pitanju ponašanja, potpuno se razlikuje od strukture

29

struct str {

char c;

int i;

double d;

}

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

struct str s;

union un {

char c;

int i;

double d;

}

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

union un u;

c i d

d

i

c

polja delememoriju

30

• polja unije dele memorijski prostor (jednak najdužem polju) što u potpunosti menja ponašanje odgovarajućih promenljivih!

• ređe se koriste, a tipična primena je reinterpretacija memorijskog prostora

//Pretpostavka: unsigned short zauzima 2 bajta, a unsigned char 1 bajt

union reg {

unsigned short rec;

unsigned char bajt[2]; //bajt[0] je nizi bajt rec, a bajt[1] je visi bajt rec

};

31

int main() {

union reg registar;

registar.rec = 0xA15D;

printf("Rec: %X\n",registar.rec);

printf("Bajtovi: %X %X\n",registar.bajt[0],registar.bajt[1]);

return 0;

}

izlaz:

Rec: A15D

Bajtovi: 5D A1

5D A1

registar.rec

registar.bajt[0]registar.bajt[1]

smer rasta adresa

323232

Rezime

• niz objedinjava elemente istog tipa, sa mogućnošću pristupa indeksiranjem

• niz skalara zove se vektor, a niz vektora zove se matrica

• memoriju za niz zauzima kompajler i ona se ne može menjati u toku izvršavanja programa

• string je tekstuelni tip koji se u C-u realizuje preko specijalnog znakovnog niza

• tip sloga (strukture) služi za objedinjavanje elemenata (polja) različitog tipa u svrhu opisa odgovarajućeg entiteta

• unija objedinjuje polja različitog tipa, s tim što polja dele memorijski prostor

5 OPERATORI I IZRAZI

222

Sadržaj

• klasifikacija operatora

• pregled operatora

• konverzija

• niz izraza

• veličina podatka

• redosled primene operatora

• bibliotečke funkcije

3

• C ima preko 40 operatora na 15 nivoa prioriteta

• indeksiranje i selektor kod strukture i unije su operatori; dodela je takođe operator; svaki poziv funkcije sa n argumenata tretira se kao n+1-arni operator (n+1-vi operand je ime funkcije)

• ima ih unarnih, binarnih i jedan ternarni

• operatori na istom nivou prioriteta podrazumevano se izvršavaju s leva u desno, ali neki se izvršavaju s desna u levo (ovo se zove smer grupisanja)

• svi operatori generišu rezultat

4

Klasifikacija operatora

(približno opadajući nivo prioriteta)

• adresni operatori

• aritmetički operatori

• relacioni operatori

• bit-operatori

• logički operatori

• operatori dodele

• operator , (zapeta)

5

Binarni aritmetički operatori+ sabiranje- oduzimanje* množenje/ deljenje% ostatak pri deljenju (za celobrojne operande)Deljenje: ako su oba operanda celobrojna, znak /predstavlja celobrojno deljenje (razlomljeni deo se odseca); u suprotnom radi se o običnom deljenju5.0/2 daje 2.55/2 daje 29999/10000 daje 0

6

Unarni operatori + i -

• unarni operator – predstavlja promenu predznaka

• unarni operator + je potvrda predznaka (nema dejstvo)

Ako je x bilo jednako 10 tada je rezultat –x jednak -10, a +x jednako je 10

7

Bočni efekat

• operator ima bočni efekat ako menja vrednost operanda

• operand koji menja vrednost mora posedovati lokaciju u memoriji; takve vrednosti nose naziv LVALUE (LVREDNOST)

• LVALUE su promenljive, indeksirani izrazi, selektovana polja, dereferencirani pokazivači i kombinacije:

LVALUE: promenljiva [] . *

8

Operatori inkrementa i dekrementa

• unarni aritmetički operatori sa bočnim efektom

• dakle, generišu rezultat i menjaju vrednost operanda

• operand može biti bilo kojeg baznog tipa (uključujući i realni), a može biti i tzv. pokazivač

• označavaju se sa ++ (inkrement) i -- (dekrement)

• pišu se ili ispred operanda (prefiksna forma) ili iza operanda (postfiksna forma)

9

Neka je k neka int promenljiva i neka ima trenutnu vrednost 10.

prefiksni inkrement je ++k

postfiksni inkrement je k++

U oba slučaja bočni efekat je povećanje vrednosti k za 1; rezultat je k+1 kod prefiksnog ili k kod postfiksnog

(k=10)

++k rezultat je 11; k postaje 11

k++ rezultat je 10; k postaje 11

10

• pažnja:

x = x + 1; //izrazito los stil programiranja u C-u

x++; odnosno ++x; //u C-u se pise ovako!

11

• dekrement -- ponaša se analogno, samo što se ovde dešava umanjenje za 1

(k=10)

--k rezultat je 9; k postaje 9

k-- rezultat je 10; k postaje 9

12

Primeri

x = 1; y = 5;

x--+y++

p = 10; q = 20;

++q-p--

r = 2; s = 4;

r+++++s

//rezultat: 6, x=0, y=6

//rezultat: 11, p=9, q=21

//rezultat: 7, r=3, s=5

13

Relacioni operatori

• standardnih 6:

== (jednako) != (nejednako)

< (manje) <= (manje ili jednako)

> (veće) >= (veće ili jednako)

rezultat je 0 ili 1!

14

Primeri

a = 1; b = 5;

4*(a < b)

p = 10; q = 20;

p == q

x = 0.3; y = 0.5; z = 0.7;

x < y < z

//rezultat: 4

//rezultat: 0

//oprez!

15

• ako je x=0.3, y=0.5, z=0.7 rezultat izraza

x < y < z

neće biti 1 nego 0!

• zato je sigurnije pisati onako kako se piše i u drugim programskim jezicima

(x < y) && (y < z)

gde je && operator konjunkcije

=1 =0.7

16

Logički operatori

&& konjunkcija|| disjunkcija! negacija• rezultat je 0 (u ulozi F) ili 1 (u ulozi T)• operandi su izrazi baznog tipa; vrednost operanada:

=0 (u ulozi F) ≠0 (u ulozi T)a = 5; b = 0; c = -3.8a && b //rezultat je 0b || c //rezultat je 1!c //rezultat je 0

17

optimizacija

• računanje konjunkcije i disjunkcije je uvekoptimizovano; ako je kod konjunkcije jedan operand =0 drugi se možda neće izračunavati jer je rezultat sigurno 0; kod disjunkcije isto, samo za vrednost 1; da li će optimizacija biti primenjena ili neće zavisi od konkretnog slučaja i programer to ne zna!

18

oprez!

• ako neki operand ima bočnih efekata treba biti oprezan

(a-b) && (c+d++)

ako je a-b=0 i ako se a-b računa prvo, bočni efekat neće biti izveden i d neće promeniti vrednost; ako se prvo računa c+d++ bočni efekat biće izveden! Rešenje je:

x = d++;

(a-b) && (c+x)

bočni efekat

19

Bit - operatori

• operatori koji se izvode nad pojedinačnim bitovima celobrojnih operanada

• služe za rad sa memorijskim registrima na nivou bita

& bit-konjunkcija

| bit-disjunkcija

^ bit-ekskluzivna disjunkcija

~ bit-negacija (komplementiranje)

<< šift ulevo

>> šift udesno

20

• bit-konjunkcija, disjunkcija i ekskluzivna disjunkcija izvode se, međusobno nezavisnonad odgovarajućim parovima bitova operanada

• komplementiranje: unarni operator; svaka 0 pretvara se u 1 i svaka 1 u 0

• u opštem slučaju

x&y ≠ x&&y x|y ≠ x||y !x ≠ ~x

x 0110 1100y 1101 0110x&y 0100 0100

21

Šiftovanje (pomeranje)

• bitovi levog operanda pomeraju se ulevo ili udesno za broj pozicija naznačen desnim operandom

• kod šifta ulevo << upražnjene pozicije popunjavaju se nulama

• kod šifta udesno upražnjene pozicije popunjavaju se nulama ako je levi operand unsigned, odn. bitom predznaka ako je levi operand signed

22

• neka je unsigned x = 0011 1101; tada

x << 2 daje rezultat 1111 0100

x >> 2 daje rezultat 0000 1111

• uočiti da šift ulevo za n pozicija ima isti efekat kao množenje sa 2n, a šift udesno za n pozicija isti efekat kao celobrojno deljenje sa 2n

23

Uslovni operator

• ternarni operator (ima 3 operanda)

• opšti oblik

izraz1 ? izraz2 : izraz3

• rezultat je jednak izraz2 ako je izraz1≠0 odnosno izraz3 ako je izraz1=0

• primer:

(a>b) ? a : b

daće za rezultat veću od vrednosti a odnosno b

24

Operatori dodele

• dodela je u C-u operator

• postoji ukupno 11 operatora dodele: tzv. osnovni operator dodele i još 10 posebnih

• svi imaju smer grupisanja s desna u levo

• svi imaju bočni efekat

25

Osnovni operator dodele

• opšti oblik

LVALUE = izraz

• bočni efekat je dodela vrednosti izrazaobjektu LVALUE

• rezultat je vrednost LVALUE (tj. levog operanda) posle dodele

26

Primeri

x = 5 //x dobija vrednost 5; rezultat je 5

y = 2*z // y dobija vrednost 2*z i to je rezultat

a = b = c = d = 1 //a,b,c,d su 1; rezultat je 1

a = b++*(1-x)+(d=c<<3)

++s||(t=3*p)

tzv. višestruka dodela

27

Ostali operatori dodele

• svi imaju istu strukturu i ponašanje

LVALUE op= izraz

• sa značenjem

LVALUE = LVALUE op izraz

gde oznaka op predstavlja jedan od operatora

+ - * / % & | ^ << >>

Dakle, operatori su

+= -= *= /= %= &= |= ^= <<= >>=

28

x += y x = x+y

p[i] *= (k=j+1) p[i] = p[i]*(k=j+1)

t -= q += 3 t = t-(q=q+3)

• smatra se vrlo lošim stilom programiranja pisati npr. a=a+b umesto a+=b, iako je efekat isti; dakle,

p -= 3 p = p-3

29

Konverzija

• C dozvoljava gotovo potpuno mešanje tipova u binarnim izrazima, tj. u izrazu α op β podizrazi α i βmogu biti ma kojeg baznog tipa

• direktno izvršavanje operacija nad različitim tipovima nije moguće zbog ograničenja računara

• u toku izvođenja operacije op tipovi operanada moraju se izjednačiti (bez uticaja na same operande!)

• takvo izjednačavanje nosi naziv konverzija

30

Vrste konverzije

• konverzija može biti:

– implicitna (na bazi ugrađenih pravila obezbeđuje je kompajler) ili

– eksplicitna (na zahtev programera, posredstvom posebnih operatora); eksplicitna konverzija zove se još i kast (od type cast)

31

Implicitna konverzija• dva pravila: jedno za sve operatore osim dodele i drugo za

operatore dodele

• svi operatori osim dodele: koristi se tzv. tablica složenosti, pri čemu se manje složen tip konvertuje u složeniji;

1. long double

2. double

3. float

4. (promocija) char, short i enum u int (jedan ili oba operanda)

5. long

6. int

• unsigned varijanta je složenija od signed

32

int i,j; double d; char c1,c2; long double ld;

d+j //j u double; rezultat double

ld-i //i u long double; rezultat long double

c1+c2 //c1 i c2 u int; rezultat int

(d+c1)*(i/j)+ld //krajnji rezultat long double

double int

double

long double

long double

33

konverzija kod dodele

• za njih važi posebno pravilo: tip desnog operanda prilagođava se tipu levog operanda (zbog bočnog efekta operatora dodele)

int j; double d;

j = 3.8 //j = rezultat = 3; decimale se seku

d = 23 //d = rezultat = 23.0

j = 1e12 // j i rezultat su slucajni! 1e12 preveliko

34

eksplicitna konverzija (kast)

• primenom posebnih unarnih operatora vrednost izraza se konvertuje u ciljni tip, bez obzira na to kakav je tip vrednosti

• oblik svih operatora kasta je

(tip)

gde je tip ciljni tip u koji se konvertuje

• operatori se primenjuju na izraze; vrednosti samih izraza ostaju nepromenjene!

• primeri: (int) (long double) (long) (float)

35

double x=3.5; int k=10;

(long)k //rezultat je 10L

(long double)(x+k) //rezultat je 13.5L

(unsigned)k //rezultat je 10U

36

Niz izraza

• niz izraza je sredstvo za objedinjavanje više izraza u jedan; to se postiže primenom operatora ,

• opšti oblik:

izraz1,izraz2,...,izrazn

• izrazi se računaju s leva u desno, a vrednost celog niza jednaka je rezultatu krajnjeg desnog izraza (izrazn)

x=10 , y+=x , z*=y , y-- , t=++z

vrednost celog niza izraza

37

Veličina podatka

• u određenim slučajevima neophodno je odrediti koliko bajtova zauzima neki podatak

• standardi ne garantuju skoro ništa (npr. int može da zauzima 2 bajta ili 4 bajta)

• veličina se dobija operatorom sizeof, koji može da se primeni na tip ili na vrednost

• sizeof(tip) daje veličinu podataka datog tipa; primenjuje se na bazne tipove i sve tipove definisane sa typedef

• (sizeof)izraz daje veličinu u bajtovima vrednosti izraza

38

typedef struct {double a; int b;} MyRecord;

int a; MyRecord rec;

sizeof(double) //velicina double podataka

sizeof(MyRecord) //velicina MyRecord

sizeof a //velicina promenljive a (tj. velicina int)

sizeof rec //velicina promenljive rec

sizeof (a+1.5) //velicina izraza a+1.5 (tj. velicina double)

39

Redosled primene operatora• redosled primene susednih operatora regulisan je prioritetom i upotrebom zagrada

• redosled primene nesusednih operatora nije regulisan nikakvim pravilima

• primer:

a*b + c/d

sigurno je da će množenje i deljenje biti izvedeno pre sabiranja; ne zna se da li će prvo biti izvedeno množenje, a zatim deljenje ili obrnuto

nesusedni operatori

40

• ovo važi u svim programskim jezicima, ali može da stvori problem samo tamo gde ima bočnih efekata

a*b + b++

ne zna se kojom vrednošću b će biti pomnoženo a: originalnom ili uvećanom za 1

• situacija se prepoznaje po tome što se nesusedni operatori primenjuju na istu promenljivu, a bar jedan ima bočni efekat

41

• rešenje je uvesti pomoćne izraze

x = b; ili x = b+1; //zavisi od toga sta programer hoće

a*x + b++

42

Bibliotečke funkcije

• gotovi potprogrami (tipa sin, printf itd.) raspoređeni su u biblioteke, prema srodnosti poslova koje obavljaju

• imena svih standardnih funkcija pišu se isključivo malim slovima

• pre prve upotrebe bilo koje standardne funkcije mora se, direktivom #include naznačiti zaglavlje biblioteke u kojoj se funkcija nalazi:

#include <zaglavlje.h>

• pored funkcija, u bibliotekama se nalaze i drugi elementi C-a: simboličke konstante, gotovi tipovi itd.

43

zaglavlja standardnih biblioteka

• stdio.h - funkcije za ulaz-izlaz

• math.h - matematičke funkcije

• string.h - rad sa stringovima

• stdlib.h - razne funkcije, uključujući i one za rad sa pokazivačima

• u praksi se pojavljuju još neke biblioteke, pa uvek treba proveriti skup i sadržaj biblioteka koje nudi konkretan C-ov sistem

444444

Rezime

• klasifikacija operatora: adresni, aritmetički, relacioni, logički, bit-operatori, dodele, uslovni, operator ,

• pregled operatora

• konverzija se vrši prilikom izračunavanja mešovitih izraza

• niz izraza služi za grupisanje izraza u jedan

• veličina podatka nije garantovana

• redosled primene operatora za nesusedne operatore nije unapred određen

• bibliotečke funkcije su gotovi potprogrami i deo su C-a

1

6 NAREDBE

222

Sadržaj

• klasifikacija naredbi

• prosta naredba

• sekvenca

• selekcije

• ciklusi

• programski skokovi

• naredbe (u užem smislu reči) jesu osnovni elementi za opis algoritma

• dele se na prostu naredbu i upravljačke strukture

3

naredbe

prosta naredba

upravljačke strukture

sekvencaselekcijeciklusiskokovi

2

Prosta naredba• izvodi se iz izraza dodavanjem terminatora ;

izraz;• rezultat koji generiše izraz se ignorišex = 5 //izrazx = 5; //naredbak++; //povecanje k za 1; isto sto i ++k;sin(2*y-1); // dozvoljeno, ali besmisleno; //prazna naredba• prosta naredba ima smisla samo ako izraz ima bočni

efekat; prazna naredba ima smisla samo kao deo neke naredbe

4

veoma različite stvari!

Sekvenca

• služi za grupisanje više naredbi u jednu (kao što niz izraza grupiše više izraza u jedan)

• opšti oblik

{naredba1 naredba2 . . . naredban}

• naredbe se razdvajaju tzv. belim znacima(blanko, novi red, razmaknica)

x = 1; y*=z+3; t++; //ovo su tri naredbe

{x = 1; y*=z+3; t++;} //ovo je jedna naredba!

5

programske zagrade

Selekcije

• svrha: omogućavanje različitih varijanata izvršenja algoritma

• tri vrste selekcije:

– selekcija if

– selekcija if-else

– višestruka selekcija switch

6

3

selekcija if

• izvršavanje naredbe pod nekim uslovom (tzv. zaštićena naredba)

if(izraz) naredba

7

sintaksa

izraz

naredba

≠0

=0

semantika

if(a>b) x++;

if((p==q)&&(s<0)) {p+=q; s++;t=sin(p);}

if(x+=--y*(z+1)) {t--;a/=2;

}

pragmatika

selekcija if-else

• izbor između dve alternative

if(izraz) naredba1 else naredba2

8

izraz

naredba2

≠0 =0

if(a>b) x++;else p=0;

if(t++) {if(a!=0) d+=4;}else z--;

if(t++) if(a!=0) d+=4;else z--;

naredba1

nije isto!

selekcija switch

• izbor između više varijanata za nastavak algoritma, na osnovu vrednosti celobrojnog izraza

• podseća na naredbu case paskala, ali nije ista!

9

4

switch(celobrojni_izraz) {

case c1:

niz_naredbi1case c2:

niz_naredbi2.............

default:

niz_naredbi0.............

case ck:

niz_naredbik}

10

celobrojniizraz

niz_naredbi1

niz_naredbi2

niz_naredbik

niz_naredbi0

c1ck

c2

default

!

deo defaultnije obavezan

uloga break

switch(i+j) {

case 2:

x = 1; y++;

case 0: case -4:

z*=t; t--;

case 6:

p = q = r = s = 0;

case 1:

x++;

}

switch(i+j) {

case 2:

x = 1; y++; break;

case 0: case -4:

z*=t; t--; break;

case 6:

p = q = r = s = 0; break;

case 1:

x++;

}uočiti višestruke case labele

i+j=-4 i+j=-4

11

Ciklusi

• osnovna svrha ciklusa jeste da omoguće da se fizički relativno malim obimom izvornog koda računaru zada velik posao

• ovo se postiže ponavljanjem neke naredbe u promenljivim uslovima

naredba

12

5

Ciklus while

while(s<a) {

t++;

s *= z++;

}

while(++x-y) z/=x;

izraz naredba

≠0

=0

while(izraz) naredba

13

• načelno, ciklus while može se koristiti u svim situacijama

• tipična primena su situacije u kojima se u trenutku otpočinjanja ciklusa ne zna koliko će se puta ponoviti naredba (nema tzv. odbrojavanja)

14

Ciklus for

//racunanje zbira nizova a i b

for(j=0;j<m;j++) c[j] = a[j]+b[j];

//racunanje n!

if(n==0) f = 1;

else for(f=1,i=1;i<=n;i++) f*=i;

izraz2

naredba

≠0

=0

for(izraz1;izraz2;izraz3) naredba

izraz3

izraz1

inicijalizacija

provera kraja modifikacija

telo ciklusa

15

6

• nijedan od 3 izraza nije obavezan; može se pisati

for(k=m;k>0;) t+=k--;

pa čak i

for( ; ;) ; //besmisleno, ali dozvoljeno

• ciklus for je najširi mogući ciklus i primenljiv je u svim situacijama

• tipična primena je kod tzv. brojačkih ciklusa (upravljačka promenljiva menja vrednost od početne do krajnje, a provera obuhvata poređenje sa krajnjom vrednošću)

16

primer brojačkog ciklusa

• računanje

for(s=0,i=0;i<n;i++) s+=a[i]*b[i];

for(s=0,i=0;i<n;s+=a[i]*b[i],i++);

for(s=0,i=0;i<n;s+=a[i]*b[i++]);

/* ne! indeksiranje a[i] i inkrement u b[i++] su nesusedni; ishod je neizvesan */

1

0

][*][n

i

ibiasupravljačka promenljiva

17

Ciklus do-while

t = 0;

do {

printf("Uneti broj > 0");

scanf("%d",&n);

if(n>0) t+=n;

} while(n>0);

/*ciklus se zavrsava kada se ukuca broj <= 0 /*

izraz

naredba

≠0

=0

do naredba while(izraz);

znak ; je obavezan

18

7

• ciklus do-while koristi se u situacijama u kojima je za proveru kraja neophodno da se prethodno izvrši naredba

• tipičan slučaj su meniji

19

Naredbe skoka

• postoje tri naredbe skoka: goto, break i continue

• naredba goto se ne koristi, izuzev u jednoj jedinoj situaciji

• naredbe break i continue koriste se retko (osim naredbe break kao dela naredbe switch)

20

Naredba goto

goto LABELA;

gde je LABELA oznaka neke naredbe.

• Naredba se labelira dodavanjem konstrukta LABELA: ispred nje

LABELA: naredba

Inače, LABELA je identifikator ili niz cifara.

• po izvršenoj naredbi goto, sledeća nije prva naredba posle goto nego ona sa LABELA-om

21

8

• naredba na koju se preskače može biti fizički ispred ili iza naredbe goto

• naredbu goto treba striktno izbegavati jer bitno smanjuje razumljivost izvornog koda i predstavlja izvor grešaka!

22

if((z=a+b)<c) goto 10;t+=z;goto 15;10: t+=a;15: (naredba)

if((z=a+b)<c) t+=a;else t+=z;

ne ovako nego ovako

23

• jedina (i vrlo retka) situacija u kojoj se preporučuje primena goto je iskok iz ugneždenih ciklusa (ciklus u ciklusu u ciklusu...)

Naredba break

break;

• koristi se u dva slučaja:

– u okviru naredbe switch (već je opisano)

– za iskakanje iz pojedinačnog cuklusa

24

while(1) {if(i<0) break;t+= x[i--];z*= t;

}

9

Naredba continue

continue;

• koristi se unutar ciklusa za momentalni prelaz na sledeće ponavljanje (iteraciju, prolaz)

25

for(j=0;j<n;j++) {if(a[j]<=0) continue;sp+=a[j];

}

262626

Rezime

• klasifikacija naredbi: prosta naredba i upravljačke strukture

• prosta naredba: izraz zatvoren terminatorom ;

• sekvenca: objedinjavanje više naredbi u jednu

• selekcije: izbor načina nastavka algoritma

• ciklusi: malim obimom izvornog koda zadati velik posao

• programski skokovi: promeniti redosled izvršavanja naredbi

1

7 POKAZIVAČI

2222

Sadržaj

• tip pokazivača

• korišćenje pokazivača

• adresna aritmetika

• dinamička alokacija memorije

• korišćenje nizova u dinamičkoj zoni

• pokazivači na strukture

3

• Pokazivači služe za pristup podacima putem adrese(uočiti da je adresa element programa koji je dostupan i u fazi prevođenja i u fazi izvršenja!)

• Vrednosti samog pokazivača su adrese, tj. skalari

• Memorijska lokacija čiju adresu sadrži pokazivač nosi naziv pokazivana lokacija

• Da bi se moglo pristupiti podatku na pokazivanoj lokaciji mora se znati tip tog podatka, te se tip pokazivača izvodi iz tipa pokazivane lokacije

2

4

Definisanje pokazivača

• pokazivač se definiše iskazom

tip *imePokazivaca;

gde tip označava tip pokazivane lokacije.

int *pI, *pJ, x, a[100]; //tip pI i pJ je int *!

pI i pJ su pokazivači na int lokaciju; x je obična int promenljiva, a je int niz.

5

Elementarno korišćenje pokazivača

• osnovna operacija nad pokazivačima je pristup pokazivanoj lokaciji; nosi naziv dereferenciranje i realizuje se unarnim operatorom *

*imePokazivaca

• na primer,

*pK //pristup lokaciji ciju adresu sadrzi pK

• konverziona specifikacija za prikaz pokazivača pomoću printf je %p. Vrednost se prikazuje heksadecimalno.

operator dereferenciranja

6

Adresni operator

• u određenoj vezi sa pokazivačima je i tzv. adresni operator: unarni operator & koji primenjen na promenljivu daje njenu adresu

x //obezbedjuje vrednost promenljive x

&x //obezbedjuje adresu promenljive x

3

7

ilustracija ponašanja pokazivačaint *pI, *pJ, x;

x = 10;

pI = &x;

//koliko je pI?

//koliko je *pI?

pJ = pI;

//koliko je *pJ?

*pI = -5;

//koliko je x?

pI pJ

10x

A

A A

8

Generički pokazivači

• Generički pokazivači su pokazivači kod kojih nije definisan tip pokazivane lokacije; realizuju se kao tip void*

void *pG;

• generički pokazivači se ne mogudereferencirati (jer se ne zna tip pokazivane lokacije)

*pG

9

Osnovni operator dodele

• Osnovni operator dodele pokazivača pokazivaču

p2 = p1

može da se izvrši

– ako su p1 i p2 istog tipa

– ako je bar jedan od njih void pokazivač

4

10

int *pJ, *pK; double *pD; void *pG;

pJ = pK; //moze

pG = pJ; //moze

pG = pD; //moze

pD = pG; //moze

pG = pK; //moze

pJ = pD; //ne moze!

pD = pK; //ne moze!

11

• razlog zašto pokazivači koji nisu istog tipa ne mogu da se dodele je dereferenciranje

• posle dodele pD=pK, rezultat *pD je slučajan!

• dodela generičkom pokazivaču dozvoljena je,jer se on ne može dereferencirati

-25

pK pD

?

*pK

*pD

pD = pK

12

Sabiranje i oduzimanje• operacije: + ++ += - -- -=

• jedan operand je pokazivač, a drugi celobrojni podatak; jedinica mere za celobrojni podatak je veličina pokazivane lokacije (1 bajt za void pokazivač)

int *pK, i; double *pD; void *pV;

pK + i izvodi se kao pK+i*sizeof(int)

pD - i izvodi se kao pD-i*sizeof(double)

pV + i izvodi se kao pV+i

pK++ na pK se dodaje sizeof(int)

5

13

Pokazivači i nizovi

• jedinstvena osobina C-a: ime niza je pokazivač na njegov nulti element

int a[100], j;

a[0] a[1] . . . . . a[j] . . . . . a[99]a

*a*(a+1) *(a+j)

*(a+j) a[j]a+j &a[j]

14

još neke operacije

• nad pokazivačima definisani su još i

– relacioni operatori == != > >= < <=

– oduzimanje pokazivača od pokazivača (koje ima smisla samo ako pokazivači pokazuju na elemente istog niza)

15

NULL vrednost pokazivača

• konkretne vrednosti pokazivača su adrese i nisu od interesa (čak se mogu menjati od slučaja do slučaja)

• uopšte, pokazivačima se ne mogu dodeljivati konstantne vrednosti

• izuzetak je simbolička konstanta NULL(definisana u zaglavljima stdio.h i stdlib.h)

• kada ne postoji pokazivana lokacija pokazivač treba da ima vrednost NULL (u suprotnom se dereferencira slučajna lokacija)

6

16

Dinamička dodela memorije• izuzetno moćan mehanizam koji omogućuje da se

tokom izvršenja, programu dodeli dodatna memorija, odnosno da se ona oslobodi

• dodela memorije zove se alokacija, a oslobađanje dealokacija

• zona operativne memorije u kojoj se vrši alokacija-dealokacija zove se hip (heap)

• rukovalac hipom (heap manager) je C-ov podsistem za upravljanje hipom

• iz programa, hipom se rukuje preko odgovarajućih funkcija

17

• u toku izvršenja programa, identifikatori više ne postoje (koristio ih je kompajler); shodno tome, jedini način da se rukuje memorijom na hipu jesu adrese,

• što znači da je osnovni mehanizam za rukovanje hipom u toku izvršenja programa pokazivač

• osnovne funkcije za korišćenje hipa su malloc(za alokaciju) i free (za dealokaciju)

18

A

p

*p

A

malloc(otvara blok, uspostavlja

vezu)

hip

statička memorija

alokacijapokazivač

7

19

p

NULL

free(oslobadja blok,

raskida vezu, upisuje NULL u

p)

A

*p

A

hip

statička memorija

dealokacija

20

funkcije za rad sa hipom

• osnovne funkcije za korišćenje hipa su:

malloc(no_bytes)

Zauzima blok od no_bytes bajtova na hipu i vraca pokazivac na taj blok; ako ne uspe vraća NULL.

free(pokazivac)

Oslobadja blok na koji pokazuje pokazivač i upisuje u pokazivač vrednost NULL

21

dodatne funkcije

calloc(n,no_bytes)

Zauzima blok od n*no_bytes bajtova na hipu i vraca pokazivac na taj blok; ako ne uspe vraća NULL; blok se popunjava nulama. Smatra se zastarelom (engl. deprecate)

realloc(pokazivac,new_bytes)

Efektivno proširuje ili skraćuje blok na koji pokazuje pokazivac na veličinu new_bytes.

8

22

primer

long double *pLD;

//zauzimanje memorije za long double podatak

pLD = malloc(sizeof(long double));

........ podatku se pristupa preko *pLD .........

//oslobadjanje memorije

free(pLD);

23

Curenje memorije

• curenje memorije (memory leak) je situacija u kojoj je nedostupni blok na hipu označen kao zauzet

• tipičan slučaj: pokazivač koji pokazuje na blok A na hipu preusmeri se na blok B, a da blok A nije prethodno oslobođen; time se efektivno smanjuje hip

• curenje memorije se ne sme tolerisati ni pod kakvim uslovima!

24

p

A

B

blok A je nedostupan!

p = malloc(sizeof(NekiTip)); //preusmeravanje na blok B

9

25

• postulat za korišćenje hipa jeste

sve što se alocira pomoću malloc, calloc ili realloc mora

se eksplicitno osloboditi pomoću free

26

Nizovi na hipu

• korišćenjem pokazivača nizovi se realizuju na hipu, što je znatno bolji način jer više ne predstavljaju rezervisani memorijski prostor

• zauzimaju tačno onoliko memorije koliko imaju aktuelnih elemenata

• broj elemenata (dužina) ne zadaje se u toku prevođenja, pa se u tu svrhu mogu koristiti i promenljive

27

int *a, i, n; //pokazivac a ponasace se kao niz!

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

//na hipu se zauzima prostor potreban za int niz

//sa n elemenata

a = malloc(n*sizeof(int));

.... i-tom elementu "niza" a pristupa se sa a[i] ....

............ zato sto je a[i] isto sto i *(a+i) .........

free(a): //obavezna dealokacija

10

28

• napomena: isto se radi i sa matricom, uz korišćenje dvostrukog pokazivača **

double **mtr; int m, n, i, j;

//alokacija

mtr = malloc(m*sizeof(double*));

for(i=0;i<m;i++) mtr[i] = malloc(n*sizeof(double));

..... elementima "matrice" pristupa se sa mtr[i][j] ......

//dealokacija

for(i=0;i<m;i++) free(mtr[i]); //oslobadjanje vrsta

free(mtr);

29

Pokazivači na strukture

• vrlo čest slučaj: strukture na hipu

• neka je pS pokazivač na strukturu i neka struktura ima polje x. Pristup polju x preko pokazivača pS izvodi se operacijom

(*pS).x

• pošto je ovo vrlo često, uveden je poseban operator ->

(*pS).x pS->x

nikad se ne koristi

30303030

Rezime

• tip pokazivača je tip* gde je tip tip pokazivane lokacije

• korišćenje pokazivača: najvažniji operator je dereferenciranje *

• dodela, sabiranje, oduzimanje i relacioni operatori mogući su pod određenim uslovima

• dinamička alokacija memorije: zauzimanje i oslobađanje memorije u toku izvršenja programa

• korišćenje nizova na hipu je, u stvari, normalan način za njihovu upotrebu

1

8 FUNKCIJE

222222

Sadržaj

• definisanje i korišćenje funkcije

• prenos argumenata u potprogram

• prototip

• lokalne i globalne promenljive

• pretprocesor

• izrada biblioteka

• rekurzivne funkcije

• pokazivači na funkcije

• argumenti programa

333

Definisanje i korišćenje funkcija

• potprogram je predstavlja sintaksnu i semantičku celinu

• generalno, potprogrami mogu i ne moraju da formiraju neki rezultat u vidu izlazne vrednosti(kaže se "imaju vrednost")

• u C-u, potprogrami nose naziv funkcije

• poziv (aktiviranje) funkcije u C-u tretira se kao primena operatora reda n+1, gde je n broj argumenata (n+1-vi operand je ime funkcije)

2

444

Definisanje funkcije

zaglavlje

bloklokalne promenljive

+naredbe

{

}

zaglavlje:

tip imeFunkcije(T1 p1, ... ,Tn pn)

tip - tip vrednosti funkcije; bilo šta osim niza; ako se ne navede,podrazumeva se int; ako funkcija nema vrednost piše se void

pi - identifikator i-tog parametra

Ti - tip (formalnog) parametra pi

555

double zbir(double x,double y) {double s;s = x+y;return s;

}

tip vrednosti f-je ime funkcije parametar (formalni parametar)

lokalna promenljiva

vraćanje vrednosti funkcije

double zbir(double x,double y) {double s=x+y; //parametri mogu ucestvovati u inicijalizacijireturn s;

}

double zbir(double x,double y) {return x+y;

} može i ovako

666

Pozivanje (aktiviranje) funkcije

• funkcije koje imaju vrednost pozivaju se uključivanjem u izraze (kao i matematičke funkcije)

t = 2 * zbir(5,6)-3; //2*(11)-3=18

• argumenti (stvarni parametri) su u opštem slučaju izrazi

z = 5.8*zbir(3*a,b*c)+zbir(1,f/g)-1;

5 i 6 su argumenti (stvarni parametri)

3

777

Vraćanje rezultata

• vrednost funkcije formira se ("vraća se") naredbom

return izraz;

• efekat naredbe return jeste formiranje vrednosti i završetak funkcije

• funkcije koje imaju vrednost mogu imati proizvoljan broj naredbi return, a najmanje jednu!

888

• funkcija koja ima vrednost, a kada to ima smisla, može biti pozvana i prostom naredbom, umesto uključivanja u izraz

• takva funkcija je scanf koja, inače, ima vrednost jednaku broju uspešno učitanih promenljivih; kada je pozovemo prostom naredbom

scanf("%d%d",&a,&b);

vrednost funkcije (jednaka 2 ako su oba učitavanja uspešna) se ne koristi

999

Prenos argumenata u potprogram

• važi za sve programske jezike, procedurne i objektne

• prenos argumenata u potprogram i vraćanje vrednosti iz njega, obavlja se posredstvom posebne memorijske zone koju poseduje svaki program i koja se zove stek (stack)

• postoje dve vrste prenosa– prenos po vrednosti

– prenos po adresi

4

101010

prenos po vrednosti

3.53.5

frezultat

stekfunkcija radi sa kopijom

arg

&arg

grezultat

arg

prenos po adresifunkcija radi sa originalom

stek

111111

prenos po vrednosti

• u C-u, svi argumenti osim nizova prenose se po vrednosti

double f(double x) {

return 2*++x; //kopija x se povecava za 1

//original se ne menja!

}

a = 5.6;

b = 2*f(a); //a zadrzava vrednosti 5.6!

121212

prenos po adresi

• prenos po adresi vrši se tako što je parametar pokazivač

int g(int *a) {

(*a)++; //original se povecava za 1

return 10*a;

}

p = 1;

b = 2*g(&p); // b=20; p=2;

očekuje se adresa argumenta

šalje se adresa argumenta

5

1313

• na steku se čuvaju:

– vrednosti svih parametara

– vrednosti svih lokalnih promenljivih (promenljivih koje su definisane unutar funkcije)

– vrednost funkcije (ako funkcija ima vrednost)

– podaci potrebni za nastavak programa po završetku funkcije (tzv. povratna adresa)

• po završetku funkcije, deo steka sa njenim podacima se eliminiše

13

141414

Formiranje rezultata preko liste parametara

• ako neka funkcija treba da vrati više vrednostiili ako je rezultat jedan ili više nizova, tada se rezultati prosleđuju preko liste parametara uz korišćenje prenosa po adresi, što se tretira kao bočni efekat

• primer za to je funkcija scanf za koju su promenljive koje se učitavaju - izlaz:

k = scanf("%lf%lf",&a,&b);prenos po adresi

151515

void funkcije

• void funkcije su potprogrami koji nemaju vrednost; ako imaju rezultat, on se prosleđuje preko liste parametara, prenosom po adresi

• pozivaju se prostim naredbama

• završavaju se ili izvršavanjem fizički poslednje linije koda ili naredbom

return;

• naredbi return može biti više (ali i nijedna)

6

161616

• primer: računanje polarnih koordinata

void polarne(double x,double y,double *r,double *fi) {

*r = sqrt(x*x+y*y);

*fi = (x==0)&&(y==0) ? 0 : atan2(y,x);

}

• poziv:

double x,y,rad,arg;

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

polarne(x,y,&rad,&arg);

arctg(y/x)

argumenti i parametri se mogu i ne moraju poklapati po imenu

prenos po adresi

pokazivači r i fi se moraju dereferencirati

171717

Nizovi kao parametri• nizovi se, kao argumenti, prenose isključivo po

adresi

• ovo je logično, jer je ime svakog niza pokazivač, tj. po prirodi je adresa

• ako je parametar neke funkcije niz a, tada se na mestu parametra navodi

tip a[]

• ako je niz čisto ulazni (tj. ne menja vrednost u funkciji), tada se ispred tipa piše modifikator const.

181818

• primer: računanje zbira n elemenata niza

double suma(const double a[],int n) {

double s; int j;

for(s=0,j=0;j<n;j++) s+=a[j];

return s;

}

• primena:

double p[100], x,t; int n;

t = 1+x*suma(p,n)-1;uočiti: ime niza p je double pokazivač

7

191919

• s obzirom na to da je ime niza pokazivač i da se na njega može primeniti indeksiranje, prethodni primer možemo rešiti i ovako:

double suma(const double *a, int n) {

double s; int j;

for(s=0,j=0;j<n;j++) s+=a[j];

return s;

} može i s+=*(a+j)

202020

Niz kao rezultat funkcije

• ako je rezultat funkcije niz, on se prosleđuje preko liste parametara, prenosom po adresi

• primer: računanje zbira c nizova a i b

void zbirniz(const double a[],const double b[],double c[],int m)

{

int i;

for(i=0;i<m;i++) c[i] = a[i]+b[i];

}

2121

Prototip funkcije

• uopšte, deklarisanjem funkcije ili globalne promenljive širi se njihov domet

• deklaracijom se domet može proširiti i izvan izvorne datoteke u kojoj se nalazi odgovarajuća definicija

• deklaracija funkcije nosi naziv prototip

• data funkcija može da ima nijedan, jedan ili više prototipova

21

8

2222

vrste prototipova

• postoje dve vrste i tri varijante prototipa:

– potpuni prototip, varijanta 1: zaglavlje sa dodatim terminatorom ;

– potpuni prototip, varijanta 2: varijanta 1 u kojoj su navedeni samo tipovi parametara (bez imena)

– nepotpuni prototip: zaglavlje sa terminatorom ;bez navođenja parametara

22

2323

primer

//potpuni prototip, varijanta 1

void zbirniz(const double a[],const double b[],double c[],int m);

//potpuni prototip, varijanta 2

void zbirniz(const double [],const double [],double [],int);

//nepotpuni prototip

void zbirniz();

23

!!

242424

double f(double x, double y) {return x*sin(y);

}

domet f bez prototipa

double f(double, double);

definicija f

prototip f

domet f sa prototipom

9

252525

double f(double x, double y){ return x*sin(y);

}

domet f bez prototipa

double f(double, double);

definicija f

prototip f

domet f sa prototipom

funkcija i prototip ne moraju biti u istoj izvornoj datoteci!

2626

Lokalne promenljive• promenljive koje su definisane unutar neke

funkcije nose naziv lokalne promenljive

• lokalne promenljive su, ustvari, obične promenljive

• nalaze se na steku

• domet im je funkcija i ne može se proširiti

• u njihovoj inicijalizaciji mogu učestvovati i parametri funkcije

• domet parametara je takođe sama funkcija

26

2727

vrste lokalnih promenljivih• automatske (modifikator auto koji se ne mora

navesti i ne navodi se): obične lokalne promenljive

• registarske (modifikator register): poruka kompajleru da pokuša da ih čuva u procesorskom registru; ako ne može, smeštaju se u memoriju; brzo rade; koriste se za kratkoživuće promenljive (npr. brojači u ciklusima)

• statičke: moraju se inicijalizovati; pamti se poslednja vrednost između dva poziva funkcije; ne preporučuju se!

27

10

2828

auto double t; //isto sto i double t;

register int k; //k se smesta u procesorski registar ako

//moze; ako ne moze - u memoriju

int h(int a) {

static int x=0;

x += 10;

..........

}

pri prvom pozivu h x=0pri drugom pozivu h x=10pri trećem pozivu h x=20itd.

2929

Globalne promenljive• promenljive koje su definisane izvan funkcija

nose naziv globalne promenljive

• obično se zaključavaju i koriste kao globalne imenovane konstante

• domet: od definicije do kraja izvorne datoteke

• domet se može proširiti deklarisanjem

• modifikatori

– extern: deklaracija (širenje dometa)

– static: zabrana širenja dometa

29

3030

extern P;

double P;

static int Q;

domet P

domet Q(ne može se širiti)

11

3131

Pretprocesor

• pretprocesor je deo kompajlerskog sistema koji vrši preliminarnu leksičku obradu izvornog koda

• rezultat obrade nije preveden program, nego prerađen izvorni kod

• izvorni kod se prerađuje u skladu sa zahtevima programa izraženim preko tzv. pretprocesorskih direktiva

• direktive počinju znakom #

• po završetku obrade, direktive se uklanjaju

3232

P.c

pretprocesor

P'.c

kompajler

P.exe

direktive:

1. direktiva za umetanje sadržaja tekstuelne datoteke (#include)

2. direktiva #define

3. direktiva za uslovno umetanje teksta (#ifndef - #endif)

4. (ima ih još)

3333

direktiva #include

#include <ime.ekst> ili #include "ime.ekst"

• sadržaj tekstuelne datoteke ime.ekst umeće se u izvorni kod na mestu na kojem je stajala direktiva #include

#include <ime.ekst> ime.ekst

12

3434

• u varijanti <ime.ekst> datoteka za umetanje ime.ekst odmah se traži u sistemskim folderima C-a

• u varijanti "ime.ekst" datoteka ime.ekst traži se prvo u folderu u kojem je izvorni kod, pa ako se ne nađe traži se u sistemskim folderima C-a.

3535

direktiva "define"

• pojavljuje se u tri uloge:

1. zamena jednog leksičkog simbola ili tokena (niz simbola bez semantike) drugim

2. definisanje tokena

3. makrodirektiva

3636

• zamena tokena drugim tokenom

#define TOKEN1 TOKEN2

• skenira se izvorni kod i gde god se pronađe TOKEN1 zamenjuje se sa TOKEN2 (osim unutar konstantnih stringova)

• najčešća primena su simboličke konstante

#define FALSE 0

#define newline printf("\n")

13

3737

• definisanje tokena: token se označi kao definisan, što se može proveravati posebnim direktivama (#ifndef odnosno #ifdef)

#define TOKEN

#define A_IS_DEFINED

3838

makrodirektive

• makrodirektive jesu alternativa jednostavnim funkcijama

• sintaksa poziva makrodirektive se uopšte ne razlikuje od sintakse poziva funkcije, ali se u prevedenom kodu bitno razlikuju

• kod poziva makrodirektive ne koristi se stek, pa poziv mnogo brže radi

3939

• sintaksa makrodirektive

#define ime(P1,...,Pn) izraz

gde su P1,...,Pn tzv. parametri makrodirektivekoji se obavezno nalaze i u izrazu

• makrodirektiva se "poziva" na isti način kao i funkcija:

ime(arg1,...,argn)

gde se vrši kontrolisana zamena P1 sa arg1 ... Pn

sa argn

14

4040

• primer:

#define max(P,Q) (P>Q)?P:Q

• prilikom obrade naredbe

t = sin(z)+max(x,a*b);

• pretprocesor će u izvorni kod ubaciti izraz

t = sin(z)+(x>a*b)?x:a*b;

zamenom P sa x i Q sa a*b.

ovo ide na prevođenje!

ovo neće stići do kompajlera

4141

• prilikom formiranja makrodirektive mora se strogo voditi računa o prioritetu operatora

• primer:

#define prod(A,B) A*B

• naredba

w = prod(x+y,z+t);

biće (loše) prerađena u

w = x+y*z+t; //prvo se mnozi y*z

• ovo se izbegava intenzivnim korišćenjem zagrada:

#define prod(A,B) ((A)*(B))

#define max(P,Q) (((P)>(Q))?(P):(Q))

4242

direktiva #ifndef• služi za uslovno umetanje teksta u prerađeni

izvorni kod

#ifndef TOKEN

(linija izvornog koda)

(linija izvornog koda)

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

(linija izvornog koda)

#endif

ovaj blok linija iz P.c biće umetnut u prerađeni izvorni kod P'.c ako TOKEN prethodno nije definisandirektivom

#define TOKEN

postoji i varijanta #ifdef kod koje se linije umeću ako TOKEN jeste definisan

15

43

Biblioteke

• Modul je softverska komponenta koja ima dve osobine:1. realizuje se autonomno

2. predstavlja skup servisa namenjen proizvoljnom klijentu

• svrha modula je da omogući višekratnu upotrebu softvera (software reuse)

• modul u C-u nosi naziv biblioteka

• sadržaj (servise) biblioteke čine funkcije, naredbe typedef, simboličke konstante, (zaključane) globalne promenljive, deklaracije i direktive

43

44

double f(double);#include "B.h"

44

… f(y) …

B.c → B.o

#ifndef B_H#define B_Hdouble f(double);…..…..…..

#endif

B.h

double f(double x) {………}

P.c

#include "B.h"

zaglavlje biblioteke

telo biblioteke

45

zašto #ifndef?

45

#include "B1.h"#include "B2.h"

P.c

#include "B2.h"

B1.h

#ifndef B2_H#define B2_Hconst int J=1;…..

#endif

B2.h

J je dva puta definisana!

ako se stavi #ifndef naredba const int J=1; se u P.c pojavljuje samo jednom

16

46

dodatne mogućnosti• kompletan sadržaj biblioteke može se smestiti u

zaglavlje; tada se biblioteka prevodi zajedno sa klijentom:

#include <math.h>#ifndef LIB_H#define LIB_Hdouble sin2(double x) {

double y;y = sin(x);return y*y;

}#endif

46

47

dodatne mogućnosti

• za isto telo biblioteke mogu se vezati više zaglavlja

47

double f(double x) {…}int g(int j) {…}void h(int a,int b) {…}long p(int a) {…}double q(double x) {…}int r(int x) {…}

B.c

double f(double);long p(int);double q(double);int r(int);

B1.h

int g(int);void h(int,int);double q(double);

B2.h

double f(double);long p(int);

B3.h

kroz ovo zaglavlje "vide se"f, p, q, r

kroz ovo zaglavlje "vide se"g, h, q

kroz ovo zaglavlje "vide se"f, p

48

Rekurzivne funkcije

• po definiciji, rekurzivna funkcija je obična funkcija koja poziva samu sebe, direktno ili indirektno

• osobine:

– izvorni kod je fizički kratak i često nejasan; fizički kratak izvorni kod uopšte ne podrazumeva veću brzinu (te dve stvari nemaju nikakve veze!)

– rekurzivne funkcije su spore

17

49

• primer (čisto ilustrativni): računanje faktorijela

bazirano na formuli

n!=1 za n=0 odnosno n!=n*(n-1)! za n>0

unsigned long fakt(unsigned n) {

return (n>0) ? n*fakt(n-1) : 1;

}

rekurzivni poziv

50

• za računanje faktorijela postoji i alternativno rešenje na osnovu formule

n!=1 za n=0 odnosno n!=n*(n-1)*...*1 za n>0

• u programskom smislu reči, ovakva rešenja podrazumevaju primenu ciklusa i zovu se iterativna rešenja

unsigned long fakt(unsigned n) {

unsigned long rez=1;

if(!n) return rez;

else for(;n>0;n--) rez *= n;

return rez;

}

• ova verzija je brža!

51

zaključak

• ako za neki problem postoji iterativno rešenje primeniti ga, iako može da deluje manje elegantno od rekurzivnog

• ako iterativna varijanta nije moguća, upotrebiti rekurziju

18

52

Pokazivači na funkcije• omogućuju poziv funkcije preko adrese,

umesto preko imena

• dakle, pozvana funkcija ne mora biti poznata u toku prevođenja programa (kao i u slučaju pokazivača na podatke)

• tip pokazivača na funkciju određen je prototipom funkcije; dakle pokazivač na double funkciju sa jednim double parametrom nije istog tipa kao pokazivač na int funkciju sa dva int parametra!

53

• pokazivač na funkciju definiše se sa

tip (*imePok)(T1,...,Tn);

gde je tip tip funkcije, a T1,...,Tn tipovi njenih parametara//pokazivac na double funkciju sa jednim double parametrom

double (*pF)(double);

//pokazivac na int funkciju sa dva int parametra

int (*pG)(int,int);

• pokazivači pF i pG nisu istog tipa!

54

• još jedna jedinstvena karakteristika C-a: ime funkcije je pokazivač na njen memorijski prostor!

• ilustracija ponašanja pokazivača na funkciju:

double (*pF)(double); //definisanje pokazivaca

double f(double x) {return x*cos(x);}

pF = f; //pokazivaci pF i f su kompatibilni

// sada je f(a) i (*pF)(a) isto!

• tipična primena pokazivača na funkciju je slučaj kada je funkcija parametar druge funkcije

19

55

primer: tabeliranje funkcije• void funkcija za tabeliranje matematičke funkcije f(x);

zapaziti da pri izradi funkcije za tabeliranje nije poznatoblik funkcije koja se tabelira

void tabela(const double x[], int n, double (*pF)(double)) {

int i;

for(i=0;i<n;i++) printf("...",x[i],(*pF)(x[i]));

}

56

• primena

tabela(p,m,sin); //tabeliranje funkcije sin

double g(double y) {return y*exp(y);}

tabela(z,k,g); --tabeliranje funkcije g

g je pokazivač na funkciju

sin je pokazivač na funkciju

57

Argumenti programa• svaki programski jezik mora imati mogućnost

poziva programa sa prosleđivanjem argumenata; primer je DOS komanda dir sa argumentom "/p"

• inače, ova situacija je sasvim uobičajena, pogotovo kada se uzme u obzir da su takvi pozivi najčešće implicitni

• u C-u, argumenti programa prosleđuju se kao stringovi, a prihvataju kao argumenti funkcije main

20

58

int main(int argc,char*argv[]) {

double arg1; int arg2;

arg1 = atof(argv[1]); //arg1=2.8

arg2 = atoi(argv[2]); //arg2=10

............ itd.

poziv programa:

test 2.8 10

argumenti programa

niz stringova!

3argc

[0]

[1]

[2]

NULL

argv

't' 'e' 's' 't' '\0'

'2' '.' '8' '\0'

'1' '0' '\0'

argv[0] je ime programa!

pretvaranje stringova u brojeve

595959595959

Rezime

• definisanje i korišćenje funkcije: postoje funkcije sa vrednošću i funkcije koje nemaju vrednost

• prenos argumenata u potprogram: po vrednosti i po adresi, preko steka

• prototip je deklaracija funkcije• lokalne i globalne promenljive: "obične" promenljive su

lokalne• pretprocesor: preliminarna leksička obrada izvornog koda• izrada biblioteka: omogućavanje višekratne upotrebe• rekurzivne funkcije: pozivaju same sebe• pokazivači na funkcije: funkcija treba da bude parametar

druge funkcije• argumenti programa: prosleđivanje argumenata celom

programu

1

9 UPRAVLJANJE TOKOVIMA (DATOTEKE)

222222

Sadržaj

• pojam toka

• vrste tokova u C-u

• definisanje datotečne promenljive

• otvaranje datoteke

• zatvaranje datoteke

• korišćenje tekstuelnih datoteka

• korišćenje binarnih datoteka

3

• u modernim programskim jezicima svi izvori i odredišta podataka koji nisu deo programa tretiraju se na isti način i nazivaju tokovima (engl. stream)

• datoteka na disku, tastatura i ekran su tokovi; datoteka je ulazno-izlazni tok, tastatura je ulazni, a ekran izlazni tok

• osnovna osobina toka jeste to što on nije deo programa

• programski jezici tretiraju tokove kao sekvence bajtova sa semantikom ili bez nje

• u nastavku ćemo razmatrati datoteke kao najopštiji slučaj

2

4

Vrste datoteka u C-u

• programski jezik C omogućava korišćenje dve vrste datoteka:

– tekstuelne datoteke (tzv. tekst-fajlovi) gde svaki element datoteke ima unapred zadatu semantiku i to semantiku znaka (tip char)

– binarne datoteke u kojima se datoteka tretira kao sekvenca bajtova, a semantika se zadaje u programu

5

• rukovanje datotekama obuhvata četiri grupe aktivnosti:

– definisanje datotečne promenljive

– otvaranje datoteke

– zatvaranje datoteke

– korišćenje datoteke

• otvaranje, zatvaranje i korišćenje datoteka obavlja se pomoću standardnih funkcija koje se nalaze u zaglavlju <stdio.h>

6

Definisanje datotečne promenljive

• datotečna promenljiva je sredstvo za rukovanje tokovima; to je obična promenljiva koja se posebnom funkcijom vezuje za datoteku

• definiše se sa

FILE* dat;

• gde je FILE* poseban tip definisan pomoću typedef u zaglavlju <stdio.h>

• primer:

• FILE* myFile;

datotečna promenljiva

3

7

Otvaranje datoteke

• otvaranje datoteke je aktivnost kojom se

– zadaje konkretna datoteka, preko putanje

– određuje interpretacija sadržaja (tekst-fajl ili binarna datoteka)

– zadaje način pristupa podacima (samo čitanje, samo upis ili i čitanje i upis).

• funkcija za otvaranje datoteke ima prototip;

FILE* fopen(char* putanja, char* režim);

gde su putanja i režim stringovi.

8

• putanja je string koji određuje apsolutnu ili relativnu putanju (tj. način identifikacije) datoteke u datom fajl-sistemu

• režim je kratak, kodirani string koji zadaje vrstu datoteke i način njene upotrebe; ima 12 varijanata

9

tekst-fajlovi

r - datoteka mora postojati; koristi se kao read-only

w - ako datoteka ne postoji biće napravljena; ako postoji biće ispražnjena; koristi se kao write-only

a - ako datoteka ne postoji biće napravljena; ako postoji, novi elementi biće dodavani na kraju; koristi se kao write-only

r+

w+

a+

isto kao gore, samo što je u sva tri slučaja dozvoljeno i čitanje i upis (read-write)

4

10

binarne datoteke

rb

wb

ab

rb+ ili r+b

wb+ ili w+b

ab+ ili a+b

sve isto kao kod tekst-fajlova, ali se odnosi na binarne datoteke

11

• funkcija fopen kao vrednost vraća tip FILE*, tj. pokazivač, koji se dodeljuje datotečnoj promenljivoj

• ako otvaranje iz bilo kojeg razloga nije uspelo, funkcija fopen vraća vrednost NULL

• po pravilu, pri otvaranju se uvek proverava uspešnost:

if((myFile=fopen("c:\\mydir\\fajl.txt","r"))==NULL) //greska

//ako se prodje gornja provera sve je u redu

12

važno!

• Treba zapaziti da neka datoteka na disku sama po sebi nije ni tekstuelna ni binarna; ona je prosto niz bajtova

• tekstuelna odnosno binarna datoteka je samo način interpretacije bajtova

• shodno tome ista datoteka može se otvoriti kao tekstuelna ili kao binarna

5

13

Zatvaranje datoteke

• operacijom zatvaranja, datoteka se prevodi u završno stanje (prazne se baferi operativnog sistema i datotečna promenljiva "odvezuje" od datoteke)

int fclose(FILE* dat);

• vraćena vrednost je 0 ako je zatvaranje uspešno; ako nije, vraćena vrednost je različita od 0 i jednaka simboličkoj konstanti EOF.

fclose(myFile);

14

• dok je otvorena, datoteka je podložna otkazima; zato se treba pridržavati principa

• drugim rečima, loša je praksa otvoriti sve datoteke na početku programa, a zatvoriti ih na kraju

datoteka se otvara tada kada je potrebna, a zatvara kada više ne treba!

15

Korišćenje datoteka

• osnovna aktivnost vezana za korišćenje datoteka jeste upis podataka u datoteku i čitanje podataka iz nje

• ove dve aktivnosti nose zajednički naziv prenos podataka

6

16

Baferovani prenos

program

baferdisk

•čitanje: isto, u obrnutom smeru

•fclose prazni bafer

17

Navigacija

• prenos podataka bazira se na mehanizmu navigacije: u svakom trenutku, definisan je tzv. tekući bajt; obe vrste prenosa (čitanje i upis) obavljaju se implicitno na mestu tekućeg bajta

• početni položaj markera tekućeg bajta postavlja fopen

• posle svakog čitanja ili upisa elementa, marker tekućeg bajta automatski se pomera na mesto iza poslednjeg učitanog odn. upisanog bajta

17

18

Prenos podataka kod tekstuelnih datoteka

• tekstuelne datoteke (tekst-fajlovi) jesu tokovi čiji su elementi znakovi

• postoje dva načina prenosa podataka:

– prenos bez konverzije (formatiranja) gde se prenose pojedinačni znakovi odnosno stringovi

– prenos sa konverzijom (formatiranjem) gde se izlazne vrednosti konvertuju u znakove u skladu sa konverzionim specifikacijama (kao kod scanf i printf)

7

19

prenos bez konverzije• int fgetc(FILE* dat);

– vraća sledeći znak iz datoteke

• int getc(FILE* dat);

– isto što i fgetc, ali je ovo makrodirektiva

• int getchar();

– isto što i fgetc; podrazumeva se da se čita sa standardnog ulaza (tastatura)

• Za sve tri varijante: ako u datoteci nema više znakova ili ako čitanje nije uspelo vraća se EOF

20

• int fputc(int zn,FILE* dat);

– upisuje znak zn u datoteku dat

• int putc(int zn,FILE* dat);

– isto što i fputc, ali je ovo makrodirektiva

• int putchar();

– isto što i fputc; podrazumeva se da se upisuje na standardni izlaz (ekran)

• Za sve tri varijante: vraća se vrednost upisanog znaka ili EOF ako upis nije uspeo

21

• char* fgets(char* tekst,int n,FILE* dat);

char* gets(char *tekst);

– fgets učitava liniju teksta u string tekst; čitanje se prekida ako se učita n-1 znak ili ako se naiđe na \n; gets očitava liniju teksta sa standardnog ulaza; obe funkcije vraćaju adresu učitanog stringa odnosno NULL ako je kraj datoteke ili greška

• int fputs(const char* tekst,FILE* dat);

int puts(const char* tekst);

– obe funkcije upisuju string tekst (bez znaka \0) u datoteku dat (fputs) ili na standardni izlaz (puts); vraćaju nenultu vrednost u slučaju uspeha odnosno EOF ako je došlo do greške

8

22

prenos sa konverzijom• za prenos se koriste funkcije

fscanf(FILE* dat,....

fprintf(FILE* dat,....

koje su iste kao i scanf odnosno printf; jedina razlika je u tome što se prenos vrši iz tekst-fajla dat ili u njega (kod scanf i printf podrazumevaju se tastatura odnosno ekran)

23

datotečne konstante• C poseduje tri datotečne konstante (tipa

FILE*) koje predstavljaju tekst- fajlove:

– stdin: standardni ulazni uređaj, tj. tastatura; može se promeniti redirekcijom ulaza

– stdout: standardni izlazni uređaj, tj. ekran; može se promeniti redirekcijom izlaza

– stderr: ekran; ne može se promeniti

• na primer, scanf(...) i fscanf(stdin,...) je isto, kao i printf(...) i fprintf(stdout,...)

24

Prenos podataka kod binarnih datoteka

int fread(void* bafer,int vel, int br,FILE* dat);

int fwrite(void* bafer,int vel, int br,FILE* dat);

adresa bafera veličina elementa broj elemenata po bloku datoteka

blokelement

9

25

• fread i fwrite vrše upis-čitanje na poziciji tekućeg bajta

• fread se može izvršiti samo ako je marker tekućeg bajta unutar datoteke

• ako je tekući bajt unutar datoteke, fwriteupisuje novi sadržaj preko starog; ako je tekući bajt na kraju datoteke, novi sadržaj se dodaje

25

26

• posle svake primene fread ili fwrite, marker tekućeg bajta pomera se iza poslednjeg bajta kojem je pristupljeno (tj. na sledeći element)

tekući bajt

blokelement

27

primer

• primer: u datoteci Spisak.dat nalaze se podaci uređeni u slogove tipa

typedef struct {

char prezime[20];

char ime[15]; } Osoba;

10

28

• sledeći segment služi za prikaz datoteke na ekranu:

FILE* fSpisak; Osoba pers;

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

fSpisak = fopen("Spisak.dat","rb");

while(fread(&pers,sizeof(Osoba),1,fSpisak)>0)

printf("%s %s\n",pers.prezime,pers.ime);

fclose(fSpisak);

29

• Marker tekućeg bajta može menjati poziciju bez menjanja sadržaja datoteke

int fseek(FILE *dat,long pomeraj,int reper)

• nova pozicija zadaje se relativno, kao pomeraj u odnosu na bazu (reper)

• za reper postoje tri simboličke konstante: SEEK_SET (početak datoteke), SEEK_END (kraj datoteke), SEEK_CUR (trenutni tekući)

SEEK_SET SEEK_END

SEEK_CUR

30

• vrednost pomeraja zadaje se u bajtovima (za tekst fajlove pomeraj mora biti 0)

• funkcija fseek vraća 0 ako je uspela, a vrednost koja nije 0 u slučaju neuspeha

• funkcija

long ftell(FILE* dat)

vraća poziciju tekućeg bajta u odnosu na početak datoteke

• funkcija

void rewind(FILE* dat)

vraća marker tekućeg bajta na početak datoteke

11

313131313131

Rezime• pojam toka: C jednako tretira sve izvore i odredišta

podataka• vrste datoteka u C-u: tekstuelne i binarne• definisanje datotečne promenljive: datotečna

promenljiva služi za rukovanje datotekom iz programa

• otvaranje datoteke: datoteka se otvara kada je potrebna

• zatvaranje datoteke: zatvara se čim više nije potrebna

• korišćenje tekstuelnih datoteka: prenos bez formatiranja i sa formatiranjem

• korišćenje binarnih datoteka: fread i fwrite