You are on page 1of 14

Matematiki fakultet

Programiranje 1 programski jezik C


Beleke sa asova vebi
kolska 2009/2010

Biljana Stojanovi
as 11, 23. 12. 2009.

1. Nizovi
1.1 Inicijalizacija elemenata niza
Inicijalizacija elemenata niza se moe izvriti navoenjem inicijalizacionih vrednosti
izmeu vitiastih zagrada koje moraju biti konstante.
Dimenzija niza se u tom sluaju automatski odreuje na osnovu broja inicijalizatora i
nije neophodno navoditi je izmeu [].
Ako se dimenzija navede, ne sme biti manja od broja inicijalizatora u listi.
Ako je vea, ostali elementi niza popunjavaju se nulama.

Primer 1 Program ilustruje inicijalizaciju nizova.


#include <stdio.h>
int main()
{
/* Niz inicijalizujemo navodjenjem vrednosti izmedju viticastih
zagrada. Dimenzija niza se odredjuje automatski na osnovu
broja inicijalizatora. */
int a[] = {1, 2, 3, 4, 5, 6};
/* Isto vazi i za niske karaktera */
char s[] = {'a', 'b', 'c'};
/* Ekvivalentno prethodnom bi bilo
char s[] = {97, 98, 99};
*/
/* Broj elemenata niza */
int a_br_elem = sizeof(a) / sizeof(int);
int s_br_elem = sizeof(s) / sizeof(char);
int i;
/* Ispisujemo nizove */
for(i = 0; i < a_br_elem; i++)
printf("a[%d] = %d\n", i, a[i]);
for(i = 0; i < s_br_elem; i++)
printf("s[%d] = %d\n", i, s[i]);
}
1
1

Zasnovano na primerima kolega Milana Bankovia (www.matf.bg.ac.rs/~milan), Jelene Graovac


(www.matf.bg.ac.rs/~jgraovac) i Stae Vujii (www.matf.bg.ac.rs/~stasa)

Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

Podseanje (operator sizeof):


Operator sizeof() je unarni operator koji se moe primenjivati na podatke i tipove.
Ako se primeni na tip T, tada je vrednost izraza sizeof(T) broj bajtova koji
zauzima jedan podatak tog tipa.
Ako se primeni na podatak(ili proizvoljan izraz), tada sizeof(izraz) ima
vrednost broja bajtova koje zauzima podatak, imajui u vidu tip podatka
(izraza).
Operator sizeof daje vrednost tipa int.
Vrednost izraza sizeof se rauna u vreme prevoenja programa, jer je ve
tada jasno koja je veliina objekta na koji se primenjuje.

2. Veza nizova i pokazivaa


U C-u postoji jaka veza izmeu nizova i pokazivaa. Svaka operacija koja se moe
postii indeksiranjem niza, moe se uraditi i pomou pokazivaa.
Primer:
Naredba
int a[10] = {0, 1, 2, 3, 4 ,5, 6, 7, 8, 9};
definie niz a veliine 10, odnosno blok od 10 susednih objekata u memoriji sa
imenima a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8] i a[9] i vrednostima 0,
1, 2, 3, 4, 5, 6, 7, 8, 9 redom.
Ako je p pokaziva na ceo broj deklarisan pomou:
int *p;
tada dodela
p = &a[0];
postavlja da p pokazuje na nulti element niza a, tj. p sadri adresu elementa a[0].
Po definiciji, ime niza je sinonim za adresu poetnog (nultog) elementa niza.
Gornja dodela
p = &a[0];
ekvivalentna je dodeli
p = a;

Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

Zapis a[i] znai isto to i *(a + i). Prilikom izraunavanja izraza a[i], C ga odmah
pretvara u *(a + i). Ova dva oblika su ekvivalenta.
a[i]

*(a + i)

Primenjujui operator & na oba dela ekvivalencije, dobija se da su i &a[i] i a+i


