UNIVERZITET EDUKONS NOVI SAD – SREMSKA · PDF file1 Dr DušanT.Malbaški 1...
Transcript of UNIVERZITET EDUKONS NOVI SAD – SREMSKA · PDF file1 Dr DušanT.Malbaški 1...
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