identini.
&a[i] a + i
a+i je adresa i-tog elementa niza a.
a je adresa nultog elementa.
Takoe, izraz p[i] tumai se kao *(p + i). Dakle, zbir pokazivaa na tip T i celog
broja je izraz tipa pokaziva na tip T. Vrednost izraza je adresa celog broja koji se
u nizu nalazi i pozicija iza elementa na koji pokazuje p.
Dakle, vai sledee:
p + i = &p[i]
*(p + i)

p[i]

Dakle, ako p pokazuje na odreeni element niza a, tada p+1 pokazuje na naredni
element, dok p+i pokazuje na element koji se u nizu a nalazi i pozicija iza elementa
na koji pokazuje p, a p-i pokazuje na element koji se u nizu a nalazi i pozicija pre
elementa na koji pokazuje p.
Razlika izmeu imena niza (a) i pokazivaa (p) je u tome to je pokaziva
promenljiva, dok ime niza nije promenljiva, pa samim tim mu se ne moe promeniti
vrednost.
Drugim reima, izrazi p = a i p++ su dozvoljeni (postavlja da p pokazuje na nulti
element niza a, odnosno pomera pokaziva p za jednu poziciju u nizu a u desno).
Izrazi a = p i a++ nisu dozvoljeni a nije promenljiva pokazivakog tipa, ve je
tipa niz celih brojeva i samo je automatski konvertovana u pokaziva na prvi lan
niza.

Primer 2 Program demonstrira veze nizova i pokazivaa u programskom jeziku C .


#include <stdio.h>
int main()
{
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int *p = a;
int i;
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

printf("Vrednost
printf("Vrednost
printf("Vrednost
printf("Vrednost

izraza
izraza
izraza
izraza

a (tipa int *): %p\n", a);


p (tipa int *): %p\n", p);
*a (tipa int): %d\n", *a);
*p (tipa int): %d\n", *p);

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


{
printf("Vrednost izraza
printf("Vrednost izraza
printf("Vrednost izraza
printf("Vrednost izraza
printf("Vrednost izraza
printf("Vrednost izraza
printf("Vrednost izraza
printf("Vrednost izraza
}

&a[%d] (tipa int *): %p\n",i,&a[i]);


&p[%d] (tipa int *): %p\n",i,&p[i]);
(a + %d) (tipa int *): %p\n",i,a+i);
(p + %d) (tipa int *): %p\n",i,p+i);
a[%d] (tipa int): %d\n", i, a[i]);
p[%d] (tipa int): %d\n", i, p[i])
*(a + %d) (tip int):%d\n",i,*(a+i));
*(p + %d) (tip int):%d\n",i,*(p+i));

return 0;
}

Primer 3 (Obrtanje niza indeksna sintaksa): Program obre elemente niza.

Program demonstrira upotrebu nizova, uz korienje indeksne (nizovske) sintakse.


#include <stdio.h>
#define MAX 100
int main()
{
int a[MAX];
int n;
int i, j;

/* Deklaracija niza a od najvise MAX elemenata */


/* Broj elemenata niza a */
/* Brojaci u petljama */

/* Unosimo broj elemenata */


printf("Uneti broj elemenata niza (<= 100): ");
scanf("%d", &n);
/* Proveravamo da li je prekoraceno ogranicenje */
/* n se postavlja na MAX u slucaju da je uneta veca vrednost */
if( n > MAX )
n = MAX;
/* Unosimo elemente niza */
printf("Uneti elemente niza:\n");
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
/* Prikaz niza */
printf("Uneli ste niz:\n");
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

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


printf("%d ", a[i]);
printf("\n");
/* Obrcemo niz */
for(i = 0, j = n-1; i < j; i++, j--)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
/* Prikaz niza */
printf("Niz nakon obrtanja:\n");
for(i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}

Primer 4 (Obrtanje niza pokazivaka sintaksa): Program obre elemente niza.


Program demonstrira upotrebu nizova, uz korienje pokazivake sintakse.
#include <stdio.h>
#define MAX 100
int main()
{
int a[MAX];
int n;
int *p, *q;

/* Deklaracija niza a od najvise MAX elemenata */


/* Broj elemenata niza a */
/* Pokazivaci na elemente niza a */

/* Unosimo broj elemenata */


printf("Uneti broj elemenata niza (<= 100): ");
scanf("%d", &n);
/* Proveravamo da li je prekoraceno ogranicenje */
/* n se postavlja na MAX u slucaju da je uneta veca vrednost */
if( n > MAX )
n = MAX;
/* Unosimo elemente niza */
printf("Uneti elemente niza:\n");
for(p = a; p - a < n; p++)
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

scanf("%d", p);
/* Prikaz niza */
printf("Uneli ste niz:\n");
for(p = a; p - a < n; p++)
printf("%d ", *p);
printf("\n");
/* Obrcemo niz */
for(p = a, q = a + n - 1; p < q; p++, q--)
{
int t = *p;
*p = *q;
*q = t;
}
/* Prikaz niza */
printf("Niz nakon obrtanja:\n");
for(p = a; p - a < n; p++)
printf("%d ", *p);
printf("\n");
return 0;
}

Primer 5 (Redni broj dana u godini): Program za uneti datum utvruje redni broj

tog dana u datoj godini. Program demonstrira upotrebu nizova, kao i veze nizova i
pokazivaa.
#include <stdio.h>
int main()
{
int obicna[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int prestupna[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30,31};
int dan, mesec, godina;
int i, *tekuca;
int dan_u_godini = 0;
printf("Uneti datum u formatu dd:mm:yyyy: ");
scanf("%d:%d:%d", &dan, &mesec, &godina);
/* Proveravamo da li je godina prestupna */
if(godina % 400 == 0 || (godina % 100 != 0 && godina % 4 == 0))
tekuca = prestupna;
/* Pokazivac tekuca pokazuje na
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

prvi element niza prestupna */


else
tekuca = obicna;

/* Pokazivac tekuca pokazuje na


prvi element niza obicna */

/* Sumiramo dane protekle prethodnih meseci. Indeks ide od 0 do


mesec - 2, jer indeksi nizova u C-u pocinju od 0. Npr, za dan u
mesecu martu (treci mesec) treba sabrati broj dana u januaru i
februaru (indeks u petlji treba da ide od 0 do 1, ukljucujuci i
1) */
for(i = 0; i < mesec - 1; i++)
dan_u_godini += tekuca[i];
/* NAPOMENA: pokazivac tekuca je postavljen na adresu prvog clana
jednog od nizova obicna[] ili prestupna[]. Izraz tekuca[i] je
ekvivalentan izrazu
*(tekuca + i), tj. dobijamo i-ti element niza na ciji prvi
element pokazuje pokazivac tekuca, sto smo i zeleli da
postignemo */
/* Nakon toga jos treba dodati broj proteklih dana u tekucem
mesecu */
dan_u_godini += dan;
printf("Uneti datum je %d. dan u godini\n", dan_u_godini);
return 0;
}

3. Nizovi i funkcije
Funkcije koje prihvataju niz kao argument, zapravo prihvataju kao argument samo
adresu prvog elementa niza. To ima nekoliko posledica:
1. Funkcija ne zna unapred koliko elemenata ima niz, ve samo gde on u
memoriji poinje. Zato se duina niza mora preneti posebnim celobrojnim
parametrom. Ovo vai za sve nizove, osim za niske karaktera.
2. Svejedno je da li emo u listi parametara napisati npr. double a[] ili double
*a, prevodilac to uvek razume kao double *a.
Ako napiemo na nizovski nain, double a[], tada se dimenzija ne navodi
izmeu [], a ako se navede, ignorie se.
3. Unutar funkcije se promenljiva a koristi kao pokaziva na double, tj. sa njom
se moe raditi sve to i sa bilo kojim pokazivaem, ukljuujui i promene
vrednosti.
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

Pri tom je nebitno da li je u listi parametara koriena nizovska ili pokazivaka


sintaksa.
4. S obzirom na gore navedeno, nizovi se uvek prenose preko adrese, tj. za niz
se nikada ne kreira lokalna kopija, kao to je sluaj sa ostalim tipovima
podataka.
Samim tim, promene na elementima niza unutar funkcije se odraavaju na
originalni niz.

Primer 6 Skalarni proizvod dva niza brojeva.


#include <stdio.h>
long mnozi(int x[], int y[], int n);
int main()
{
int a[] = {1, 2, 3, 4, 5, 6}, b[] = {8, 7, 6, 5, 4, 3};
printf("Skalarno a*b = %ld\n", mnozi(a, b, 6));
return 0;
}
long mnozi(int x[ ], int y[ ], int n)
{
int i;
long suma = 0;
for(i = 0; i < n; i++)
suma += x[i] * y[i];
return suma;
}
Izlaz:
Skalarno a*b = 98

Primer 7 (Nizovi i funkcije): Program unosi realne brojeve sa ulaza i rauna zbir i
proizvod elemenata, kao i najvei i najmanji element u nizu.
#include <stdio.h>
#define MAX 100
/* Funkcija racuna zbir elemenata niza */
double zbir(double a[], int n)
{
double s = 0;
int i;
/* Sumiramo n elemenata niza */
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

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


return s;
}
/* Funkcija racuna proizvod elemenata niza */
double proizvod(double a[], int n)
{
double p = 1;
/* Mnozimo n elemenata niza */
for(; n; n--) p *= *a++;
return p;
}
/* Funkcija racuna najveci element niza */
double max(double *a, int n)
{
double max = *a;
/* Odredjujemo najveci element */
for(a++, n--; n > 0; a++, n--)
if(*a > max)
max = *a;
return max;
}
/* Funkcija racuna najmanji element niza */
double min(double *a, int n)
{
double min = a[0];
int i;
/* Odredjujemo najmanji element */
for(i = 1; i < n; i++)
if(a[i] < min)
min = a[i];
return min;
}
int main()
{
double a[MAX];
int n, i;

/* Ucitavamo dimenziju niza */


Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

printf("Uneti broj elemenata niza (<= 100): ");


scanf("%d", &n);
/* Proveravamo da li je dimenzija veca od MAX */
if(n > MAX)
n = MAX;
/* Unosimo elemente niza */
printf("Uneti elemente niza:\n");
for(i = 0; i < n; i++)
scanf("%lf", a + i);
/* Pozivamo gornje funkcije i prikazujemo vrednosti */
printf("Zbir elemenata niza je: %5.3f\n", zbir(a, n));
printf("Proizvod elemenata niza je: %5.3f\n", proizvod(a, n));
printf("Najveci element u nizu je: %5.3f\n", max(a, n));
printf("Najmanji element u nizu je: %5.3f\n", min(a, n));
return 0;
}

Primer 8 (Transformacije nizova): Program zamenjuje susedne elemente niza na


parnim i neparnim pozicijama. Program demonstrira prenos nizova po adresi.
#include <stdio.h>
/* Deklaracije funkcija */
void zameni(int a[], int n);
void prikazi(int a[], int n);
int main()
{
int a[] = {0,1,2,3,4,5,6,7,8,9,10};
int n = sizeof(a)/sizeof(int);
/* NAPOMENA: Jedna od retkih situacija u
kojoj se ime niza ne konvertuje automatski
u pokazivac na njegov prvi element je kod
operatora sizeof. sizeof(a) racuna broj
bajtova koje zauzima sam niz (u ovom slucaju
cak 44 bajta), a ne pokazivac (sto bi bilo
svega 4 bajta). Slicna je situacija sa izrazima
&a, a++, a--, a = izraz. U svim ovim situacijama
a se ponasa kao niz, a ne kao pokazivac (&a je adresa nultog
elementa niza, dok u poslednje
tri situacije prevodilac prijavljuje gresku, jer
date operacije nad nizovima nisu dozvoljene). U
svim ostalim izrazima a se ponasa kao pokazivac
na prvi element u nizu, tj. kao adresa pocetka
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

10

niza. */
prikazi(a, n);
zameni(a, n);
prikazi(a, n);
return 0;
}
/* Funkcija zamenjuje susedne elemente niza na
parnim i neparnim pozicijama. */
void zameni(int a[], int n)
{
int i;
/* NAPOMENA: funkcija zameni() menja vrednosti
elementima niza. Kako je a pokazivac na
prvi element originalnog niza koji je predat
kao argument funkciji prilikom poziva,
promene koje funkcija izvrsi odrazice se
na originalni niz, tj. pozivajuca funkcija
ce moci da "vidi" promene na nizu koje je
izvrsila funkcija zameni() */
for(i = 0 ; i < n - 1 ; i += 2)
{
int t = a[i];
a[i] = a[i + 1];
a[i + 1] = t;
}
}
/* Funkcija prikazuje niz */
void prikazi(int a[], int n)
{
int i;
for(i = 0 ; i < n ; i++)
printf("%d ", a[i]);
printf("\n");
}

NAPOMENA!
Funkcija NE MOE da vrati podatak tipa niz. Fragment koda nalik sledeem:
int [] f()
{
int a[10];
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

11

........napunimo niz a ........


return a;
}
nije mogu u C-u. Razlog tome je neefikasnost koja bi nastala prilikom
prosleivanja povratne vrednosti pozivajuoj funkciji, jer objekat tipa niz moe biti
veoma veliki podatak.
Mogue je vratiti adresu niza a, nalik ovome:
int * f()
{
int a[10];
.........napunimo niz a ......
return a;
}
Ovo bi prevodiliac prihvatio, ali je semantiki potpuno pogreno. Niz a je lokalni
podatak, pa samim tim prestaje da postoji u memoriji u trenutku kada se funkcija
f() zavri.
Ako bismo pozivajuoj funkciji vratili adresu poetka ovog niza, kao u primeru gore,
tada bi ta adresa ukazivala na objekat koji na tom mestu vie ne postoji, to je
ozbiljan propust, koji moze dovesti do prekida programa u toku izvrenja.
Dakle, nije mogue kreirati lokalno niz u funkciji, izraunati njegove elemente i
onda ga kao celinu vratiti pozivajuoj funkciji.
Jedini nain da se postigne eljeni efekat je da pozivajua funkcija alocira niz
potrebne veliine i da njegovu adresu prosledi pozvanoj funkciji kao argument:
void f(int a[], int n)
{
...... napunimo niz a ........
}
Funkcija f() sada menja originalni niz iz pozivajue funkcije, pa samim tim promene
na nizu ostaju i nakon zavretka funkcije f().

Primer 9

(Vraanje nizova iz funkcija): Program generie niz Fibonaijevih


brojeva. Program demonstrira vraanje podataka nizovskog tipa iz funkcije.
#include <stdio.h>
#define MAX 46
/* Funkcija izracunava prvih n Fibonacijevih brojeva
i smesta ih u niz a */
void fibonaci(int a[], int n)
{
Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

12

int i;
for(i = 0 ; i < n ; i++)
if(i < 2)
a[i] = 1;
else
a[i] = a[i - 1] + a[i - 2];
}
/* Funkcija prikazuje niz */
void prikazi(int a[], int n)
{
int i;
for(i = 0 ; i < n ; i++)
printf("%d ", a[i]);
printf("\n");
}
int main()
{
int f[MAX];
int n;
/* Ucitavamo dimenziju niza */
printf("Uneti broj Fibonacijevih brojeva (<=46): ");
scanf("%d", &n);
/* Proveravamo prekoracenje */
if(n > MAX)
n = MAX;
/* Pozivamo funkciju fibonaci() koja generise niz
Fibonacijevih brojeva, i smesta ih u niz f. */
fibonaci(f, n);
/* Prikazujemo niz */
prikazi(f, n);
return 0;
}

13

Biljana Stojanovi | Univerzitet u Beogradu, Matematiki fakultet

You might also like