You are on page 1of 322

1.

POGLAVLJE

FUNKCIJE

1
1.1. POJAM I DEFINICIJA FUNKCIJE

Složeniji problemi se rešavaju dekompozicijom u veći broj manjih problema.


Potprogrami predstavljaju mehanizam koji direktno podržava funkcionalnu
dekompoziciju kao jednu od osnovnih metoda strukturnog programiranja.

Definicija potprograma:

Potprogrami su sastavni segmenti programskog koda koji se pozivaju radi


obavljanja konkretno specificiranog zadatka.

Potprogrami u razvoju programa se koriste iz tri razloga:


1) Segmenti programa se mogu više puta pojavljivati u okviru istog ili u okviru
različitih programa (iscrtavanje table igrice se pojavljuju na više mesta u
okviru programa, ili sortiranje niza koje nam treba ne samo u jednom već i u
više različitih programa). Korišćenje potprograma u takvim situacijama pre
svega omogućava da jednom napisan potprogram bude neograničeno puta
pozivan. Sa druge strane ovakav pristup je prevencija od mogućnosti
pravljenja grešaka prilikom kopiranja programskog koda sa jednog mesta na
drugo u okviru istog ili u okviru različitih programa.

2) Podprogrami predstavljaju logičke jedinice dekomponovanih programa. Čak


i da se programski kod izvršava samo jednom, veoma je korisno odvojiti
programski kod sa jasno definisanim ciljem zbog dekomponovanosti,
čitljivosti i potreba testiranja celokupnog rešenja. Ispred svakog
potprograma postoji dokumentacija: opis potprograma i datum poslednje
izmene. Poželjno je da telo main() -na bude prikazan (stane) na ekran radi
preglednosti i čitljivosti programa.

3) Potprogrami predstavljaju i fizičku jedinicu programske dekompozicije, koji


se posmatra kao jedinični kod u postupku prevođenja. Programski jezik C
koristi module (datoteke) u kojima se nalaze deklaracija promenljivih i
deklaracija potprograma kao jedinice fizičke dekompozicije. Više programa
može koristiti isti potprogram koji se nalazi u posebnom modulu.

U većini programskih jezika se jasno razlikuju potprogrami koji vraćaju vrednost


(funkcije), od onih koji to ne čine (procedure). Programski jezik C poznaje samo funkcije
kao tip potprograma, ali se u okviru ovakvog pristupa procedure formalno zamenjuju
funkcijama koje ne vraćaju nikakvu vrednost.
Sa pojmom funkcija srećemo se u matematici gde se na osnovu argumenta funkcije
(nezavisna promenljiva x) dobija vrednost rezultata funkcije (zavisna promenljiva y).

2
Na primer: y  e 3 x  2  4  x  5

Definicija funkcije:

Funkcije su potprogrami koji na osnovu izvesnog broja argumenata daju


jedan rezultat koji se naziva vrednost funkcije.

Osobine funkcija:

 Vrednost funkcije može da se koristi ugrađivanjem poziva funkcije u izraze.


Poziv funkcije se, u stvari, smatra operatorom kao i svi ostali operatori.
 Funkcije kontrolišu pristup do važnih podataka i čuvaju ih od neovlašćenih
promena.
 Funkcija skriva detalje načina obavljanja određenog zadatka. Ovaj princip
se zasniva na ideji da onoga ko poziva funkciju ne mora interesovati kako
određena funkcija rešava odabrani problem koji je rezultat funkcionalne
dekompozicije.

3
1.2. DEFINISANJE FUNKCIJE

Definisanje funkcije
Funkcija se definiše naredbom za definisanje funkcije:

tip naziv_funkcije(lista _argumenata)


{
telo_ funkcije
}

tip - predstavlja osnovni tip vrednosti funkcije (svi standardni prosti tipovi).
Vrednost funkcije može da bude samo jedan podatak. Za tip vrednosti funkcije
ne može da bude niz. Za funkcije koje ne stvaraju vrednost funkcije kao
oznaka tipa treba da se koristi službena reč void. Ako se izostavi oznaka tipa
podrazumeva se tip int.

naziv_funkcije - sastoji se od indentifikatora funkcije, koji je istovetan sa bilo


kojom vrstom indentifikatora.

lista_argumenata - predstavljaju argumente funkcije pomoću kojih se vrši


unošenje početnih vrednosti funkcije. Vrednost funkcije se izračunava na
osnovu tih početnih podataka. Argumenti se u listi argumenata razdvajaju sa
zarezom. Pojedini argumenti definišu se na isti način kao i podaci: tip naziv.
Za razliku od naredbi za definisanje podataka ovde se za svaki argument mora
zasebno navesti oznaka tipa. U slučaju vektora dovoljno je da se samo parom
zagrada označi da se radi o vektoru. Argumenti koji se pominju prilikom
definisanja funkcije nazivaju se i formalnim argumentima. Oni nisu stvarni
podaci koji se obrađuju u toku izvršavanja funkcije.Formalni argumenti koji
se pominju prilikom pozivanja funkcije zamenjuju vrednostima odgovarajućih
stvarnih argumenata koje se onda obrađuju.

telo_funkcije - predstavlja sadržaj funkcije koja se definiše. Ona je po formi blok


(nalazi se između vitičastih zagrada), što znači da može da sadrži deklarativne
i izvršne naredbe. Ako funkcija kao rezultat svog rada vraća neku vrednost u
okviru tela funkcije mora se nalaziti naredba return.
Opšti oblik naredbe return je:
return izraz;
ili return;
Izraz mora da se po tipu slaže sa predviđenim tipom vrednosti
funkcije.Naredba return se koristi kada je potrebno izvršiti povratak u glavni
program (u okviru funkcije na više mesta se može nalaziti naredba return).
Znači osim što može da vrati vrednost u glavni program, omogućava i

4
prekidanje izvršavanja programskog toka u funkciji, bez obzira na kom mestu
se nalazi u telu funkcije. Kod funkcija tipa void naredba return ne sme da
sasdrži izraz.

Tip vrednosti funkcije, naziv funkcije i lista argumenata predstavljaju zaglavlje


funkcije.

Primer 1:
Definisati C funkciju hipotenuza koja na osnovu kateta a i b izračunava hipotenuzu
pravouglog trougla.

Rešenje

prvi način:

float hipotenuza(float a, float b)


{
return sqrt(a*a+b*b);
}

drugi način:

float hipotenuza(float a, float b)


{
float c; /* Deklarativna naredba */

c=sqrt(a*a+b*b);

return c;
}

Primer 2:
Definisati C funkciju slika koja na osnovu neparnog broja zvezdica n iscrtava sliku
sledećeg izgleda:

*
***
*****
******* Za n = 7 napravljena je ova slika
****** gde je n neparan broj i predstavlja
***** gornju katetu trougla zvezdica.
****
***
**
*

5
Rešenje

void slika(int n)
{
unsigned i, j;

printf("\n\n");
for(i=1;i<=n/2+1;i++)
{
for(j=1;j<=n/2-i+1;j++) printf(" ");
for(j=1;j<=2*i-1;j++) printf("* ");
printf("\n");
}
for(i=1;i<=n-1;i++)
{
for(j=1;j<=i;j++) printf(" ");
for(j=1;j<=n-i;j++) printf("* ");
printf("\n");
}
}

6
1.3. POZIVANJE FUNKCIJA

Pozivanje funkcija u jeziku C smatra se binarnim operatorom i obeležava se sa ().


Za razliku od ostalih binarnih operatora ovaj operator se ne piše između svojih operanada
već "oko" drugog operanda. Prvi operand je funkcija koja se poziva, a drugi operand je
niz stvarnih argumenata:

funkcija(izraz1, izraz2, izraz3,...,izrazn)

funkcija - označava funkciju čije se izvršavanje traži. Ona je u većini slučajeva


indentifikator funkcije koja se poziva, ali može da bude i adresni izraz
čija je vrednost adresa željene funkcije.

izrazi - predstavljaju stvarne argumente funkcije čije vrednosti služe za


inicijalizaciju formalnih argumenata funkcije pre obrade tela funkcije.
Stvarni argumenti mogu biti: promenljive, konstante ili izrazi i moraju
imati u potpunosti definisanu vrednost u momentu prosleđivanja
(predaje) funkciji Izrazi koji predstavljaju stvarne argumente funkcije
izračunavaju se po proizvoljnom redosledu, neposredno pre pozivanja
funkcije.

Izraz za pozivanje funkcije može se koristiti kao operand u složenijem izrazu, tada
se vrednost funkcije koristi u izračunavanju tog izraza. Kako je operator poziva funkcije
() visokog prioriteta, to obezbeđuje da se izračunavanje vrednosti funkcije (pozivanje
funkcije) izvrši pre bilo kog susednog operatora u izrazu. Ukoliko funkcija nema svoju
vrednost (tip void) može da se koristi samo kao drugi operand operatora zarez ili kao
drugi ili treći operand trinarnog operatora. Funkcija koja nema svoju vrednost najčešće se
koristi kao operand izraza u prostoj naredbi (fun(...);).

Primer 1:
Napisati C program koji na osnovu unetih kateta pravouglog trougla a i b
izračunava dužinu hipotenuze. Dužinu hipotenuze računati funkcijom hipotenuza čija je
sintaksa: float hipotenuza(float a, float b);

Rešenje

prvi način:

#include <stdio.h>
#include <conio.h>
#include <math.h>

7
float hipotenuza(float a, float b)
{
return sqrt(a*a+b*b);
}

void main(void)
{
float a,b;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\n\n\tUNESITE KATETE PRAVOUGLOG TROUGLA:\n\t\ta = ");


scanf("%f",&a);
printf("\t\tb = ");
scanf("%f",&b);

printf("\n\n\n\n\n\n\n");
printf("\n\n\n\n\n\n\n\tHIPOTENUZA PRAVOUGLOG TROUGLA JE:\n\t\t");
printf("c = %.3f",hipotenuza(a,b));

gotoxy(1,25);
getch();
}

drugi način:

#include <stdio.h>
#include <conio.h>
#include <math.h>

float hipotenuza(float a, float b)


{
return sqrt(a*a+b*b);
}

void main(void)
{
float a,b,c;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();
printf("\n\n\tUNESITE KATETE PRAVOUGLOG TROUGLA:\n\t\ta = ");
scanf("%f",&a);
printf("\t\tb = ");
scanf("%f",&b);

8
c = hipotenuza(a,b); /* Prilikom poyiva funkcije pored stvarnih argumenata pogresno je
stavljati tip podatka, tj nije dobro pisati c=hipotenuza(int a, int
b); */

printf("\n\n\n\n\n\n\n");
printf("\n\n\n\n\n\n\n\tHIPOTENUZA PRAVOUGLOG TROUGLA JE:\n\t\t");
printf("c = %.3f",c);

gotoxy(1,25);
getch();
}

Primer 2:
Napisati C program koji korišćenjem unetog neparnog prirodnog broja n, pozivom
funkcije slika prikazuje na ekranu sliku od zvezdica sledećeg izgleda:

*
***
*****
******* Za n = 7 napravljena je ova slika
****** gde je n neparan broj i predstavlja
***** gornju katetu trougla zvezdica.
****
***
**
*

Rešenje

#include <stdio.h>
#include <conio.h>

void slika(int n)
{
unsigned i, j;

printf("\n\n");
for(i=1;i<=n/2+1;i++)
{
for(j=1;j<=n/2-i+1;j++) cprintf(" ");
for(j=1;j<=2*i-1;j++) cprintf("* ");
printf("\n");
}

9
for(i=1;i<=n-1;i++)
{
for(j=1;j<=i;j++) printf(" ");
for(j=1;j<=n-i;j++) printf("* ");
printf("\n");
}
}

void main(void)
{
unsigned xn,yn;
int n;

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("\n\tN = ");
xn=wherex(), yn=wherey();
do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0||n%2==0);

slika(n); /* Poziv funkcije koja nema svoju vrednost (tip void). */

gotoxy(1,25);
getch();
}

Test primer programa:

10
1.4. PREDAJA PARAMETARA

Prilikom pozivanja funkcije tipične su sledeće akcije:


 Prosleđivanje stvarnih argumenata,
 Alokacija i inicijalizacija lokalnih promenljivih funkcije,
 Prenos kontrole na funkciju, ali tek kada se na neki način zapamti adresa u
pozivajuću celinu koja se nalazi odmah iza mesta poziva funkcije.

Pri povratku iz funkcije redosled akcija je obrnut. Prvo se restaurira pozivajuća


adresa u pozivajuću rutinu, oslobađa se prostor za lokalne promenljive i vrši bezuslovni
skok na povratnu adresu. Formalni argumenti, lokalne promenljive i povratna adresa
predstavljaju jednu celinu oblika strukture pod nazivom aktivizacioni zapis, koji se
zapisuje na stek-u prilikom pozivanja funkcije. Prilikom završetka funkcije aktivizacioni
zapis se uklanja sa steka.

Jedna bitna akcija prilikom pozivanja funkcije je prosleđivanje vrednosti


stvarnih argumenata formalnim argumentima funkcije, ili predaja parametara.
Vrednosti stvarnih argumenata funkcije služe za inicijalizaciju formalnih
argumenata funkcije pre obrade tela funkcije.
Predaja parametara može se biti: predaja parametara po vrednost i predaja
parametara po referenci.
Prilikom predaje parametara po vrednoasti kopija vrednosti promenljive se
prosleđuje funkciji, odnosno formalnim parametrima funkcije.

Primer 1:
Napisati C program koji na osnovu dužine stranice kvadrata izračunava obim i
površinu kvadrata. Za izračunavanje obima kvadrata koristiti funkciju obim, a površine
kvadrata funkciju povrsina.

Rešenje

U ovom primeru koristi se predaja parametara po vrednosti.

#include <stdio.h>
#include <conio.h>

/* Funkcija za izracunavanje obima kvadrata. */


double obim(double a)
{
return 4*a;
}

11
/* Funkcija izracunava povrsinu kvadrata. */
double povrsina(double x)
{
double p; /* Promenljiva p je lokalna promenljiva i ima doseg do kraja funnkcije gde je i
deklarisana. */
p=x*x;

return p;
}

void main(void)
{
double a,o;
unsigned xa,ya;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\n\ta = ");
xa=wherex();
ya=wherey();
do{
gotoxy(xa,ya);
printf(" ");
gotoxy(xa,ya);
scanf("%lf",&a);
}while(a<=0);

o=obim(a);

/* Prilikom startovanja programa operativni sistem rezerviše pet zona memorije, koji
su delovi RAM memorije. Za sada posmatraćemo dve zone memorije: Zona podataka i stek
memorija. Prilikom poziva funkcije a je stvarni argument funkcije i nalaze se u ZONI
PODATAKA. Vrednost promenljive a predaje se formalnom parametru koji u ovom
primeru ima isto ime. Formalni parametar a se nalazi na STEK-u te fizički nije ista
memorijska lokacija kao stvarni argument, koji se nalazi u ZONI PODATAKA. */

printf("\n\n\n\tO = %.3f\n\tP = %.3f",o,povrsina(a));

/* U ovom pozivu funkcija se poziva u okviru druge funkcije. Vrednost stvarnog


parametar a iz ZONE PODATAKA se predaje formalnom parametru x sa STEK-a. Kažemo
da je time izvršena inicijalizacija parametra x koji sada ima vrednost parametra a.
Parametar x može menjati svoju vrednost u okviru tela funkcije, ali nakon zavrsetka
funkcije promenljiva a iz ZONE PODATAKA imace istu vrednost kao i pre poziva
funkcije. */

gotoxy(1,25);
getch();
}

12
Primer 2:
Napisati C program koji korišćenjem funkcije suma izračunava zbir prvih n
članova beskonačnog periodičnog niza periode p.
Beskonačni niz ima sledeći oblik:

1, 1, 2, 2, 4, 8, 12, 96, ...,1, 1, 2, 2, 4, 8, 12, 96,..., 1, 1, 2, 2, 4, 8, 12, 96, ...

U funkciji suma koristiti funkciju zbir koja može na osnovu unetog broja k da
sabira celu periodu (ako je k=p) ili deo periode (ako je k<p) beskonačnog niza.
Zadatak rešiti bez korišćenja nizova.

Rešenje

#include <stdio.h>
#include <conio.h>

/* Omogucava unos pozitivnog broja na zadatoj poziciji. Koristi se kao funkcija jer se
posebno mora uneti podatak kolika je perioda i podatak koliko elemenata treba sabrati. */

int unesi(int xpoz, int ypoz)


{
int br;

do{
gotoxy(xpoz,ypoz);
printf(" ");
gotoxy(xpoz,ypoz);
scanf("%d",&br);
}while(br<=0);

return br;
}

/* Funkcija zbirdeo je u stanju da izracuna zbir cele periode ili dela periode. Parametar k
opisuje koliko clanova niza treba sabrati, a da su manji ili jednaki od duzine periode. */
int zbirdeo(int k)
{
int i,p,q,pom,s;

if(k==1) return 1;
if(k==2) return 2;

p=1,q=1,s=2;
for(i=3;i<=k;i++)
{
/* Parnost je ispitivana pomocu bita parnosti. */
if(i&0x1) pom=q, q=p+q, p=pom;
else pom=q, q=p*q, p=pom;
s+=q;
}

13
return s;
}

/* Funkcija zbir izracuvava trazeni zbir pozivajuci funkciju zbirdeo. Funkcija zbirdeo je
sposobna da izracuna deo ili celu periodu. Nema nikakvih problema prilikom poziva jedne u
okviru druge funkcije. Promenljive koje ;ine deo izraza od stvarnih argumenata funkcije moraju
biti lokalne promenljive funkcije u okviru koje se vrsi poziv, ili promenljive koje su prosledjene
funkciji u okviru koje se vrsi poziv druge funkcije.
U ovom slucaju su promenljive n i p formalni parametri funkcije zbir a kao takvi mogu
ucestvovati u izrazima koji pretstavljaju stvarne parametre funkcije zbirdeo.*/

int zbir(int n, int p)


{
int s=0;

/* Na osnovu n i p moze se zakljuciti da ima n/p celih perioda i mozda jedan deo ostatka
periode koji ima n%p clanova. */

if(n%p!=0) s+=(n/p)*zbirdeo(p)+zbirdeo(n%p);
else s+=(n/p)*zbirdeo(p);

return s;
}

void main(void)
{
int p, n;
unsigned xn=-1, yn=-1, xp=-1, yp=-1;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\n\n\tPerioda je: ");


xp=wherex(), yp=wherey();
p=unesi(xp,yp);

printf("\n\n\tKoliko clanova treba sabrati: ");


xn=wherex(), yn=wherey();
n=unesi(xn,yn);
printf("\n\n\n\n\tTrazeni zbir je: %d",zbir(n,p));

gotoxy(1,25);
getch();
}

14
1.5. PROTOTIPOVI FUNKCIJA

Prototip funkcije pretstavlja deklaraciju funkcije i nastaje navođenjem prazne


naredbe umesto tela funkcije.

tip naziv_funkcije(lista _argumenata);

Prototipovi funkcija mogu da se pišu u datotečkom ili blokovskom dosegu, što


određuje deo programa u kojem je prototip u važnosti. Prototipovi se najčešće pišu u
datotečkom dosegu. U glavnom programu nalazi se iznad main funkcije. Uloga prototipa
je samo da prevodiocu ukaže na namenu njihovih argumenata.
Na primer:
int zbir(int n, int p);

Ovaj prototip ukazuje prevodiocu da će se kasnije koristiti funkcija zbir koja vraća
podatak tipa int i da funkcija zbir ima dva argumenta tipa int. Njega uopšte ne zanimaju
promenljive n i p. Iz tih razloga dozvoljeno je pisanje prototipa funkcije i u sledećem
obliku.
int zbir(int , int );
Posmatraćemo primer 2 sa časa 6. Ako bismo izvršili zamene mesta definisanja
funkcija zbir i zbirdeo program bi imao grešaka, jer se u funkciji zbir poziva funkcija
zbirdeo koju prevodilac „ne poznaje“. Korišćenjem prototipova funkcija ne moramo
voditi računa o rasporedu definicija funkcija, a definisanje funkcija se izvode u
proizvoljnom poretku ispod tela main funkcije.

Primer:
Napisati C program koji korišćenjem funkcije suma izračunava zbir prvih n
članova beskonačnog periodičnog niza periode p.
Beskonačni niz ima sledeći oblik:

1, 1, 2, 2, 4, 8, 12, 96, ...,1, 1, 2, 2, 4, 8, 12, 96,..., 1, 1, 2, 2, 4, 8, 12, 96, ...

U funkciji suma koristiti funkciju zbir koja može na osnovu unetog broja k da
sabira celu periodu (ako je k=p) ili deo periode (ako je k<p) beskonačnog niza.
Zadatak rešiti bez korišćenja nizova.

Rešenje

#include <stdio.h>
#include <conio.h>

/* Prototipovi funkcija koje se koriste u programu. */


int unesi(int xpoz, int ypoz);
int zbir(int n, int p);
int zbirdeo(int k);

15
void main(void)
{
int p, n;
unsigned xn=-1, yn=-1, xp=-1, yp=-1;

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("\n\n\tPerioda je: ");


xp=wherex(), yp=wherey();
p=unesi(xp,yp);

printf("\n\n\tKoliko clanova treba sabrati: ");


xn=wherex(), yn=wherey();
n=unesi(xn,yn);
printf("\n\n\n\n\tTrazeni zbir je: %d",zbir(n,p));

gotoxy(1,25);
getch();
}

/* Omogucava unos pozitivnog broja na zadatoj poyiciji. Koristi se kao funkcija jer se
posebno mora uneti podatak kolika je perioda i podatak koliko elemenata treba sabrati. */
int unesi(int xpoz, int ypoz)
{
int br;

do{
gotoxy(xpoz,ypoz);
printf(" ");
gotoxy(xpoz,ypoz);
scanf("%d",&br);
}while(br<=0);

return br;
}

/* Funkcija zbir izracunava trazeni zbir pozivajuci funkciju zbirdeo. */


int zbir(int n, int p)
{
int s=0;

/* Na osnovu n i p moze se zakljuciti da ima n/p celih perioda i mozda jedan deo
ostatka periode koji ima n%p clanova. */

if(n%p!=0) s+=(n/p)*zbirdeo(p)+zbirdeo(n%p);
else s+=(n/p)*zbirdeo(p);
return s;
}

16
/* Funkcija zbirdeo je u stanju da izracuna zbir cele periode ili dela periode. Parametar k
opisuje koliko clanova niza treba sabrati, a da su manji ili jednaki od duzine periode. */

int zbirdeo(int k)
{
int i,p,q,pom,s;

if(k==1) return 1;
if(k==2) return 2;

p=1,q=1,s=2;
for(i=3;i<=k;i++)
{
/* Parnost je ispitivana pomocu bita parnosti. */
if(i&0x1) pom=q, q=p+q, p=pom;
else pom=q, q=p*q, p=pom;
s+=q;
}

return s;
}

Test primer programa:

17
1.6. REKURZIVNE FUNKCIJE

Algoritamske strukture u opštem slučaju mogu biti rekurzivne ili iterativne.


Programski jezik C podržava rešavanje oba tipa algoritama koristeći iterativne i
rekurzivne funkcije.
Osnovna ideja rekurzije uključuje dva aspekta:
 Da se poznati problem redukuje na jednostavnije.
 Da se u rešavanju problema svakim rekurzivnim korakom približavamo
željenom rešenju izmenom parametara prvobitnog problema.

Definicija rekurzivne funkcije:


Rekurzivne funkcije su funkcije koje neposredno ili posredno pozivaju same
sebe.
Rekurzivna rešenja su po pravilu manje efikasna od iterativnih rešenja istih
problema. Dešava se da rekurzivna rešenja traju neprihvatljivo dugo, ili se traži
dosta operativne memorije na steku za čuvanje međustanja između rekurzija.

Princip funkcionisanja rekurzije objasniće se najlakše na primeru.

Primer 1:
Napisati C program koji pozivanjem rekurzivne funkcije prikaz na ekranu na
osnovu unetog prirodnog broja n prikazuje ispis brojeva: 1 2 3 … n n … 3 2 1.

Rešenje

#include <stdio.h>
#include <conio.h>

/*Prototip rekurzivne funkcije. */


void prikaz(int k, int n);

void main(void)
{
int n, xn, yn;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

/*Unos prirodnog broja n. */


printf("\n\tN = ");
xn=wherex(), yn=wherey();

do{
gotoxy(xn,yn);
printf(" ");

18
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0);

/*Pozivanje rekurzivne funkcije. */


prikaz(1, n);
getch();
}

/*Definisanje rekurzivne funkcije. */


void prikaz(int k, int n)
{
printf("%d\t",k);

/*U ovom redu se vidi da je prikaz rekurzivna funkcija jer u okviru svog tela
poziva sama sebe. */
if(k<n) prikaz(k+1,n);

printf("%d\t",k);
}

Analiziraćemo program na pretpostavku da je korisnik programa uneo da je n=3.


Nakon poziva funkcije formalni parametar k dobija stvarnu vrednost 1 i formalni
parametri se u obliku aktivacionog zapisa upisuju na stek, a pokazivač steka se povećava
za 1 na sledeću lokaciju.

STEK
k: 1,Aktivaciono
n: 3 Aktivacioni zapis 1.
Pok na stek

Funkcija prikaz poziva sama sebe, ali sa promenjenim parametrom (što je i odlika
rekurzije). Kako se funkcija pozvala na steku se formira njen aktivacioni zapis sa novim
vrednostima parametara i pokazivač steka se povećava za 1 na sledeću lokaciju.

STEK
k: 1,Aktivaciono
n: 3 Aktivacioni zapis 1.
k: 2, n: 3
Aktivacioni zapis 2.
Pok na stek

19
Na ekranu se štampa broj 2 i ponovno poziva rekurzivna funkcija prikaz sa
promenjenim parametrom k. Na steku se stvara novi aktivacioni zapis.

STEK
k: 1,Aktivaciono
n: 3 Aktivacioni zapis 1.
k: 2, n: 3
Aktivacioni zapis 2.
k: 3, n: 3
Aktivacioni zapis 3.
Pok na stek

Na ekranu se ispisuje broj 3, uslov nije ispunjen u if selekciji, te se ponovno ispisuje


broj 3 na ekranu. Kako se došlo do kraja funkcije uništava se aktivacioni zapis 3,
pokazivač na stek se smanjuje za 1.

STEK
k: 1,Aktivaciono
n: 3 Aktivacioni zapis 1.
k: 2, n: 3
Aktivacioni zapis 2.
Pok na stek

Izvršava se na prva sledeća naredba iz funkcije prikaz koja odgovara aktivacionom


zapisu 2, tj štampaće se ponovno broj 2. Dolazi se do kraja funkcije te se sa steka
uništava aktivacioni zapis 2, a pokazivač steka se smanjuje za 1. Ponovno se izvršava
prva sledeća naredba iz funkcije prikaz sa parametrima koji odgovaraju tom
aktivacionom zapisu.

STEK
k: 1,Aktivaciono
n: 3 Aktivacioni zapis 1.
Pok na stek

20
Nakon završetka funkcije prikaz sa parametrima koji odgovaraju aktivacionom
zapisu 1 vraćamo se u glavni program.

Iz navedenog principa funkcionisanja rekurzivnih funkcija mogu se uočiti sledeće


osobine:
 Prilikom rada sa rekurzivnim funkcijama potrebno je da rekurzivna funkcija
ima što manje argumenata i da po pravilu nema lokalnih promenljivih, jer se
na taj način neće bespotrebno opterećivati stek.
 Programer ne upravlja mehanizmom čuvanja stanja funkcije na steku pre
rekurzivnog stanja i obnavljanja stanja po povratku iz rekurzivnog poziva,
jer se to dešava automatski.
 U okviru funkcije neki od parametara se mora porediti sa nekom
konstantnom vrednošću kako bi se iz rekurzije moglo izaći, u suprotnom
program bi se beskonačno dugo izvršavao.
 Ako se koristi rekurzija prethodno se problem mora prikazati u rekurzivnom
duhu.

Primer 2:
Napisati C program koji korišćenjem rekurzivne funkcije suma izračunava zbir
elemenata niza A od n članova n<31.

Rešenje

Prvo se mora definisati rekurzivna zakonitost.


Zbir elemenata niza = prvi element + zbir ostalih elemenata.

#include <stdio.h>
#include <conio.h>

#define MAX_NIZ 30

/*Prototip rekurzibne funkcije. */


int zbir(int a[], int n);

void main(void)
{
int a[MAX_NIZ], n, pom;
unsigned i, j, xn, yn, xu, yu;

/*Inicijalizacija niza. */
for(i=0;i<MAX_NIZ;i++) a[i]=0;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

21
printf("Broj elemenata niza je:\n\tN = ");
xn=wherex(), yn=wherey();

do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0||n>MAX_NIZ);

printf("Unesite elemente niza X:\n");


xu=wherex(), yu=wherey();

/* Niz se unosi pomocu ciklusa. */


for(j=0,i=0;i<n;i++)
{
if(j==16)
{
j=j%16;
yu++;
xu=1;
}
gotoxy(xu+5*j,yu);
scanf("%4d",&a[i]);
j++;
}

printf("\n\nZbir = %d", zbir(a, n));


getch();
}

/*Definisanje rekurzivne funkcije. */


int zbir(int a[], int n)
{
return (n>0) ? a[0] + zbir(a+1, n-1) : 0;
}

22
2. POGLAVLJE

POKAZIVAČI

23
2.1. POKAZIVAČI

Definicija pokazivača:
Pokazivač je promenljiva koja sadrži adresu druge promenljive ili funkcije.

Kada se započne program operativni sistem priprema različita područja


memorije, bazirajući se na zahtevima vašeg kompajlera. Program raspolaže sa
sledećim područjima memorije: zona podataka, registarska memorija, zona za kod,
stek i hip.

Pored direktnog i indeksnog adresiranja koristi se i indirektno adresiranje.


Pokazivači koriste indirektan pristup vrednostima programskih promenljivih korišćenjem
njihovih memorijskih adresa. Pokazivači obično zauzimaju 2 ili 4 bajta. Broj bajtova koje
zauzima pokazivač zavisi od mogućeg opsega adresa na datom računaru, a ne od broja
bajtova koliko zauzima pokazivani podatak. Kada neki podatak sadrži više bajtova, pod
adresom podatka podrazumeva se bajt sa najmanjim rednim brojem.
U neposrednoj vezi sa pokazivačima su dva specijalna operatora programskog
jezika C:
 Adresni operator & koji daje memorijsku adresu promenljive na koga je
primenjen.
 Operator diferenciranja * omogućava deklarisanje pokazivačke promenljive
i indirektan pristup do vrednosti za koje su korišćene pokazivačke
promenljive.

Deklaracija pokazivačke promenljive:

tip *pok;

Ovom deklaracijom pok je pokazivačka promenljiva koja je u stanju da pokazuje


(sadrži adresu) promenljive tipa tip. U deklaraciji se vidi da je pok pokazivačka
promenljiva jer se ispred nje nalazi operator *.

Inicijalizacija pokazivačke promenljive:


Inicijalizacija pokazivačke promenljive vrši se operatorom dodele gde se
pokazivačkoj promenljivoj dodeljuje NULL.

pok = NULL;

NULL – je simbolička konstanta koja se nalazi u biblioteci stdio.h i ima


vrednost 0.

Inicijalizacija pokazivačke promenljive može se izvršiti i prilikom deklaracije.

tip *pok=NULL;

24
Pokazivačka promenljiva pokazivaće na drugu promenljivu ako sadrži njenu adresu.
To se postiže na sledeći način.

pok = &prom;

U ovom slučaju pokazivačka promenljiva pok mora prethodno biti deklarisana tako
da pokazuje na promenljive tipa tip, a da je i promenljiva prom takođe tipa tip.

Na primer:
int *pok=NULL, a, b;

a=10, b=15;
pok = &a; /* pok sadrzi adresu od promenljive a. */
*pok=b; /* Podatak na koji pokazuje pokazivac pok dobija vrednost promenljive b,
a time i promenljiva a nema vise vrednost 10 vec 15. */
a++; /* vrednost promenljive a je sada 16. */
*pok+=5; /* vrednost promenljive a je sada 21. */

Primer 1:
Objasniti šta se dešava sa memorijskim lokacijama gde su smeštene promenljive a i
b (tokom čitavog koda).

#include <stdio.h>
#include <conio.h>

void main(void)
{
int a=10, b=2, *p1, *p2;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

p1=&a, p2=&b; /* p1 sadrzi adresu promenljive a, a p2 sadrzi adresu promenljive b. */


(*p1)++;
(*p2)--;
*p1+=a;
*p2-=*p1;
(*p2)--;
a+=*p2;
b=*p1;

printf("A = %d\tB = %d",a,b);


getch();
}

25
Rešenje

#include <stdio.h>
#include <conio.h>

void main(void)
{
int a=10, b=2, *p1, *p2; /* p1 i p2 su pokazivaci na promenljive tipa int. */

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

p1=&a, p2=&b; /* p1 sadrzi adresu promenljive a, a p2 sadrzi adresu promenljive b. */


(*p1)++; /* a = 11 */
(*p2)--; /* b = 1 */
*p1+=a; /* a = 22 */
*p2-=*p1; /* b = -21 */
(*p2)--; /* b = -22 */
a+=*p2; /* a = 0 */
b=*p1; /* b = 0 */

printf("A = %d\tB = %d",a,b); /* Stampanje vrednosti promenljivih a i b. */


getch();
}

a: 10, 11, 22, 0 b: 2, 1, -21, -22, 0

Adresna aritmetika sa pokazivačima:


 Dodela vrednosti jednog pokazivača drugom,
 Dodavanje celobrojnog podatka na vrednost pokazivača i oduzimanje
celobrojnog podatka od vrednosti pokazivača,
 Oduzimanje i upoređivanje dva pokazivača,
 Upoređivanje pokazivača sa nulom ili sa NULL, i
 Indentifikator niza je konstantan pokazivač (ne smete mu promeniti
adresu na koju pokazuje), na početak niza,
 Veza između niza i pokazivača može se pretstaviti pomoću formule

x[i]  *(x + i)

Primer 2:
Napisati C program koji isključivo korišćenjem pokazivača izračunava zbir
pozitivnih elemenata niza X od n elemenata n<31.

Rešenje

26
#include <stdio.h>
#include <conio.h>

#define MAX 30

void main(void)
{

int n,x[MAX], *pok=NULL;


unsigned xn,yn, br;

/*Inicijalizacija niza pomocu pokazivaca. */


pok=x;
while(pok-x<MAX) *pok=0, pok++;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("Broj elemenata niza je:\n\tN = ");


xn=wherex(), yn=wherey();
do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0||n>MAX);

printf("Unesite elemente niza X:\n");

/* Niz se unosi pomocu ciklusa, pri cemu ovde razlika pokazivaca pok-x pretstavlja
indeks niza Kako pok sadrzi adresu gde treba odgovarajuceg clana niza to nam u
funkciji scanf ne treba adresni operator. */

pok=x;
while(pok-x<n)
{
scanf("%d",pok);
pok++;
}

br=0;
pok=x;
while(pok-x<n)
{
if(*pok>0) br++;
pok++;
}
printf("Niz sadrzi %d pozitivnih elemenata.",br);

27
gotoxy(1,25);
getch();
}

Generički pokazivači:
Pored pokazivača na podatke poznatih tipova, postoje i generički pokazivači
kod kojih nije određen tip pokazivačkih podataka. Deklaracija generičkog
pokazivača vrši se stavljanjem rezervisane reči void umesto opisa tipa pokazivačkih
podataka.
void *pok;

Da bi se pomoću generičkog pokazivača pristupilo podacima potrebno je prethodno


izvršiti njegovu konverziju u poznati tip podatka.

Na primer:
int x, y, *pok1=NULL, *pok2=NULL;
void *pok3=NULL;

x=0;
y=5;

pok1=&x; /* pok1 sadrzi adresu promenljive x. */


*pok1++; /* Prvo ce se povecati adresa na koju pokazuje pokazivac pok za 1, a time
pok1 nece vise pokazivati na promenljivu x i pitanje je ciji smo to
podatak promenili. Znaci potrebno je pisati (*pok)++; */
pok2=&y; /* pok2 sadrzi adresu promenljive y. */
y++; /* povecava se vrednost promenljive y za 1. */
pok3=pok2, /* Sada i pokazivac pok3 sadrzi adresu promenljive y. */
*pok3=*pok3+4, /* Ovde je GRESKA jer genericki pokazivac ne moze promeniti
vrednost podatka na koji pokazuje pre nego sto se izvrsi
konverzija, a sto je ucinjeno u sledecem redu. */
*((int *)pok3)+=4;

28
2.2. PREDAJA PARAMETARA PO REFERENCI
BOČNI EFEKTI

Prenos parametara po referenci najlakše možemo objasniti kroz jedan prost zadatak.

Primer 1:
Napisati C program koji korišćenjem funkcije zameni vrši zamenu vrednosti dve
promenljive. Prototip funkcije zameni je void zameni(int a, int b);

Rešenje

#include <stdio.h>
#include <conio.h>

/* Prototip funkcije. */
void zameni(int a, int b);

void main(void)
{
int a, b;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

printf("\n\tUnesite podatke:\n");
printf("\ta = ");
scanf("%d",&a);
printf("\tb = ");
scanf("%d",&b);

/* Poziv funkcije */
zameni(a,b);

printf("\n\n\tNakon zamene je:\n");


printf("\ta = %d",a);
printf("\n\tb = %d",b);

gotoxy(1,25);
getch();
}

void zameni(int a, int b)


{
int pom;

pom=a;

29
a=b;
b=pom;
}

Ako istestiramo ovaj program videćemo da program ne radi ispravno. Ispisaće iste
vrednosti kao i pre poziva funkcije zameni. Problem leži u tome što formalni parametri a
i b respektivno pozivom funkcije zameni dobijaju stvarne vrednosti promenljivih a i b.
Formalni parametri nalaze se na steku i više nikakve veze nemaju sa promenljivama a i b
iz ZONE PODATAKA. Zamena će biti izvršena između formalnih promenljivih a i b.
Posle završetka funkcije sadržaj steka se briše, a time i sadržaj formalnih parametara.
Podaci a i b iz zone podataka ostali su nepromenjeni.

Problem možemo rešiti samo ako bismo pristupali promenljivama iz ZONE


PODATAKA u okviru funkcije zameni. Problem se rešava korišćenjem pokazivača koji
sadrže adrese (reference) promenljivih a i b iz zone podataka. Na taj način možemo u
okviru funkcije indirektno (diferenciranjem) menjati njihov sadržaj.

Rešenje pomoću prenosa parametara po referenci.

#include <stdio.h>
#include <conio.h>

/*Prototip funkcije. Kako su formalni argumenti pokazivaci radi se znaci o prenosu


parametara po referenci. */

void zameni(int *a, int *b);

void main(void)
{
int a, b;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

printf("\n\tUnesite podatke:\n");
printf("\ta = ");
scanf("%d",&a);
printf("\tb = ");
scanf("%d",&b);

/*Kada se poziva funkcija tamo gde se u prototipu funkcije nalazi pokazivac mora se
proslediti adresa promenljive uz pomoc adresnog operatora &. */

zameni(&a,&b);

printf("\n\n\tNakon zamene je:\n");


printf("\ta = %d",a);

30
printf("\n\tb = %d",b);

gotoxy(1,25);
getch();

/*Definisanje funkcije. */
void zameni(int *a, int *b)
{
/* Promenljiva pom je lokalna promenljiva. */
int pom;

pom=*a; /*Promenljiva pom dobija vrednost podatka ciju adresu sadrzi formalni
parametar a, a to je vrednost promenljive a iz zone podataka. */

*a=*b; /*Promenljiva a iz zone podataka dobija vrednost promenljive b iz zone podataka.


*/

*b=pom; /*Promenljiva b iz zone podataka dobija vrednost lokalne promenljive pom. */


}

Startovanjem programa vidi se da će promenljive a i b zameniti vrednosti.

Funkcija može da vrati samo jednu vrednost. Nekada je to dovoljno, međutim


uglavnom je potrebno da funkcija uradi više stvari. Funkcija može uraditi više stvari na
osnovu prenosa parametara po referenci.

Funkciji se prosledi adresa promenljive iz zone podataka, i nakon završetka


funkcije u njoj se nalazi jedan od rezultata, dok se jedan rezultat prosledio preko naredbe
return. Ako funkcija prenosom parametara po referenci zapamti rešenje drugog problema,
kaže se da je funkcija rešila taj problem bočnim efektom.

Najčešće se funkcije tako i realizuju da se u povratnoj vrednosti vraća neka


vrednost koja ukazuje da li je funkcija obavila uspešno zadatak, ili šta je obavila, dok
se bočnim efektima funkcija obavlja jedan ili više zadataka..

Primer 2:
Napisati šta radi sledeći program i objasniti šta radi funkcija pronadji.

#include <stdio.h>
#include <conio.h>

#define MAX 50

void pronadji(int x[], int a, int k);

31
void main(void)
{
int i,j,k,n,x[MAX];
unsigned xu, yu;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

printf("\n\n\tN = ");
xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0||n>50);

for(i=0;i<n;i++) x[i]=i+1;

printf("\nNiz nakon formiranja:\n");


for(i=0;i<n;i++) printf("%5d",x[i]);

for(i=0;i<n-1;i++) pronadji(x,0,n-i-1);

printf("\n\nNiz nakon izvrsene modifikacije funkcijom:\n");


for(i=0;i<n;i++) printf("%5d",x[i]);
getch();
}

void pronadji(int x[], int a, int k)


{
int pom, i;

pom=*(x+a);
for(i=a;i<k;i++) *(x+i)=*(x+i+1);
*(x+k)=pom;
}

Rešenje

Program na osnovu unetog broja n formira niz od n elemenata čiji članovi imaju
vrednost jednaku rednom broju člana niza. Korišćenjem funkcije pronađi niz se
modifikuje tako da postaje zapisan u inverznom poretku i takav se ponovno štampa na
ekranu.
Funkcija pronadji vrši rotaciju niza X između indeksa a i k za jedno mesto u levo.

32
Primer 3:
Napisati šta radi sledeći program i objasniti šta radi funkcija utvrdi.

#include <stdio.h>
#include <conio.h>

#define MAX 50

void uradi(int x[], int *a, int k);

void main(void)
{
int i,j,k,n,x[MAX],a=0;
unsigned xu, yu;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

printf("\n\n\tN = ");
xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0||n>50);

for(i=0;i<n;i++) x[i]=i+1;

printf("\nNiz nakon formiranja:\n");


for(i=0;i<n;i++) printf("%5d",x[i]);

for(i=0;i<n;i++) uradi(x,&a,i);
uradi(x,&a,0);

printf("\n\nNiz nakon izvrsene modifikacije funkcijom:\n");


for(i=0;i<n;i++) printf("%5d",x[i]);
getch();
}

void uradi(int x[], int *a, int k)


{
int pom;

pom=*a;
*a=*(x+k);
*(x+k)=pom;
}

33
Rešenje

Program na osnovu unetog broja n formira niz od n elemenata čiji članovi imaju
vrednost jednaku rednom broju člana niza. Korišćenjem funkcije uradi niz se modifikuje
tako da postaje zarotiran za jedno mesto u desno i takav se ponovno štampa na ekranu.
Funkcija uradi vrši zamenu vrednosti elementa niza X na k-toj poziciji sa vrednosti
promenljive a.

Primer 4:
Napisati C program koji proverava da li elementi datog niza X od n članov n< 51
obrazuju:

a) aritmetičku, ili
b) geometrijsku progresiju

Za određivanje da li niz obrazuje aritmetičku ili geometrijsku progresiju koristiti


funkciju utvrdi, koja vraća -1 ako je niz aritmetički, -2 ako je niz geometrijski ili 0 ako
niz nije aritmetički ni geometrijski.
Prenosom podataka po referenci funkcija utvrđuje d ako je niz aritmetički i q ako
je niz geometrijski.

Rešenje

#include <stdio.h>
#include <conio.h>

#define MAX 50

/*Prototip funkcije. */
int utvrdi(int x[], int n, int *d, float *q);

void main(void)
{
int n,d,x[MAX];
unsigned xn,yn,xu,yu,i,j;
float q;

/*Inicijalizacija niza. */
for(i=0;i<MAX;i++) x[i]=0;

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("Broj elemenata niza je:\n\tN = ");


xn=wherex(), yn=wherey();
do{
gotoxy(xn,yn);

34
printf(" ");
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0||n>MAX);

printf("Unesite elemente niza X:\n");


xu=wherex(), yu=wherey();

/* Niz se unosi pomocu ciklusa. */


for(j=0,i=0;i<n;i++)
{
if(j==16)
{
j=j%16;
yu++, xu=1;
}
gotoxy(xu+5*j,yu);
scanf("%4d",&x[i]);
j++;
}

/*Kako funkcija vraca jednu od tri vrednost sta je zakljucila koristicemo switch
strukturu. */

switch(utvrdi(x,n,&d,&q))
{
case -1: printf("\nNiz je aritmeticki!!\n\n\td = %d",d);
break;
case -2: printf("\nNiz je geometrijski!!\n\n\tq = %.2f",q);
break;
default: printf("\nNiz nije aritmeticki ni geometrijski!!");
}

gotoxy(1,25);
getch();
}

/*Definisanje funkcije. */
int utvrdi(int x[], int n, int *d, float *q)
{
unsigned i;

/*Prvo utvrdjujemo da li je niz aritmeticki. */


*d=x[1]-x[0];
i=1;
while(i<n&&x[i]-x[i-1]==*d) i++;
if(i==n) return -1;

/*Niz nije geometrijski ako je vrednost prvog clana niza 0. */


if(x[0]==0) return 0;

35
/*Utvrdjujemo da li je niz geometrijski. */
*q=x[1]/x[0];
i=1;
while(i<n&&x[i]==x[i-1] * (*q)) i++;
if(i==n) return -2;

return 0;
}

Test primer programa:

Primer 5:
Zadati su celobrojni nizovi A od n elemenata i B od m elemenata. Napisati C
program koji na osnovu nizova A i B formira niz C po sledećim pravilima.
 Niz C imaće isti broj elemenata kao i niz B,
 I-ti element niza C dobija se sabiranjem
odgovarajućih elemenata niza A (redom sleva na desno ili sa desna na levo), koliko je po
apsolutnoj vretnosti vrednost i-tog elementa niza B,
 Ako je vrednost i-tog elementa niza B pozitivna
sa sabiranjem se kreće sa leva na desno, a ako je negativna sa desna na levo,
 Ako je vrednost elementa niza B nula, tada je
odgovarajuća vrednost elementa niza C jednaka vrednosti elementa niza A na kojoj se
trenutno u nizu A nalazimo,
 Prvi element niza C dobija se sa sabiranjem
počev od prvog elementa iz niza A, dok se ostali dobijaju sabiranjem od trenutne pozicije
gde se sa sabiranjem završilo prilikom dobijanja predhodnog elementa, i
 Ako se dođe do kraja ili početka niza sa
sabiranjem se nastavlja u suprotnom smeru.
Za sabiranje elemenata sa leva na desno koristiti funkciju sabdesno, a za sabiranje
elemenata sa desna na levo koristiti funkciju sablevo.

Test primer: A = 3 5 7 3 1 8 4 2 7 9
B = 4 15 -12 0 -3

36
Niz C imaće sledeći izgled C = 18 75 55 7 13
Rešenje

#include <stdio.h>
#include <conio.h>
#include <math.h>

#define MAX_NIZ 30

/*Prototipovi funkcija. */
int sabdesno(int *s,int n,int a[],unsigned *k,unsigned *j);
int sablevo(int *s,int a[],unsigned *k,unsigned *j);

void main(void)
{
int s,n,a[MAX_NIZ], m,p,b[MAX_NIZ],c[MAX_NIZ];
unsigned i,j,k,xn,yn,xm,ym,xu,yu;
for(i=0;i<MAX_NIZ;i++) a[i]=b[i]=c[i]=0;

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("Broj elemenata niza A je:\n\tN = ");


xn=wherex(), yn=wherey();

do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0||n>MAX_NIZ);

printf("Unesite elemente niza A:\n");


xu=wherex(), yu=wherey();

/* Niz se unosi pomocu ciklusa. */


for(j=0,i=0;i<n;i++)
{
if(j==16) j=0, yu++, xu=1;

gotoxy(xu+5*j,yu);
scanf("%4d",&a[i]);
j++;
}

printf("\n\nBroj elemenata niza B je:\n\tM = ");


xm=wherex(), ym=wherey();
do{

37
gotoxy(xm,ym);
printf(" ");
gotoxy(xm,ym);
scanf("%d",&m);
}while(m<=0||m>MAX_NIZ);

printf("Unesite elemente niza B:\n");


xu=wherex(), yu=wherey();

/* Niz se unosi pomocu ciklusa. */


for(j=0,i=0;i<m;i++)
{
if(j==16) j=0, yu++, xu=1;

gotoxy(xu+5*j,yu);
scanf("%4d",&b[i]);
j++;
}

j=0; /* Sa indeksom j krecemo se kroz niz A, a sa indeksom i kroz niz B. */


for(i=0;i<m;i++)
{
k=abs(b[i]); /* Sa k promenljivom utvrdjujemo koliko elemenata niza A treba
sabrati. */

/* Promenljiva p govori u kom smeru se vrsi prolazak kroz niz A. Ako je p


pozitivno vrsi se sa leva na desno, ako je negativno sa desna na levo, a ako je
jednako nuli ne vrsi se sabiranje. */

if(b[i]<0) p=-1;
else{
if(b[i]>0) p=1;
else p=0;
}

/* Ako je p jednako 0 zbir je jednak elementu niza A gde se trenutno nalazimo u


nizu A a to nam govori indeks j. */
if(p!=0) s=0;
else s=a[j];

/* Sabiranje se vrsi sve dok je p razlicito od nule. Prenosom po referenci


prosledjuje se zbir s, jer se sa sabiranjem nastavlja i ako se promeni smer
kretanja, indeks j kojim se prolazi kroz niz A, jer se on stalno menja, i
promenljivu k koja nam stalno ukazuje koliko jos elemenata iz niza A treba
sabrati. */

while(p!=0)
{
if(p==1) p=sabdesno(&s,n,a,&k,&j);
else p=sablevo(&s,a,&k,&j);
}

38
c[i]=s;
}
/* Niz C ima isti broj elemenata kao i niz B. */
printf("\n\n\n\nNiz C je:\n");
for(i=0;i<m;i++) printf("%d ",c[i]);

gotoxy(1,25);
getch();
}

/*Funkcija sabdesno sabira prolazeci kroz niz A sa leva na desno. */


int sabdesno(int *s,int n,int a[],unsigned *k, unsigned *j)
{
unsigned i, p;

/* Prvo je potrebno ustanoviti da li ce se u ovom prolasku zavrsiti sa sabiranjem, te ako


jeste promenljiva p dobija vrednost nula, a ako ne promenljiva p dobija vrednost -1 koji
oznacava da ce se sa sabiranjem nastaviti u suprotnom smeru sdesna na levo. U tom
slucaju je potrebno odrediti koliko je jos elemenata ostalo za sabiranje u suprotnom
smeru I tu vrednost proslediti promenljivoj k. */

if(*k>n-(*j))
{
(*k)-=n-(*j);
for(i=*j;i<n;i++) *s+=a[i];
*j=n-1;
p=-1;
}else{
for(i=1;i<=*k;i++) *s+=a[*j],(*j)++;
(*j)--;
p=0;
}

/* Funkcija vraca vrednost koja odredjuje da li je sa sabiranjem zavrseno ili je potrebno


nastaviti u suprotnom smeru. */

return p;
}

/*Funkcija sabdesno sabira prolazeci kroz niz A sa desna na levo. */


int sablevo(int *s,int a[],unsigned *k,unsigned *j)
{
unsigned i, p;

if(*k>(*j)+1)
{
(*k)-=(*j)+1;
p=(*j)+1;
for(i=1;i<=p;i++)
{
*s+=a[*j];

39
(*j)--;
}
*j=0;
p=1;
}else{
for(i=1;i<=*k;i++) *s+=a[*j],(*j)--;
(*j)++;
p=0;
}

return p;
}

Test primer programa:

40
2.3. FUNKCIJE KOJE VRAĆAJU POKAZIVAČE
POKAZIVAČI NA FUNKCIJE

Funkcija i pokazivači omogućavaju četiri različita načina povezivanja:


1) tip fun(); - Deklariše funkciju koja vraća vrednost tipa tip.
2) tip *fun(); – Deklariše funkciju koja vraća pokazivač na vrednost tipa
tip.
3) tip (*pokf)(); - Deklariše pokazivač na funkciju koja vraća vrednost
tipa tip.
4) tip *(*pok)(); - Deklariše pokazivač na funkciju koja vraća pokazivač
na vrednost tipa tip.

Funkcije koje vraćaju pokazivače


Funkcije mogu naredbom return da vrate samo jednu vrednost. Osim vrednosti
rezultat može pretstavljati pokazivač (adresa neke memorijske lokacije). Pokazivač koji
se vraća mora odgovarati tipu povratne vrednosti.

Primer 1:
Napisati C program koji omogućava izbacivanje iz niza X od n elemenata (n<51),
sve one elemente koje imaju određenu vrednost. Izbacivanje elemenata vršiti funkcijom
izbaciizniza koja vraća broj izbačenih elemenata. U funkciji izbaciizniza koristiti
funkciju trazi koja utvrđuje da li u nizu ima elementa koga treba izbaciti i vraća adresu
elementa niza gde je pronađen ili NULL u suprotnom. Na ekranu štampati sažeti niz ili
poruku da je niz ostao nepromenjen.

Rešenje

#include <stdio.h>
#include <conio.h>

#define MAX 50

/* Prototipovi funkcija. */
unsigned izbaciizniza(int x[], int *n, int izbaci);
int *trazi(int izbaci, int x[], int n);

void main(void)
{
int izbaci,n,x[MAX];
unsigned xn,yn,xu,yu,i,j,k;

/* Inicijalizacija niza. */
for(i=0;i<MAX;i++) x[i]=0;

41
textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("Broj elemenata niza je:\n\tN = ");


xn=wherex(), yn=wherey();
do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0||n>MAX);

printf("Unesite elemente niza X:\n");


xu=wherex(), yu=wherey();
for(j=0,i=0;i<n;i++)
{
if(j==16)
{
j=j%16;
yu++;
xu=1;
}
gotoxy(xu+5*j,yu);
scanf("%4d",&x[i]);
j++;
}

printf("\nBroj koga izbacijes je: ");


scanf("%d",&izbaci);

/* Poziva se funkcija izbaci koja ako vrati vrednost 0 znaci da je niz ostao nepromenjen. */
if(izbaciizniza(x,&n,izbaci)!=0)
{
if(n!=0){
printf("\n\nSazeti niz X je:\n");
for(i=0;i<n;i++) printf("%d\t",x[i]);
}else printf("\n\nNiz vise nema elemenata!!");
}else printf("\n\nNiz je ostao nepromenjen!!");

gotoxy(1,25);
getch();
}

/* Funkcija izbaciizniza izbacuje iz niza sve one elemente koji imaju vrednost jednaku sa
vrednosti promenljive izbaci. U funkciji se n prenosi po referenci jer mu se u funkciji u
slucaju sazimanja menja vrednost. */

unsigned izbaciizniza(int x[], int *n, int izbaci)


{

42
unsigned i, k, br=0;
int *p=NULL;

/* Funkcija trazi vraca pokazivac na vrednost, te se morao deklarisati pokazivac


p koji ce prihvatiti adresu koju vraca funkcija trazi. */

while((p=trazi(izbaci,x,*n))!=NULL)
{

br++;

/* Indeks elementa niza jednak je razlici izmedju adrese tog elementa i


adrese pocetka niza. */

i=p-x;
for(k=i+1;k<*n;k++) x[k-1]=x[k];
x[*n-1]=0,(*n)--;
}

return br;
}

/* Funkcija trazi vraca pokazivac na element niza koji ima vrednost istu kao i vrednost
promenljive izbaci. */

int *trazi(int izbaci, int x[], int n)


{
unsigned i=0;

while(x[i]!=izbaci&&i<n) i++;

/* Adresa i-tog clana niza je x+i */


if(i<n) return x+i;
else return NULL;
}

Pokazivači na funkcije

Pokazivači pored toga što mogu da sadrže adresu podatka, mogu da sadrže i
adresu programskog koda.

Opšti oblik pokazivača na funkciju je:

tip (*indentifikator_pokazivača)(niz_tipova_argumenata);

indentifikator_pokazivača – je pokazivač koji se definiše.


niz_tipova_argumenata – određuje broj i tipove formalnih argumenata funkcija na
koje može da pokazuje pokazivač koji se definiše.

43
Priliko deklaracije zagrade u okviru kojih se nalazi pokazivač su neophodne, jer u
suprotnom umesto pokazivača na funkcije imali bi smo funkciju koja vraća pokazivač.
Zagrade omogućavaju da se prvo izvrši indirektno adresiranje pokazivača, čime dolazimo
do adrese funkcije, a u drugoj zagradi nalaze se argumenti nad kojima će se funkcija
izvršiti. Postoje dva slučaja kada se pokazivači najčešće koriste. Prvi je da pokazivač
zapamti adresu jedne od funkcija koja je izabrana, a da se naknadnim pozivanjem
pokazivača na funkciju odabrana funkcija izvrši. Drugi slučaj je da pokazivač na funkciju
predstavlja argument neke funkcije. Na taj način se adresa jedne funkcije pomoću
pokazivača na funkciju prenosi drugoj funkciji.

Primer 2:
Napisati C program koji omogućava unos niza od n, n<11 tačaka i tabelarni prikaz
vrednosti jedne od tri funkcije, na osnovu niza tačaka. Funkcije su:

ex
y  x 2  log* ( x 2  1), y x 2  1, i y
log( x 2  4)

Rešenje

#include <stdio.h>
#include <conio.h>
#include <math.h>

#define MAX 10

/* Prototipovi funkcija. */
void unos(double x[], int *n);
double fun1(double x);
double fun2(double x);
double fun3(double x);

/* Funkcija kao argument sadrzi pokazivac na funkciju. */


void tabela(double (*pok)(double ), double x[], int n);

void main(void)
{
int i,n=0;
double x[MAX];
char odluka;
for(i=0;i<MAX;i++) x[i]=0;

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

/* Unosi se niz X od n tacaka. */


unos(x,&n);

44
/* Vrsi se izbor jedne od tri ponuđene funkcije. */
printf("\nIzaberi jednu od tri sledece funkcije:\n");
printf("\t1: y = x²log(x²+1)\n"); /* ² - ALT+253 */
printf("\t2: y = (x²+1)«\n");
printf("\t3: y = exp(x)/log(x²+4)\n");
printf("\n\tVas izbor je: ");

do{
odluka=getch();
}while(odluka>'3'||odluka<'1');
printf("%c",odluka);

/* Prvi argument funkcije tabela je pokazivac na funkciju. Iz tog razloga njemu se


prosledjuje ime funkcije koje predstavlja adresu iz koda programa gde je pocetak
izvrsavanja te funkcije. */
switch(odluka)
{
case '1': tabela(fun1,x,n);
break;
case '2': tabela(fun2,x,n);
break;
case '3': tabela(fun3,x,n);
}
getch();
}

/* Funkcija unos omogucava unos niza tacak X od n elemenata. */


void unos(double x[], int *n)
{
unsigned xn,yn,xu,yu,i,j,k;

/* Vrsi se unos broja tacaka uz zastitu prilikom unosa. */


printf("Broj tacaka je:\n\tN = ");
xn=wherex(), yn=wherey();
do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
scanf("%d",&(*n));
}while((*n)<=0||(*n)>MAX);

printf("Unesite elemente niza tacaka X:\n");


xu=wherex(), yu=wherey();
for(j=0,i=0;i<*n;i++)
{
if(j==16) j=j%16, yu++, xu=1;
gotoxy(xu+5*j,yu);
scanf("%4lf",&x[i]);
j++;
}
}

45
/* Funkcija fun1 je prva funkcija iz izbora. */
double fun1(double x)
{
return x*x*log(x*x+1);
}

/* Funkcija fun2 je druga funkcija iz izbora. */


double fun2(double x)
{
return sqrt(x*x+1);
}

/* Funkcija fun3 je treca funkcija sa izbora. */


double fun3(double x)
{
return exp(x)/log(x*x+4);
}

/* Funkcija vrsi tabelarni prikaz apcise i odrinate funkcije. Prvi argumenat funkcije je
pokazivač na funkciju. */
void tabela(double (*pok)(double ), double x[], int n)
{
unsigned i;

printf("\n\n\tR.br. x f(x)\n");
printf("\t=============================================\n");

/* Pozivanjem pokazivaca na funkcija poziva se funkcija čiju adresu on poseduje.


Prilikom pozivanja pokazivaca na funkciju moraju se pisati i stvarni argumenti funkcije,
kao i kod obicnog poziva bilo koje funkcije. */

for(i=0;i<n;i++) printf("\t%2d.%20.3f%20.3f\n",i+1,x[i],(*pok)(x[i]));
}

Test primer programa:

46
2.4. FORMIRANJE SOPSTVENE BIBLIOTEKE FUNKCIJA

Pretprocesor u C jeziku omogućava da se u izvorni kod programa uključe


kompletne datoteke i na taj način se znatno ubrza razvoj programa. Direktiva #include
uključuje u izvornu datoteku takozvane datoteke zaglavlja (header file) koji ima
ekstenziju h. Postoje dva načina uključivanja datoteke zaglavlja u programu:

#include <imedatoteke.h>
#include “imedatoteke.h“

Prvi način pretražuje sistemske direktorijume u potrazi za datotekama zaglavlja,


dok drugi način pretražuje trenutni radni direktorijum gde se nalazi program. Kada mi
formiramo header datoteku uključujemo je na drugi način. Datoteka zaglavlja ima
ekstenziju h, formira se na isti način kao i datoteka koda programa sa ekstenzijom C.
Nakon editovanja koda u datoteci zaglavlja, datoteka se snimi pod ekstenzijom h i potom
kompajlira. Datoteka zaglavlja ne sadrži funkciju main i ne može se pozvati povezivač
(prijaviće se greška). Nakon kompajliranja stvoriće se objektni fajl. U datotekama
zaglavlja pored direktiva pretprocesora, definisanja novih tipova podataka, deklaracije
promenljivih, nalaze se prototipovi funkcija i izvršeno je njihovo definisanje.
Datoteke zaglavlja podržavaju osnovne koncepte modularnog programiranja. Kako
u programu može postojati više datoteka zaglavlja. Svaka datoteka zaglavlja sadrži
srodne funkcije (odnose se na isti pojam, rad sa mišem, rad sa stringovima, rad sa
menijima, sortovi, itd...). Datoteka zaglavlja sadrži funkcije koje pretstavljaju module.
Dobro kreirani modul komunicira sa spoljnim svetom samo preko parametara funkcije.
Na taj način se vrši zaštita podataka. Jednom formirani moduo povezivanjem datoteke
zaglavlja sa programom, možemo koristiti u više programa. Datoteke zaglavlja se
kompajliraju posebno što omogućava lakše otklanjanja grešaka.

Primer 1:
Napisati C program TEST1.C koji omogućava unos niza X od n elemenata i
njegovo sortiranje u rastućem redosledu i program TEST2.C koji formira niz Y od m
elemenata u opadajućem redosledu n<31 i m<41. Prilikom realizacije programa koristiti
funkcije unos_ceo koja omogućava unos celog broja tipa int, ali da se prilikom unosa
broja omogući zaštita unosa (ne dozvoljava unos drugih karaktera osim dekadnih cifara).
U hederu NIZ.H se pored opisane funkcije nalaze i funkcije:
unos_niza - koja omogućava unos niza pozivajući funkciju unos_ceo,
unos_brc - koja omogućava unos broja članava niza uz zaštitu unosa pozivajući
funkciju unos_ceo,
sort - koja vrsi sortiranje niza u rastućem ili opadajućem redosledu u određenom
intervalu, i
ispis_niza - koja omogućava ispis niza na ekranu.

Rešenje

47
NIZ.H

#include <stdio.h>

/* Prototipovi funkcija. */
int unos_ceo(void);
int unos_brc(unsigned m);
void unos_niza(int x[], int n);
void sort(int x[], int p, int q, int odl);
void ispis_niza(int x[], int n, int startx, int starty, int endx);

/* Funkcija unos_ceo omogucava unos celog broja. */


int unos_ceo(void)
{
unsigned xu, yu;
char c;
int x, pom=1;

/* Sa unosom broja pocinjemo od trenutne pozicije na ekranu. */


xu=wherex(); yu=wherey();
x=0;
do{
c=getch();

/* U slucaju da je predznak negativan promenljiva pom


dobija vrednost -1. */
if(c=='-'&&x==0) pom=-1, putch(c);

/* Cifra je ako je karakter veci od 48 a manji od 57, jer su to redni brojevi koji
odgovaraju decimalnim ciframa iy ASCII tabele. Prva cifra ne moye da bude 0.
*/
if((c>48&&c<=57)||(c==48&&x!=0))
{
x=x*10+c-48;
putch(c);
}

/* Znajuci da ako broj predje granicu 32767 automatski postaje negativan,


utvrdjujemo da li se to desilo I usled prekoracenja vracamo korisnika na ponovni
unos. */
if(x<0)
{
x=0;
pom=1;
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
}

}while(c!='\r' || x==0);

48
/* Vracamo dobijeni broj pomnozen sa zapamcenim predznakom. */
return x*pom;
}

/* Funkcija omogucava unos broja clanova niza koriscenjem funkcije unos_ceo, uz


kontrolu unosa gde je dimenzija niza zapamcena u promenljivoj m. */
int unos_brc(unsigned m)
{
unsigned xn, yn;
int n;

printf("Broj elemenata niza je:\n\tN = ");


xn=wherex(), yn=wherey();
do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
n=unos_ceo();
}while(n<=0||n>m);

return n;
}

/* Funkcija unos_niza omogucava unos elemenata niza pozivajuci funkciju unos_ceo. */


void unos_niza(int x[], int n)
{
unsigned xu, yu, i, j;

printf("Unesite elemente niza:\n");


xu=wherex(), yu=wherey();

/* Niz se unosi pomocu ciklusa. */


for(j=0,i=0;i<n;i++)
{
if(j==16) j=j%16, yu++, xu=1;
gotoxy(xu+5*j,yu);
x[i]=unos_ceo();
j++;
}
}

/* Funkcija sort omogucava sortiranje niza izmedju dva indeksa i to u rastucem redosledu
ako je odl jednak 1, a u opadajucem redosledu ako je odl razlicit od 1. */
void sort(int x[], int p, int q, int odl)
{
unsigned i, j;

for(i=p;i<=q-1;i++)
{
for(j=i+1;j<=q;j++)

49
{
if(odl==1)
{
if(x[j]<x[i]) x[i]+=x[j],x[j]=x[i]-x[j],x[i]-=x[j];
}else{
if(x[j]>x[i]) x[i]+=x[j],x[j]=x[i]-x[j],x[i]-=x[j];
}
}
}
}

/* Funkcija ispis_niza omogucava ispis elemenata niza pocev od startnih pozicija na ekranu
startx i starty, do granice endx. */
void ispis_niza(int x[], int n, int startx, int starty, int endx)
{
unsigned i, j, m, xs, ys;

/* Utvrdjujemo koliko se brojeva moze ispisati na ekranu, polazeci od cinjenice da je


maksimalni broj 32767, a minimalni -32768 sto odgovara 6 mesta na ekranu.. Taj podatak
se upisuje u promenljivu m. */

m=(endx-startx)/6;
gotoxy(startx,starty);
xs=startx;
ys=starty;

for(j=0,i=0;i<n;i++)
{
if(j==m)
{
j%=m;
ys++;
gotoxy(xs,ys);
}
printf("%-6d",x[i]);
j++;
}
}

TEST1.C

#include <stdio.h>
#include <conio.h>

/* Ukljucivanje datoteke zaglavlja niz.h u program. */

#include "niz.h"

#define MAX 30

void main(void)

50
{

/* Deklaracjia promenljivih. */

int x[MAX], n, i;

/* Inicijalizacija niza X. */
for(i=0;i<MAX;i++) x[i]=0;

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

/* Unos broja clanova niza X. */


n=unos_brc(MAX);
printf("\n\n");

/* Unos elemenata niza X. */


unos_niza(x,n);

/* Sortiranje elemenata niza X u rastucem redosledu. */


sort(x,0,n-1,1);

/* Ispis elemenata niza X. */


printf("\n\n\nSortirani niz:u rastucem redosledu:\n");
ispis_niza(x,n,wherex(),wherey(),79);

getch();

Test primer programa:

TEST2.C

51
#include <stdio.h>
#include <conio.h>

/* Ukljucivanje datoteke zaglavlja niz.h u program. */


#include "niz.h"
#define MAX_NIZ 40

void main(void)
{
/* Deklaracjia promenljivih. */
int y[MAX_NIZ], m, i;
/* Inicijalizacija niza Y. */
for(i=0;i<MAX_NIZ;i++) y[i]=0;

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

m=unos_brc(MAX_NIZ);
printf("\n\n");
unos_niza(y,m);

/* Sortiranje elemenata niza Y u rastucem redosledu. */


sort(y,0,m-1,2);

printf("\n\n\nSortirani niz u opadajucem redosledu:\n");


ispis_niza(y,m,wherex(),wherey(),79);
getch();
}

Test primer programa:

Primer 2:

52
Zadat je celobrojan niz X od n elemenata n<51 i celobrojni podatak p. Napisati C
program koji korišćenjem što većeg broja funkcija iz već formirane biblioteke NIZ.H na
ekranu štampa sve intervale niza koji imaju osobinu da je zbir elemenata niza sa tog
intervala jednak podatku p. Prilikom realizacije ovog problema zamislite da niz
predstavlja ogrlicu (posle zadnjeg elementa sledi prvi element niza). Interval mora
zadovoljiti osobinu da je veći ili jednak od 2 a manji ili jednak od n.
Deo niza koga obrazuje najveći interval i ujedno je zbir njegovih indeksa najveći, sa
gore navedenom osobinom, sortirati u rastućem redosledu a potom prikazati na ekranu
novonastali niz, kao i broj zamena elemenata niza koji se izvršio prilikom sortiranja dela
niza.

Na primer:
N = 12
X = 2 5 -6 4 3 2 1 2 23 4 1 2

P = 10

[1..6] 2 5 -6 4 3 2
[4..7] 4 3 2 1
[11..12] U [1..2] 1 2 2 5
12 U [1..5] 2 2 5 -6 4 3

Sortirani niz X = 2 2 3 4 5 2 1 23 4 1 -6
Prilikom sortiranja izvrsene su 3 izmene.

Rešenje

#include <stdio.h>
#include <conio.h>
#include "niz.h"

#define MAX_NIZ 50

/* Prototipovi funkcija. */
void inicijalizacija(int a[]);
unsigned intervali(int x[], int n, int p, int *a, int *b);
int sortint(int x[], int a, int b, int n);

void main(void)
{
int x[MAX_NIZ],n,p,a=0,b=0,br=0;
inicijalizacija(x);

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

53
/* Unos koliko ce niz imati elemenata uz ogranicenje da ne bude vece od dimenzije niza.
*/

n=unos_brc(MAX_NIZ);
printf("\n\n");

/* Unos elemenata niza. */


unos_niza(x,n);
printf("\n\np = ");

/* Unos broja koji se sabiranjem intervala mora dobiti. */


p=unos_ceo();
printf("\n\n");

if(!intervali(x,n,p,&a,&b)) printf("Nema trazenih intervala!!");


else{
/* Sortira deo niza u rastucem redosledu. */
br=sortint(x,a,b,n);

/* Prikaz niza nakon sortiranja. */


printf("\n\nNakon sortiranja niz X je:\n ");
ispis_niza(x,n,wherex(),wherey(),79);
/* Ispis podatka koliko je izvrseno zamena. */
if(br==1||br>4)
printf("\n\n\nPrilikom sortiranja izvrseno je %d izmena.",br);
else printf("\n\n\nPrilikom sortiranja izvrsene su %d izmene.",br);
}
getch();
}

/* Funkcija inicijalizacija vrsi inicijalizaciju niza. */


void inicijalizacija(int x[])
{
int i;

for(i=0;i<MAX_NIZ;i++)
{
x[i]=0;
}
}

/* Funkcija intervali ispisuje na ekranu sve intervale sa osobinom da je zbir elemenata niza
sa tog intervala jednak broju p. Ako postoji barem jedan slucaj da je funkcija ispisala bice
vracena 1 a u suprotnom bice vracena 0. Bocnim efektom odredjuje pocetak i kraj intervala
koji je imao najveci zbir indeksa, jer se taj interval posle mora sortirati u rastucem
redosledu. */

unsigned intervali(int x[], int n, int p, int *a, int *b)


{
int i,j,k,s=0,m, kon=0;

54
/* Kroz niz prolazimo sa dvostrukim ciklusom jer se mora ispitati svi podintervali. Indeks
koji oznacava pocetak intervala krece se od 0 do n-1 jer je niz povezan kao ogrlica, a
kako interval ne moze biti veci od n elemenata to se pocetak intervala moze u najgorem
slucaju desiti od poslednjeg clana niza (posle nastupaju ponovljeni slucajevi). Indeks
kraja intervala krece se od 2*n jer ogrlica moze da se opise sa duplim nizom (niz i
inverzni poradak tog istog niza). Kako mi u stvarnosti nismo formirali dupli niz, vec smo
to zamislil, osnovna ideja je da se operatorom % obeybedjuje da se takvo kretanje
ostvari. */

for(i=0;i<=n-1;i++)
{
for(j=2*n;j>i;j--)
{
/* Izracunava se zbir sa intervala izmedju indeksa i i j */
for(k=i,s=0;k<=j;k++) s+=x[k%n];

if(s==p)
{
/* Ispis granica intervala. */
if(i%n+1<j%n+1) printf("\n[%d..%d]\t",i%n+1,j%n+1);
else{
if(i%n+1==n) printf("\n%d U [1..%d]\t", i%n+1,j%n+1);
else{
if(j%n+1==1) printf("\n[%d..%d] U %d\t", i%n+1,j%n+1);
else printf("\n[%d..%d] U [1..%d]\t", i%n+1,n,j%n+1);
}
}
/* Ispis elemenata sa tog intervala. */
for(m=i;m<=j;m++) printf("%d ",x[m%n]);
if(i>(*a)&&j>(*b)) (*a)=i,(*b)=j;
kon=1;
}
}
}
return kon;
}

/* Funkcija sortint sortira najveci interval koji yadovoljava svojstvo da mu je ybir jednak
broju p I ujedno ako ih ima vise poseduje najveci zbir indeksa. Funkcija vraca broj
izvrsenih zamena elemenata prilikom sortiranja intervala.*/
int sortint(int x[], int a, int b, int n)
{
int i,j,min,pom,poz,br=0;

/* Ovde je prikazana tehnika sortiranja gde se najmanji element smesta na pocetak


intervala, pa se posmatra podinterval gde nema prvog, odredi opet najmanji i smesti na
pocetnu poziciju tog podintervala, itd... */
for(i=a;i<b;i++)
{
min=x[i%n];
poz=i;

55
for(j=i;j<=b;j++) if(x[j%n]<min) min=x[j%n], poz=j%n;
if(x[i%n]!=min) br++;
pom=x[i%n];
x[i%n]=min;
x[poz%n]=pom;
}
return br;
}

Test primer programa:

56
2.5. ZADACI IZ FUNKCIJA

Zadatak 1 (2)
Napisati C program koji na osnovu unetog prirodnog broja n i racionalnog broja x
izračunava i štampa sumu zaokruženu na četiri decimale. Sumu računati pozivom
funkcije suma čija je sintaksa: double suma(int n, double x);
Suma je zadata oblikom:

x x2 x3 xn
S  1    ...  n
x  1 x2  1  2 x3  1  2  3 x  1  2  3  ...  n

Zadatak 2 (2)
Napisati C program koji na osnovu unetih prirodnih brojeva n i x izračunava i
štampa sumu zaokruženu na tri decimale. Sumu računati pozivom funkcije suma.
Suma je zadata oblikom:

3  x 3  (1  2) 4  x 4  (1  2  3) n  x n  (1) n  (1  2  3  ...  n  1)
S  1 x    ... 
2  x2 1 2  3 2  x3 1 2  3  4 (n  1)  x n1  1  2  3  ...  n

Zadatak 3 (2)
Napisati C program koji korišćenjem unetog prirodnog neparnog broja n (2<n>12),
pozivom funkcije slika prikazuje na ekranu sliku od zvezdica sledećeg izgleda:

******************
*****************
****************
*** * *
*** *** *
*** ***** *
*** ******* * Za n = 7 je napravljena ova slika,
*** ***** * a 2n je broj zvezdica kvadrata.
*** *** *
*** * *
****************
*****************
******************

Oko kvadrata nalazi se ram koji se uvek sastoji od dva reda zvezdica.
U unutrašnjosti kvadrata nalazi se deltoid čija manja dijagonala ima n zvezdica.

57
Zadatak 4 (2)
Napisati C program koji na osnovu unetog prirodnog broja n izračunava zbir
kvadrata prvih n prirodnih brojeva. Za izračunavanje zbira koristiti funkciju zbir.

Zadatak 5 (2)
Napisati C program koji na osnovu unetog prirodnog broja n izračunava
korišćenjem funkcije zbir, zbir prvih n članova niza:

3, -6, 12, -24, 48, -96, ...

Zadatak 6 (2)
Napisati C program koji na osnovu unesenih stranica kvadra a, b i c pozivom
funkcije kvadar izračunava i vraća površinu kvadra a po referenci određuje zapreminu
kvadra.

Zadatak 7 (2)
Napisati C program koji korišćenjem funkcije suma izračunava zbir pozitivnih
elemenata celobrojnog niza X. Niz X ima n elemenata (n<41).

Zadatak 8 (2)
Zadati su celobrojni nizovi X i Y od po n elemenata n<50. Napisati C program koji
na osnovu nizova X i Y formira niz Z po sledećem pravilu: z[i] = max(x[i],y[i]), i=[1..n]
Odgovarajući element niza Z dobija se pozivom funkcije max.

Zadatak 9 (2)
Napisati C program koji pozivom funkcije trazi, utvrđuje da li se u celobrojnom
nizu X od n (n<31) elemenata nalazi broj p. Ako se broj p nalazi u nizu funkcija vraća 1
a u suprotnom 0.

Zadatak 10 (2)
Napisati C program koji korišćenjem funkcije minmax određuje po referenci
vrednosti minimalnog i maksimalnog elemenata celobrojnog niza X. Niz X ima n
elemenata (n<41). Funkcija nema povratne vrednosti.

Zadatak 11 (3)
Napisati C program koji na osnovu celobrojnog niza X formira niz Y. I-ti element
niza Y (i=[1..n]) jednak je zbiru svih prethodnika od i-tog elementa niza X. Za
izračunavanje zbira prethodnika koristiti funkciju zbir.

Zadatak 12 (3)
Napisati C program koji korišćenjem funkcije min određuje po referenci vrednosti
minimalnog elemenata celobrojnog niza X, a vraća broj minimalnih elemenata niza. Niz
X ima n elemenata (n<41).

Zadatak 13 (3)

58
Napisati C program koji vrši konverziju dekadnog broja n (n<250) u njegov binarni
ekvivalent i vrši njegov binarni ispis na ekranu. Pretvaranje i ispis realizovati funkcijom
bin_ispis.

Zadatak 14 (3)
Napisati C program koji na osnovu unetog prirodnog broja n izračunava pozivom
funkcije zbir, zbir prvih n članova niza:

1, 1, 2, 5, 7, 74, ...

Prva dva člana niza imaju vrednost 1, a počev od trećeg svaki sledeći član dobija se
kao zbir kvadrata predhodna dva člana.

Zadatak 15 (3)
Napisati C program koji na osnovu unetog prirodnog broja n korišćenjem funkcije
prost utvrđuje i na ekranu štampa sve proste brojeve koji se nalaze na intervalu 1..n.
U funkciji prost pozivati funkciju utvrdi koja utvrđuje da li je broj k sa intervala
1..n prost, te vraća 1 ako jeste ili 0 u suprotnom.

Zadatak 16 (3)
Eksponencijalna funkcija y  e x može se izračunati razvojem u Maklorenov red,
kao:
x2 x3 xk
ex  1 x    ... 
1 2 1 2  3 1  2  3  ...  k

pri čemu je k korak, ili broj članova u razvoju.


Napisati C program koji korišćenjem funkcije ekspo izračunava približnu vrednost
eksponencijalne funkcije y  e x za zadat broj koraka k i zadat argument x, i štampa
razliku između tog rezultata i rezultata dobijenog pozivom bibliotečke funkcije exp čija je
sintaksa double exp(double x); i nalazi se u math.h.

Zadatak 17 (3)
Napisati C program koji korišćenjem funkcije datum na osnovu rednog broja dana
u godini ispisuje datum koji odgovara tom rednom broju. Funkcija vraća 1 ako je redni
broj korektan, a u suprotnom 0. Funkcijom korišćenjem bočnog efekta odrediti dan i
redni broj meseca.

Zadatak 18 (3)
Zadat je celobrojan niz A od n elemenata n<100. Napisati C program koji za uneto
k, vrši pozivom funkcije rotiraj rotiranje niza za k elemenata. Ako je k>0 vrši se
rotiranje za k elemenata u desno, ako je k<0 za k elemenata u levo, a za k=0 ne vrši se
rotacija niza. Funkcija vraća 0 ako nije vršila rotaciju niza, a u suprotnom vraća 1.

Zadatak 19 (3)

59
Brojčano su dati dan, mesec i godina. Ispisati dan u mesecu, naziv datog meseca,
godinu i dan u godini. Za izračunavanje dana u godini napisati funkciju reddan.

Na primer:

Dan: 15
Mesec:3 => 15 mart 1987 dan 74
Godina:1987

Zadatak 20 (3)
Zadat je celobrojan niz A od n elemenata n<100. Napisati C program koji na
osnovu niza A formira niz B u koji ulaze samo oni elementi niza A čija je apsolutna
vrednost manja od apsolutne vrednosti razlike između maksimalnog i minimalnog
elementa niza A.
Niz B formirati funkcijom formb u okviru koje se pozivaju funkcije minimum i
maksimum za traženje minimalnog odnosno maksimalnog elementa niza A.

Zadatak 21 (3)
Dati su celobrojni nizovi A od n i B od m elemenata pri čemu je m>n, n<50 i
m<50. Napisati C program koji na osnovu nizova A i B formira niz C po pravilu:

c[i] = a[i] + br[i] + s[i], i = [1..n]

pri čemu je br[i] broj elemenata niza B koji imaju vrednost veću od a[i] a dobija se
korišćenjem funkcije broji, a s[i] je zbir svih elemenata niza B čiji je indeks manji ili
jednak sa i, a vrednost pozitivna a dobija se korišćenjem funkcije suma.
.
Zadatak 22 (4)
Napisati C program koji na osnovu unetog prirodnog broja n sa intervala 1..n traži
korišćenjem funkcije trazi_del broj koji ima najviše delilaca. Štampati sve brojeve u
slučaju da ima više takvih brojeva.. Funkcija trazi_del na osnovu prirodnog broja k
utvrđuje i vraća broj delilaca broja k.

Zadatak 23 (4)
Napisati C program koji po izboru korisnika vrši sortiranje celobrojnog niza X od n
(n<41) elemenata u rastućem ili opadajućem redosledu. Sortiranje niza vrši se pozivom
samo jedne funkcije pod imenom sort. Prenosom po vrednosti prosleđuje se da li će se
sortirati u rastućem ili opadajućem redosledu.

Zadatak 24 (2)
Napisati C program koji kojim se ispituje koliko elemenata niza X od n (n<41)
elemenata je deljivo sa brojem a a nije deljivo sa brojem b. Brojevi a i b su celobrojni.
Funkcija odredi ima prototip unsigned odredi(int a[], int m, int p, int q);
Funkcija u nizu a od m elemenata utvrđuje koliko elemenata je deljivo sa brojem p
a nije sa brojem q.
Zadatak 25 (4)

60
Napisati C program koji korišćenjem funkcije utvrdi utvrđuje broj različitih
elemenata u celobrojnom nizu X od n elemenata (n<41).

Zadatak 26 (3)
Zadat je niz X od n (n<41) elemenata. Napisati C program koji iz niza izbacuje
elemente koji imaju osobinu da im je vrednost jednaka sa vrednosti prethodnog elementa
niza. Funkcija sazmi vrši sažimanje niza poozivajući funkciju utvrdi. Fdunkcija utvrdi
vraća adresu pronađenog elementa niza, sa osobinom da mu je vrednost jednaka
prethodnom elementu niza.

Zadatak 27 (2)
Zadat je niz X od n (n<41) elemenata. Napisati C program koji na osnovu niza X
formira niz Y. Elementi niza Y dobijaju se tako što se elementima prve polovine niza
oduzima polovina minimuma, a elementima druge polovine niza dodaje polovina
maksimuma. Ako niz ima neparan broj elemenata tada prva polovina niza ima više
elemenata.
Funkcija minmax po referenci određuje indeks prvog minimuma i imdeks
poslednjeg maksimuma niza.

Zadatak 28 (4)
Zadat je niz X od n (n<41) elemenata. Napisati C program koji pozivom funkcije
ciklpom cikličnim pomakom u levo prvi maksimum premešta na prvu poziciju u nizu.
Funkcija ciklpom poziva funkciju max koja vraća adresu prvog maksimuma.

Zadatak 29 (4)
Zadat je niz X od n (n<41) elemenata. Napisati C program kojim se iz niza izbacuju
svi elementi niza sa osobinom da im je vrednost tri puta veća od minimuma a nisu
maksimumi, Za odrešivanje minimuma i maksimuma niza koristiti funkciju minmax koja
vraća minimum a po referenci određuje maksimu. Funkcija izbaci na osnovu prosleđene
adrese elementa niza izbacuje element niza koji se na toj adresi nalazi.

Zadatak 30 (4)
Zadat je niz X od n (n<41) elemenata. Napisati C program koji na osnovu unesenih
rednih brojeva i i j (i<n i j<i) vrši rotiranje niza za jedno mesto i određuje srednju
vrednost ostatka niza, bez elemenata sa tim rednim brojevima. Funkcijum rot vršiti
rotiranje niza za jedno mesto u desno ili u levo, na oslovu prosleđenog parametra
funkciji. Funkcija sredvre određuje srednju vrednost ostatka niza.

Zadatak 31 (4)
Zadat je niz X od n (n<41) elemenata. Napisati C program koji utvrđuje da li je niz
X monotono rastući. Funkcija utvrdi vraća 1 ako je niz strogo monotono rastući ili 0 u
suprotnom. Ako niz nije monotono rastući pozivom funkcije sort izvršiti njegovo
sortiranje u rastućem redosledu.

Zadatak 32 (4)

61
Napisati C program za poređenje dva niza celih brojeva A i B od po n elemenata
n<100. Poređenje dva niza vršiti funkcijom poredi koja vraća -1 ako je niz A manji od
niza B, 0 ako je niz A jednak nizu B ili 1 ako je niz A veći od niza B.

Poređenje vršiti po sledećem pravilu:

a) A<B, ako do nekog k-tog k=[1..n] elementa važi a[i]=b[i] i=[1..k], a


a[k+1]<b[k+1],
b) A>B, ako do nekog k-tog k=[1..n] elementa važi a[i]=b[i] i=[1..k], a
a[k+1]>b[k+1], i
c) A=B, ako je a[i]=b[i], i=[1..n]

Na ekranu štampati odgovarajuću poruku: NIZ A JE MANJI OD NIZA B,


NIZOVI A I B SU ISTI, ili NIZ A JE VECI OD NIZA B.

Zadatak 33 (4)
Zadat je celobrojan niz X od n elemenata n<100. Napisati C program koji pozivom
funkcije ekstremi štampa na ekranu ekstreme niza X na sledeći način:

VREDNOST TIP

**** minimum
**** maksimum

Funkcija ekstremi vraća 0 ako i-ti član niza X x[i] i=[1..n] nije ekstrem, 1 ako je
maksimum i -1 ako je minimum.

Na primer:
Neka je X = 1, 5, 3, 6, 2, 1, 10, 11, 23 i 0.
tada će izveštaj imati sledeći izgled:

VREDNOST TIP

5 maksimum
3 minimum
6 maksimum
1 minimum
23 maksimum

Zadatak 34 (4)
Zadat je niz X od n elemenata (n<51). Napisati C program koji pozivom funkcije
sazmi izbacuje iz celobrojnog niza svaku pojavu odgovarajućeg broja broj. Ako broja
nema u nizu funkcija vraća 0, a u suprotnom koliko je elemenata niza imalo tu vrednost.
Zadatak 35 (5)

62
Zadat je niz X od n elemenata (n<51). Napisati C program koji sve maksimalne
elemente prebacuje na početak niza a minimalne na kraj niza. Modifikovanje niza vršiti
funkcijom mod u okviru koje se poziva funkcija minmax. Funkcija minmax ima prototip
unsigned minmax(int a[], int m, char tip, int *ekstrem);
Parametar tip može imati vrednosti 0 (traži se minimum) ili 1 (traži se maksimum).
Po referenci određuje se vrednost određenog ekstrema, a funkcija vraća broj pojavljivanja
određenog ekstrema.

Zadatak 36 (5)
Zadat je niz X od n elemenata (n<51). Napisati C program koji određuje sumu
elemenata niza pre prvog ekstrema i srednju vrednost posle drugog ekstrema.
Funkcija minmax po referenci određuje vrednosti minimuma i maksimuma, a vraća
broj ekstrema. Funkcija ekstrem pronalazi prvi ekstrem od početka niza i vraća njegovu
adresu. Funkcija suma izračunava zbir elemenata niza do prvog ekstrema. Funkcija
sredvred određuje srednju vrednost dela niza od drugog ekstrema.

Zadatak 37 (5)
Zadat je niz X od n elemenata (n<51). Napisati C program koji određuje prvi
interval elemenata kod koga svi elementi imaju veću vrednost od unetog racionalnog
broja a. Interval mora imati najmanje tri elementa. Funkcija interval vraća dužinu
intervala ako postoji ili 0 u suprotnom, dok se bočnim efektom određuju indeksi početka
i kraja intervala.

Zadatak 38 (4)
Napisati C program koji pozivom funkcije trazi, utvrđuje da li se u celobrojnom
nizu X od n (n<31) elemenata nalazi broj p. Ako se broj p nalazi u nizu funkcija vraća 1
a u suprotnom 0. Koristeći funkciju trazi u funkciji izbaci, izbaciti svako višestruko
pojavljivanje broja p u nizu X. U nizu ostaviti onaj broj p koji je imao najveći indeks.
Funkcija izbaci vraća broj izbačenih elemenata iz niza X, ili 0 ako ni jedan element nije
izbačen iz niza.

Zadatak 39 (4)
Zadat je niz X od n (n<41) elemenata. Napisati C program koji određuje vrednost
zbira dela niza između pozicija minimalnog i maksimalnog elementa ili maksimalnog i
minimalnog elementa i srednju vrednost ostatka niza.
Za formiranje niza X od n elemenata koristiti funkciju unos. U nizu X nema
ponavljanja elemenata.
Funkcija uradi izračunava i po vrednosti vraća zbir elemenata niza između pozicija
minimalnog i maksimalnog elementa, a bočnim efektom srednju vrednost ostatka niza.
Funkciji po referenci proslediti vrednost logičke promenljiva koja nakon završetku
funkcije dobija vrednost 1 ako je izračunata srednja vrednost ili 0 ako se srednja vrednost
ne može izračunati.
Funkcijom minmax odrediti po referenci pozicije minimalnog i maksimalnog
elementa niza. Funkcija minmax nema povratne vrednosti..

Zadatak 40 (5)

63
Zadat je niz X od n (n<51) elemenata. Napisati C program koji određuje najveći
rastući interval niza. Ako ima više takvih intervala ispisati ih sve na ekranu, i za svaki
utvrditi da li sadrži maksimalni element niza. Određivanje najvećih rastućih intervala niza
vrši se pozivom funkcije interval koja vraća dužinu podniza ili -1 ako rastućeg intervala
nema, dok se početak i kraj intervala određuje po referenci.
Funkcija max utvrđuje vrednost maksimalnog elementa niza, a funkciju pronadji
(pozivom funkcije max) pripadnost maksimalnog elementa najvećem rastućem intervalu.
Rastući interval mora imati barem dva člana niza.

Zadatak 41 (5)
Napisati C program koji pozivom funkcije period utvrđuje da li je celobrojan niz X
od n (n<51) elemenata periodičan. Funkcija vraća 0 ako niz nije periodičan, ili broj
p  0 koji predstavlja traženi period.

Zadatak 42 (5)
Novac kojim raspolaže (trenutno se nalazi u kasi) služba platnog prometa jedne
banke zadata je nizom novac. Prvi član niza sadrži broj novčanica apoena 1000, drugi
broj novačanica apoena 500, treći broj novčanica apoena 200, sledeći se odnosi na apoen
100, pa 50, pa 20, pa 10, pa 5, pa 2, pa 1 apoen.
Napisati C program koji treba da odredi kako će služba isplatiti klijenta od N dinara
a da pri tome utoši što manje novčanica sa manjim apoenima. Problem rešiti funkcijom
isplata koja vraća vrednost 1 ako je moguće isplatiti klijenta, a 0 u suprotnom.
Korišćenjem bočnog efekta i niza novac, ispisati kako je izvršena isplata, kao i koliko je
novca po apoenima ostalo u banci.

Zadatak 43 (5)
Napisati C program koji omogućava ispis ASCII tabele na ekranu, a zatim za unos
nekog rednog broja označiti odgovarajući znak na ekranu. Oznaku odgovarajućeg znaka
sa ekrana vrši se pozivom funkcije oznaci.

Zadatak 44 (5)

64
Zadat je prirodan broj n. Napisati C program koji rastavlja prirodan broj n na dva
sabirka k i p tako da se sabirak p dobija od broja k brisanjem jedne cifre. Ukoliko je broj
k jednocifren broj tada je p nula. Štampati sve moguće slučajeve.
Funkcija rastavi za dato k, p i n utvrđuje da li je moguće rastaviti i vraća 1 ako
može ili 0 u suprotnom.

Zadatak 45 (5)
Dopuniti C program (zadatak 9 iz poglavja nizovi) tako da igra samo jedan igrač, a
da je drugi igrač računar. Računar uvek igra kao "X". Programski igra računara je
realizovana funkcijom kompot. Funkcija vraća poziciju u nizu gde treba upisati broj 2
(što označava da digrao računar). Pozicija mora biti korektna,tj na toj poziciji nalazi se u
nizu vrednost 0. Po mogućućstvu funkcija kompot treba da vraća takve poteze da na kraju
igre pobednik uvek bude računar, ili je igra završena nerešeno.

Zadatak 46 (2)
Napisati C program koji na osnovu unetog prirodnog broja n korišćenjem
rekurzivne funkcije rek na ekranu štampa brojeve od 1 do n i od n do 1, tj:

1 2 3 4 5 ... n n ... 5 4 3 2 1

Zadatak 47 (2)
Napisati C program koji na osnovu unetog prirodnog broja n korišćenjem
rekurzivne funkcije faktorijal izračunava faktorijal prirodnog broja n. Faktorijel
prirodnog broja n računa se po formuli:

n! n  (n  1)  (n  2)  ...  3  2  1
Zadatak 48 (3)
Napisati C program koji korišćenjem rekurzivne funkcije zbir izračunava zbir cifara
dekadnog prirodnog broja n.

Zadatak 49 (3)
Zadat je niz X od n elemenata (n<51). Napisati C program koji korišćenjem
rekurzivne funkcije zbir izračunava zbir elemenata niza X.
Zadatak 50 (3)

65
Napisati C program koji na osnovu unetog prirodnog broja n izračunava zbir prvih
n brojeva Fibonačijevog niza.
Fibonačijev niz ima sledeći izgled: 1 1 2 3 5 8 13 21 34 55 ...
Za računanje vrednosti k-tog člana Fibonačijevog niza koristiti rekurzivnu funkciju
fib.

Zadatak 51 (4)
Napisati C program koji izračunava korišćenjim rekurzivne funkcije rekdet
determinantu Dp oblika:
n m 0 0 . . . 0 0
k n m 0 . . . 0 0
0 k n m . . . 0 0
. . . . . . . . .
Dp  . . . . . . . . . p , n , m, k  N
. . . . . . . . .
. . . . . . . . .
0 0 0 0 . . . n m
0 0 0 0 . . . k n pxp

Gde je p red determinante, a n,m i k su parametri.

Zadatak 52 (4)
Formirati heder MOJEFUN.H gde će se nalaziti tvoje najčešće korišćene funkcije.
Formirati funkciju un_ceo koja onemogućava unos znaka koji nije cifra (0..9), a
završava se unosom kada se pritisne taster ENTER. Funkcija vraća uneti broj koji se
ispisuje na ekranu, a kursor se nalazi posle zadnje unete cifre. Demonstrirati korišćenje
funkcije pisanjem glavnog C programa (sadrži main funkciju).

Zadatak 53 (4)
Formirati funkciju un_rac i smestiti je u heder MOJEFUN.H koja onemogućava
unos znaka koji nije cifra (0..9) ili decimalna tačka, a završava se unosom kada se pritisne
taster ENTER. Funkcija vraća uneti broj koji se ispisuje na ekranu, a kursor se nalazi
posle zadnje unete cifre. Demonstrirati korišćenje funkcije pisanjem glavnog C programa
(sadrži main funkciju).

Zadatak 54 (4)
Formirati funkcije unos_niza i ispis_niza. Prilikom unosa niza koristiti funkciju
un_ceo koja se nalazi se u hederu MOJEFUN.H i smestiti je u heder NIZ.H.
Demonstrirati korišćenje funkcija pisanjem glavnog C programa (sadrži main funkciju).

Zadatak 55 (3)
Formirati funkcije minimum, maksimum i sort_niz i smestiti ih u heder NIZ.H.
Funkcija sort_niz može da sortira u rastućem ili opadajućem redosledu.

66
Demonstrirati korišćenje funkcija pisanjem glavnog C programa (sadrži main
funkciju).

Zadatak 56 (3)
Zadat je celobrojan niz X od n elemenata pri čemu je n paran broj i n<100. Napisati
C program koji korišćenjem funkcija unos_niza, ispis_niza i sort_niz koji se nalaze u
hederu NIZ.H, prvu polovinu zadatog niza sortira u opadajućem redosledu, a drugu
polovinu u rastućem redosledu.

Zadatak 57 (3)
Napisati C program koji korišćenjem raspoloživih funkcija iz hedera MOJEFUN.H
i NIZ.H omogućava unos racionalnog niza X od n elemenata (n<41) i utvrđuje koliko
elemenata niza ima vrednost veću od minimuma a manju od maksimuma niza.

Zadatak 58 (4)
Napisati funnkcije unos_dug_broja i ispis_dug_broja. Dugačak ceo broj se smešta
u niz pri čemu svaki element niza počev od drugog sadrži broj koji predstavlja cifru od 0
do 9, dok prvi element sadrži redni broj predznaka (+ ili -) iz ASCII tabele. Funnkcije
smestiti u heder MOJEFUN.H. Demonstrirati korišćenje funkcija pisanjem glavnog C
programa (sadrži main funkciju).

Zadatak 59 (5)
Napisati C program koji će korišćenjem funkcija saberi, oduzmi, ili mnozi po
izboru korisnika vrši sabiranje, oduzimanje ili množenje dva dugačka cela broja. Dugački
brojevi se nalaze smešteni u dva niza. Svaki element niza počev od drugog sadrži broj
koji predstavlja cifru od 0 do 9, dok prvi element sadrži redni broj predznaka (+ ili -) iz
ASCII tabele Takođe za unos cifre koristiti funkciju unceo koja omogućava unos znaka
iz intervala 0..9 i vraća ceo broj (0..9) ili -1 ako je pogrešno unet znak. Rezultat je takođe
dugačak ceo broj čije su cifre smeštaju u niz, po gore navedenom pravilu.
Sve napisane funkcije treba smestiti u hederu MOJEFUN.H.

Zadatak 60 (5)
Dopuniti "Zmijicu" iz 60 zadatka oblasti nizovi, tako da se koriste funkcije.
Program mora imati četiri nivoa:
 Prvi nivo je zadatak 60 iz prošle glave stim
što igrač ima tri života, a igrač gubi život kada "Zmijica" sa glavom naiđe na samu sebe.
 Drugi nivio dobija veliki vertikalni tunel, a
ako se naiđe na zid tunela gubi se život.
 Treći nivo ima dva tunela: jedan
horizontalni i jedan vertilkalni, a "Zmijica" se dosta brže kreće nego što je to bio uslučaj
u prva dva nivoa.
 Četvrti nivo ima dva tunela horizontalni i
vertikalni, "Zmijica" se još brže kreće, a posle svake pojedene hrane mora proći kroz
jedan od dva tunela, jer ako opet pojede hranu a nije prošla kroz tunel zmijica gine.

67
68
3. POGLAVLJE

VIŠEDIMENZIONALNI NIZOVI

69
3.1. VIŠEDIMENZIONALNI NIZOVI

Definicija višedimenzionalnog niza:


Višedimenzionalni nizovi su nizovi čiji su elementi takođe nizovi.

Definicija matrice:
Dvodimenzionalni niz ili matrica sastoji se od vrsta, pri čemu je svaka vrrsta jedan
vektor (jednodimenzionalni niz), tj matrica je niz vektora. Po analogiji je
trodimenzionalni niz je niz matrica, itd.

Deklaracija višedimenzionalnog niza:


Deklaracija višedimanzionalnog niza je slična sa deklaracijom vektora, s tom
razlikom što višedimenzionalni niz ima više dimenzija.

tip imeniza[MAX][MAX][MAX][MAX]…[MAX];

Svaka zagrada predstavlja novu dimenziju niza, a podatak u zagradi predstavlja


maksimalni broj elemenata koji poseduje data dimenzija. Elementi predstavljaju
nizovi manje dimenzije.

Na primer:
int matrica[3][4], trodniz[3][6][4];

Svi elementi višedimenzionalnih nizova su celi brojevi. Matrica je dvodimenzionalni niz


i prva dimenzija ima maksimalno 3 vektora pri čemu se svaki vektor sastoji od
maksimalno 4 elementa. Trodimenzionalni niz ima tri dimenzije pri čemu je prva
dimenzija sa maksimalno 3 matrice, a svaka matrica se sastoji od maksimalno 6 vektora,
pri čemu svaki vektor ima 4 elementa koji su celi brojevi.

Višedimenzionalne nizove treba koristiti kada je potrebno opisati složeni


podatak koji je opisan sa više podataka, pri čemu i indeksi koji opisuju
višedimenzionalni niz predstavljaju podatak neophodan za opis elementa.

Na primer ako posmatramo igricu minsko polje. Tada se svako polje može opisati
sa x koordinatom, y koordinatom i brojem koji opisuje šta se nalazi na toj koordinati.
Koristili bi matricu gde bi prvi indeks opisivao horizontalnu poziciju, drugi vertikalnu
poziciju, a vrednost elementamatrice bi opisivalo šta se na toj poziciji nalazi: 1 – postoji
mina ili 2 – mina se nenalazi na toj poziciji.

70
Sa pojmom matrica susrećete se i u matematici prilikom rešavanja sistema
jednačina. Opisana je sa dve dimenzije pri čemu se prva uvek odnosi na vrstu, a druga na
kolonu.
Na primer:

 2 4 0 1
A  4 6 7 3
 2 1 3 5  3 x 4

Matrica A ima tri vrste i četiri kolone. Deklaracija matrice A i ujedno njena inicijalizacija
s tim da matrica ima ovakav izgled je:

unsigned a[3][4]={{2, 4, 0, 1},{4, 6, 7, 3},{2, 1, 3, 5}};

Za slučaj da smo hteli inicijalizovati matricu a da pri tome ne napišemo sve elemente, ne
obuhvaćenim elementima automatski bi se dodelila vrednost nula. Za slučaj da smo
deklarisali i inicijalizovali sa:

unsigned a[3][4]={{2, 4},{4, 6, 7, 3},{2, 1, 3}};

matrica a bi imala sledeći izgled:

 2 4 0 0
A   4 6 7 3
 2 1 3 0  3 x 4

Smeštanje višedimenzionalnih nizova u memoriju:


Operativna ili RAM memorija je po prirodi linearno organizovana
(predstavlja jednodimenzionalni niz), sa rastućim adresama, vektor se u memoriju
smešta na prirodan način, gde su logički i fizički redosled elemenata u memoriji isti.
Prilikom smeštanja matrice u memoriji mora se izvršiti njena linearizacija.
Linearizacija se u programskom jeziku C vrši po vrstama. Od početne adrese
matrice prvo se smešta prva vrsta, pa druga vrsta, i tako redom do poslednje vrste.
Vrsta se tretira kao zapis koji ima onoliko elemenata koliko ima kolona.

Na primer:
int a[3][4];

A00 A01 A02 A03 A10 A11 A12 A13 A20 A21 A22 A23
Iz primera se lako vidi kako je izvršena linearizacija matrice u memoriji.

71
Kao i kod jednodimenzionalnog niza ili vektora tako i kod višedimenzionalnih
nizova postoji prisna veza između pokazivača i niza.
Pristup odgovarajućem podatku matrice može se vršiti pomoću indeksa ili
pokazivača Kod matrice ima dva indeksa (prvi je indeks vrste, a drugi je indeks kolone).
Indeksi moraju biti prirodni brojevi ili promenljive koje su celobrojnog tipa. Kao i kod
vektora u indeksu može mostojati i celobrojni izraz.

Na primer:
unsigned s, i, j, a[3][4]={{2, 4, 0, 1},{4, 6, 7, 3},{2, 1, 3, 5}};

Pristup pomoću operatora indeksiranja:

Prvi način:
s=a[2][1]; - nakon ove naredbe dodele promenljiva s ima vrednost 1.

Drugi način:
int i=1, j=0;
s=a[i][j]; - nakon ove naredbe dodele s je 4.

Pristup pomoću pokazivača:


Indentifikator a nije pokazivač na podatke tipa unsigned, već pokazivač na nizove
(ima ih tri, jer ima tri vrste) koji su tipa unsigned. Zbog toga a+1 nije adresa elementa
matrice a[0][1] već početna adresa podniza a[1], a to je druga vrsta matrice čiji je prvi
element a[1][0]. Zbog toga se primenom cast operatora u pokazivačkoj aritmetici mora
indentifikator niza a pretvoriti u pokazivač na celobrojne podatke tipa unsigned.

unsigned s, i, j, k,a[MAXV][MAXK], b[P][Q][R];

a[i][j]  *((unsigned *)a +MAXK*I +j)


b[i][j][k] *((unsigned *)b +Q*R*i + R*j +k)

Na sličan način se može pristupiti i proizvoljnom elementi bilo koje


višedimenzionalne matrice.

Važno je uočiti da se u formulama za izračunavanje adrese datog elementa


višedimenzionalnog niza nikada ne pojavljjuje dužina po prvoj dimenziji niza.
Ova sobina se koristi kod funkcija kada se prosleđuje matrica, jer se ne mora
prosleđivati prva dimenzija dok su ostale dimenzije neophodne.

Na primer:
int a[MAXV][MAXK];

Prototip funkcija koja koristi matricu a kao parametar imala bi sledeći izgled:

int zbir(int a[][MAXK], int n);

72
3.2. PROLASCI KROZ VŠEDIMENZIONALNI NIZ

Od višedimenzionalnih niziva najviše se koriste dvodimenzionalni nizovi ili


matrice. Matrice imaju dve dimenzije, prva dimenzija odnosi se na vrste (redove) a druga
dimenzija se odnosi na kolone. Kroz matricu se može izvršiti jedna od sledećih vrsta
prolazaka:
 Prolazak kroz matricu vrsta po vrsta,
 Prolazak kroz matricu kolona po kolona,
 Prolazak kroz matricu preko dijagonala (paralelnih glavnoj dijagonali pri
čemu glavnu dijagonalu čine elementi koji imaju istu vrednost indeksa vrste
i kolone), i
 Spiralni prolasci kroz matricu.

Primer 1:
Zadata je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ).. Napisati C
program koji izračunaa zbir elemenata matrice prolazeći kroz matricu vrsta po vrsta.

Rešenje

#include<stdio.h>
#include<conio.h>

#define MAX 9

void main(void)
{
int a[MAX][MAX];
int m,n,s;
unsigned i,j,xu,yu,xp=5,yp=5;

for(i=0;i<MAX;i++)
{
for(j=0;j<MAX;j++) a[i][j]=0;
}

textmode(3);
textcolor(9);
textbackground(0);
clrscr();

/* Posebno se mora unositi koliko ima vrsta, a posebno koliko ima kolona. */
printf("Unesi broj vrsta: ");
xu=wherex(), yu=wherey();

73
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&m);
}while(m<=0||m>MAX);

printf("Unesi broj kolona: ");


xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0||n>MAX);

/* Matrica se unosi vrsta po vrsta. Iz a[i][j] vidi se da je indeks vrste i dok je indeks
kolone j. Kako je j brojac unutrasnjeg ciklusa to se on menja dok se vrednost brojaca
spoljasnjeg ciklusa i ne menja. To je znak da se kroz matricu krecemo vrsta po vrsta. */

printf("Unesi matricu: ");


xu=wherex(),yu=wherey();
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a[i][j]);
gotoxy(xp,yp);
printf("%d",a[i][j]);
xp+=4;
}
yp++;
xp=5;
}

/* Prolazi se kroz matricu vrsta po vrsta jer je indeks vrste brojac spoljasnjeg ciklusa dok
je indeks kolone brojac unutrasnjeg ciklusa. */

s=0;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++) s+=a[i][j];
}

printf("\n\nZbir = %d",s);
gotoxy(1,25);
getch();
}

74
Primer 2:
Zadata je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji izračunva zbir elemenata matrice prolazeći kroz matricu kolona po kolona.

Rešenje

#include<stdio.h>
#include<conio.h>

#define MAX 9

void main(void)
{
int a[MAX][MAX];
int m,n,s;
unsigned i,j,xu,yu,xp=5,yp=5;

for(i=0;i<MAX;i++)
{
for(j=0;j<MAX;j++) a[i][j]=0;
}

textmode(3);
textcolor(9);
textbackground(0);
clrscr();

/* Posebno se mora unositi koliko ima vrsta, a posebno koliko ima kolona. */

printf("Unesi broj vrsta: ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&m);
}while(m<=0||m>MAX);

printf("Unesi broj kolona: ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0||n>MAX);

75
/* Matrica se unosi vrsta po vrsta. Iz a[i][j] vidi se da je indeks vrste i dok je indeks
kolone j. Kako je j brojac unutrasnjeg ciklusa to se on menja dok se vrednost brojaca
spoljasnjeg ciklusa i ne menja. To je znak da se kroz matricu krecemo vrsta po vrsta. */

printf("Unesi matricu: ");


xu=wherex(),yu=wherey();
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a[i][j]);
gotoxy(xp,yp);
printf("%d",a[i][j]);
xp+=4;
}
yp++;
xp=5;
}

/* Prolazi se kroz matricu kolona po kolona jer je indeks vrste brojac unutrasnjeg ciklusa
dok je indeks kolone brojac spoljasnjeg ciklusa. */

s=0;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++) s+=a[j][i];
}

printf("\n\nZbir = %d",s);
gotoxy(1,25);
getch();
}

Primer 3:
Zadata je kvadratna matrica A dimenzije n ( n  N , n  12) . Napisati C program koji
na osnovu matrice A formira niz B. Elemente niza B čini zbir elemenata matrice A koji
se nalaze na glavnoj dijagonali ili su elementi paralelni elementima sa glavne dijagonale.
Kao da smo sa desne strane matricu proširili za prvih n-1 kolonu. Iz razloga zanimljivosti
zadatka ne sme se vršiti proširivanje matrice.

Rešenje

#include<stdio.h>
#include<conio.h>
#define MAX 9

76
void main(void)
{
int a[MAX][MAX], b[MAX];
int m,n,s;
unsigned i,j,d,xu,yu,xp=5,yp=5;

for(i=0;i<MAX;i++)
{
b[i]=0;
for(j=0;j<MAX;j++) a[i][j]=0;
}

textmode(3);
textcolor(9);
textbackground(0);
clrscr();

printf("Unesi dimenyiju kvadratne matrice: ");


xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0||n>MAX);

printf("Unesi matricu: ");


xu=wherex(),yu=wherey();
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a[i][j]);
gotoxy(xp,yp);
printf("%d",a[i][j]);
xp+=4;
}
yp++, xp=5;
}

/* Promenljiva d broji i odnosi se na to koja se dijagonala sabira. Ako je d jednako


0 sabiraju se elementi sa glavne dijagonale. Glavni deo problema je j%n koji

77
omogucava da se sa sabiranjem nastavi bas tamo gde treba, jer ub slucaju da j ima
vrednost n krece se automatski na prvu kolonu, a to nam i treba. */

for(d=0;d<n;d++)
{
j=d;
for(i=0;i<n;i++) b[d]+=a[i][j%n],j++;
}

printf("\n\n B = ");
for(i=0;i<n;i++) printf("%d ",b[i]);
gotoxy(1,25);
getch();
}

Primer 4:
Data je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji bez korišćenja pomoćnih nizova ili matrica sažima matricu izbacivanjem
odgovarajuće i-te vrste i j-te kolone, pri čemu se i i j unose sa ulaza i
i  [1..m], j  [1..n] .

Rešenje

#include<stdio.h>
#include<conio.h>

#define MAX 9

void main(void)
{
int a[MAX][MAX];
int m,n,p,q;
unsigned i,j,xu,yu,xp=5,yp=5;

/* Inicijalizacija nizova i matrice. */


for(i=0;i<MAX;i++)
{
for(j=0;j<MAX;j++) a[i][j]=0;
}

textmode(3);
textcolor(9);
textbackground(0);
clrscr();

printf("Unesi broj vrsta: ");

78
xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&m);
}while(m<=0||m>MAX);

printf("Unesi broj kolona: ");


xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0||n>MAX);

printf("Unesi matricu: ");


xu=wherex(),yu=wherey();
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a[i][j]);
gotoxy(xp,yp);
printf("%d",a[i][j]);
xp+=4;
}
yp++;
xp=5;
}

printf("\n\nUnesi redni broj vrste koja se brise: ");


xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&p);
}while(p<=0||p>m);
printf("Unesi redni broj kolone koja se brise: ");
xu=wherex(), yu=wherey();
do{

79
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&q);
}while(q<=0||q>n);

/* Ako se izbacuje poslednja kolona ne mora se vrsiti sazimanje matrice po


vrstama, vec se samo smanji broj vrsta matrice za 1 i time je ta vrsta izbacena iz
matrice. */

if(p==m) m--;
else{
/* Nema potrebe dirati prethodne vrste. Iz tih razloga je i=p-1.
Smanjujemo za jedan jer smo p uneli ne kao indeks vrste vec kao redni
broj vrste. */

for(i=p-1;i<m-1;i++)
{
for(j=0;j<n;j++) a[i][j]=a[i+1][j];
}
/* Nakon sazimanja broj vrsta moramo smanjiti za 1. */
m--;
}

/* Na slican nacin se izbacuje kolona iz matrice. */


if(q==n) n--;
else{
for(j=q-1;j<n-1;j++)
{
for(i=0;i<m;i++) a[i][j]=a[i][j+1];
}
n--;
}

/* Matrica se stampa na ekranu vrsta po vrsta. */


printf("\n\nNakon izbacivanja %d vrste i %d kolone matrica je:\n\n",p,q);
for(i=0;i<m;i++)
{
for(j=0;j<n;j++) printf("%4d",a[i][j]);
printf("\n");
}
gotoxy(1,25);
getch();
}

80
3.3. VIŠEDIMENZIONALNI NIZOVI I FUNKCIJE

Funkcija kao povratnu vrednost ne može da vrati višedimenzionalni niz.


Višedimenzionalni niz može biti argument funkcije, s tim da u odnosu na vektor
višedimenzionalni niz ne mora prosleđivati prvu dimenziju funkciji, ali ostale se
moraju proslediti.

Razlog prosleđivanja ostalih dimenzija funkciji leži u formuli po kojoj se računa


adresa elementa višedimenzionalnog niza. Sa prošlog časa se videlo kako u izrazu osim
prve dimenzije figurišu sve ostale.

Primer 1:
Zadata je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji na osnovu matrice A formira nizove X i Y. Niz X formiraju zbirovi
elemenata kolona matrice A. Niz Y predstavljaju broj onih elemenata iz vrsta matrice A
koji imaju vrednost različitu od minimalne i maksimalne vrednosti vrste.

Za izračunavanje minimalne vrednosti vrste koristiti funkciju minvrsta, za


izračunavanje maksimalne vrednosti vrste koristiti funkciju maxvrsta, a za izračunavanje
zbira elemenata kolone koristiti funkciju zbirkolone.

Na primer: m = 6, n = 7

Matrica A je:
2 12 4 0 0 6 0
15 0 11 6 15 7 0
5 23 4 1 22 7 12
5 13 0 3 0 6 41
15 6 34 6 15 9 6
4 14 1 2 2 17 3

Nizovi X i Y su:
X = 46, 68, 54, 18, 54, 52, 62
Y = 3, 3, 5, 4, 3, 5

Rešenje

#include<stdio.h>
#include<conio.h>

#define MAX 9

81
/* Prototipovi funkcija gde se vidi da se u prvoj dimenziji ne mora nista pisati, dok se u
drugoj dimenziji morala napisati dimenzija. */

int minvrsta(int a[][MAX], int n, unsigned i);


int maxvrsta(int a[][MAX], int n, unsigned i);
int zbirkolone(int a[][MAX], int m, unsigned j);

void main(void)
{
int max, min, a[MAX][MAX], x[MAX], y[MAX];
int m,n;
unsigned i,j,xu,yu,xp=5,yp=5;

/* Inicijalizacija nizova i matrice. */


for(i=0;i<MAX;i++)
{
x[i]=y[i]=0;
for(j=0;j<MAX;j++) a[i][j]=0;
}

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("Unesi broj vrsta: ");


xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&m);
}while(m<=0||m>MAX);

printf("Unesi broj kolona: ");


xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0||n>MAX);

printf("Unesi matricu: ");


xu=wherex(),yu=wherey();
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
gotoxy(xu,yu);

82
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a[i][j]);
gotoxy(xp,yp);
printf("%d",a[i][j]);
xp+=4;
}
yp++, xp=5;
}

/* Mora se dobro procitati tekst zadatka kako bi se utvrdilo tacno sta koja funkcija radi.
Elemente niza X formira podatak koji vrati funkcija zbirkolone. Stvarni parametar
matrica upisuje se samo ime matrice. Broj elemenata niza X jednak je broju kolona
matrice A. */

for(j=0;j<n;j++) x[j]=zbirkolone(a,m,j);
printf("\n\nX = ");
for(i=0;i<n;i++) printf("%d ",x[i]);

/* Poziv funkcije maxvrsta i minvrsta ne treba pisati unutar drugog for ciklusa jer se na
taj način funkcija umesto jednom poziva n puta cime se usporava program. Znamo da
svaki element niza Y prilikom inicijalizacije ima vrednost 0, te se is tih razloga ne mora
koristiti pomocni brojac, vec se direktno uvecava za 1 odgovarajuci element niza Y. */

for(i=0;i<m;i++)
{
max=maxvrsta(a,n,i);
min=minvrsta(a,n,i);
for(j=0;j<n;j++) if(a[i][j]!=min&&a[i][j]!=max) y[i]++;
}

printf("\n\nY = ");
for(i=0;i<m;i++) printf("%d ",y[i]);
gotoxy(1,25);
getch();
}

/* Funkcija minvrsta odredjuje vrednost minimalnog elementa vrste. */


int minvrsta(int a[][MAX], int n, unsigned i)
{

/* Proglasavamo da je prvi element iz posmatrane vrste minimalan. */


int min=a[i][0];
unsigned j;

/* Prolazimo kroz vrstu. To se vidi po tome sto se indeks vrste ne menja za razliku od
indeksa kolone. */
for(j=1;j<n;j++)
{
if(a[i][j]<min) min=a[i][j];
}

83
return min;
}

/* Funkcija maxvrsta odredjuje vrednost maksimalnog elementa vrste. */


int maxvrsta(int a[][MAX], int n, unsigned i)
{
int max=a[i][0];
unsigned j;

for(j=1;j<n;j++)
{
if(a[i][j]>max) max=a[i][j];
}

return max;
}

/* Funkcija zbirkolone utvrdjuje zbir elemenata odgovarajuce kolone. */


int zbirkolone(int a[][MAX], int m, unsigned j)
{
int s=0;
unsigned i;

/* Prolazimo kroz kolonu. To se vidi po tome sto se indeks kolone ne menja za razliku od
indeksa vrste. */

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

return s;
}

Test primer programa:

84
Primer 2:
Napisati C program koji na osnovu celobrojne matrice A (dobijene korišćenjem
random funkcije) dimenzija nxn, (n je paran broj i n<10), formira niz B na osnovu slike:

S1i 
           
 
 S12 
 
         
  S1   
 3

       
 
A         za n = 6
       
 
  S2 3  
 
         
 S 22  
 
           
 S 21 

S1i – je zbir elemenata matrice A na gornjem i-tom ugaoniku, a
S2i – je zbir elemenata matrice A na donjem i-tom ugaoniku,
n
pri čemu i1.. .
2
Niz B se formira po formuli:

S1i S1i  S 2i
bi  
S 2i u suprotnom
Za računanje zbira S1i i S2i koristiti funkciju zbir.

Rešenje:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>

85
#define MAX_DIM 9

/* Prototip funkcije. */
int zbir(int a[][MAX_DIM],int,int,int,int);

void main(void)
{
int n,i,j,s1,s2,b[MAX_DIM],a[MAX_DIM][MAX_DIM];

randomize();
textbackground(0);
textcolor(15);
do{
clrscr();
printf("\n\t\t Unesite dimenziju matrice (N<10): ");
printf("\n\t\t\t N = ");
scanf("%d",&n);
}while(n<1||n>MAX_DIM||n%2!=0);
for(i=0;i<n;i++)
for(j=0;j<n;j++) a[i][j]=random(8)+1;

printf("\n\n\n\t Matrica A je:\n");


for(i=0;i<n;i++)
{
printf("\n\t");
for(j=0;j<n;j++) printf(" %d",a[i][j]);
}

/* Ovde se vidi da parametri funkcije odredjuju sta funkcija moze da uradi.


Dobrim izborom parametara, za koje nas u zadatku niko nije ni u jednom
trenutku ogranicio (koliko ih je i koji treba da budu), data funkcija
moze resavati trazenje zbira s1 i zbira s2. */

for(i=0;i<n/2;i++)
{
s1=zbir(a,n-i,i,i,1);
s2=zbir(a,i-1,n-i-1,n-i-1,-1);
if(s1>s2) b[i]=s1;
else b[i]=s2;
}

printf("\n\n\n\t Niz B je:\n\n\t");


for(i=0;i<n/2;i++) printf(" %d",b[i]);
gotoxy(1,25);
}

int zbir(int a[][MAX_DIM],int m,int p,int k,int q)


{
/* Definicija lokalnih promenljivih i njihova inicijalizacija. */
int s=a[p][p],j=p+q;

86
/* Izracunavanje trazenog zbira. */
while(j!=m)
{
s=s+a[k][j]+a[j][k];
j+=q;
}

return s;
}

Primer 3:
Data je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji bez korišćenja pomoćnih nizova ili matrica vrši sortiranje matrice desnom
spiralom u rastućem redosledu.

Rešenje

#include <stdio.h>
#include <conio.h>

#define MAX 9

int minimum(int a[][MAX],int m,int n,int k,int i,int j,int p,int str,int *q, int *w);

void main(void)
{
int a[MAX][MAX],m,n,min,pom,q,w;
int i,j,p,xu,yu,kon,k,xp=5,yp=5;

for(i=0;i<MAX;i++)
{
for(j=0;j<MAX;j++) a[i][j]=0;
}

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("Broj vrsta = ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&m);
}while(m<=0);

printf("Broj kolona = ");

87
xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0);

printf("Unesi matricu: ");


xu=wherex(),yu=wherey();
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a[i][j]);
gotoxy(xp,yp);
printf("%d",a[i][j]);
xp+=4;
}
yp++, xp=5;
}

/* Promenljiom p reguliše se zavrsetak prolaska kroz spiralu. Promenljiva k predstzavlja


red spirale. Svaka spirala sastoji se od cetiri prolaska (sleva na desno, od gore na dole,
sdesna na levo i od dole na gore). */

p=1;
kon=0;
k=0;
while(kon==0)
{
/*Svaki krug spirale pocinje sa glavne dijagonale.*/
i=j=k;
while(j<n-k&&kon==0)
{
/* Funkcija minimum odredi minimum od trenutnog elementa na spirali
do kraja spirale, po vrednosti vrati minimum, a po referenci odredi
pozicije prvog minimuma. */
min=minimum(a,m,n,k,i,j,p,1,&q,&w);

/* Mora se izvrsiti zamena mesta kako bi se izvrsilo sortiranje. */


a[q][w]=a[i][j];
a[i][j]=min;
if(p==m*n) kon=1;
p++, j++;
}

88
j--, i++;

while(i<m-k&&kon==0)
{
min=minimum(a,m,n,k,i,j,p,2,&q,&w);
a[q][w]=a[i][j];
a[i][j]=min;
if(p==m*n) kon=1;
p++, i++;
}
j--, i--;

while(j>=k&&kon==0)
{
min=minimum(a,m,n,k,i,j,p,3,&q,&w);
a[q][w]=a[i][j];
a[i][j]=min;
if(p==m*n) kon=1;
p++, j--;
}
j++, i--;

while(i>k&&kon==0)
{
min=minimum(a,m,n,k,i,j,p,4,&q,&w);
a[q][w]=a[i][j];
a[i][j]=min;
if(p==m*n) kon=1;
p++, i--;
}
i++, j++;
k++;
}

/* Stampanje sortirane matrice.*/


printf("\n\nSortirana matrica A poo desoj spirali je:\n");
for(i=0;i<m;i++)
{
for(j=0;j<n;j++) printf("%d\t",a[i][j]);
printf("\n");
}

getch();
}

/* Funkcija je lep primer koriscenja ekapsulacije podataka. Prosledjujemo po vrednosti red


spirale k, broj predjenih elemenata po spirali p I poziciju gde se u spirali nalazimo i i j. Mi
mozemo menjati te vrednosti jer funkcija mora naci minimum od pozicije i i j do kraja
spirale. Trenutne vrednosti ovih promenljivih se menjaju u funkciji, ali po zavrsetku
funkcije njihove vrednosti su ostale ne promenjene. */

89
int minimum(int a[][MAX],int m,int n,int k,int i,int j,int p,int str,int *q, int *w)
{
int min,pom;
unsigned kon;

/* Prvi element spirale proglasi se da je minimum. Sa q i w pamte se njene pozicije.Sa


promenljivom str regulisemo na kom se delu spirale nalazimo.*/

min=a[i][j];
*q=i,*w=j;
kon=0;
while(kon==0)
{
switch(str)
{
case 1: while(j<n-k&&kon==0)
{
if(a[i][j]<min) min=a[i][j],*q=i,*w=j;
if(p==m*n) kon=1;
p++;
j++;
}
j--, i++, str++;
break;

case 2: while(i<m-k&&kon==0)
{
if(a[i][j]<min) min=a[i][j],*q=i,*w=j;
if(p==m*n) kon=1;
p++, i++;
}
j--, i--, str++;
break;

case 3: while(j>=k&&kon==0)
{
if(a[i][j]<min) min=a[i][j],*q=i,*w=j;
if(p==m*n) kon=1;
p++, j--;
}
j++, i--, str++;
break;

case 4: while(i>k&&kon==0)
{
if(a[i][j]<min) min=a[i][j],*q=i,*w=j;
if(p==m*n) kon=1;
p++, i--;
}
i++, j++, str=1;

90
k++;
}
}

return min;
}

Primer 4:
Napisati C program koji omogućava unos rezultata svih utakmica na polusezoni, na
osnovu koje se formira matrica golova. Na osnovu matrice golova prikazuje se na ekranu
tabela lige sa brojem pobeda, nerešenih, poraza, datih golova, primljenih golova i broja
osvojenih bodova na polusezoni. Potom se unose rezultati utakmica drugog dela sezone,
(vodeći pri tome računa ko je domaćin a ko gost) i ispisuje tabela na kraju sezone pri
čemu su u tabeli odgovarajućim bojama vrste označene ekipe koje:

1 – idu u kup šampiona,


2 – idu u kup uefa, i
2 – ispadaju iz lige.

Rešenje

#include <stdio.h>
#include <conio.h>

#define MAX 10
#define BR 0
#define POB 1
#define NER 2
#define POR 3
#define DATI 4
#define PRIM 5
#define BOD 6
#define REZ 7

/* Prototipovi funkcija. */
int ispis(int n, int tabela[][REZ],int xi, int yi, int koji);
void unos(int n,int a[][MAX],int xu, int yu, int koji);
void sortiranje(int n, int tabela[][REZ], int a[][MAX], int koji);

void main(void)
{
int i,j,a[MAX][MAX],n,x,y,tabela[MAX][7],pom,k,xi,yi=0,xs,ys,xu,yu,yt;

91
/* Inicijalizacija matrice golova. */
for(i=0; i<MAX; i++)
for(j=0; j<MAX; j++) a[i][j]=0;

/* Inicijalizacija tabele prvenstva. */


for(i=0; i<MAX; i++)
{
for(j=0; j<REZ; j++) tabela[i][j]=0;
}

/* U tabelu se upisuju redni brojevi ekipa. */


for(i=0;i<MAX;i++) tabela[i][BR]=i+1;

textmode(64);
textcolor(0); textbackground(15);
clrscr();

do{
clrscr();
printf("\n\tBroj klubova: ");
scanf("%d", &n);
}while(n<4 || n>MAX);
printf("\n\n\tUnesite rezultate 1. dela");
xu=wherex()-26, yu=wherey()+1;

/* Funkcijom unos prvo se formira matrica golova prvog dela prvenstva. */


unos(n,a,xu,yu,1);

/* Sada se funkcijom sortiranje na osnovu matrice golova a, formira tabela


sortirana po broju bodova, a u slučaju istog broja bodova drugi kriterijum je gol
razlika. */

sortiranje(n,tabela,a,1);

/* Sada se prikazuje tabela prvog dela prvenstva, pozivajuci funkciju ispis. */


gotoxy(1,yu+3+n*(n-1)/4);
printf("\t\t\t TABELA POSLE 1. DELA");
printf("\n\t\b╔"); /* ALT+201 */
for(i=1;i<=57;i++) printf("═"); /* ALT+205 */
printf("╗"); /* ALT+187 */
yt=wherey();
printf("\n\t Br.\tPob\tNer\tPor\tDati\tPrim\tBodovi\n\t");
xi=wherex(),yi=wherey();
yi=ispis(n,tabela,xi,yi,1);

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

92
{
gotoxy(8,yt+i+1),printf("║"); /* ALT+186 */
gotoxy(66,yt+i+1),printf("║");
}

printf("\n\t\b╚");
for(i=1;i<=57;i++) printf("═");
printf("╝");

/* Unistava se matrica golova prvog dela prvenstva jer se moraju u nju smestiti
sada golovi drugog dela prvenstva. Matrica tabela se ne sme unistiti jer se
rezultati prenose u drugi deo lige. */

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


{
for(j=0; j<MAX; j++) a[i][j]=0;
}

gotoxy(45,yu-1);
printf("Unesite rezultate 2. dela");
xu=wherex()-25,yu=wherey()+1,yi-=2;

/* Unos matrice golova za drugi deo prvenstva. */


unos(n,a,xu,yu,2);

/* Sortiranje tabele na osnovu rezultata prvog i drugog dela prvenstva. */


sortiranje(n,tabela,a,1);

if(n<7) gotoxy(1,yi);
else gotoxy(1,yu+3+n*(n-1)/4);

printf("\t\t\t TABELA POSLE 2. DELA");


printf("\n\t\b╔");
for(i=1;i<=57;i++) printf("═");
printf("╗");
yt=wherey();
printf("\n\t Br.\tPob\tNer\tPor\tDati\tPrim\tBodovi\n\t");
xi=wherex(),yi=wherey();

/* Ispis tabele drugog dela prvenstva. */


ispis(n,tabela,xi,yi,2);

/* Oznacavanje odredjenom bojom ekipe koja ide u kup sampiona, ekipa koje idu
u kup uefa i ekipa koje napustaju drustvo najboljih. */

93
for(i=0;i<n+1;i++)
{
/* Oznaka ekipe za kup sampiona. */
if(i==0)
{
textbackground(BLUE);
textcolor(15);
gotoxy(65,yt+i+2);
cprintf(" ");
}

/* Oznaka ekipa za kup uefa. */


if(i==1||i==2)
{
textbackground(GREEN);
textcolor(0);
gotoxy(65,yt+i+2);
cprintf(" ");
}

/* Oznaka ekipa koje ispadaju iz lige. */


if(n-1==i||i==n-2)
{
textbackground(RED); textcolor(YELLOW);
gotoxy(65,yt+i+2); cprintf(" ");
}
gotoxy(8,yt+i+1),printf("║");
gotoxy(66,yt+i+1),printf("║");
}

printf("\n\t\b╚");
for(i=1;i<=57;i++) printf("═");
printf("╝");

gotoxy(65,50); textattr(32);
cprintf("Made by <mod64>");
_setcursortype(_NOCURSOR);
getch();
}

/* Funkcija ispis na osnovu formirane tabele prvenstva ispisuje tabelu prvog ili
drugog dela. Ako se promenljivoj koji prosledi broj 1 bice prikazana tabela prvog, a
u slucaju broja 2 drugog dela prvenstva. */

94
int ispis(int n, int tabela[][REZ],int xi, int yi, int koji)
{
int i,j;

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


{
if(koji==2)
{
if(i==0)textbackground(BLUE),textcolor(15);
if(i==1||i==2)textbackground(GREEN),textcolor(0);
if(i==n-1||i==n-2)textbackground(RED),textcolor(YELLOW);
}
for(j=0;j<REZ;j++)
{
gotoxy(xi+j*8,yi+i);
cprintf(" %d ",tabela[i][j]);
}
textbackground(15); textcolor(0);
}
yi=wherey()+n;
return yi;
}

/* Funkcija unos omogucava unos golova prvog ili drugog dela prvenstva. */
void unos(int n,int a[][MAX],int xu, int yu, int koji)
{
int i,j,x,y,br=0;

/* Klasican algoritam unosa, pri cemu u drugoj petlji j krece od i+1 kako bi se
izbegli susreti ekipe sa samom sobom ili dva puta igranja iste utakmice u jednom
delu prvenstva. */

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


{
for(j=i+1; j<n; j++)
{
/* Unos vrsimo u dve kolone kako bi svi rezultati bili
pregledni na ekranu. Nakon unosa oba dela prvenstva bice
prikazane cetiri kolone. */

if(br>n*(n-1)/4+1) gotoxy(xu+17,yu-1+br%(n*(n-1)/4+1));
else gotoxy(xu-1,yu+br);

/* Moramo voditi racuna da se obrcu indeksi vrsta i kolona


zbog domacinstva za drugi deo prvenstva u odnosu na prvi

95
deo. Tako se mora izvrsiti i prikaz ekipa (domacin : gost)
da se korisnik programa ne bi zbunio. */

if(koji==1) printf("%2d. - %2d. = ", i+1,j+1);


if(koji==2) printf("%2d. - %2d. = ", j+1,i+1);
x=wherex()+1, y=wherey();

/* Golovi se unose pomocu funkcije getch polazeci od


pretpostavke da jedna ekipa na jednoj utakmici nece dati
vise od devet golova. */

if(koji==1) a[i][j]=getche()-48;
if(koji==2) a[j][i]=getche()-48;
gotoxy(x,y);
printf(" : ");

if(koji==1) a[j][i]=getche()-48;
if(koji==2) a[i][j]=getche()-48;
br++;
}
}
}

/* Funkcija sortiranje na osnovu matrice tabele prvenstva i matrice golova, sortira


tabelu po opadajucem kriterijumu u odnosu na broj osvojenih bodova. */

void sortiranje(int n, int tabela[][REZ], int a[][MAX], int koji)


{
int i,j,k,pom;

/* Vrsi se prvo preuredjivanje tabele tako da redni brojevi vrsta odgovaraju


rednim brojevima ekipa radi lakseg kasnijeg sortiranja, na osnovu matrice golova.
Sortiranje ne treba vrsiti za prvi deo prvenstva jer je sve vec podeseno kako treba.
*/

if(koji==1)
{
for(i=0;i<n;i++)
{
for(j=n-1;j>i;j--)
{
if(tabela[j][BR]<tabela[i][BR])
{
/* Vrsi se zamena dve vrste. */
for(k=0;k<REZ;k++)

96
{
pom=tabela[i][k];
tabela[i][k]=tabela[j][k];
tabela[j][k]=pom;
}
}
}
}
}

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


{
for(j=0; j<n; j++)
{
/* Bodovi, pobede, nereseno, porazi */
if(j!=i)
{
/* Ko ne zna pravila fudbala, za pobedu se dobija tri boda,
a za nereseno 1 bod. */

if(a[i][j]>a[j][i]) tabela[i][BOD]+=3,tabela[i][POB]++;
if(a[i][j]==a[j][i]) tabela[i][BOD]+=1,tabela[i][NER]++;
if(a[i][j]<a[j][i]) tabela[i][POR]++;

/* Dopisuje se broj datih i broj primljenih golova. */

tabela[i][DATI]+=a[i][j];
tabela[i][PRIM]+=a[j][i];
}
}
}

/* Vrsi se sortiranje zamenom odgovarajucih vrsta. */

for(i=0;i<n;i++)
{
for(j=n-1;j>i;j--)
{
/* Proverava se prvi kriterijunm, a toje broj osvojenih bodova. */

if(tabela[j][BOD]>tabela[i][BOD])
{
/* Vrsi se zamena odgovarajucih vrsta. */
for(k=0;k<REZ;k++)
{
pom=tabela[i][k];

97
tabela[i][k]=tabela[j][k];
tabela[j][k]=pom;
}

/* Proverava se sada drugi kriterijum, a to je u slucaju jednakog


broja bodova, bolja je ona ekipa cija je gol-razlika broj datih i
primljenih golova veca. */

if(tabela[j][BOD]==tabela[i][BOD]&&
tabela[j][DATI]-tabela[j][PRIM]>tabela[i][DATI]-tabela[i][PRIM])
{
for(k=0;k<REZ;k++)
{
pom=tabela[i][k];
tabela[i][k]=tabela[j][k];
tabela[j][k]=pom;
}
}
}
}
}

Test primer programa:

98
3.4. ZADACI IZ VIŠEDIMENZIONALNIH
NIZOVA

Zadatak 1 (2)
Zadata je kvadratna matrica A dimenzije n ( n  N , n  12) . Napisati C program koji
utvrđuje koliko elemenata matrice A ima pozitivnu vrednost.

Zadatak 2 (2)
Zadata je kvadratna matrica A dimenzije n ( n  N , n  12) . Napisati C program koji
utvrđuje koliko elemenata matrice je veće od maksimalnog elementa na glavnoj
dijagonali.

Zadatak 3 (2)

99
Zadata je kvadratna matrica A dimenzije n ( n  N , n  12) . Napisati C program koji
na mestima gde su minimalni elementi upisati vrednosti maksimalnog elementa, a na
mestima gde se nalaze maksimalni elementi upisati vrednosti minimalnog elementa.

Zadatak 4 (2)
Zadata je kvadratna matrica A dimenzije n ( n  N , n  12) . Napisati C program koji
vrši zamenu elemenata glane dijagonale sa elementima sporedne dijagonale.

Zadatak 5 (2)
Zadata je kvadratna matrica A dimenzije n ( n  N , n  12) . Napisati C program koji
vrši zamenu elemenata prve i zadnje kolone.

Zadatak 6 (2)
Zadata je kvadratna matrica A dimenzije n ( n  N , n  12) . Napisati C program koji
na osnovu matrice A formira niz B. Niz B pretstavljaju maksimalne vrednosti kolona
matrice A.

Zadatak 7 (3)
Napisati C program koji utvrđuje koliko elemenata matrice A dimenzije mxn ( m
 N , n  N , m  10, n  10 ) predstavlja ujedno najmanji element svoje vrste i kolone.

Zadatak 8 (2)
Zadata je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji vrši sortiranje matrice A vrsta po vrsta.

Zadatak 9 (2)
Zadata je matrica X dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji na osnovu matrice X formira niz Z u koji ulaze redom minimalne vrednosti
kolona. Za određivanje minimalne vrednosti kolone koristiti funkciju minmkolone.
Zadatak 10 (2)
Napisati C program koji na osnovu matrice A dimenzije mxn ( m
 N , n  N , m  10, n  10 ) formira matricu B dimenzije (m-1)xn tako što se iz matrice A
u matricu B ne upisuje ona vrsta koja ima najveći zbir elemenata.

Zadatak 11 (2)
Napisati C program koji na osnovu unetog prirodnog broja n formira kvadratnu
matricu X dimenzije nxn ( n  N , n  12) sledećeg izgleda:

1 2 3    n 
0 1 2    n  1
A
       
 
0 0 0 0 0 0 1

Zadatak 12 (3)

100
Data je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji bez korišćenja pomoćnih nizova ili matrica sažima matricu izbacivanjem
odgovarajuće i-te vrste i j-te kolone, pri čemu se i i j unose sa ulaza i
i  [1..m], j  [1..n] .

Zadatak 13 (3)
Napisati C program koji na osnovu unetog prirodnog broja n formira kvadratnu
matricu A dimenzije nxn ( n  N , n  12) sledećeg izgleda:

1 n n  1    2
2 1 n    3

A  3 2 1    4
      
 
n n  1 n  2    1 

Zadatak 14 (3)
Napisati C program koji na osnovu unetog prirodnog broja n formira kvadratnu
matricu A dimenzije nx2n ( n  N , n  12) sledećeg izgleda:

1 2 3   n n    3 2 1 
n 1 2  n  1 n  1   2 1 n
A 
               
 
2 3 4    1 1    4 3 2 
Matrica A se formira vrsta po vrsta korišćenjem funkcije formirajvrstu.
Zadatak 15 (3)
Napisati C program koji na osnovu matrice A dimenzije nxn ( n  N , n  12) , pri
čemu se elementi matrice unose sa jednog polja i stalno se ima vizuelni prikaz formiranja
matrice (na samom početku formiranja svi elementi matrice imaju vrednost nula i tako su
i štampani na ekranu). Program treba da na osnovu matrice A formira niz B od n
elemenata na sledeći način:

b(1) = a(1,1)+a(1,2)+...+a(1,n)+a(2,1)+a(3,1)+...+a(n,1)
b(2) = a(2,2)+a(2,3)+...+a(2,n)+a(3,2)+a(4,2)+...+a(n,2)

101
.
.
.
b(n) = a(n,n)

Zadatak 16 (3)
Napisati C program koji omogućava unos matrice A dimenzije mxn ( m
 N , n  N , m  10, n  10 ) i sortira njene kolone u rastućem ili opadajućem redosledu.
Kolona j se sortira u opadajućem redosledu ako je srednja vrednost elemenata j-te kolone
manja ili jednaka srednjoj vrednosti svih elemenata matrice A, u suprotnom treba j-tu
kolonu sortirati u rastućem redosledu pri čemu j uzima vrednost sa intervala [1..n]. Za
sortiranje elemenata kolona koristiti funkciju sortkol, a za pronalaženje sredenje
vrednosti koristiti funkciju srednja. Na ekranu štampati preuređenu matricu A.

Zadatak 17 (3)
Napisati C program koji vrši sortiranje matrice A dimenzije mxn ( m
 N , n  N , m  10, n  10 ) vrsta po vrsta, na osnovu maksimalnog zbira po vrstama. Za
izračunavanje zbira elemenata vrste koristiti funkciju zbirvrste. Za sortiranje matrice A
vrsta po vrsta koristiti funkciju sortmatrice.
Napomena: Prilikom realizacije programa ne smeju se koristiti pomoćni nizovi ili
matrice.

Zadatak 18 (4)
Napisati C program koji na osnovu unetih prirodnih brojeva m i n koji sui manji od
sedam, korišćenjem generatora pseudoslučajnih jednocifrenih ili dvocifrenih prirodnih
brojeva formira matrice Amxn, a potom utvrđuje zonu određenu indeksima vrsta ili
kolona i, j, k i p (i, k - su indeksi vrsta koji obrazuju zonu i<k, a j, p - su indeksi
kolona koji obrazuju zonu j<p) koja ima najmanji zbir.
Zona mora sadržati minimalno četiri elementa matrice A. U slučaju da više zona
ima isti minimalni zbir, na ekranu štampati indekse koji obrazuju zonu, a ispod nje celu
zonu, itd..

Zadatak 19 (3)
Data je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). U matrici veliki
broj elemenata ima vrednost nula. Napisati C program koji određuje i štampa najmanji
broj nula po vrstama odnosno kolonama. Za određivanje broja nula u pojedinoj vrsti ili
koloni koristiti funkciju brojnula.

Na primer:
Ako matrica A ima sledeći izgled:

1 0 3 0 9 1 0 0 5
0 0 0 3 0 0 2 0 1
2 2 0 1 2 2 0 1 2
0 0 1 0 1 0 1 0 0

102
NAJMANJI BROJ NULA PO VRSTAMA = 2
NAJMANJI BROJ NULA PO KOLONAMA = 1

Zadatak 20 (4)
Napisati C program koji na osnovu unetih prirodnih brojeva m, n i k koji sui manji
od sedam, korišćenjem generatora pseudoslučajnih jednocifrenih prirodnih brojeva
formira matrice Amxn i Bmxk, a potom vrši cirkularnu rotaciju matrica A i B
istovremeno za jedno mesto u desno.
Za pomeranje elemenata jedne vrste za jedno mesto u desno koristiti funkciju
pomvrs, a za cirkularnu rotaciju niza za jedno mesto u desno koristiti funkciju
cirkrotniz.

Na primer:
m=5 n=7 k=4
Matrica A je: Matrica B je:
1 2 3 1 5 9 4 3 4 8 1
2 3 1 4 6 8 1 9 5 1 2
5 1 2 2 1 7 1 1 4 1 3
3 4 5 8 5 3 1 7 3 0 4
2 3 1 4 6 2 4 6 2 0 5

Nakon rotacije:
Matrica A je: Matrica B je:
5 1 2 3 1 5 9 4 3 4 8
1 2 3 1 4 6 8 1 9 5 1
2 5 1 2 2 1 7 1 1 4 1
3 3 4 5 8 5 3 1 7 3 0
4 2 3 1 4 6 2 4 6 2 0

Zadatak 21 (5)
Napisati C program koji na osnovu unetog prirodnog broja n 1<n<11 formira
kvadratnu matricu A dimenzije nxn i određuje determinantu matrice A.
Determinanta matrice se određuje postupkom kojim se matrica transformiše da svi
elementi ispod glavne dijagonale imaju vrednost nula i tada proizvod elemenata na
glavnoj dijagonali predstavlja determinantu matrice.
Zadatak 22 (4)
Napisati C program koji za svakog studenta učitava broj indeksa i osvojene bodove
sa tri zadatka A, B i C, a zatim izračunava ukupan broj osvojenih bodova i na osnovu
toga pozivom funkcije ocena određuje zaključnu ocenu.
Obezbediti da se reziltati štampaju po opadajućoj vrednosti broja bodova u obliku:

1. 5653 20 30 30 80 8
2. 5555 25 25 22 72 7
.

103
.
.

Zadatak 23 (4)
Napisati C program koji korišćenjem generatora pseudoslučajnih jednocifrenih
prirodnih brojeva i unetog prirodnog broja n formira kvadratnu matricu dimenzije nxn,
n<10. Program utvrđuje koja dijagonala paralelna glavnoj dijagonali ima najviše
proizvoljno ponovljenoh elemenata (na primer ako se na i-toj dijagonali nalaze sledeći
elementi 5 3 1 1 5 5 6 1 i 5, traženi broj ponavljanja je 4 jer se među različitim
brojevima 5 3 1 i 6 broj 5 najviše puta ponovio i to 4 puta). Za određivanje traženog
broja jedne dijagonale koristiti funkciju odredi.
Broj dijagonala je n a kreće se od glavne dijagonale kao prve a naredne se dobijaju
redom iz gornjeg trougla matrice. Svaka dijagonala ima tačno po n elemenata (u slučaju
da ima n-3 elementa dopunjava se sa odgovarajućom dijagonalom iz donjeg trougla
matrice koja ima 3 elementa).

Zadatak 24 (4)
Data je matrica A dimenzije mxn ( m  N , n  N , m  10, n  10 ). Napisati C
program koji bez korišćenja pomoćnih nizova ili matrica određuje redni broj vrste koja
sadrži najviše različitih elemenata. Za određivanje broja različitih elemenata vrste
koristiti funkciju brojrazvrste.

Zadatak 25 (4)
Podaci o dizačima tegova jednog turnira smeštaju se u matricu DIZACI3xN pri
čemu je N broj dizača koji su učestvovali na turniru. U matrici A i-ta kolona sadrži
podatke za i-tog dizača tegova u istoj težinskoj kategoriji. Prvi podatak u koloni je težina
koju je takmičar podigao u dizanju sa trzajem, drugi je težina koju je takmičar podigao u
dizanju sa izvlačenjem, a treći je telesna težina takmičara.
U slučaju istih podataka, uzima se da je uspešniji takmičar manje telesne težine.
Napisati C program koji ispisuje redni broj dizača koji je šampion: u prvoj kategoriji,
drugoj kategoriji i u obe kategorije (zbir težina) u ukupnom plasmanu.

Zadatak 26 (5)
Napisati C program koji matricu A dimenzije mxn ( m  N , n  N , m  10, n  10 )
formira korišćenjem generatora pseudoslučajnih jednocifrenih ili dvocifrenih prirodnih
brojeva, a zatim po izboru korisnika vrši rotaciju matrice za 90 0, 1800 ili 2700.
korišćenjem funkcija rot90, rot180 ili rot270.
Zadatak 27 (5)
Napisati C program koji na osnovu unetog prirodnog broja n n<11, prikazuje
simulaciju spiralnog formiranja kvadratne matrice A (leva spirala) dimenzije nxn.

Napomena: Voditi računa da li je n paran ili neparan broj što može uticati na
formiranje matrice.

Na primer:
Za n = 5 matrica A ima sledeći izgled:

104
1 16 15 14 13
2 17 24 23 12
3 18 25 22 11
4 19 20 21 10
5 6 7 8 9

Zadatak 28 (5)
Napisati C program koji će predstavljati igricu pod nazivom XOX dimenzije nxn
(2<n<10) Igra je namenjena za dva igrača. Pozicije polja na tabli numerisani su
brojevima od 1 do 9 o što moraju znati i igrači. Prvi je uvek "O", a drugi je "X".
Pobednik je onaj igrač koji ima sastavljene n u nizu oznake ("O" ili "X"). Na kraju igre
ispisati koji je igrač pobednik ili da je igra završena nerešeno. Program realizovati
matricom A koja je dimenzije 60x50, koliko ima i polja za igru. Ako je vrednost člana 0
znači da niko od igrača do tada nije osdigrao potez na tom polju, ako je vrednost 1 na tom
polju je ranije već odigran potez od strane igrača "O", a ako je vrednost 2 na tom polju je
ranije već odigran potez od strane igrača "X". Igra se može završiti i ranije ako neko od
igrača odigra nulu kao potez sa numeričke tastature, i tada se na ekranu ispisuje koji je
igrač predao partiju.

Zadatak 29 (5)
Napisati C program koji omogućava formiranje matrica Amxn i Bkxp te po izboru
korisnika izračunava i prikazuje: zbir, razliku ili proizvod matrica A i B.
Funkcijom prikaziizbor treba prikazati sledeću sliku na ekranu:

*********************************
* RAD SA MATRICAMA *
*********************************
* 1) - UNOS MATRICA A I B *
* 2) - SABIRANJE MATRICA, A+B *
* 3) - RAZLIKA MATRICA, A-B *
* 4) - MNOZENJE MATRICA, A*B *
* 5) - IZLAZ IZ PROGRAMA *
*********************************
* VAS IZBOR: _ *
*********************************
Funkcija prikaziizbor omogućava da korisnik izabere jednu od ponuđenih opcija i
vraća redni broj izabrane opcije.
Funkcija unos matrica omogućava unos matrica A i B pri čemu se prvo unose
dimenzije matrice A uz ispisan opseg vrednosti promenljivih m i n, a potom se
omogućava unos matrice tako što se na ekranu ispisuje koji se element matrice unosi (na
primer a(1,1) = ). Elementi se unose vrsta po vrsta pri čemu su vrste razdvojene praznim
redom (na ekranu). Na isti način se frmira i matrica B. Funkcija nakon unosa vraća
vrednost 1 ako je unos uspešno urađen.

105
Funkcija sabiranjematrica omogućava da se saberu matrice A i B ako je to
moguće. U slučaju da je sabiranje moguće funkcija vraća 1 a u suprotnom 0. Matrice se
mogu sabrati ako imaju iste dimenzije i ako su prvo unesene matrice. Na ekranu ispisati
odgovarajuću poruku zašto se matrice nisu mogle sabrati.
Funkcija oduzimanjematrica omogućava da se oduzmu matrice A i B ako je to
moguće. U slučaju da je oduzimanje moguće funkcija vraća 1 a u suprotnom 0. Matrice
se mogu oduzeti ako imaju iste dimenzije i ako su prvo unesene matrice. Na ekranu
ispisati odgovarajuću poruku zašto se matrice nisu mogle oduzeti.
Funkcija mnozenjematrica omogućava da se pomnože matrice A i B ako je to
moguće. U slučaju da je množenje moguće funkcija vraća 1 a u suprotnom 0. Matrice se
mogu pomnožiti ako je broj vrsta matrice A jednak broju kolona matrice B. Rezultujuća
matrica imaće broj vrsta jednak broju vrsta matrice A i broj kolona jednak broju kolona
matrice B. Matrice moraju prvo biti unesene. Na ekranu ispisati odgovarajuću poruku
zašto se matrice nisu mogle pomnožiti.

Zadatak 30 (5)
Napisati C program koji predstavlja igricu “pogodi“. Igra je namenjena za samo
jednog igrača. Na ekranu se iscrtava tabla koja se sastoji od hodnika i zidova. U
hodnicima mogu se nalaziti kose crte u desno ili kose crte u levo. Na vrhu table nalazi se
pokretni klizač koji se stalno kreće sve dok se ne pritisne SPACE. Nakon pritiska na
SPACE klizač prestaje da se kreće iz iz njega na dole spušta se loptica. Loptica može da
se kreće samo kroz tunele, na dole slobodnim padom, ako naiđe na kosa crta na desno da
se kreće na desno sve dok ne naiđe do kraja table ili na rupu na dole, ili ako naiđe na kosa
crta na levo da se kreće na levo sve dok ne naiđe do kraja table ili na rupu na dole.
Sa leve i desne strane na krajevima table nalaze se zidovi, a sa donje strane nalaze
se polja koja su tamne boje i koja treba pogoditi, a ima ih šest (numerisani su od 1 do 6) i
razbacani su u donjem redu table. Nakon pritisnutog tastera SPACE kuglica u obliku
slova o počinje da se kreće i ako se spusti na neki broj taj broj promeni boju tako da je
vidno da je pogođen. Ako kuglica udari u jedan od zidova kugla nije ništa uradila i klizač
ponovno počinje sa kretanjem. Tabla se može (ne uključujući liniju sa klizačem i liniju
sa brojevima) rorirati za jedno mesto cirkularno na gore ili za jedno mesto cirkularno na
dole (upravljanje se vrši sa strelicama na gore ili strelicama na dole). Rotiranje table
može se vršiti samo dok se klizač kreće (tj nema loptice da se kreće kroz tablu). Ako
igrač sa lopticom pogodi već pogođeno mesto (broj je označen svetlom bojom) broj
potamni tako da izgleda kao da ranije nije ni pogodio to polje. Na raspolaganju igrač ima
deset pokušaja da pređe tablu.
Problem se rešava sa statičnom matricom koja se mora dobro osmisliti tako da igra
ima smisla.

106
107
4. POGLAVLJE

STRINGOVI

108
4.1. STRINGOVI

Definicija stringa:

String je niz znakova koji se završava znakom '\0'. Prazan string sadrži samo
znak '\0'.

U definiciji stringa naznačeno je da je string niz. To znači da se kroz string prolazi


kao i kroz niz sa indeksom. Indeks prvog znaka stringa je 0. Za string ne moramo znati
koliko ima znakova jer je poslednji znak stringa '\0'. Uslov izlaska iz ciklusa kada se
prolazi kroz string je: prolazi kroz string sve dok je znak stringa različit od znaka '\0'.

Deklaracija stringa:

char imestringa[MAX];

Prilikom inicijalizacije stringa prvo se navodi rezervisana reč char koja


označava da elementi niza pretstavljaju znakovi. Srednje zagrade označavaju da je u
pitanju niz. Konstantan izraz MAX mora imati uvek za 1 veću vrednost u odnosu na
klasičan niz, jer striing mora sadržati znak '\0'. Na primer ako string treba da prihvati
JMBG (jedinstveni matični broj građana) koji uve ima 13 brojeva, to MAX mora imati
vrednost 14.

Inicijalizacija stringova:

String se može inicijalizovati prilikom deklaracije stringa ili u toku


izvršavanja programa. Inicijalizacijom stringa se vrši tako što se prvom elementu
stringa dodeli znak '\0 ' koji označava kraj stringa.

Inicijalizacija stringa prilikom deklaracije:


char imestringa[MAX]= ""; /* Nema nista izmedju znakova navoda.
*/

Inicijalizacija stringa u toku izvršavanja programa:


imestringa[0]= '\0';

Unos stringa:
Unos stringa se najčešće vrši bez indeksa, kao što je to
slučaj kod niza, a uz pomoć funkcija scanf ili gets.

scanf("%s ",imestringa); ili


gets(imestringa);

109
Format %s označava konverziju u string. Funkcija fgets omogućava unos
stringa sve dok se ne pritisne ENTER i time dodaje znak '\0'. Ako funkcija naiđe na
grešku prilikom unosa vraća simboličku konstantu NULL.

Ispis stringa:
Ispis stringa se najčešće vrši bez korišćenja indeksa (za
razliku od niza) a uz pomoć funkcija printf ili puts.

printf("%s ",imestringa); ili


puts(imestringa);

Funkcija puts izvršava ispis znakova sve dok se ne dođe do znaka '\0' i prelazi
u novi red.

Primer 1:
Napisati C program koji omogućava unos stringa s i utvrđuje
koliko se puta znak c nalazi u stringu s. Znak c se unosi sa tastature.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h> /* U ovoj biblioteci se nalai funkcija fgets. */

#define MAX 30

void main(void)
{
char c, s[MAX];
unsigned i,br=0;
s[0]='\0'; /* Inicijalizacija stringa s. */

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("String = ");
gets(s); /* Unos stringa s. */
printf("Znak = ");
c=getche();

br=0, i=0;
while(s[i]!='\0')
{
if(s[i]==c) br++;
i++; /* Kada koristite while ciklus cesto zaboravite da povecate indeks sa
kojim se prolazi kroz string. */
}

110
printf("\n\nBroj pojave = %d.",br);
getch();
}

Test primer programa:

Primer 2:
Napisati C program koji vrši sažimanje stringa s, tako što se uzastopni višestruki niz
praznina zamenjuje sa samo jednom prazninom.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define MAX 30

void main(void)
{
char c, s[MAX];
unsigned i,j;

s[0]='\0';

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("String = ");
gets(s);

111
i=0;
while(s[i]!='\0')
{
/* Preskaci znakove do prve praznine. */
while(s[i]!=' '&&s[i]!='\0') i++;

if(s[i]!='\0')
{
if(s[i+1]!=' ') i++;
else{
/* Sazimanje stringa. */
j=i;
while(s[j]!='\0') s[j]=s[j+1],j++;
}
}
}
printf("\n\nNovi string = %s",s); /* Ispis novog stringa. */
getch();
}

Test primer programa:

112
4.2. STRINGOVI I FUNKCIJE

Iz definicije se vidi da je string niz znakova. To znači da sve osobine koje su


važile za niz važe i za string.

Kao i kod nizova string se ne može preneti kao argument funkcije, već se po
referenci prosleđuje adresa početka stringa. Za rad sa stringovima u funkcijama
osim adrese početka stringa ništa više nije potrebno, jer se string završava sa
znakom '\0'.
Prilikom testiranja zadataka sa stringovima, potrebno je samo prilikom
prvog testa uneti string. Sva ostala testiranja kada se unosi string pritiskate taster
desna strelica i string koji ste poslednji uneli biće ponovno ispisan.

Primer 1:
Napisati funkciju unos koja omogučava unos imena. Završetak unosa imena je
pritisak na taster ENTER. Ako korisnik unese neki karakter koji nije slovo, osim praznog
mesta, string će se izbrisati i moraće se izvršiti ponovni unos. Prvom slovo mora bitio
veliko, a ako nije funkcija prvo slovo konvertuje u veliko slovo.
Napisati C program koji demopnstrira primenu funkcije unos.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

/* Prototip funkcije za unos imena. Funkcija vraca adresu na formirani string.*/


char *unos(char *s);

void main(void)
{
/* Deklaracija stringa. */
char str[30]= "";

textmode(3);
textbackground(0);
textcolor(15);
clrscr();
printf("Unesite ime: ");
unos(str);

printf("\n\nVase ime je %s!!",str);


getch();
}

/* Definisanje funkcije. */

113
char *unos(char *s)
{
/*Deklaracija lokalnih promenljivih. */
unsigned xp, yp, i=0, j;
char c;

xp=wherex(), yp=wherey();
do{
c=getch();

if((c>='a'&&c<='z')||(c>='A'&&c<='Z')||c==' ')
{
/* Ako je prvo slovo malo, vrsi se pretvaranje u veliko.
*/
if(i!=0) if(c>='A'&&c<='Z') s[i]='a'+c-'A';
else s[i]=c;
else if(c>='a'&&c<='z') s[i]='A'+c-'a';
else s[i]=c;

/* Sada je slovo ispravno i moze se stampati na ekranu.


*/
printf("%c",s[i]);
i++;
}else{

/* Ako nije slovo ispitujemo da li je ENTER te ako nije mora


izvrsiti ponovni unos. ENTER odgovara karakteru ’\r’ */

if(c!='\r')
{
gotoxy(xp,yp);
for(j=0;j<i;j++) printf(" ");
gotoxy(xp,yp);
i=0;
}
}
}while(c!='\r');
s[i]='\0';
gotoxy(xp+strlen(s),yp);
return s;
}

Primer 2:
Napisati C program kojim se unosi korektno zapisan aritmetički izraz sa
zagradama, a zatim određuje njegova vrednost. Operandi u izrazu su celi brojevi, a
operacije mogu biti (+,-,* i /) pri čemu je / celobrojno deljenje. Pri određivanju vrednosti
izraza voditi računa o prioritetu operacija. Prikazati simulaciju formiranja rezultata izraza
red po red, pri čemu se u svakom novom redu ispisuje izraz bez izraza (koji se alazio
između dve zagrade sa najvećim prioritetom) i zagrada između kojih se izraz nalazio.
Rešenje

114
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>

#define MAX 200

/* Prototipovi funkcija. */
void brisipraznineitabulatore(char *s);
char *izraz1(char *s);
char *izraz(char *s);
int operand(char *s, int k, char *s1);
int operacija(char *x, char *y, char op);
void pretvori(int rez, char *s);
char *brisi(char *s, int k, int m);
void ubaci(char *s, int k, char *s1);

void main(void)
{
int x,y;
char s[MAX];

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

printf("Unesite izraz:\n");
gets(s);
brisipraznineitabulatore(s);
printf("\n = %s",s); /* Prikaz stringa s bez praznina i tabulatora. */
izraz1(s);
getch();
}

/* Funkcija brisipraznineitabulatore brise sve moguce praznine i tabulatore iz stringa s. */


void brisipraznineitabulatore(char *s)
{
int i=0, j;

while(s[i]!='\0')
{
if(s[i]==' '||s[i]=='\t')
{
/* Ako naidjemo na prazninu ili tabulator ’\t’ pomeramo string sdesna na
levo tako da se taj karakter izbrise iz stringa. */

j=i+1;
while(s[j]!='\0') s[j-1]=s[j],j++;

115
/* Obavezno dodati ’\0’ za kraj stringa. */
s[j-1]='\0';
}else i++;

/* Brojac se pomera samo ako karakter nije praznina ili tabulator, inace da se i
povecava uvek za jedan nastali bi problemi ako bi string imao uzastopan niz
praznina ili tabulatora. Ne bi se svi obrisali. */
}
}

/* Funkcija izraz1 izracunava izraz koji poseduje zagrade pozivajuci funkciju izraz koja
racuna izraz bez zagrada. */
char *izraz1(char *s)
{
int i,j,k,br;
char s1[MAX],*s2;

/* Pokazivac s2 nam treba jer funkcija izraz vraca pokazivac. Prvo se mora
izdvojiti izraz koji je izmedju zagrada. Da bi se to postiglo prvo se trazi
zatvorena zagrada, prolazeci kroz string sleva na desno, te se od nje krece nazad
da bi se pronasao indeks otvorene zagrade. Izraz izmedju zagrada se smesta u
string s1 i brise se taj deo stringa zakljucno sa zagradama. Izracunava se izraz
koji se nalazi u stringu s1 i rezultat smesta u string s2. String s2 se ubacuje u
string s. Postupak se ponavlja dok postoji zagrada u izrazu. */

do{
i=0;
while(s[i]!=')'&&s[i]!='\0') i++;
if(s[i]!='\0')
{
j=i;
while(s[j]!='(') j--;
for(k=j+1;k<i;k++) s1[k-j-1]=s[k];
s1[k-j-1]='\0';
brisi(s,j,i);
s2=izraz(s1);
if(atoi(s2)<0)
{

/* Ako je rezultat izraza izmedju zagrada negativan broj ne


smemo ubaci kao takvog ako je pre zagrada bio neki operator, jer
bismo tada dobili dva operatora jedan do drugog. Problem se
resava tako sto se upise njegova pozitivna vrednost, a menja
znak prvom znaku plus u minus ili minus u plus koji su
prethodili tim zagradama. Ako se dodje do prve otvorene zagrade
ili pocetka izraza, to je znak da se posle otvorene zagrade ili na
pocetku izraza mora ubaciti negativni predznak. */

k=1;
while(s2[k]!='\0') s2[k-1]=s2[k],k++;
s2[k-1]='\0';

116
ubaci(s,j,s2);
k=j;
while(s[k]!='+'&&s[k]!='-'&&s[k]!='('&&k>0) k--;
if(k==0&&s[k]!='+'&&s[k]!='-'&&s[k]!='(') strcpy(s2,"-"),ubaci(s,0,s2);
else{
if(s[k]=='+') s[k]='-';
else
{
if(s[k]=='-') s[k]='+';
else if(s[k]=='(') strcpy(s2,"-"),ubaci(s,k+1,s2);
}
}
}
else ubaci(s,j,s2);
}else{
s2=izraz(s);
strcpy(s,s2);
}

/* Ispisujemo izraz jer smo se u ovom trenutku oslobodili jednog izraza izmedju
zagrada. */
printf("\n = %s",s);

/* Uvek se mora brojati broj operatora, jer se u izrazu izmedju zagrada moze
osloboditi vise od jednog operatora. */
br=0;
i=0;
while(s[i]!='\0')
{
if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/') br++;
i++;
}
if(br==1&&s[0]=='-') br--;
}while(br>0);
return s;
}

/* Funkcija izraz omogucava izracunavanje izraza bez zagrada uz postovanje prioriteta


operacija. */
char *izraz(char *s)
{

/* U funkciji je a prvi operand, b je drugi operand, d je treci operand, a c je rezultat.


Promenljiva op1 je prvi operator a op2 drugi operator. */
int i,i1,i2,i3,rez,k,br=0;
char a[MAX],b[MAX],c[MAX],d[MAX],op1,op2;

/* Prvo utvrdimo koliko dati izraz sadrzi operatora. Krece se od drugog znaka jer moze se
desiti da prvi znak bude predznak broja a on ne cini operator. */
i=1;
while(s[i]!='\0')

117
{
if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/') br++;
i++;
}

/*Mozda osim predznaka prvog broja nije bilo operatora. */


if(br==0) return s;

/* Izraz se izracunava sve dokle god izraz sadrzi bar jedan operator. */
do{
i1=operand(s,0,a); /* Uzima se prvi operand. */
op1=s[i1]; /* Izdvaja se prvi operator. */
i2=operand(s,i1+1,b)+i1+1; /* Izdvaja se drugi operand. */

if(br>1)
{
i3=operand(s,i2+1,d)+i2+1; /* Izdvaja se treci operand. */
op2=s[i2]; /* Izdvaja se drugi operator. */

/* Sada se mora resiti problem prioriteta operatora, te se zbog toga


posmatra drugi operator, i ako je on * ili / on ce se prvi izvrsiti. Izracuna
se operacija izmedju dva operanda (mora se voditi racuna ko je levi a ko
desni operand), pretvori se rezultat iz broja u string c. Prethodni izraz
koga su cinila dva operanda i operacija se izbrisu iz stringa s i umesto
njih se ubacuje rezultujuci string c. */

if(op2=='*'||op2=='/')
{
rez=operacija(b,d,op2);
pretvori(rez,c);
brisi(s,i1+1,i3-1);
ubaci(s,i1+1,c);
}else{
rez=operacija(a,b,op1);
pretvori(rez,c);
brisi(s,0,i2-1);
ubaci(s,0,c);
}
}else{
rez=operacija(a,b,op1);
pretvori(rez,c);
brisi(s,0,i2-1);
ubaci(s,0,c);
}

/* Broj operatora se smanjuje ali ne uvek za jedan nakon zavrsetka uzraza. Stoga
uvek moramo brojati broj operacija koji je preostao. */

br=0;
i=0;
while(s[i]!='\0')

118
{
if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/') br++;
i++;
}

/* Moze se desiti da se u izrazu nalazi samo jedna operacija koja pretstavlja predznak broja,
tada u sustini nema vise operatora i broj operacija se mora smanjiti na nulu. */

if(br==1&&s[0]=='-') br--;
}while(br>0);

return s;
}

/* Funkcija operand iz stringa s koji pretstavlja izraz bez zagrada izdvaja string koji
pretstavlja operand. Operand se vadi od indeksa k do sledeceg operatora ili kraja stringa s.
String s1 pretstavlja formirani operand, a funkcija vraca indeks pojave znaka ’\0’. */
int operand(char *s, int k, char *s1)
{
int i=0;

/* Moramo preskociti predznak operanda, pa tek tada traziti kraj operanda, a on se nalazi
pri pojavi sledece operacije. */

if(s[k]=='+'||s[k]=='-') s1[0]=s[k],i++;
while(s[k+i]!='+'&&s[k+i]!='-'&&s[k+i]!='*'&&s[k+i]!='/'&&s[k+i]!='\0') s1[i]=s[k+i],i+
+;
s1[i]='\0'; /* Formirani string mora sadrzati znak '\0'. */

/* Funkcija vraca adresu pocetka formiranog stringa. */


return strlen(s1);
}

/* Funkcija operacija izracunava operaciju izmedju dva operanda i vraca celobrojni


rezultat. Operandi su stringovi. */
int operacija(char *x, char *y, char op)
{
int rez;

switch(op)
{
case '+': rez=atoi(x)+atoi(y);
/* Funkcija atoi konvertuje string u ceo broj. */
break;
case '-': rez=atoi(x)-atoi(y);
break;
case '*': rez=atoi(x)*atoi(y);
break;
case '/': if(atoi(y)!=0) rez=atoi(x)/atoi(y);
else{

119
/* Deljenje sa nulom. */
printf("ERROR");
exit(1);
}
}
return rez;
}

/* Funkcija vrsi pretvaranje broja rez u string s. */


void pretvori(int rez, char *s)
{
int i,j,k;

/* Prvo se utvrdi da li operand ima negativni predznak. Zatim utvrdimo koliko cifara ima
broj rez i taj podatak smestimo u promenljivu k. */

if(rez<0)
{
strcpy(s,"-");
j=1;
}else{
s[0]='\0';
j=0;
}
i=abs(rez);

k=1;
while(i!=0) k*=10,i/=10;
k/=10;

/* Sada treba konvertovati cifru po cifru u karakter i upisivati ga u string. */


rez=abs(rez);
while(k!=0)
{
s[j]=rez/k+48;
rez=rez-(rez/k)*k;
k/=10, j++;
}
s[j]='\0';
}

/* Funkcija brisi brise deo stringa s pocev od pozicije k do pozicije m i vraca pokazivac
na pocetak stringa */
char *brisi(char *s, int k, int m)
{
int i=0;
while(s[m+i+1]!='\0')
{
s[k+i]=s[m+i+1];
i++;
}

120
s[k+i]='\0';
return s;
}

/* Funkcija ubaci vrsi ubacivanje stringa s1 (koji pretstavlja resenje dela izraza u obliku
jednog broja) u string s pocev od pozicije k. */
void ubaci(char *s, int k, char *s1)
{
int i=0,n,p;

n=strlen(s); /* Funkcija strlen izracunava duzinu stringa (broji znakove do znaka ’\0’). */
while(s1[i]!='\0')
{
p=n+1;
while(p>=k+i) s[p]=s[p-1],p--;
s[k+i]=s1[i];
i++;
n++;
}
}

Test primer programa:

121
4.3. STRINGOVI I POKAZIVAČI

 Indentifikator stringa je konstantan pokazivač (ne smete mu promeniti


adresu na koju pokazuje) na početak stringa,
 Veza između stringa i pokazivača može se predstaviti pomoću formule

s[i]  *(s + i)

 Kraj stringa označava se sa znakom '\0' čija je vrednost broj nula.


 Prenosom po referenci adrese početka stringa formalnom argumentu
funkcije omogućava da se pomoću formalnog argumenta prolazi kroz string.

Primer 1:
Napisati C program koji omogućava unos stringa i korišćenjem funkcije duzina
određuje dužinu stringa. Dužinu stringa pretstavlja broj znakova stringa bez znaka '\0'.
Prilikom realizacije funkcije nemojte koristiti lokalne promenljive (samo formalne
argumente) kao ni bilo koju bibliotečku funkciju.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define MAX 30

unsigned duzina(char *s, int k);

void main(void)
{
char s[MAX];

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\n\tString = ");
gets(s);

printf("\n\tDuzina stringa = %d",duzina(s,0));


gotoxy(1,25);
getch();
}

122
/* Funkcija izracunava duzinu stringa, a kako se ne smeju koristiti lokalne promenljive
prosledili smo jos jedan parametar koji pretstavlja brojac karaktera. */

unsigned duzina(char *s, int k)


{

/* Uslov koji se nalazi u while naredbi je jako interesantan. Prvo se nailazi na operator
diferenciranja, te ako karakter nije '\0' vrednost argumenta s se povecava za 1 cime je
adresa povecana za 1 i prelazi se na sledeci karakter stringa. Kada se dodje na kraj
stringa, diferenciranjem (*s) pokazace karakter '\0', a kako je njena vrednost broj 0, time
je zavrsen while ciklus. Brojac k nije odbrojao karakter '\0'. */

while(*s++) k++;

/* Funkcija vraca broj karaktera koji ima string, a ujedno ta vrednost pretstavlja indeks
kraja stringa, odnosno poziciju gde se nalazi znak '\0'. */
return k;
}

Primer 2:
Napisati C program koji omogućava brisanje dela stringa pomoću funkcije brisi.
Funkcija brisi omogućava brisanje dela stringa s između indeksa k i p, uključujući i
karaktere koji se nalaze na tim indeksima Funkcija vraća 1 ako je uspešno obavila posao
ili 0 u suprotnom. Prilikom realizacije funkcije nemojte koristiti lokalne promenljive
(samo formalne argumente) kao ni bilo koju bibliotečku funkciju osim funkcije duzina iz
prošlog zadatka.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define MAX 30

unsigned duzina(char *s, int k);


unsigned brisi(char *s, int k, int p);

void main(void)
{
char s[MAX];
int k, p;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\n\tString = ");
gets(s);

123
printf("\tk = ");
scanf("%d",&k);
printf("\tp = ");
scanf("%d",&p);

if(brisi(s,k-1,p-1)) printf("\n\n\tNovi stringa = %s",s);


else printf("\n\n\tOva operacija brisanja se ne moze izvrsiti!!");

gotoxy(1,25);
getch();
}

/* Funkcija izracunava duzinu stringa. */


unsigned duzina(char *s, int k)
{
while(*s++) k++;
return k;
}

/* Funkcija omogucava brisanje dela stringa izmedju indeksa k i p. */


unsigned brisi(char *s, int k, int p)
{
if(p<k||p>duzina(s,0)) return 0;

/* Pracenjem promenljive s videcete da nestaje raniji deo stringa (koji se prati) kada se
menja vrednost promenljive s, jer s predstavlja pokazivac na pocetak stringa. */

s+=k;
while(*(s+p-k+1))
{
*s=*(s+p-k+1);
*s++;
}
*s='\0';

return 1;
}

Primer 3:
Napisati C program koji poredi dva stringa korišćenjem funkcije poredi. Funkcija
poredi poredi string s kao prvi argument sa stringom t koji je drugi argument funkcije i
vraća: 0 – ako su stringovi isti, pozitivna vrednost ako je s>t, ili negativnu vrednost ako
je s<t. String s je veći od stringa t ako su do indeksa k svi karakteri stringa s bili isti kao i
kod stringu t, a na k-tom indeksu je redni broj (iz ASCII tabele) karaktera iz stringa s
imao veću vrednost od rednog broja karaktera na k-tom indeksu stzringa t.
Prilikom realizacije funkcije nemojte koristiti lokalne promenljive (samo formalne
argumente) kao ni bilo koju bibliotečku funkciju.

Rešenje

124
#include <stdio.h>
#include <conio.h>
#include <string.h>

#define MAX 30

int poredi(char *s, char *t);

void main(void)
{
char s[MAX], t[MAX];
int k;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\n\tPrvi string = ");


gets(s);
printf("\tDrugi string = ");
gets(t);

k=poredi(s,t);
if(k<0) printf("\n\n\tPrvi string je manji od drugog stringa!!");
else{
if(k==0) printf("\n\n\tStringovi su jednaki!!");
else printf("\n\n\tPrvi string je veci od drugog stringa!!");
}

gotoxy(1,25);
getch();
}

/* Funkcija poredi dva stringa. */


int poredi(char *s, char *t)
{

/* Dokle god su karakteri iz stringova jednaki i nismo dosli do kraja niti jednog
stringa ciklus se izvrsava. */

while(*s++ == *t++ && *s && *t);

return *s - *t;
}

125
4.4. OSNOVNE FUNKCIJE ZA RAD SA ZNAKOVIMA I
STRINGOVIMA

Osnovne funkcije za rad sa znakovima

Zaglavlje <ctype.h> deklariše funkcije za proveravanje znakova, tj određuje u


koju kategoriju spada dati znak (malo slovo, veliko slovo, broj, itd).

int insalnum(int charakter);

character – je ASCII znak koji se proverava.

Funkcija isalnum vraća vrednost različitu od nule ako je navedeni znak character
slovo ili cifra.

int isalpha(int caracter);

character – je ASCII znak koji se proverava.

Funkcija isalpha vraća vrednost različitu od nule ako je navedeni znak slovo.

int isdigit(int carakter);

character – je ASCII znak koji se proverava.

Funkcija isdigit vraća vrednost različitu od nule ako je navedeni znak character
cifra.

int isgraph(int character);

character – je ASCII znak koji se proverava.

Funkcija isgraph vraća vrednost različitu od nule ako se navedeni znak character
može prikazati na ekranu (opseg kodova od 33 do 126) izuzimajući znak za razmak.

126
int islower(int caracter);

character – je ASCII znak koji se proverava.

Funkcija islower vraća vrednost različitu od nule ako je navedeni znak character
malo slovo.

int isupper(int character);

character – je ASCII znak koji se proverava.

Funkcija isupper vraća vrednost različitu od nule ako je navedeni znak character
veliko slovo.

int isspace(int character);

character – je ASCII znak koji se proverava.

Funkcija isspace vraća vrednost različitu od nule ako je navedeni znak character
nevidljiv na ekranu (tabulator, vertikalni tabulator,...)

int isprint(int caracter);

character – je ASCII znak koji se proverava.

Funkcija isprint vraća vrednost različitu od nule ako se navedeni znak character
može prikazati na ekranu.

int toupper(int caracter);

character – je ASCII znak koji se proverava.

Funkcija toupper konvertuje malo slovo u veliko. Ako je navedeno slovo character
veliko funkcija ga ostavlja nepromenjenim.

int tolower(int caracter);

character – je ASCII znak koji se proverava.

Funkcija tolower konvertuje veliko slovo u malo. Ako je navedeno slovo character
malo funkcija ga ostavlja nepromenjenim.

127
Osnovne funkcije za rad sa stringovima

U zaglavlju <string.h> definisane su funkcije za rad sa stringovima.

char *strcpy(char *s, char *t);

Funkcija strcpy kopira string t u string s znak po znak. Prethodni sadržaj stringa s se
gubi. Funkcija vraća pokazivač na string s.

char *strcnpy(char *s, char *t, int n);

Funkcija strncpy kopira prvih n znakova iz stringa t u string s. Funkcija vraća


pokazivač na string s.

char *strcat(char *s, char *t);

Funkcija strcat dodaje string t na kraj stringa s i vraća pokazivač na string s.

char* strncat(char *s, char *t, int n);

Funkcija strncat dopisuje najviše n znakova iz stringa t na kraj stringa s.

int *strcmp(char *s, char *t);

Funkcija strcmp poredi dva stringa znak po znak. Ako je znak u prvom stringu s
veći od odgovarajućeg znaka u drugom stringu t, funkcija vraća negativnu vrednost. Ako
su stringovi indentični funkcija vraća 0.

int *strncmp(char *s, char *t, int n);

Funkcija strncmp poredi prvih n bajtova dva niza znakova. Funkcija je identična
funkcija strcmp, stim što poredi samo prvih n karaktera.

char *strchr(char *s, int character);

Funkcija strchr traži prvo pojavljivanje navedenog ASCII znaka character u stringu
s, te ako uspešno obavi zadatak funkcija vraća pokazivač na prvo pojavljivanje
navedenog znaka ili vrednost NULL u suprotnom.

128
char *strrchr(char *s, int character);

Funkcija strchr vraća pokazivač na prvu pojavu određenog znaka character s desne
strane stringa s. Ako funkcija uspešno obavi zadatak biće vraćen pokazivač na prvu
poziciju unutar stringa, ili vrednost NULL u suprotnom.

char *strstr(char *s, char *t);

Funkcija strstr vraća pokazivač na prvu pojavu podstringa t unutar stringa s. Ako
uspešno obavi zadatak funkcija vraća pokazivač na prvu pojavu podstringa, ili vrednost
NULL u suprotnom.

int strlen(char *s);

Funkcija strlen vraća dužinu stringa s u bajtovima, tj broj znakova stringa bez
znaka '\0'.

char *strtok(char *s, char *tokeni);

Funkcija strtok vraća pokazivač na lokaciju tokena u stringu. U stringu s se traže


tokeni. Ako je string NULL, funkcija strtok koristi završnu lokaciju prethodnog stringa.
tokeni pretstavlja string koji sadrži tokene koje treba naći. Ako uspešno obavi zadatak,
funkcija vraća pokazivač na poziciju tokena. Ako ni jedan token nije pronađen funkcija
strtok vraća vrednost NULL.

Funkcije za numeričke konverzije

int atoi(char *s);

Funkcija atoi konvertuje string s u celobrojnu vrednost. Funkcija vrši konvertovanje


sve dok se ne naiđe na nevažeći karakter unutar stringa ili znaka '\0'. Funkcija ne pruža
informaciju da li postoje nevažeći znakovi unutar stringa.

double atof(char *s);

Funkcija atof konvertuje string s u decimalanu vrednost. Funkcija vrši


konvertovanje sve dok se ne naiđe na nevažeći karakter unutar stringa ili znaka ‘\0’.
Funkcija ne pruža informaciju da li postoje nevažeći znakovi unutar stringa.

129
4.5. NIZ POKAZIVAČA NA STRINGOVE

Niz pokazivača na stringove pretstavlja niz koji sadrži adrese prvih članova
(početne adrese) stringova.

Deklaracija niza pokazivača na stringove:


char *niz[MAX];

U deklaraciji uglaste zagrade označavaju da je u pitanju niz, a operator zvezdica,


da taj niz sadrži pokazivače na promenljive tipa char.
Prilikom deklaracije niza pokazivača na stringove može se izvrćiti i njihova
inicijalizacija.

Na primer:
char *imena[3]={ "Petar","Misa","Slavko"};

Zona u memoriji gde su smšeteni stringovi jedan iza drugog

P e t a r \0 M i s a \0 S l a v k o \0

imena

Sa slike se može videti da je promenljiva imena pretstavlja niz pokazivača koji


sadrže adrese (pokazuju) na prva slova stringova (imena). Prilikom praćenja promenljive
imena u watch prozoru C okruženja, imali bismo utisak da niz pokazivača na stringove
pretstavlja niz stringova (kao što se vidi i iz deklaracije).

Inicijalizacija niza pokazivača na stringove:


Inicijalizacija niza pokazivača na stringove vrši se kao i inicijalizacija niza,
pomoću ciklusa, pri čemu svaki član niza sadrži simboličku konstantu NULL.

for(i=0;i<MAX;i++) niz[i]=NULL;

130
Mora se obezbediti da prvi pokazivač iz niza pokazivača pokazuje na neki prostor
u memoriji koji je dosta veliki (u stanju je da reši bilo koji slučaj).

char *niz[MAX], c[VELIKI_PROSTOR], *pom=c;


niz[0]=pom;
for(i=1;i<MAX;i++) niz[i]=NULL;

Pokazivac pom pokazuje na adresu prvog elementa stringovne promenljive c.


Počev od te lokacije smeštaće se redom stringovi u memoriji. Dodeljujemo prvom
pokazivaču iz niza pokazivača adresu od po;etka stringa c, dok se svi ostali pokazivači iz
niza pokazivača postavljaju na NULL, što označava da ti pokazivači ne sadrže nikakvu
adresu.

Formiranje niza pokazivača na stringove:

Niz pokazivača na stringove moraju sadržati takve adrese da se zadovolji gornja


predstava. Svaki pokazivač pokazuje na početak sledećeg stringa, a stringovi su
nadovezani jedni iza drugih u memoriji (iza poslednjeg znaka jednog stringa '\0'
nadovezuje se prvi karakter sledećeg stringa). Kao i svaki drugi niz, i niz stringova se
formira sa ciklusom. Ako hoćemo da unesemo n stringova, zadatak možemo uraditi na
sledeći način:

char *niz[MAX], c[VELIKI_PROSTOR], *pom=c;


niz[0]=pom;
for(i=1;i<MAX;i++) niz[i]=NULL;

for(i=0;i<n;i++)
{
/* Svaki sledeci clan niza dobija adresu tako sto se na adresu prethodnog
clana niza sabere duzina stringa na koji on pokazuje i dodaje 1 kako bi se
preskocio znak '\0'. */

if(i!=0) niz[i]=niz[i-1]+strlen(niz[i-1])+1;
gets(s)
strcpy(niz[i],s);
}

Razlike između matrice znakova i niza pokazivača na stringove:


Često se između matrice znakova i niza pokazivača na stringove ne pravi razlika,
jer se niz pokazivača na stringove smatra nizom stringova. Niz pokazivača na stringove
omogućava da se stringovi smeštaju jedan do drugog u memoriji. Ovim se ušteđuje na
zauzetosti memorijskog prostora. Osim toga za prenos matrice znakova u funkciju
potrebno je preneti drugu dimenziju, dok kod niza pokazivača na stringove to niije
potrebno. Rad sa matricama znakova je jednostavniji u odnosu na rad sa nizom
pokazivača na stringove.

131
Primer 1:
Napisati C program koji omogućava unos imena i prezimena n osoba n<31, a
potom vrši njihovo sortiranje po abecednom redosledu. Prilikom realizacija zadatka
koristiti niz pokazivača na stringove. Unos imena i prezimena vršiti odvojeno
korišćenjem funkcije unos. Funkcija unos prvo slovo imena ili prezimena pretvara u
veliko a sva ostala u mala slova. Unos imena ili prezimena završava se pritiskom na
SPACE, ENTER ili TAB. Ako se unese karakter koji nije slovo funkcija trazi ponovni
unos imena ili prezimena (jer je nastala greška).

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define MAX 30
#define VELIKI_PROSTOR 5000

/* Definisanje prototipa funkcije. */


char *unos(char *s);

void main(void)
{
/* Deklaracija promenljivih. */
char *niz[MAX], s[MAX], pom[MAX], c[VELIKI_PROSTOR], *pom1=c;
unsigned i, j, xu, yu;
int n;

/* Inicijalizacija niza pokazivaca na stringove. */


niz[0]=pom1;
for(i=1;i<MAX;i++) niz[i]=NULL;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

/* Koliko imena i prezimena treba uneti. */


printf("N = ");
xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&n);
}while(n<=0);

/* Unos imena i prezimena. */

132
printf("\n\nPrerzime:\tIme:\n--------\t-----\t\n");

for(i=0;i<n;i++)
{
if(i!=0) niz[i]=niz[i-1]+strlen(niz[i-1])+1;

/* Unos imena. */
unos(pom);
strcpy(s,pom);

/* Nadovezivanje praznog mesta. */


strcat(s," ");
printf("\t\t");

/* Unos prezimena i njegovo nadovezivanje na kraj stringa s. Sada string s sadrzi


ime i prezime. */

unos(pom);
strcat(s,pom);
strcpy(niz[i],s);
printf("\n");
}

/* Sortiranjem imena i prezimena ne vrsi se nikakvo fizicko premestanje stringova u


memoriji, vec zamena adresa koje sadrze elementi niza pokazivaca. */

for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(strcmp(niz[i],niz[j])>0)
{
pom1=niz[i];
niz[i]=niz[j];
niz[j]=pom1;
}
}
}
printf("\nSortirana imena\n");
printf("Prezime i Ime:\n--------------\n");
for(i=0;i<n;i++) printf("%s\n",niz[i]);
getch();
}

/* Funkcija unos omogućava unos imena ili prezimena. */


char *unos(char *s)
{
/*Deklaracija lokalnih promenljivih. */
unsigned xp, yp, i=0, j;
char c;

133
xp=wherex(), yp=wherey();

do{
c=getch();

if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))
{

/* Ako je prvo slovo malo, vrsi se pretvaranje u veliko. */

if(i!=0) if(c>='A'&&c<='Z') s[i]='a'+c-'A';


else s[i]=c;
else if(c>='a'&&c<='z') s[i]='A'+c-'a';
else s[i]=c;

/* Sada je slovo ispravno i moze se stampati na ekranu. */

printf("%c",s[i]), i++;
}else{
if(c!='\r'&&c!=' '&&c!='\t')
{
gotoxy(xp,yp);
for(j=0;j<i;j++) printf(" ");
gotoxy(xp,yp);
i=0;
}
}
}while(c!='\r'&&c!=' '&&c!='\t');

s[i]='\0';
gotoxy(xp+strlen(s),yp);
return s;
}

Ako je na primer izvršen samo unos imena pomoću niza pokazivača imena (redom
Petar, Misa i Slavko) imaćemo sledeću sliku.

pom1 Zona u memoriji gde su smšeteni stringovi jedan iza drugog

P e t a r \0 M i s a \0 S l a v k o \0

134
imena

Nakon opisanog sortiranja imena slika, ima sledeći izgled:

pom1
Zona u memoriji gde su smšeteni stringovi jedan iza drugog

P e t a r \0 M i s a \0 S l a v k o \0

imena

Primer 2:
Napisati C program koji omogućava unos stringa u formatu:

String = "brv/brk/string_od_slova"

Znak tabulacije u stringu mora se nalaziti samo na jednom mestu. Na osnovu


unetog stringa formirati matricu znakova koja ima brv vrsta i brk kolona. Podaci se
dobijaju iz unetog stringa i razdvojeni su znakom '/'. U stringu mže postojati samo na dva
mesta znak '/'. Iza drugog znaka '/' nalazi se string koji se smešta u matricu znakova.
Matrica se formira vrsta po vrsta, pri čemu se znak tabulacije '\t' zamenjuje znakom '\0'.
Dešifrovani string se dobija tako što se kroz matricu znakova prolazi levom
spiralom do znaka '\0', Svaki znak '_' zamenjuje se znakom praznina ' '.
Na primer:

String = "5/6/Mop_imiz _sl eliti\tcim_da_"

Nastala matrica je:

M o p _ i m
i z _
s l e
l i t i \0 c
i m _ d a _

Desifrovani string = "Mislim da ce mi pozliti"

135
Rešenje

#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>

#define MAX 80

void main (void)


{
char s[MAX],*c,*s1,m,n,a[10][10];
int i,j,k,p=0;
s[0]='\0';

/* Inicijalizacija matrice znakova. */


for(i=0;i<10;i++)
{
for(j=0;j<10;j++) a[i][j]='_';
}

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

/* Unos sifriranog stringa po uslovu teksta zadatka, bez kontrole unosa. */


printf("\n\tString:");
gets(s);

/* Izdvajanje iz striga koliki je broj vrsta i broj kolona. */


strcpy(s1,s);

/* Izdvaja se deo stringa do znaka '/'. Taj string pretstavlja broj vrsta matrice, te se
funkcijom atoi dati string konvertuje u broj. */

c=strtok(s1,"/");
m=atoi(c);

/* Prilikom rada sa funkcijom strtok potrebno je koristiti pokazivac na karakter, jer


funkcija vraca pokazivac na karakter. */

c=strtok(NULL,"/");
n=atoi(c);

/* Utvrdjivanje pozicije drugog pojavljivanja znaka '/'. */


i=0;
while(s[i]!='\0')
{

136
if(s[i]=='/') k=i;
i++;
}

/* Brisanje dela stringa koji sadrzi zakljucno sa drugom kosom crtom. */


i=0;
while(s[k]!='\0')
{
s[i]=s[k+1];
i++,k++;
}
s[i]='\0';

/* Formiranje matrice znakova na osnovu stringa. Tamo gde se nalazi znak '\t' treba upisati
znak '\0'*/
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(s[i*n+j]!='\t') a[i][j]=s[i*n+j];
else{a[i][j]='\0';}
}
}

/* Matrica znakova se stampa vrsta po vrsta. */


for(i=0;i<m;i++)
{
for(j=0;j<n;j++) gotoxy(15+3*j,5+i),printf("%c ",a[i][j]);

/* Formira se novi string s koji predstavlja desifrovani string, na osnovu spiralnog


prolaska kroz matricu znakova (leva spirala). Kroz matricu se spiralno prolazi sve dok se
ne dodje do znaka '\0', cime je i formiran desifrovani string. */
k=0;
while(a[i][j]!='\0')
{
j=p;
for(i=p;i<m-p-1;i++) s[k]=a[i][j],k++; /* Vertikalno na dole. */
i=m-p-1;
for(j=p;j<n-p-1;j++) s[k]=a[i][j],k++; /* Horizontalno s leva na desno. */
j=n-p-1;
for(i=m-p-1;i>p+1;i--) s[k]=a[i][j],k++; /* Vertikalno na gore. */
i=0-p;
for(j=n-p;j>=p+1;j--) s[k]=a[i][j],k++; /* Horizontalno s desna na levo. */
p++;
}

/* Prolazi se kroz formirani string i svaki karakter ’_’ zamenjuje se sa prazninom. */


while(s[i]!='\0')
{

137
if(s[i]=='_') s[i]=' ';
i++;
}
s[k]='\0';

/* Ispis desifrovanog stringa. */


printf("\n\n\n\t Desifrovani string: %s",s);

gotoxy(1,25);
getch();
}

Test primer programa:

138
4.6. MAKROI I FUNKCIJE SA PROMENLJIVIM
BROJEM ARGUMENATA

Makroi:

Definicije simbola u C jeziku se nazivaju makroi. Svi indentifikatori definisani


direktivama define do eventualnog uništavanja direktivom undef smatraju se
makroima.

Definisanje makroa:

#define INDENTIFIKATOR niz_simbola ili


#define INDENTIFIKATOR (niz_argumenata) niz_simbola

Uobičajeno je da se indentifikator piše velikim slovima kako bi se skrenula pažnja


da je u pitanju makro. U drugoj definiciji ne sme biti razmaka između indentifikatora
makroa i otvorene zagrade koja započinje listu argumenata.

Na primer:
#define MAX 30
#define PORUKA { \
gotoxy(25,24);\
printf("Za nastavak pritisnite SPACE taster!!");\
getch();
}
#define MAXBROJ(a,b) a>b a : b
#define KVADRAT(a) a*a

Prvi primer smo već ranije koristili za definisanje simboličke konstante. Nakon
indentifikatora MAX koji je napisan velikim slovom jer je indentifikator makroa
(poželjno je da je velikim slovom ispisan, iako prevodilac prihvata da je malo), sledi niz
simbola, a to je u ovom slučaju broj 30. Tokom celog programa gde god se pojavi
indentifikator MAX prevodilac će ga zamenjivati brojem 30. Niz simbola ne sme se
završiti sa znakom tačka zarez.
Drugi primer koristi blok jer se niz simbola ne sme završiti znakom tačka zarez.
Dugačak niz simbola, koji se ne može napisati u jednom redu znakom '/' na kraju reda
označava da je nastavak u sledećem redu. Makro može da se zamenjuje nekim delom
složene upravljačke strukture (da osim funkcija sadrži selekcije i cikluse).
Kod prvog i drugog primera makroi se pozivaju navođenjem imena makroa iza
koga ne mora pisati znak tačka zarez.

139
Treći primer koristi makro MAXBROJ koji slično funkcijama sadrži formalne
argumente a i b. Stvarni argument se prosleđuju formalnim argumentima izračuna se
izraz i vrednost se nalazi u indentifikatoru makroa. U ovom slučaju biće vraćena vrednost
argumenta a ili b.
Osnovna razlika između poziva makroa i poziva funkcije je u tome što se prilikom
poziva makroa tip argumenta makroa može biti proizvoljan. Makroi se zamenjuju još
pre prevođenja izvornog programa, dok funkcije postoje i za vreme izvršenja programa.
Za razliku od funkcija gde se prvo izračunala vrednost izraza, pa se vrednost prosledila
formalnom argumentu funkcije, kod poziva makroa to nije slučaj, već se ceo izraz
prosleđuje formalnom argumentu i kao takav učestvuje u nizu simbola.

Iz tih razloga četvrti primer radiće pogtrešno.

Na primer ako pozovemo makro sa:


x= KVADRAT(3)
niz simbola postaje 3*3 i daje tačan rezultat 9 koji se prosledio promenljivoj x.

Međutim ako pozovemo makro sa


x=KVADRAT(2+1)
niz simbola postaje 2+1*2+1 i vrednost promenljive x postaje 5 što je pogrešan
rezultat.
Da bi makro KVADRAT ispravno radio moraju se koristiti zagrade u nizu simbola
kako bi se izbegli problemi sa prioritetima operatora.

#define KVADRAT(x) (x)*(x)

Nakon pozivanja makroa


x=KVADRAT(2+1)
niz simbola postaje (2+1)*(2+1) te x dobija vrednost 9 što je tačan rezultat.

Preporučuje se strogo korišćenje zagrada oko svakog korišćenja formalnog


argumenta u nizu simbola. Prilikom korišćenja makroa izrazi kao stvarni
argumenti doslovce će se uvrstiti u formalne argumente makroa. To prouzrokuje
velike probleme ako se u stvarnim argumentima nalaze izrazi sa operatorima koji
prouzrokuju bočne efekte.

Ako funklcije i makroi mogu da prime ulazne vrednosti putem parametara šta
kada koristiti?

Korišćenje funkcije prouzrokuje dodatna opterećenja usled poziva funkcije, jer se


vreme troši na smeštanje podataka na stek, prenošenje izvršavanja programa na drugo
mesto u memoriji i zatim nazad na naredbu iza poziva funkcije. To će uzrokovati da
program sporije radi. Makro se razvija u svoj niz simbola zamene, svaki put kada
procesor sretne ime simbola. Pozivanjem makroa povećava se brzina izvršavanja
programa, ali je cena toga povećanje veličine izvršivog programa. Dobit od funkcija je da

140
se izvrši kod koga prevodilac proizvodi pojavljuje u programu samo jednom, a može se
pozivati proizvoljan broj puta bez ikakvog povećanja programa.

Funkcije sa promenljivim brojem argumenata:

Funkcija sa promenljivim brojem argumenata ima nekoliko obaveznih argumenata


iza kojih može da postoji proizvoljan broj neobaveznih argumenata.

Prototip funkcije sa promenljivim brojem argumenata je:

tip naziv_funkcije(lista_obaveznih_argumenata, lista_neobaveznih_argumenata);

Postojanje neobaveznih formalnih argumenata se prilikom deklarisanja ili


definisanja funkcije označava stavljanjem tri tačke iza poslednjeg obaveznog formalnog
argumenta. Tri tačke se mogu nalaziti samo na kraju liste obaveznih formalnih
argumenata.

Na primer:
Prototip funkcije prikaz koja ima četiri obavezna formalna argumenta.
int prikaz(int x, int y, int br, char *text,...);

Funkcija prikaz imaće prilikom pozivanja minimalno četiri stvarna argumenta.


Primeri pozivanja funkcija prikaz:
prikaz(5,10,4, "UNOS","ISPIS","PRIKAZ");
prikaz(15,6,7, "OBRADA","ISPIS","PRONADJI","KRAJ");

Iz primera se može zaključiti da je prilikom pozivanja funkcija prikaz broj


parametara različit od poziva do poziva funkcije.

Prilikom pozivanja funkcija prevodilac može da proverava ispravnost broja i tipova


samo obaveznih argumenata. Iza njih prihvatiće proizvoljan broj stvarnih argumenata
proizvoljnih tipova, promenljivo od poziva do poziva. Za obavezne argumente vršiće se
uobičajena automatska konverzija tipova. Kod neobaveznih argumenata argument tipa
char se obavezno konvertuje u tip int, a argumenti tipa float u tipa double.
Prilikom pozivanja funkcije u obaveznim stvarnim argumentima se krije
informacija o broju i tipu neobaveznih srgumenata.

Standardno zaglavlje stdarg.h sadrži skup definisanih makroa koje definišu kako se
prolazi kroz listu neformalnih argumenata. Tip va_list se koristi za deklarisanje
promenljive ap (skraćeno od argument pointer) koja redom ukazuje na svaki neobavezni
argument funkcije.

va_list ap;

141
Makro va_start inicijalizuje pokazivačku promenljivu ap tako da pokazuje na prvi
neobavezni argument. Makro va_start se mora pozvati jedanput pre korišćenja
pokazivača ap.

va_start(ap, indentifikator_poslednjeg_obaveznog_argumenta);
Svaki poziv makroa va_arg vraća jedan argument i pomera pokazivač ap na
naredni argument.

va_arg(ap, tip);

Na kraju makro va_end pretstavlja završetak dohvatanja argumenata.

va_end(ap);

Primer:
Napisati C program koji demonstrira koriscenje funkcije zbir sa promenljivim
brojem argumenata. Funkcija zbir izračunava zbir uzastopnih celih argumenata i nakon
toga zbir uzastopnih racionalnih argumenata.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <stdarg.h>

/* Prototip funkcije sa promenljivim brojem argumenata. */


void zbir(unsigned brc, unsigned brr, int *s1, double *s2,...);

void main(void)
{
int s1=0;
double s2=0; /* Obratiti paznju sta ce se desiti da smo deklarisali s2 da je tipa float. */

textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("\tDemonstracija funkcije sa promenljivim brojem argumenata!!\n");


zbir(4,3,&s1,&s2,1,2,3,4,2.5,3.4,1.2);
printf("\n\n\t1 + 2 + 3 + 4 = %d\n\t2.5 + 3.4 + 1.2 = %.2f",s1,s2);

/* Vidi se prilikom poziva da je razlicit broj argumenata u prvom i drugom pozivu


funkcije. */

zbir(5,8,&s1,&s2,5,4,3,3,2,3.1,2.5,1.7,2.8,4.2,2.1,1.1,3.3);
printf("\n\n\t5 + 4 + 3 + 3 + 2 = %d\n",s1);
printf("\t3.1 + 2.5 + 1.7 + 2.8 + 4.2 + 2.1 + 1.1 + 3.3 = %.2f",s2);

142
gotoxy(1,25);
getch();
}

/* Definisanje funkcije sa promenljivim brojem argumenata. Funkcija mora sadrzati dva


formalna obavezna argumenta, gde ce jedan pretstavljati broj uzastopnih celih argumenata, a
drugi, broj uzastopnih racionalnih argumenata. */

void zbir(unsigned brc, unsigned brr, int *s1, double *s2,...)


{
unsigned i;

/* Deklarise se pokazivac ap na neobavezne argumente. */


va_list ap;

/* Pokazivacu ap se prosledjuje adresa poslednjeg obaveznog formalnog argumenta, a to


je *s2. */

va_start (ap,*s2);

/* Sa makroom va_arg pomeramo pokazivac ap na sledeci argument, navodeci mu tip


argumenta, kako bi znao gde da se pomeri. Vrsimo njegovo sabiranje. */

for(i=1;i<=brc;i++) *s1+=va_arg(ap,int );

/* Nakon sabiranja celih brojeva pokazivac ap se pozicionirao i pokazuje na prvi


sledeci racionalni argument. Nastavljamo sa sabiranjem ali sada uzastopnog niza
racionalnih argumenata. Vidi se da je jako vazno ispravno pozicioniranje pokazivaca ap, te
jako dobro moramo voditi racuna o tome gde se koji neobavezni argument nalazi i kog je
tipa. Napravila bi se velika greska da smo promenljivu s2 deklarisali kao float, jer se
vrednost neformalnog argumenta automatski iz float konvertuje u double. */

for(i=1;i<=brr;i++) *s2+=va_arg(ap,double );

/* Nakon zavrsetka prolaska kroz neobavezne formalne argumente, mora se to saopstiti


prevodiocu pozivom makroa va_end. */

va_end(ap);
}

Test primer programa:

143
4.7. ZADACI IZ STRINGOVA

Zadatak 1 (2)
Napisati C program koji iz stringa datum zapisan u obliku: dan.mesec.godina
(09.12.1968 ili 9.12.1968) izdvaja podstringove dan, mesec i godina.

Zadatak 2 (2)
Aritmetički izraz unet sa tastature zapisan je u stringu s. Napisati C program koji
utvrđuje broj pojavljivanja aritmetičkih operatora (+,-,* i /) u izrazu.

Zadatak 3 (2)
Napisati funkciju koja iz stringa s briše svako pojavljivanje slova c. Funkcija vraća
0 ako slova c nema u stringu s ili broj izbrisanih slova iz stringa s.

Zadatak 4 (2)
Napisati C program koji u stringu s, svaku pojavu slova zapisane u promenljivoj c
zamenjuje slovom zapisane u promenljivoj d. Slovo koje se menja i slovo sa kojim se
vrši zamena uneti sa tastature.
Za realizaciju zamene koristiti funkciju zameni koja vraća broj izvršenih zamena.
Na ekranu prikazati novonastali string, kao i broj izvršenih zamena.

Na primer:
c=nd=m
String = Mislin da ni je zadatak iz stringa dosao kao kec na deset.

Novi String = Mislim da mi je zadatak iz stringa dosao kao kec na deset.


Broj zamena = 2

Zadatak 5 (3)
Napisati funkciju koja vraća pokazivač na prvo pojavljivanje određenog znaka c
s desne strane stringu s, ili NULL ako slova c nema u stringu s.

Zadatak 6 (2)

144
Napisati C program koji utvrđuje koliku u strigu s ima znakova interpunkcije: tačka,
zarez, tačka zarez, znak pitanja i znak uzvika. Za određivanje pojave određenog znaka
interpunkcije koristiti funkciju odredi. Na ekranu se prikazuje broj pojavljivanja onih
znakova interpunkcije kojih je bilo uopšte u stringu.

Na primer:
String=Sta!! Ne svidja ti se zadatak, koji je pred tobom. Da li ga uraditi?

Znak Pojava
, 1
. 1
? 1
! 2
Zadatak 7 (2)
Napisati C program koji iz stringa s višestruki niz praznina zamenjuje sa samo
jednom prazninom.

Zadatak 8 (3)
Napisati funkciju dodaj koja korišćenjem pokazivača (bez indeksa) vrši
nadovezivanje stringa t na kraj stringa s.

Zadatak 9 (2)
Napisati funkcijju void umetni(char *s, int k, char *t); koja umeće string t u string
s počev od pozicije k.

Zadatak 10 (5)
Napisati C program koji korišćenjem funkcije brisizagrade, iz stringa s uklanja
podstring koji se nalazi između zagrada uključujući i same zagrade. Podstring se uklanja
iako sadrži u sebi druge zagrade. Funkcija brisizagrade vraća broj izbrisanih
podstringova.

Zadatak 11 (3)
Napisati C program koji utvrđuje koliko reči ima u stringu s i transformiše string s
tako što najdužu i najkraću reč pretvara u reči sa velikim slovima. Ako ima više najdužih
ili najkraćih reči sve ih pretvoriti u velika slova. Pretvaranje malog slova u veliko
realizovati funkcijom malauvelika.

Zadatak 12 (4)
Napisati C program koji u stringu s prvo briše višestruke praznine, a potom svaku
reč u stringu zamenjuje rečju koja se dobija tako što se data reč stringa zapisuje u istom
stringu ali u inverznom poretku. Za brisanje praznina koristiti funkciju brisipraznine, a
za transformaciju stringa funkciju inverznarec.

Na primer:
String = Mislim da mi je zadatak iz stringa dosao kao kec na deset.

145
Novi String = milsiM ad im ej katadaz zi agnirts osaod oak cek an tesed.

Zadatak 13 (3)
Napisati C program koji utvrđuje broj reči u stringu s unesenog sa tastature i briše
višestruke praznine u stringu. Za utvrđivanje broja reči u stringu koristiti funkciju
brojreci, a za brisanje višestrukih praznina funkciju brisipraznine, koja vraća 0 ako nije
bilo višestrukih praznina u tekstu.

Na primer:
String = Mislim da mi je zadatak iz stringa dosao kao kec na deset.

Novi String = Mislim da mi je zadatak iz stringa dosao kao kec na deset.


Broj reci u stringu je: 12.
Zadatak 14 (3)
Napisati funkciju int strrindex(char *s, char *t); koja vraća krajnju desnu poziciju
u kojoj se string t nalazi u stringu s, ili -1 ukoliko se t ne pojavljuje u s. Napisati C
program koji demonstrira primenu funkcije strindex.

Zadatak 15 (3)
Napisati funkcijju int strend(char *s, char *t); koja vraća 1 ako se string t nalazi na
kraju stringa s, ili 0 ukoliko se t ne pojavljuje na kraju stringa s. Napisati C program koji
demonstrira primenu funkcije strend.

Zadatak 16 (3)
Napisati funkciju int brisistring(char *s, intk, int n); kojom se iz stringa s briše k
znakova počev od pozicije n. Ako od pozicije n do kraja stringa nema k znakova funkcija
vraća 0, a u suprotnom 1.

Zadatak 17 (4)
Napisati funkciju char *satoi(unsigned broj); koja celobrojni podatak broj pretvara
u string i vraća pokazivač na početak stringa.

Zadatak 18 (4)
Napisati funkciju entab koja u stringu niz praznina zamenjuje minimalnim brojem
tabulatora i praznina da bi se postigao isti prazan prostor. Funkcija vraća broj koji
pokazuje za koliko je string manje dužine od prvobitnog stringa i po referenci vraća
koliko string ima tabulatora a koliko praznina.

Zadatak 19 (4)
Napisati funkciju za šifrovanje i dešifrovanje stringa. Šifrovanje stringa se vrši tako
što se svako slovo reči iz stringa kružno pomeri za k mesta udesno.

Zadatak 20 (3)
Napisati C program koji po izboru korisnika transformiše reči koje se nalaze u
stringu s po sledećim pravilima:

146
1) Sve reči u stringu moraju početi velikim slovom, a sva ostala malim slovom; ili
2) Sva slova koja su bila mala postaju velika, a slova koja su bila velika postaju
mala.
Svaka opcija mora biti realizovana posebnom funkcijom.

Na primer:
String = Mislim da MI je ZADATAK iz strINGA dosao KAo keC na DESET.

Ako korisnik izabere opciju:


1. Novi = Mislim Da mi Je Zadatak Iz stringa Dosao Kao Kec Na Deset.
2. Novi = mISLIM DA mi JE zadatak IZ STRinga DOSAO kaO KEc NA deset.

Zadatak 21 (4)
Napisati C program koji demonstrira primenu funkcije tokeni koja vraća koji se
prvi token pojavio u stringu s, pri čemu su tokeni karakteri iz stringa t.

Zadatak 22 (4)
Napisati funkciju zbir koja vrši sabiranje brojeva koji se nalaze u stringu s. Broj
može uopšteno biti realan (sadrži decimalnu tačku) i da ispred (bez praznina između)
stoji znak broja.
Na primer:
String = Ako na -32.21 saberem 13.21 a potom dodam broj -21.2, ne znam sta bih
dobio. Pomozi mi druze!!
Zbir = -40.2

Zadatak 23 (4)
Napisati C program koji je zaštićen. Prilikom startovanja programa od korisnika
programa se traži da unese šifru i prikazano mu je sa oznakama *, koliko šifra ima
karaktera. Nakon unesene šifre, ako šifra nije ispravna korisnik dobija odgovarajuću
poruku o tome, a zatim se obaveštava koji put po redu unosi šifru. Ima tri pokušaja da
pogodi koja je šifra. Ako ne pogodi iz tri pokušaja ispisaće se odgovarajuća poruka
praćena zvučnim signalom, a u slučaju da pogodi šifru odgovarajuća poruka praćena
drugim zvučnim signalom.

Zadatak 24 (4)
Napisati C program koji umeće string t (tj. reč) ispred najduže reči iz stringa s. Ako
postoji više najdužih reči, string t umetnuti ispred reči koja je bila najbliža početku
stringa s. Za određivanje pozicije u stringu s gde treba umetnuti string t koristiti funkciju
odredi, a za umetanje stringa t u string s funkciju umetni.

Na primer:
String = Mislim da mi je zadatak iz stringa dosao kao kec na deset.
Rec koja se umece = ovaj
Novi String = Mislim da mi je ovaj zadatak iz stringa dosao kao kec na deset.

147
Zadatak 25 (5)
Napisati C program kojim se unosi korektno zapisan izraz u jednoj liniji, a zatim
određuje njegova vrednost. Operandi u izrazu su celi brojevi, a operatori mogu biti (+,-,*
i /) pri čemu je / celobrojno deljenje. Pri određivanju vrednosti izraza voditi računa o
prioritetu operacija, i u izrazu je dozvoljeno korišćenje zagrada.

Zadatak 26 (5)
Dopuni prethodni zadatak koji je u stanju da reši sledeće programske zahteve:
- Ako je izraz neispravno zapisan na izlazu prikazati reč ERROR.
- Ako se oslobađamo zagrada, a rezultat u zagradi je negativan broj, negativan
broj ostaje u zagradi i zagrada će nestati tek nakon sledeće operacije, ili ako je
to krajnji rezultat.
- Ako postoje zagrade koje su ispravno zapisane ali su višak potrebno ih je na
početku programa izbrisati.

Zadatak 27 (5)
Napisati C program koji je u stanju da dešifruje string s unesen sa tastature na
osnovu matrice. U stringu nema praznina, već je praznina zamenjena sa donjom crticom.
Dešifrovanje stringa se vrši pomoću matrice znakova.
Matrica se formira na osnovu stringa tako što je poznato koliko matrica ima vrsta,
tako što prvi karakter stringa pretstavlja broj vrsta matrice.
Karakteri iz stringa se u matricu upisuju kolona po kolona.
Prilikom dešifrovanja stringa kreće se od znaka koji se nalazi kao prvi element
matrice i prolazimo kolona po kolona s tim što svaka naredna kolona ima po: dva znaka
manje iz stringa koji je rezultat dešifrovanja od prethodnog (ako je prethodni broj
znakova bio veći od 1, a išlo se od pune kolone prema koloni koja će imati jedan znak),
odnosno dva znaka manje u suprotnom.
Na primer:
Šifrovani string = 5Ovaj_pdazoaaapk_kato_ce_mod_isbaogfc_iceglaveab!!

Matrica znakova:
O p a _ _ o b c g a
v d a k c d a _ .l b
a a a a e _ o i a !
j z p t _ i g c v !
_ o k o m s f e e

Dešifrovani string = Ovaj zadatak ce mi doci glave!!

Zadatak 28 (5)
Napisati C program koji vrši šifrovanje i dešifrovanje stringa s. Šifrovanje stringa
vrši se tako što se svaka reč stringa zarotira cirkularno za k mesta, a potom se svaki niz
praznina imeđu reči zamenjuje sa brojem praznina u toj reči. Smatrati da u rečima nema
drugih simbola osim malih ili velikih slova abecede. U stringu se osim slova abecede
mogu pojaviti i znakovi interpunkcije (. , ; ! ?).

148
Za realizaciju šifrovanja koristiti funkciju sifruj, a za dešifrovanje funkciju
desifruj.

Zadatak 29 (5)
Napisati funkciju kompresija koja vrši kompresiju stringa po sledećem pravilu
datom u primeru.
aabaab -> 2(aab) -> 2(2(a)b)
Funkcija kompresija vraća broj tipa double koji (na osnovu početne i krajnje
dužine) vraća procenat izvršene kompresije.

Zadatak 30 (5)
Napisati funkciju dekompresija koja vraća nastali string iz prošlog zadatka u
prvobitan položaj.

149
150
5. POGLAVLJE

TEKSTUALNE DATOTEKE

151
5.1. DEFINICIJA DATOTEKE, PODELA DATOTEKA

Definicija:
Datoteka je osnovna logička jedinica u pogledu zapisa informacija na
jedinicama masovne memorije.

Za unos velikog obima podataka u programu ne koristimo ulaz sa tastature već iz


datoteke (što takođe važi i u slučaju izlaza).

Prema načinu smeštanja podataka, postoje dve vrste datoteka:


 tekstualne datoteke, i
 binarna datoteke.

Tekstualne datoteke sastoje se od niza znakova koji je znakovima za prelazak u


novi red ('\n') podeljen u redove. Binarne datoteke sastoje se od niza bajtova čiji je
sadržaj verna slika načina predstavljanja podataka u memoriji. U toku prenosa ne
primenjuje se konverzija, već se vrši prosto prenošenje podataka bajt po bajt. Podela
tekstualnih datoteka u redove je logička, a ne fizička organizacija. Tekstualne datoteke su
samo dugački niz znakova (bajtova).

Pri radu sa datotekama postoje sledeće radnje:


 otvaranje datoteke,
 pristup datoteci,
 ispitivanje stanja datoteke, i
 zatvaranje datoteke.

Otvaranje datoteke služi za uspostavljanje veze sa fizičkom datotekom. Tom


prilikom stvara se u memoriji određena struktura podataka koja omogućava efikasan
pristup datoteci u toku rada. Ta struktura sadrži određene podatke o trenutnom stanju
datoteke. Pristupom datoteci realizuje se prenos podataka u datoteku ili iz datoteke sa ili
bez konverzije u toku prenosa. Ispitivanjem stanja datoteke mogu da se dobiju
informacije o eventualnim greškama koje su nastale u toku prenosa podataka. Zatvaranje
datoteke je završna radnja kojom se raskida veza sa fizičkom datotekom. Tom prilikom
poništavaju se strukture podataka stvorene prilikom otvaranja datoteke.
Opisane radnje mogu se ostvariti samo pod određenim uslovima:
 Funkcije za rad sa datotekama tretiraju datoteku kao sekvencijalni niz
karaktera.
 Datotekama se pristupa pomoću pokazivača na sistemsku strukturu u
oznaci FILE. Struktura FILE je definisana u datoteci zaglavlja stdio.h, a
sadrži članove koji opisuju tekuće stanje datoteke.
 U datoteci zaglavlja su definisane dve simboličke konstante:
 Konstanta EOF (End of file) koja definiše oznaku kraja datoteke i
prema inicijalizaciji u datoteci zaglavlja ima vrednost -1.

152
 Konstanta NULL koja označava neuspešno izvršavanje nekih
funkcija za upravljanje datotekama čija je vrednost 0 definisana u
datoteci zaglavlja stdio.h.
 Standardizovane funkcije koriste bafer odakle čitaju ili upisuju podatke.
Kad se bafer napuni njegov sadržaj se prebacuje na datoteku. Kad se bafer
isprazni njegov sadržaj se popunjava iz datoteke. Korišćenjem bafera
smanjuje se broj pristupa datoteci. Standardizovane funkcije su: fopen(),
fgetc(), fputc(), fprintf(), fscanf(), fgets(), fputs(), feof(), fclose(), ftell(),
fseek(), rewind(), fread() i fwrite().

Za svaku datoteku koja se koristi u programu mora da postoji pokazivač na podatak


tipa FILE. Neka je to pokazivač pod nazivom dat, njegova deklaracija je:

FILE *dat;

Na osnovu deklaracije pokazivača dat saopštava se prevodiocu da je dat pokazivač


(ispred dat nalazi se *) koji može da sadrži adresu podattka tipa FILE. On trenutno ne
pokazuje na strukturu jer strukture trenutno nema. Strukturu formira funkcija fopen() koja
će biti obrađena na sledećem času.

153
5.2. OTVARANJE I ZATVARANJE DATOTEKE

Datoteka pre bilo kakve obrade mora biti otvorena. To se postiže funkcijom fopen().
Funkcija fopen otvara navedenu datoteku i vraća pokazivač na tu datoteku (tip FILE), a
ako dođe do greške funkcija vraća vrednost NULL. Prototip funkcije fopen je:

FILE fopen(const char *ime_staze, const char *access_mode);

ime_staze - je niz znakova koji sadrži konpletnu stazu do navedene datoteke.


access_mode - određuje način pristupa datoteci. Dozvoljene vrednosti za
access_mode su:

"r" - otvara tekstualnu datoteku samo za čitanje.


"w" - otvara tekstualnu datoteku samo za pisanje, odbacujući postojeći sadržaj
ako postoji bez opomene, ili kreirajući datoteku ako ona ne postoji.
"a" - otvara tekstualnu datoteku za pisanje, dodajući nove elemente na njen
kraj, ili stvarajući potpuno novu datoteku ako je nema.
"r+" - otvara tekstualnu datoteku za ažuriranje, čitanje i pisanje, postavljajući
pokazivač na početak datoteke.
"w+" - otvara tekstualnu datoteku za ažuriranje, čitanje i pisanje, odbacujući
postojeći sadržaj ako postoji, ili kreira datoteku ako ona ne postoji.
"a+" - otvara tekstualnu datoteku za ažuriranje, čitanje i pisanje, dodajući nove
elemente na njen kraj, ili stvara novu datoteku ako je nema.
Režimi otvaranja datoteka: "rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b",
"ab+", "a+b" imaju istu sematiku kao i prethodno opisani načini, sa jednom razlikom
što oznaka b upućuje na binarni umesto tekstualnog režima pristupa datoteci.

Na primer:

FILE *dat;
dat = fopen("primer.txt","r");

Nakon poziva funkcije fopen(); pokazivač dat kažemo da pokazuje na datoteku, ali
on u suštini ne pokazuje na stvarnu datoteku, već na strukturu FILE.

Struktura FILE sadrži članove:


 pokazivač na prihvatnu memoriju (bafer);
 broj bajtova, koje treba preneti;
 početnu adresu prihvatne memorije;
 stanje indentifikastora; i
 brojna oznaka datoteke.

154
U ovom primeru deklaracijom pokazivača dat saopšteno je prevodiocu da je dat
pokazivač koji će sadržati u sebi adresu promenljive tipa FILE. Nakon poziva funkcije
fopen(), funkcija fopen() traži datoteku primer.txt na direktorijumu gde se nalazi exe fajl
našeg programa. Ako ga nađe formiraće strukturu tipa FILE u ZONI PODATAKA,
upisaće brojnu oznaku datoteke, početnu adresu prihvatne memorije i inicijalizovaće
pokazivač na prihvatnu memoriju. Nakon popunjavanja strukture pokazivaču dat biće
prosleđena adresa strukture u ZONI PODATAKA. Druge funkcije će kasnije koristiti
strukturu preko pokazivača dat, kako bi na osnovu početne adrese prihvatne memorije i
pokazivača na prihvatnu memoriju smeštale podatke na prihvatnu memoriju.

Zatvaranje datoteke vrši se funkcijom fclose(); čiji je prototip:

int fclose(FILE *dat);

Zatvaranje jedne datoteke znači da se prekida veza, koja postoji između pokazivača
na datoteku i imena datoteke, tj pokazivača na strukturu dobija vrednost NULL. Prilikom
izvršavanja funkcije fclose, a pre prekidanja veze između pokazivača na datoteku i imena
datoteke, dolazi do ispisivanja sadržaja prihvatne memorije u datoteku. Funkcija vraća
vrednost 0 u slučaju uspešnog zatvaranja datoteke, ili EOF u slučaju otkrivanja grešaka.
Završetak izvršavanja programa dovodi do automatskog zatvaranja svih otvorenih
datoteka. Programi rade optimalnije kada ima otvoreno manje datoteka(od 10 do 20
datoteka). Zatvorenoj datoteci ne možemo pristupiti bez ponovnog otvaranja.

Primer:
Napisati deo koda koji omogućava definisanje pokazivača na datoteku, a potom
omogućiti otvaranje datoteke PRIMER.TXT za čitanje. Ako datoteka nije uspešno
otvorena prikazati odgovarajuću poruku.

Rešenje:

FILE *dat;

if((dat = fopen("primer.txt","r")==NULL)
{
printf("Datoteka primer.txt ne moze biti otvorena!!");
return;
}

fclose(dat);

155
5.3. ZNAKOVNO USMERENI ULAZ I IZLAZ

Funkcijama za prenos znakova vrši se čitanje ili pisanje pojedinačnih znakova ili
nizova znakova bez konverzije. Sada će biti prikazani prototipovi i opisi nekih od
funkcija:

int fgetc(FILE *dat);

dat - je pokazivač na datoteku koji je dobijen kao rezultat funkcije fopen();

Funkcija fgetc(); čita znak iz navedene datoteke, vraća znak i pomera se na sledeći
znak u datoteci. ako je uspešno obavila zadatak, funkcija će vratiti znak iz datoteke koji
je bio na redu za čitanje. Ako dođe do greške ili kraja datoteke, biće vraćena vrednost
EOF.

int fputc(int character, FILE *dat);

character - je znak koji se upisuje u datoteku


dat - je pokazivač na datoteku koji je dobijen kao rezultat funkcije fopen();

Funkcija fputc(); upisuje znak u datoteku. Ako funkcija uspešno obavi svoj zadatak,
biće vraćen znak koji je upisan u datoteku, inače, biće vraćena vrednost EOF.

char *fgets(char *buffer, int max_char, FILE *dat);

buffer - je početna adresa bafera u koji funkcija smešta pročitane znakove.


max_char - je vrednost kojom određujete maksimalan broj znakova koje treba
pročitati iz datoteke.
dat - je pokazivač na datoteku koji je dobijen kao rezultat funkcije fopen();

Funkcija fgets(); čita niz znakova iz navedene datoteke. Funkcija može da pročita
maksimalno max_char - 1 znakova ili do pojave znaka za novi red '\n' (koga ne stavlja u
string promenljivu buffer) i iza pročitanih znakova doda znak '\0'.
Ako funkcija uspešno obavi svoj zadatak biće vraćen pokazivač na niz pročitanih
znakova (buffer). Ako dođe do greške ili kraja datoteke, biće vraćena vrednost NULL.

int fputs(char *buffer, FILE *dat);

dat - je pokazivač na datoteku koji je dobijen kao rezultat funkcije fopen();


buffer - je niz znakova koji treba upisati u datoteku.

Funkcija fputs(); upisuje znakovni niz u određenu datoteku

156
int ungetc(int character, FILE *dat);

dat - je pokazivač na datoteku koji je dobijen kao rezultat funkcije fopen();


charakter - je znak koji treba biti vraćen u datoteku, kako bi taj znak bio vraćen pri
sledećem čitanju.

Funkcija ungetc(); dodaje znak nazad u datoteku. Znak EOF se ne može dodati
nazad. Funkcija vraća znak koji je dodat nazad ili EOF u slučaju greške.

int feof(FILE *dat);

dat - je pokazivač na datoteku koji je dobijen kao rezultat funkcije fopen();

Funkcija feof(); testira indikator kraja datoteke i daje kao rezultat vrednost različitu
od nule, ukoliko je dostignut kraj datoteke, inače će biti vraćena vrednost nula.

int fflush(FILE *dat);

dat - je pokazivač na datoteku koji je dobijen kao rezultat funkcije fopen();

Funkcija fflush(); briše sadržaj izlaznog bafera ili briše sadržaj ulaznog bafera. Ako
je funkcija uspešno obavila zadatak biće vraćena vrednost nula, inače, funkcija će vratiti
vrednost EOF.

Primer 1:
Napisati C program koji u tekstualnoj datoteci PRIMER.TXT utvrđuje koliko se
puta učitani znak sa tastature pojavljuje u datoteci.

Rešenje

#include <stdio.h>
#include <conio.h>

void main(void)
{
char c, e;
unsigned br=0;
FILE *dat;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

157
printf("\n\tZnak koji se posmatra> ");
c=getche();

if((dat=fopen("PRIMER.TXT","r"))==NULL)
printf("\n\n\tDatoteka PRIMER.TXT se ne moze otvoriti!!!");
else{
printf("\n\n\n\tDatoteka PRIMER.TXT je uspesno otvorena!!");
while((e=fgetc(dat))!=EOF)
{
if(e==c) br++;
}
fclose(dat);
printf("\n\n\tU datoteci se znak %c pojavio %d puta.",c,br);
}

gotoxy(1,25);
getch();
}

Primer 2:
Napisati C program koji u tekstualnoj datoteci PRIMER.TXT jedan znak
zamenjuje drugim znakom. Znak kojeg treba zameniti i znak sa kojim se vrši zamena
uneti sa tastature.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define DUZINA_LINIJE 81 /* Za jedan je vise od 80 zbog kraja stringa '\0' */

void sredi(char *s, char e, char d);

void main(void)
{

char c[81*25],d,e,*s1, *s2[DUZINA_LINIJE],*pom=c;


unsigned i,j;

FILE *dat;

for(i=0;i<DUZINA_LINIJE;i++) s2[i]=NULL;
s2[0]=pom;

textmode(3);
textcolor(15);
textbackground(0);

158
clrscr();

printf("\n\tUnesite znak koji se menja> ");


e=getche();

printf("\n\tUnesite znak sa kojim se vrsi zamena> ");


d=getche();

if((dat=fopen("PRIMER.TXT","r"))==NULL)
{
printf("\n\n\tDatoteka PRIMER.TXT se ne moze otvoriti!!!");
return;
}

printf("\n\n\n\tDatoteka PRIMER.TXT je uspesno otvorena!!");


i=0;
while(fgets(s1,DUZINA_LINIJE-1,dat)!=NULL)
{
sredi(s1, e, d);
strcpy(s2[i],s1);
if(i!=0) s2[i]=s2[i-1]+strlen(s2[i-1])+1;
i++;
}
fclose(dat);

dat=fopen("PRIMER.TXT","w");

for(j=0;j<i;j++) fputs(s2[j],dat); /* Upis niza stringova u datoteku. */

fclose(dat);

gotoxy(1,25);
getch();
}

/* Funkcija u stringu s menja svaku pojavu znaka c sa znakom d. */

void sredi(char *s, char e, char d)


{
unsigned i;

i=0;
while(s[i]!='\0'&&s[i]!='\n')
{
if(s[i]==e) s[i]=d;
i++;
}
}

159
Primer 3:
Napisati C program koji iz zadate tekstualne datoteke ekstrahuje i prikazuje
ispravno zapisane datume. Svaki red datoteke DATUMI.TXT sastoji se od samo jednog
datuma. Datum se smatra ispavno zapisan ako je u obliku:

datum = dan separator mesec separator godina


separator = {‘.’ | ’/’ | ’-‘}
dan = {01...09...31 | 1...31}
mesec = {01...09...12 | 1...12}
godina = {00...99 | 1...2999}

DATUMI.TXT (Izgled test datoteke)

28.03.2002
29.2.02
13/1/99
15-6-78
31/9/1000
55/6/4000
1/1/3000
28.2.2000
29.2.2000
12.05/2003

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>

#define MAX 81
void main (void)
{
FILE *dat;
unsigned i;
char c, *p=NULL, s[MAX], string[MAX]="";
unsigned dan, mesec, godina;

dan=mesec=godina=0;

textmode(3); textcolor(0); textbackground(15);


clrscr();

if ((dat=fopen("DATUMI.TXT","r"))!=NULL)
{
do {
string[0]='\0';

160
/* Sve podatke iz datoteke smestamo u string. */

i=0;
do {
string[i++]=fgetc(dat);
}while (string[i-1]!='\n'&& string[i-1]!=EOF);

/* U ovom delu programa koristi se funkcija strtok. Niz poziva funkcije


strtok(p,str); deli string p u tokene koji su medjusobno razdvojeni nekim
znakom iz stringa str. Prvi poziv u tom nizu poziva, ima string p koji nije
jednak NULL. On pronalazi prvi token u p koji se sastoji od znakova koji
ne pripadaju stringu str, i zavrsava rad upisujuci znak ’\0’ preko narednog
znaka stringa p i vraca pokazivac na taj token. Svaki naredni poziv
odredjen vrednoscu NULL za p, vraca sledeci takav token, trazeci ga od
pozicije koja se nalazi odmah iza prethodnog tokena. Funkcija strtok
vraca NULL kada nijedan dalji token nije pronadjen. String str moze biti
razlicit u svakom pozivu. */

if (string[i-1]=='\n')
{

/* Kraj reda se u datotekama obelezava znakom '\n', a kraj


stringa sa '\0' */

string[i]='\0';
strcpy(s,string);

/* Sada se pomocu funkcije strtok iz stringa p odvaja deo stringa


sve do prvog znaka koji moze biti znak '/' ili znak
'-'. Funkcija vraca pokazivac na string p. Funkcijom atoi se
string konvertuje u broj, sto pretstavlja dan. */

p=strtok(s,"./-");
/* U promenljivoj c pamti se prvi separator. Oba separatora
moraju biti ista. */

i=strlen(p);
c=string[i];
dan=atoi(p);

if (dan>0 && dan <32)


{
/* Iz preostalog stringa se izvlaci sledeci string do
pojave nekog od znakova '/' ili '-'. Taj deo stringa
pretstavlja mesec. */

p=strtok(NULL,"./-");
i+=strlen(p)+1;
mesec=atoi(p);

161
if (mesec>0 && mesec<12 && string[i]==c)
{
/* Sledeci deo stringa je godina. */

p=strtok(NULL,"./-\n");
godina=atoi(p);
if (godina>0 && godina<2999)
{
if (((mesec==1||mesec==3||mesec==5
||mesec==7||mesec==8||mesec==10
||mesec==12) && (dan < 32)) ||
((mesec==4||mesec==6||mesec==9
||mesec==11) && (dan < 31)) ||
((mesec==2) && (dan<30)
&& (!(godina%4)
&& (godina%400) ||
((mesec==2)&&(dan<29)))))
printf("%s",string);
}
}
}
}

/* Radi lakseg otklanjanja gresaka pokazivac se uvek pre ponovnog


koriscenja mora inicijalizovati. */

p=NULL;
}while(string[i-1]!=EOF);

/* Datoteka se uvek mora zatvoriti. */


fclose(dat);

}else printf("\nNemoguce je otvoriti datoteku DATUMI.TXT\a");

printf("\nPritisnite bilo koji taster za zavrsetak programa..");


getch();
}

162
5.4. ARGUMENTI IZ KOMANDNE LINIJE

Operativni sistem koji podržava razvoj softvera u programskom jeziku C


omogućava i prenos parametara u glavni program, kao da je u pitanju komanda
operativnog sistema. Formalno posmatrano, svaki program kreiran u C jeziku se sa nivoa
komandnog poziva operativnog sistema poziva kao funkcija sa dva argumenta. Prvi
argument je argc koji specificira broj argumenata (broj nizova karaktera) prenetih sa
komandne linije u funkciju main() i uvek je celobrojna vrednost. Drugi argument koji se
naziva argv specificira vrednosti pomoću niza pokazivača na stringove, koji u suštini
predstavljaju argumente funkcije main(). Argc uvek ima početnu vrednost 1, jer prvi
element niza argv pokazuje na ime programa.

Zaglavlje main() funkcije ima sledeći izgled:

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

Funkcija main() kao prvi argument ima indentifikator tipa int (ne mora ime
indentifikatora biti argc), a kao drugi argument indentifikator tipa niza pokazivača na
stringove (ne mora ime indentifikatora biti argv).
Ako se program PRIMER.EXE dobijen linkovanjem PRIMER.C ili PRIMER.CPP
izvornog koda programa, startuje iz komandne linije naredbom:

C:\TC\BIN>PRIMER A:\PRIMER1.TXT A:\PRIMER2.TXT

Vrednosti argumenata funkcije main() su:


argc: 3
argv: "PRIMER", "A:\PRIMER1.TXT", "A:\PRIMER2.TXT"
Argument argc ima vrednost 3 jer se niz stringova argv sastoji od tri stringa.
argv[0]: PRIMER
argv[1]: A:\PRIMER1.TXT
argv[2]: A:\PRIMER2.TXT

U ovom primeru navedene su putanje datoteka PRIMER1.TXT i PRIMER2.TXT,


ali ako se ne navedu podrazumeva se da se datoteke nalaze na trenutno aktivnom
direktorijumu.

Primer 1:
Napisati C program koji izračunava zbir brojeva zapisanih u tekstualnim
datotekama. Brojevi su realni i svaki broj nalazi se zapisan u novom redu tekstualne
datoteke. Omogućiti unos datoteka iz komandne linije. Utvrditi koja datoteka ima najveći
zbir. Ukoliko dođe do greške prilikom otvaranja datoteke, ispisati poruku koja datoteka
nije uspešno otvorena.

Rešenje

163
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>

float zbir(FILE *dat);

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


{
FILE *dat;
unsigned i, k;
float s, smax;

textmode(3), textbackground(0), textcolor(15), clrscr();

for(i=1;i<argc;i++)
{
if((dat=fopen(argv[i],"r"))==NULL)
{
printf("\n\tDatoteka %s nije uspesno otvorena!!", argv[i]);
return;
}else{
s=zbir(dat);
if(i==1) smax=s, k=1;
else if(s>smax) smax=s, k=i;
}
fclose(dat);
}

printf("Datoteka %s je imala najveci zbir %f od svih datoteka.",argv[k], smax);

gotoxy(1,25);
getch();
}

/* Funkcija zbir izracunava zbir brojeva iz jedne datoteke na koju pokazuje pokazivac dat.
Datoteka je vec ranije uspesno otvorena.*/

float zbir(FILE *dat)


{
char *s;
float sz=0;

while(fgets(s,81,dat)!=NULL) sz+=atof(s);

return sz;
}

164
Primer 2:
Napisati C program koji utvrđuje koliko tekstualna datoteka sadrži reči koje
počinju i završavaju se znakom '#', kao i tabelarni prikaz pojava takvih reči u datoteci po
redovima. U datoteci nema reci koje počinju u jednom redu a završavaju se u drugom.
Naziv tekstualne datoteke sa putanjom unosi se sa tastature ili iz komandne linije.

Na primer:

Unesite naziv tekstualne datoteke: PRIMER.TXT

U tekstualnoj datoteci ima 29 reci koje pocinju i zavtsavaju se znakom #.

REDNI BROJ REDA BROJ POJAVLJIVANJA


----------------------------------------------------------------------
1 12
4 10
5 7

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define MAX_NIZ 100

void main(int BrArg, char *naziv[])


{
char izvor[30],s[150];
unsigned i, k=0, brre, br=0, niz[MAX_NIZ];

FILE *dat;

for(i=0;i<MAX_NIZ;i++) niz[i]=0;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

if(BrArg==1)
{
printf("Unesite naziv datoteke sa putanjom: ");
gets(izvor);
}else strcpy(izvor, naziv[1]);

165
if((dat=fopen(izvor,"r"))==NULL)
{
printf("\n\n\n\n\tDatoteka %s se ne moze otvoriti!!");
return;
}

/* Ucitava se red po red iz tekstualne datoteke. Brojac br broji ukupan broj znakova '#',
dok brojac brre broji broj znakova '#' u jednom redu. Tabelarni prikaz se moze napraviti
ako se podaci o broju pojavljivanja znaka '#' podeljen sa 2 sacuva u nizu. Osnovni
zakljucak je da kako sve svaka rec nalazi zapisana u jednom redu, to je broj reci izmedju
znakova '#' jednak broju znakova '#' podeljeno sa 2. */

while(fgets(s,150,dat)!=NULL)
{
brre=0;

/* Prolazimo kroz string s koji predstavlja jedan red datoteke. */


i=0;
while(s[i]!='\0')
{
if(s[i]=='#') brre++,br++;
i++;
}
niz[k]=brre/2;
k++;
}

printf("\n\nU datoteci %s ima %d reci koje pocinju",izvor,br/2);


printf(" i zavrsavaju se znakom '#'.\n\n");

if(br!=0)
{
printf("\n\n\tREDNI BROJ REDA\t\t\tBROJ POJAVLJIVANJA\n");
printf("\t---------------------------------------------------\n");
for(i=0;i<k;i++)
{
if(niz[i]!=0) printf("\t\t%d\t\t\t\t%-3d\n",i+1,niz[i]);
}
}
gotoxy(1,25);
getch();
}

Primer 3:
Napisati C program koji vrši dešifrovanje rečenice zapisane u tekstualnoj dazoteci
čiji naziv sa putanjom se unosi sa tastature. U datoteci namerno postoji jedna reč koja
počinje i završava sa duplim slovom. Ako data tekstualna datoteka sadrži takvu reč i ako
se takva reč nalazi u datoteci SIFARNIK.TXT, znak je da je iz datoteke potrebno
dešifrovati rečenicu.

166
Datoteka SIFARNIK.TXT sadrži u svakom redu po jedan format oblika:
šifrovanareč broreči/brojrečenice* broreči/brojrečenice...@interpunkcijskiznak

šifrovanareč – je reč koja je pronađena u datotci,


brojreči – je redni broj reči u rečenici sa rednim brojem brojrečenice.
oznaka ... znači da postoji više reči u rečenici.
Prva reč iz dešifrovane rečenice mora početi velikim slovom, između reči je jedna
praznina, a rečenica se završava sa jednim interpunkcijskim znakom koji se nalazi posle
znaka @.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define MAX_NIZ 100

char *utvrdi(FILE *dat, char *s);


char *formrecenicu(char *t, char *niz[]);

void main(int BrArg, char *naziv[])


{
char izvor[30],ss[2000],*pom,*niz[150],s[1500]="",t[150]="",tt[150]="";
unsigned i,j,k;

FILE *dat;

niz[0]=ss;
for(i=1;i<150;i++) niz[i]=NULL;

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

if(BrArg==1)
{
printf("Unesite naziv datoteke sa putanjom: ");
gets(izvor);
}else strcpy(izvor, naziv[1]);

if((dat=fopen(izvor,"r"))==NULL)
{
printf("\n\n\t\tDatoteka %s se ne moze otvoriti!!",izvor);
getch();
return;
}

167
/* Pozivamo funkciju utvrdi koja utvrdjuje da li ulazna datoteka sadrzi sifrovanu rec. Ako
ne sadrzi funkcija vraca NULL, a u suprotnom pokazivac na string gde se nalazi format
uz pomoc koga se dobija desifrovana recenica. Prenosom po referenci funkcija u string s
smesta celokupnu ulaznu datoteku. */

if((pom=utvrdi(dat,s))==NULL)
{
printf("\n\n\t\tDatoteka nema sifrovanu rec!!");
fclose(dat);
return;
}
fclose(dat);
strcpy(t,pom);

/* Na osnovu stringa s gde je smestena ulazna datoteka formiramo niz pokazivaca na


stringove niz, gde ce svaki string sadrzati po jednu recenicu datoteke. */

i=0;
j=0;
while(s[i]!='\0')
{
k=0;
while(s[i]!='\0'&&s[i]!='.'&&s[i]!='!'&&s[i]!='?') tt[k]=s[i],k++,i++;
while(s[i]!='\0'&&(!isalpha(s[i]))) tt[k]=s[i],k++,i++;
tt[k]='\0';
strcpy(niz[j],tt);
j++;
tt[0]='\0';
if(j!=0) niz[j]=niz[j-1]+strlen(niz[j-1])+1;
}

/* Funkcija formrecenicu na osnovu stringa t gde je smesten format za desifrovanje


recenice i niza pokazivaca niz, formira trazenu recenicu, i vraca pokazivac na string gde
se ta recenica nalazi. */
printf("\n\nTrazena recenica je: %s",formrecenicu(t,niz));
getch();
}

/* Funkcija utvrdi utvrdjuje da li ulazna datoteka sadrzi sifrovanu rec. Ako ne sadrzi
sifrovanu rec funkcija vraca NULL, a u suprotnom pokazivac na string gde se nalazi format
uz pomoc koga se dobija desifrovana recenica. Prenosom po referenci funkcija u string s
smesta celokupnu ulaznu datoteku.*/

char *utvrdi(FILE *dat, char *s)


{
char sifra[50]="",c,sifrarec[100]="",*pom=NULL;
unsigned i,j,k,kk;
FILE *dat1;

168
if((dat1=fopen("SIFARNIK.TXT","r"))==NULL)
{
printf("\n\n\t\tDatoteka SIFARNIK.TXT se ne moze otvoriti!!");
getch();
exit(1);
}
/* Ucitavamo ulaznu datoteku karakter po karakter i smestamo u string s. */
i=0;
while((c=fgetc(dat))!=EOF) s[i]=c,i++;
s[i]='\0';

/* U stringu s trazimo sifrovanu rec. Prvo utvrdjujemo koja rec pocinje duplim slovom.
Ako nadjemo takvu rec utvrdjujemo da li se i zavrsava sa duplim slovom. */
i=0;
while(s[i]!='\0')
{
while(s[i]!='\0'&&s[i]!=s[i+1]) i++;
if(s[i]!='\0')
{
j=i+1;
while(s[j]!='\0'&&s[j]!=' '&&s[j]!= '\t'&&s[j]!='.'&&s[j]!='!'&&s[j]!='?') j+
+;

if(s[j]!='\0'&&s[j-1]==s[j-2])
{
/* Nasli smo rec koja pocinje duplim slovom i zavrsava se sa duplim
slovom, ali moramo utvrditi da li takve reci postoji u sifarniku. Prvo rec
izdvajamo u poseban string sifra, i prvo slovo tog stringa pretvaramo u
veliko jer svaka sifrovana rec u sifarniku pocinje sa velikim slovom. */
k=0;
for(kk=i+1;kk<j-1;kk++) sifra[k]=s[kk],k++;
sifra[k]='\0';

sifra[0]=toupper(sifra[0]);

/* Ucitavamo iz datoteke SIFARNIK.TXT red po red jer se u


svakom redu nalazi po jedan format sifrovane reci. */

while(fgets(sifrarec,100,dat1)!=NULL)
{
/* Izdvajamo sifrovanu rec znajuci da se posle nje nalazi
prazno mesto. */

pom=strtok(sifrarec," ");
if(!strcmp(pom,sifra))
{
/* Ako nadjene reci postoji u sifarniku,
zatvaramo datoteku i vracamo format
desifrovane rcenice. */

fclose(dat1);

169
return strtok(NULL,"\0,\n");

}else sifrarec[0]='\0';
}
}
}
/* ako nadjene reci nema u sifarniku pozicioniramo se na pocetak datoteke
SIFARNIK.TXT, i pocinjemo nadalje traziti u stringu s gde se nalazi ulazna
datoteka rec koja pocinje i zavrsava se sa duplim slovom. */

rewind(dat1);
i++;
}
fclose(dat1);

/* U slucaju da nema reci koja pocinje i zavrsava se duplim slovom i ujedno se nalazi u
sifarniku, funkcija vraca NULL.*/

return NULL;
}

/* Funkcija formrecenicu na osnovu stringa t gde je smesten format za desifrovanje


recenice i niza pokazivaca niz, formira trazenu recenicu, i vraca pokazivac na string gde se
ta recenica nalazi. */

char *formrecenicu(char *tt, char *niz[])


{
unsigned i, j, k, br=0, kon, brrec,brrece,brpom;
char *pom, s[150], p[150], res[150]="",t[150]="";

strcpy(t,tt);

/* Prvo prebrojimo koliko ima znakova '/' u formatu t, jer taj broj ce predstavljati i broj
reci koje ce sadrzati desifrovana recenica. */
i=0;
while(t[i]!='\0')
{
if(t[i]=='/') br++;
i++;
}

/* Iz cinjenice da funkciji strtok samo prvi put moramo proslediti string u kojem ce se
traziti tokeni, a svaki sledeci put se prosledjuje NULL, to prvo moramo desifrovati prvu
rec. */

pom=strtok(t,"/*");
brrec=atoi(pom);
pom=strtok(NULL,"/*@");
brrece=atoi(pom);
strcpy(s,niz[brrece-1]);

170
/* Promenljiva brpom sadrzace u svakom trenutku redni broj utvrdjene reci iz recenice
tekstualne datoteke, koja je vec ranije smestena u niz pokazivaca na stringove niz, dok ce
promenljiva kon kontrolisati da li je stvarno pronadjena prava rec ciji je redni broj u
recenici brrec. Kada se rec pronadje kontrolna promenljiva kon imace vrednost 1. */

i=0;
brpom=0;
kon=0;
while(s[i]!='\0'&&kon==0)
{

/* U stringu s nalazi se trazena recenica sa rednim brojem brrece. */


while(s[i]!='\0'&&(!isalnum(s[i]))) i++;

/* Utvrdjujemo da li je rec i brojac reci povecavamo za 1. */


if(s[i]!='\0') brpom++;

/* Utvrdjujemo da li je to nasa rec, te ako nije preskacemo je. */


if(brpom!=brrec)
{
while(s[i]!='\0'&&isalnum(s[i])) i++;
}else{

/* U slucaju da je to nasa trazena rec izdvajamo je u string p i kontrolnoj


promenljivoj kon dodeljujemo vrednost 1. */

j=0;
while(isalnum(s[i])) p[j]=s[i],j++,i++;
p[j]='\0';

kon=1;
}
}

if(br!=1)
{
/* Na nacin koji je gore opisan izdvajaju se preostale reci i formiraju string res,
koja predstavlja trazenu recenicu. */

for(k=1;k<=br;k++)
{
strcat(res,p);
strcat(res," ");
pom=strtok(NULL,"/*");
brrec=atoi(pom);
pom=strtok(NULL,"/*@");
brrece=atoi(pom);
strcpy(s,niz[brrece-1]);

i=0;
brpom=0;

171
kon=0;
while(s[i]!='\0'&&kon==0)
{
while(s[i]!='\0'&&(!isalnum(s[i]))) i++;
if(s[i]!='\0') brpom++;
if(brpom!=brrec)
{
while(s[i]!='\0'&&isalnum(s[i])) i++;
}else{
j=0;
while(isalnum(s[i])) p[j]=s[i],j++,i++;
p[j]='\0';
kon=1;
}
}
}

/* Formirana je recenica od potrebnih reci. */


res[strlen(res)-1]='\0';
}

/* Izdvajaju se interpunkcijski znaci koji su se nalazili posle znaka '@' u sifrovanoj


recenici iz sifarnika. */

i=0; while(tt[i]!='@') i++;


i++;
j=0; while(tt[i]!='\0') p[j]=tt[i],i++,j++;
p[j]='\0';

/* Interpunkcijski znaci se nadovezuju na kraj formirane recenice i prvo slovo recenice se


pretvara u veliko slovo. */
strcat(res,p);
res[0]=toupper(res[0]);

return res;
}

Test primer programa:

Test primer programa obuhvata tekstualne datoteke SIFARNIK.TXT I PRIMER.TXT.


U datoteci PRIMER.TXT nalaze se reči zapisane u datoteci SIFARNIK.TXT koje obrazuju
traženu rečenicu. Datoteka SIFARNIK.TXT formirana je po uslovima zadatka i u sprezi je sa
datotekom PRIMER.TXT (reči i pozicije reči se moraju polapati).

SIFARNIK.TXT

Povracanje 2/3*5/4@.
Srecan 1/2*5/3*12/4@!
Tuzan 7/2*12/4*13/5*11/2@.
Taster 6/1*8/9*5/8*6/2*12/9*6/7@.
Milostiv 5/2*4/1*12/6*11*3*20/3*11/1*25/6*32/4@?

172
PRIMER.TXT

Da bi forma bila funkcionalna mora joj se dodeliti kontrole. Kontrole su objekti


koje postavljate na formu da bi interagovali sa njima. Sve kontrole koje mozete
dodati formi nalaze se u kutiji sa alatom Toolbox. Najlaksi nacin da dodate kontrolu
formi je dupli klik na kontrolu koja se nalazi u okviru sa alatom. Ukoliko hocete
odmah da postavite kontrolu gde zelite mozete je prevuci na formu. Kada se kursor
otprilike nalazi gde zelite da kontrola bude kreirana oslobodite ttasterr misa.
Poslednji i najprecizniji metod postavljanja kontrole na formu je crtanje kontrole
na formi. Iz okvira sa alatkama kliknete na formu. Pomerate pokazivac misa na mesto
gde zelite da se gornji levi ugao forme nalazi, pa kliknete i drzite taster misa.
Prevucite pokazivac gde zelite da se nalazi donji desni ugao kontrole i oslobodite
dugme misa. Ova klasa definise osnovno funkcionisanje kontrola, zbog cega su mnogi
dogadaji osobine kontrola indenticni.

Izgled programa nakon pokretanja:

173
5.5. FORMATIRANI ULAZ I IZLAZ

Funkcije koje predstavljaju formatirani ulaz i izlaz su: fprintf() i fscanf(). Ove dve
funkcije su slične sa funkcijama printf() i scanf(), tj. sve je isto osim što im je potrebno
dodati argument pokazivač na datoteku sa kojom će se raditi.
Kada sistem startuje program, automatski se otvaraju tri datoteke. Ove datoteke su
indentifikovane sa tri konstantna pokazivača na tip FILE i to su: stdin, stdout i stderr,
koji su definisani u datoteci stdio.h. Pokazivač stdin indentifikuje standardni ulaz
programa i pridružen je terminalu sa kog je program startovan. Sve standardne ulazne
funkcije ne zahtevaju eksplicitni argument za indentifikaciju ulazne datoteke, jer po
definiciji koriste pokazivač stdin. Pokazivač stdout indentifikuje standardni izlaz, koji je
takođe pridružen terminalu sa kog je program aktiviran. Pokazivač stderr indentifikuje
standardnu datoteku za štampanje poruka o greškama, generisanih od strane sistema.
Pokazivač stderr je pridružen terminalu sa kojeg je program aktiviran.

Primer:
scanf("%d",&n); <=> fscanf(stdin,"%d",&n);
printf("N = %d",n); <=> fprintf(stdout,"N = %d",n);

Osim ova tri pokazivača DOS operativni sistem podržava i pokazivače: stdprn
usmeren na standardni priključak za štampač, i stdaux koji ide na standardnu funkciju za
serijsku komunikaciju.

Primer:
Napisati C program koji utvrđuje broj reči u tekstualnoj datoteci čije ime sa
putanjom se unosi sa tastature.

Rešenje

#include <stdio.h>
#include <conio.h>

#define DUZINA 81

unsigned brojireci(char *s);

void main(void)
{
char *ime, *s;
unsigned n=0;
FILE *dat;

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

174
printf("\n\tUnesite ime datoteke: ");
gets(ime);

if((dat=fopen(ime,"r"))==NULL)
fprintf(stderr,"\n\n\t\tGreska!! Datoteka se ne moze otvoriti!!");
else{
while(fgets(s,DUZINA,dat)!=NULL) n+=brojireci(s);
}
fclose(dat);
fprintf(stdout,"\n\n\tU datoteci %s nalazi se %u reci.",ime,n);

gotoxy(1,25);
getch();
}

unsigned brojireci(char *s)


{
unsigned br=0;

while(*s)
{
while(*s == ' ' || *s == '\n' || *s == '\t') s++;
if(*s)
{
br++;
while(*s != ' ' && *s != '\n' && *s != '\t' && *s != '\0') s++;
}
}

return br;
}

Test primer programa:


Test primer programa koristi datoteku PRIMER.TXT iz prošlog zadatka.

Izgled programa:

175
5.6. POZICIONIRANJE UNUTAR DATOTEKE

Pozicioniranje unutar datoteke pretstavlja direktan pristup datoteci. Najčešće se za


pozicioniranje unutar datoteke koriste funkcije fseek, ftell i rewind.

int fseek(FILE *dat, long offset, int mode );

Funkcija fseek podešava poziciju datoteke za tok dat. Narednim čitanjem ili
pisanjem pristupa se podacima na početku te nove pozicije. Datoteka se tretira kao niz
bajtova, a funkcija fseek omogućava da se direktno pristupi do bilo kog bajta u datoteci.
Argument mode označava polaznu tačku, i može imati jednu od tri vrednosti zapisanih u
simboličkim konstantama:

 SEEK_SET početak datoteke


 SEEK_CUR trenutna pozicija
 SEEK_END kraj datoteke

Simboličke konstante SEEK_SET, SEEK_END i SEEK_CUR definisane su u


zaglavlju stdio.h.

Argument offset koliko daleko u bajtovima treba da se pomeramo od početne tačke.


Ako offset ima pozitivnu vrednost kreće se napred, ili negativnu vrednost kreće se nazad.
U slučaju tekstualne datoteke offset može da ima vrednost nula ili vrednost koju je dala
funkcija ftell, dok mode mora imati vrednost SEEK_SET.
Funkcija fseek vraća vrednost 0 ako je uspešno obavila posao, ili -1 u suprotnom
(pokušaj pozicioniranja izvan granica datoteke).
Funkcija fseek mora obavezno da se poziva pre prvog čitanja posle nekoliko
upisivanja, odnosno pre prvog upisivanja posle nekoliko čitanja. Na primer prepisujemo
jedan podatak preko drugog, a potom hoćemo da čitamo sledeći podatak. Bez obzira što
se čita sledeći bajt mora se pozvati funkcija fseek.

long ftell(FILE *dat);

Funkcija ftell trenutnu poziciju datoteka za tok dat izražen u bajtovima u odnosu na
početak datoteke, ili -1 u slučaju greške.

void rewind(FILE *dat);

Funkcija vrši pozicioniranje na početak datoteke.

176
Primer 1:
Napisati C program koji u tekstualnoj datoteci PRIMER.TXT jedan znak
zamenjuje drugim znakom. Znak kojeg treba zameniti i znak sa kojim se vrši zamena
uneti sa tastature. Na ekranu štampati izmenjeni sadržaj datoteke.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

void main(void)
{
char c,d,car;
long poz;
FILE *dat;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\n\tUnesite znak ji se menja: ");


c=getche();
printf("\n\tUnesite znak sa kojim se vrsi zamena: ");
d=getche();

/* Otvaramo datoteku za citanje i pisanje te se stavlja r+ mod. */


if((dat=fopen("PRIMER.TXT","r+"))==NULL)
{
printf("\n\n\tDatoteka PRIMER.TXT se ne moze otvoriti!!!");
return;
}

printf("\n\n\n\tDatoteka PRIMER.TXT je uspesno otvorena!!\n\n");


do{
/* Pamtimo trenutnu poziciju u datoteci i smestamo u promenljivu poz. */
poz=ftell(dat);

/* Ucitavamo karakter iz datoteke i smestamo ga u promenljivu car, i automatski


se prelazi na sledeci karakter (bajt) u datoteci. */
car=fgetc(dat);

/* Ako je karakter iz datoteke onaj koji se menja vrsi se zamena. */


if(car == c)
{
/* Pozicioniramo se na prethodni karakter u datoteci (onaj kojeg je
ucitala funkcija fgetc), a poziciju smo zapamtili pozivom funkcije ftell u
promenljivoj poz.

177
Vrsimo upis karaktera u datoteku pomocu funkcije fputc. */

fseek(dat,poz,SEEK_SET);
fputc(d,dat);

/* Kako posle pisanja vrsimo citanje podatka iz datoteke moramo izvrsiti


ponovno pozicioniranje pozivom funkcije fseek. */
fseek(dat,poz+1,SEEK_SET);

/* Stampamo izmenjeni podatak na ekranu. */


printf("%c",d);
}else printf("%c",car);
}while(car!=EOF);
fclose(dat);

gotoxy(1,25);
getch();
}

Primer 2:
Napisati C program koji predstavlja poznatu igru "slagalica" iz televizijskog kviza
muzička slagalica. Korisnik unosi deset slova engleske abecede. Nakon svakog
pritisnutog tastera SPACE u odgovarajuće polje upisuje se po jedan znak. Korisnik ima
jedan minut na raspolaganju da unese svoju reč sa što više slova od ponuđenih. Program
utvrđuje da li je reč ispravno unesena na osnovu ponuđenih slova, a potom na osnovu
tekstuale datoteke RECI.TXT daje svoje rešenje koje ima najveći broj slova u sebi.

Rešenje

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<dos.h>
#include<time.h>
#include<ctype.h>

#define BR 18
#define ESC 27
#define VREME 60
#define ZADNJIDEO 10

/* Prototipovi funkcija. */
void rand(char *rec,char *slova);
void crtaj(void);
unsigned bacaj(char *slova);
int provera(char *slova,char *druga);
unsigned uzmi(char *druga);

178
void main(void)
{
int i=0,j=0;
char *rec="",*slova,c,*druga;
FILE *fajl;

randomize();
textmode(3);
textcolor(3);
textbackground(0);
clrscr();

/* U datoteci RECI.TXT nalaze se najduze reci naseg jezika. */


if( (fajl=fopen("reci.txt","r")) ==NULL)
{
printf("Nesto nije u redu sa fajlom RECI!!");
getch();
return;
}

/* Pozicioniramo se na pocetak datoteke. Znamo da se u jednom redu


nalazi tacno jedna rec. Iz tog razloga kada ucitamo znak '\n' znaci
da smo ucitali jednu rec. U ovom delu koda brojimo reci. */

fseek(fajl,0,SEEK_SET);
while(c!=EOF)
{
if((c=fgetc(fajl))=='\n')i++;
};

/*Utvrdili smo broj reci i ponovno se pozicioniramo na pocetak datoteke. */


rewind(fajl);

/* Na slucajan nacin biramo najduzu rec iz datoteke RECI.TXT i to ce navodno biti i


najduza rec koju je racunar pronasao. Ucitana rec se smesta u promenljivu rec i datoteka
se zatvara. */
randomize();
for(j=0;j<random(i);j++) fgets(rec,BR+2,fajl);
fclose(fajl);

/* Svaki string se zavrsava sa znakom '\0'. */


*(rec+strlen(rec)-1)='\0';

/* Sva slova date reci se pretvaraju u velika. */


rec=strupr(rec);

slova=" "; /* String slova ima sada BR praznina. */

rand(rec,slova);
gotoxy(15,5);
crtaj();

179
if(bacaj(slova)==0) return;

gotoxy(15,14);
if(uzmi(druga)==0) return;

druga=strupr(druga);
if((i=provera(slova,druga))!=0)
{
gotoxy(15,15);
printf("Ova rec ne moze da se prizna, fale %d slova!!",i);
}

if((i=provera(slova,druga))!=0&&strlen(druga)<strlen(rec))
{
delay(1700);
gotoxy(15,17);
printf("To nije najduza rec!");
}

gotoxy(15,18);
printf(" ");
gotoxy(15,18);printf("Kompjuter je nasao rec: ");
delay(1500);
gotoxy(15,20);
for(i=0;i<strlen(rec);i++) printf("%c ",rec[i]);
gotoxy(1,25);
getch();
}

/* Funkcija rand formira rec od 18 slova koja sadrzi sva slova iz reci ucitane
iz datoteke, a ostalo popunjenih proizvoljnim slovima.
Datu rec ce igrac kasnije navodno izabrati. */
void rand(char *rec,char *slova)
{

int i,j,d,r;
char cr;
d=strlen(rec);
randomize();

/* Popunjava se string od slova koji ce pretstavljati navodno izabrana slova od


strane igraca. String se popunjava na slucajan nacin razbacivanjem slova iz reci
koja je ucitana iz datoteke. */

for(i=0;i<d;i++)
{
do{
r=random(BR);
}while(slova[r]!=' ');
slova[r]=rec[i];
}

180
/* Ostace jos nepopunjenih mesta u stringu slova jer rec ucitana iz datoteke ima
manje slova nego rec koja se formira navodnim biranjem od strane korisnika. */

for(i=0;i<BR-d;i++)
{
/* Izaberemo nepopunjenu poziciju. */
do{
r=random(BR);
}while(slova[r]!=' ');

/* Slova moraju biti velika a ona se u ASCII tabeli nalaze od rednog


broja 65, a ima ih 26. . */
do{
cr=random(26)+65;
}while(cr=='Y'||cr=='X'||cr=='W'||cr=='Q'||cr=='A'||cr=='O'||
cr=='E'||cr=='I'||cr=='U');
slova[r]=cr;
}
}

/* Funkcija crtaj stampa izgled igrice. */


void crtaj(void)
{
int i,j;
gotoxy(15,2);printf("\t\tS L A G A L I C A");

for(i=10;i<70;i++) gotoxy(i, 4), printf("▒"); /* ALT+178 */


for(i=10;i<72;i++) gotoxy(i,22), printf("▒");
for(i=4;i<22;i++) gotoxy(10,i), printf("▒▒");
for(i=4;i<22;i++) gotoxy(70,i), printf("▒▒");
for(i=10;i<70;i++) gotoxy(i,10), printf("▒");
for(i=10;i<70;i++) gotoxy(i,16), printf("▒");
gotoxy(15,6);
printf("Izaberite slova: ");
gotoxy(15,12);
printf("Vasa rec je: ");
gotoxy(15,18);
printf("Kompjuter je nasao rec: ");
gotoxy(21,23);
cprintf("Ako ste sastavili rec pritisnite ENTER");
for(i=0;i<60;i++)
{
gotoxy(11+i,24);
cprintf("░"); /* ALT+177 */
}
}

/* Funkcija bacaj simulira izgled bacanja slova ali kako se slova brzo vrte igrac nece ni
znati da slovo koje je izabrao nije stampano na ekranu. */
unsigned bacaj(char *slova)
{

181
int i,c,cr;

_setcursortype(_NOCURSOR);
for(i=0;i<BR;i++){
do{
do{
cr=random(26)+65;
gotoxy(23+(2*i),8);
putch(cr);
delay(100);
}while(!kbhit());
c=getch();
if(c==ESC) return 0;
}while(c!=32);
gotoxy(23+(2*i),8);
putch(slova[i]);
}
return 1;
}

/* Funkcija provera utvrdjuje da li slova iz reci koje je formirao korisnik ima u stringu
slova koje je izabrao bacanjem. */
int provera(char *slova,char *druga)
{
int p,i,j,d=strlen(druga),k=0;
char *sl2;

/* Rec od slova dobijenih bacanjem, zapamti se u pomocnom stringu jer ce se taj


string modifikovati. U njega na pozicijama gde je karakter nadjen upisuje se
karakter '*', kako se isto slovo vec utvrdjeno da postoji u stringu ponovo
ucestvovalo u poredjenju. */
sl2=slova;
for(i=0;i<d;i++)
{
for(j=0;j<BR;j++)
{
if(*(druga+i)==*(sl2+j))
{
*(sl2+j)='*';
j=BR;
}
}
}
/* Izbrojimo koliko ima karaktera '*' u modifikovanom stringu, jer je razlika izmedju
duzine stringa koje je korisnik odabrao da je najduza rec i broja karaktera '*' upravo broj
slova kojih nema u reci koja je dobijena bacanjem. */
for(i=0;i<BR;i++)if(*(sl2+i)=='*') k++;
if(k==d) return 0;
else return (d-k);

182
/* Funkcija omogucava korisniku da izabere najduzu rec. */
unsigned uzmi(char *druga)
{
char c;
int i=0;
time_t t;
long start,vr;

_setcursortype(_NOCURSOR);

/* Pre pocetka same igre ucitava vreme koje pokazuje sistemski sat u sakundama. */
start=time(&t);

do{
do{

/* Izracunava se uvek razlika izmedju trenutnog vremena koje


pokazuje sistemski sat i vremena koje je pokazao na pocetku
igre, a to je trenutno vreme trajanja igre, */
vr=time(&t)-start;

/* Pale se polja sa palete, i na taj nacin korisnik ima vizuelni


izgled trajanja igrice. Zadnji deo vremena se na paleti prikazuje
crvenom bojom. */
gotoxy(11+vr,24);
if(vr<VREME-ZADNJIDEO) textcolor(14);
else textcolor(4);
cprintf("▒"); /* ALT+178 */

_setcursortype(_NORMALCURSOR);

if(vr==VREME)
{
gotoxy(20,23);
printf(" ");
gotoxy(32,23);
printf("VREME JE ISTEKLO");
return 0;
}
gotoxy(15+i*2,14);
delay(20);
}while(!kbhit());
c=getch();
if(c==ESC) return 0;

/* Pretvaramo karakter u veliko slovo, u slucaju da je malo, dok funkcija


isalpha utvrdjuje da li je karakter slovo. */
c=toupper(c);
if(c!= '\b'&&c!= '\r'&&isalpha(c)&&
c!=' '&&c!='X'&&c!='Y'&&c!='Q'&&c!='W'&&i<=BR)
{

183
druga[i++]=c;
druga[i]='\0';
gotoxy(13+i*2,14);
printf("%c",c);
}

/* Ako je pritisnut BACKSPACE mora se izbrisati i zadnje uneto slovo iz


stringa. */
if(i>0&&c=='\b')
{
druga[i--]='\0';
gotoxy(14+i*2,14);
printf(" ");
}
}while(c!= '\r');
return 1;
}

Test primer programa:

184
5.7. ZADACI IZ TEKSTUALNIH DATOTEKA

Zadatak 1 (2)
Napisati C program koji izračunava zbir brojeva zapisanih u tekstualnoj datoteci čiji
naziv bez putanje se unosi sa tastature. Brojevi su realni i svaki broj nalazi se zapisano u
novom redu tekstualne datoteke.

Zadatak 2 (2)
Napisati C program koji utvrđuje broj linija u tekstualnoj datoteci i štampa najdužu
liniju iz datoteke. Naziv datoteke bez putanje se unosi sa tastature.

Zadatak 3 (2)
Napisati C program koji utvrđuje koliko tekstualna datoteka sadrži reči. Naziv
tekstualne datoteke može se uneti preko komandne linije ili tastature.

Zadatak 4 (3)
Napisati C program koji određuje liniju koja sadrži najdužu reč. Ispisati na ekranu
redni broj linije i najdužu reč. Naziv tekstualne datoteke može se uneti preko komandne
linije ili tastature.

Zadatak 5 (3)
Napisati funkciju koja upoređuje dve tekstualne datoteke i vraća redni broj reda u
kojoj se po prvi put datoteke razlikuju, ili 0 ako su datoteke indentične. Naziv tekstualne
datoteke može se uneti preko komandne linije ili tastature.

Zadatak 6 (3)
Napisati C program koji pozivanjem funkcije brisi, višestruki uzastopni niz
znakova zamenjuje sa jednim znakom, u tekstualnoj datoteci čije ime bez ekstenzije se
unosi sa tastature. Veliko i malo slovo tretira se istim znakom.

Na primer:

PRIMER.TXT
Eeeh da miiiii jje laksiiii zzaddattak dao!!
Ovi pppprofesorrri uvekkk naas muce i mmaltreeetirraju.
Nnnnapokonn sam zavrssiooo.

Nakon sređivanja datoteka ima sledeći izgled:

PRIMER.TXT
Eh da mi je laksi zadatak dao!!
Ovi profesori uvek nas muce i maltretirraju.
Napokon sam zavrsio.

185
Zadatak 7 (2)
Napisati C program koji omogućava unos naziva tekstualne datoteke sa putanjom i
prebrojava koliko ima reči da a koliko ne u tekstualnoj datoteci. Za brojanje reči koristiti
funkciju brojireci.

Zadatak 8 (3)
Napisati C program koji utvrđuje koja linija u tekstualnoj datoteci poseduje najviše
reči. Ispisati datu liniju na ekranu i broj reči koliko ima data datoteka. Naziv tekstualne
datoteke može se uneti preko komandne linije ili tastature.

Zadatak 9 (2)
U tekstualnoj datoteci MATRICA.TXT nalazi se matrica. Prvi red datoteke sadrži
dva celobrojna podatka: broj vrsta i broj kolona koje ima matrica. Podaci su razdvojeni
blanko mestom (mestima) ili tabulatorom (tabulatorima).
Napisati C program koji izračunava zbir elemenata matrice, i vrši zatim sažimanje
matrice izbacivanjem svih onih kolona koji imaju zbir manji od zbira celokupne matrice.
Za izračunavanje zbira celokupne matrice koristiti funkciju zbir, a za izračunavanje zbira
elemenata jedne kolone funkciju zbirkolone.
Ispod već postojeće matrice napraviti dva prazna reda, a zatim ispisati zbir
elemenata matrice, a ispod jedan prazan red pa novonastalu matricu, u istom formatu
kakav je i bio u datoteci.

Na primer:

MATRICA.TXT

5 7
-3 1 2 0 -2 -6 -7
-3 0 -1 4 5 -2 -6
7 -4 0 -11 -3 4 10
5 1 0 -1 -2 7 22
4 -1 -10 -3 4 -4 -5

Zbir matrice = 2

5 3
-3 -2 -7
-3 5 -6
7 -3 10
5 -2 22
4 4 -5

186
Zadatak 10 (3)
Napisati C program koji uklanja komentare iz nekog C programa. Komentari u C
programu počinju sa /* a završavaju se sa */.

Zadatak 11 (4)
Napisati C program koji prikazuje sadržaj tekstualne datoteke na ekranu, tako što je
centrirano u prvoj liniji ekrana ispisan naziv datoteke a od 3 do 22 linije ispisano 20 linija
teksta datoteke, a u 24 liniji ekrana je centrirano ispisan redni broj strane koji se
prikazuje. Smatrati da svaka strana ima po 20 linija teksta. Za nastavak prikazivanja
sledeće strane koristiti taster SPACE.

Zadatak 12 (4)
Zadata je tekstualna datoteka ULAZ.TXT, pri čemu svaki red ove datoteke ima
samo jednu potpunu rečenicu koja se završava tačkom. Znači da posle tačke nema više
karaktera u rečenici. Između reči u rečenici može postojati više praznih mesta. Rečenica
može imati najviše 80 karaktera. Koristeći funkciju najveci iz svakog reda datoteke
utvrđuje se reč koja je najduža, a potom se svi karakteri (mala slova) reči pretvaraju u
velika slova. Uz pomoć funkcije upis, ove reči se upisuju u izlaznu datoteku
IZLAZ.TXT. Funkcijom ispis se sadržaj datoteke IZLAZ.TXT štampa na ekranu.
Program realizovati u programskom jeziku C.

Zadatak 13 (4)
Napisati C program koji utvrđuje koja rečenica u tekstualnoj datoteci poseduje
najviše reči. Ispisati koliko ima rečenica u datoteci kao i rečenicu koja ima najviše reči i
broj reči koliko ima data rečenica.
Rečenica se završava tačkom, upitnikom ili uzvičnikom.

Zadatak 14 (4)
Napisati C program koji pronalazi sva pojavljivanja date reči (sekvenca od
maksimalno 30 karaktera) u datoj tekstualnoj datoteci. Na izlazu štampati redne brojeve
rečenica iz datoteke u kojima se reč pojavljuje Ignorisati višestruko pojavljivanje reči u
jenoj rečenici.

Zadatak 15 (3)
Napisati C program koji spaja dve sortirane datoteke u treću sortiranu datoteku koja
sadrži samo različite elemente ulaznih datoteka. Program omogućava rad sa više ulaznih
sortiranih datoteka, pri čemu se imena datoteka unose iz komandne linije.
Datoteke se sastoje od redova pri čemu se u svakom redu nalazi po dve reči (ime i
prezime) razdvojeni blanko mestom. Obe reči počinju velikim slovom. Ako se pojave
greške da neka od reči počinje malim slovom program automatski ispravlja tu grešku u
izlaznoj datoteci.

187
Zadatak 16 (4)
Napisati C program koji vrši šifrovanje datoteke tako što se svaka reč u datoteci
zapisuje u invernom poretku. Ako je neka reč počinjala velikim slovom i rotirana reč
počinjaće sa velikim slovom. Tabulatori, praznine, prelazak u novi red i znakovi
interpunkcije ostaju na istim pozicijama u datoteci.
Za šifrovanje datoteke koristiti funkciju void sifrujdat(FILE *filepointer); U
okviru funkcije sifradat koristiti i funkciju char *izdvojrec(char *s); iz linije fajla koji je
zapisan u stringu s.

Zadatak 17 (5)
Napisati C program koji u tekstualnoj datoteci vrši zamenu svake pojave reči s sa
reči t. Program realizovati funkcijom int zamenirec(FILE *filepionter, chat *s, char *t);
koja vraća 0 ako reči s nema u datoteci, a 1 u suprotnom.

Zadatak 18 (5)
Napisati C program koji u datoj tekstualnoj datoteci, pronalazi i briše rečenice koje
se višestruko ponavljaju. Rečenice počinju velikim slovom ili brojem, a završavaju se
tačkom, uzvičnikom, upitnikom ili oznakom EOF. Omogućiti unos naziva iz komandne
linije.

Zadatak 19 (5)
Napisati C program koji prikazuje spisak referenci u datoj tekstualnoj datoteci.
Svaka referenca u tekstu je označena sa svojim brojem u uglastim zagradama. Na izlazu
štampati reference sa brojevima, svaka referenca u novom redu.

Zadatak 20 (4)
Napisati C program koji utvrđuje koliko datoteka, čije ime sa ekstenzijom se unosi
iz komandne linije, sadrži pasusa. Pasus koji sadrži najveći broj reči formatizovati tako
da sve reči budu pretvorene reči sa velikim slovima.

Zadatak 21 (5)
Učenici su napisali velike C programe na praktičnoj nastavi. Profesor je zadao
pravilo da se u programu ne sme koristiti naredba bezuslovnog skoka goto. Kako
profesora mrzi da kontroliše ceo kod, potrebno je napisati C program koji utvrđuje da li
proizvoljni C ili CPP program čije ime sa ekstenzijom se unose sa tastature sadrži
naredbu goto, te ako jeste na ekranu ispisuje poruku.

Zadatak 22 (5)
Potrebno je modifikovati tekstualnu datoteku čije ime se unosi sa tastature, tako da
se u svakom redu nalazi tačno jedna rečenica. Ako rečenica ima više od 80 karaktera
nastavlja se upis u novom redu.

188
Zadatak 23 (5)
Napisati C program koji utvrđuje koliko ima zbirova u datoteci. Svaki zbir počinje
u novom redu datoteke i završava se znakom jednakosti. Zbir se može prostirati u više
redova. Brojevi mogu biti celobrojni ili racionalni. U izrazima nema zagrada, ali se mora
poštovati prioritet operatora. Ako se zbir nastavlja u sledećem redu poslednji znak mora
biti znak operacije. Formirati novu datoteku REŠENJE.TXT koja će sadržati isto što i
ulazna datoteka, stim što se posle jednakosti mora nalaziti i rezultat, čime se završava taj
red. Naziv ulazne datoteke uneti sa tastature ili iz komandne linije.

Zadatak 24 (4)
U tekstualnoj datoteci čiji naziv se učitava sa tastature nalazi se inicijalizacija
trodimenzionalne matrice. Potrebno je modifikovati datoteku tako da u njoj ostaju samo
elementi trodimenzionalne matrice odvojeni međusobno jednim praznim mestom.
U jednom redu datoteke nalazi se samo jedna dimenzija matrice. Posle elemenata
koji pretstavljaju poslednje elemente druge dimenzije postoji prazan red.

ULAZ.TXT

Int matrica[MAX][MAX][MAX]={
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
},
{
{4, 3, 4, 5},
{5, 6, 7, 8},
{9, 4, 11, 22}
}
}

Modifikovana ulazna datoteka je:

ULAZ.TXT

1234
5678
9 10 11 12

4345
5678
9 4 11 22

189
Zadatak 25 (5)
Data je tekstualna datoteka pod imenom TEKST.TXT. Napisati C program koji
štampa sadržaj datoteke na ekran, ali tako da kompletan tekst bude poravnat i po desnoj i
po levoj margini na sledeći način.:
 Poravnavanje na levo vršiti najobičnijim štampanjem od prve kolone ekrana;
 Poravnavanje na desno vršiti tako da desna margina bude u onoj koloni u
kojoj se završava najduži redoriginalnog teksta; i
 Ostale redove (koji su kraći od originalno najdužeg), “Produžavati“ tako što
će se između reči ubacivati približno ravnomerno prazna mesta, onoliko
njih koliko je potrebno da red dostigne dužinu najdužeg.

Zadatak 26 (5)
Na osnovu C programa koji je obrađen u zadatku 30 oblasti višedimenzionalni
nizovi, igrica POGODI, doraditi program tako da poseduje tri nivoa.
Prvi nivo je već obrađen u predhodnoj verziji.
Drugi nivo omogućava da se mora redom pogađati brojevi od 1 do 6. Ako se pogodi
pogrešno polje ne menja se boja (ostaje tamna).
Treći nivo omogućava da se polja moraju tako pogađati da na kraju dobijemo
sortiran niz brojeva. Nakon svakog pogotka na neki broj on se zarorira sa svojim
sledbenikom, dok u slučaju da se pogodi poslednji broj on se rotira sa prvim elementom u
nizu. Svaki nivo ima po pet tabli. Table se nalaze zapisane u tekstualnoj datoteci
POGODI.TXT, pri čemu su table odvojene sa jednim praznim redom.
Za svaki pogodak u polje dobija se jedan broj, dok se za svaku pređenu tablu dobija
po 5 bodova pomnoženo sa brojem nivoa koji je poslednji pređen u igri.

Zadatak 27 (5)
U tekstualnoj datoteci nalazi se neki tekst sastavljen od reči i tačaka koje
označavaju krajeve rečenica. Između reči se nalazi jedna ili više praznina.
Napisati C program koji vrši formatiranje teksta po sledećim pravilima:
 Između reči može da bude tačno jedna praznina;
 Ispred prve reči teksta nema praznina;
 Ispred tačke nema praznine;
 Iza tačke postoji tačno jedna praznina i prva reč iza tačke počinje uvek
velikim slovom; i
 dužina reda u datoteci ne sme biti veća od 80 karaktera.

Zadatak 28 (5)
Potrebno je napraviti tekst procesor koji je u stanju da:
1) unosi tekst;
2) umeće nove redove teksta;
3) kretanje kroz tekst pomoću strelica;
4) sa breakspace briše znak iz teksta uz pomeranje teksta toga reda u levo za
jedno mesto; i
5) uz pomoć tastera delete briše jedan red teksta gde se trenutno kursor nalazi.

Omogućiti unos imena datoteke sa ekstenzijom iz komandne linije ili sa tastature.

190
Zadatak 29 (5)
Date su tekstualne datoteke REZULTATI.TXT i GOLOVI.TXT sa sledećim
izgledom:

REZULTATI.TXT

Tim Pobede Nerešeno Porazi Dati golovi Primljeni golovi


1 13 4 8 23 13
2 15 3 7 25 14 itd...

GOLOVI.TXT

Tim Igrač 1 Igrač 2 Igrač 3 ... Igrač 22


1 0 0 2 ... 1
1 2 2 0 ... 1 itd...

Spisak ekipa sa igračima nalazi se u tekstualnoj datoteci EKIPE.TXT. Prvo se


navodi naziv ekipe, a ispod u svakom redu po jedno prezime i ime igrača raydvojenih
praznim mestom. Ekipe su razdvojene sa jednim praznim redom.
Napisati C program koji učitava tekstualne datoteke i na ekranu i u datoteci
TABELA.TXT štampa tabelu prvenstva, dok u datoteci IGRACI.TXT i na ekranu
štampa listu golgetera.

Zadatak 30 (5)
Napisati C program koji pretstavlja poznatu igricu TETRIS. Omogućiti formiranje
četiri nivoa igrice. Postoji više oblika u tetrisu. Stalno se prikazuje koji je sledeći oblik.
Sledeći oblik se dobija na slučajan način. Sa strelicom levo pomera se oblik na levo, sa
strelicom desno pomera se oblik na desno, sa strelicom na gore vrši se rotiranje oblika, a
sa strelicom na dole vrši se brzo spuštanje na dole. Kraj igrice je ako se pritisne taster
ESC. Ako se skupi određeni broj bodova prelazi se u sledeći nivo. U slučaju da se ne
uspe u tom nivou vraća se na prethodni nivo.
U tekstualnoj datoteci čuvati pet najboljih rezultata. Rezultat je opisan sa
skljupljenim brojem poena i imenom igrača.

191
192
6. POGLAVLJE

STRUKTURE I BINARNE DATOTEKE

193
6.1. DEFINICIJA STRUKTURE DEKLARACIJA STRUKTURE
PRISTUP ČLANOVIMA STRUKTURE ITIPOVI
KOJE DEFINIŠE KORISNIK

Definicija strukture:
Struktura predstavlja izvedeni tip podatka koji sadrži promenljive istog ili
različitog tipa. Koristi se u slučajevima kada su podaci u međusobnoj vezi, jer se
mogu grupisati pod istim imenom.

Strukture omogućavaju kreiranje potpuno korisnički orjentisane tipove podataka.

Deklaracija šablona strukture:

struct ime_strukture {
niz_deklaracija
};

niz_deklaracija – nabrajaju se polja strukture, oblikom tip polje;


Tip polja strukture ne može da bude struktura koja se definiše, ali može da bude
pokazivač na strukturu.

Deklaracija strukturne promenljive:

struct ime_strukture ime_strukturne_promenljive;

Pristup članovima structure:


Pristup članovima strukture vrši se pomoću operatora člana strukture (.).

Primer 1:
Napisati C program koji omogućava formiranje strukture radnik sa poljima:

1) Prezime i ime od maksimalno 30 karaktera;


2) Koeficijen za dato radno mesto; i
3) Godine radnog staža.

Poznato je da je vrednost boda k dinara, a da se na svaku godinu radnoga staža


dohodak uvećava za 0.5%. Pripravnik je onaj radnik gde se za godine radnoga staža
unese broj 0 i ima 80% dohodak u odnosu na radnika sa obavljenim pripravničkim
stažom. Progam treba da ispiše koliki je dohodak radnika.

Rešenje

194
U zadatku je logično koristiti strukturu, jer kad kažemo radnik ne može se opisati
kao jedan osnovni podatak, jer se sastoji od više podataka koji ga opisuju: Prezime i ime
je string, datum rođenja je string, godina radnoga staža je celobrojan podatak, koeficijent
je racionalan podatak. Ne može se opisati ni nizom jer kod niza svi podaci moraju biti
istog tipa Radnik se ne može opisati sa jednim podatkom osnovnog tipa. Tip podatka je
izvedeni tip i nije niz već struktura.
Kako struktura predstavlja izvedeni tip podatka koga prevodilac ne poznaje, to se
iznad main funkcije ili u nekom hederu koji je povezan sa programom struktura mora
definisati. Prilikom definisanja strukture ne zauzima se nikakva memorija, već se
prevodilac upoznaje sa novim tipom podataka kako ga u programu ne bi tretirao kao
nedefinisani indentifikator. Tek nakon deklaracije strukturne promenljive u operativnoj
memoriji se odvaja prostor na osnovu imena izvedenog tipa strukture i njene definicije
koja je gore navedena. Strukturna promenljiva se sastoji od podataka različitog tipa.
Ti podacin predstavljaju polja ili članove strukture, a u nekim literaturama se sreće i
termin atributi strukture.

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include<ctype.h>

#define MAX 31

/*Definicija strukture radnik, kao novi tip podatka. Obavezno se uz radnik uvek ispred
mora pisati rezervisana rec struct kako bi prevodilac bio siguran da je to strukturni tip
podatka. */
struct radnik{
char prezime_i_ime[MAX];
double koeficijent;
int staz;
double dohodak;
};

void main(void)
{
struct radnik a; /* Deklarise se promenljiva a koja predstavlja slozeni tip podatka, ali ga
prevodilac tretira kao jedan podatak koji je smesten u promenljivoj a.
*/
unsigned xu, yu;
double k;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\t\tUNESITE PODATKE O RADNIKU:\n\n");

printf("\tIme i prezime: ");

195
gets(a.prezime_i_ime); /* Polju strukture se pristupa pomocu operatora tacka, stim sto je
od ranije poznato da se string unosi najcesce sa funkcijom
gets. */

printf("\tKoliki je koeficijenat: ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%lf",&a.koeficijent); /* Polju strukture se pristupa pomocu operatora
tacka. */
}while(a.koeficijent<=0);

printf("\tGodine radnoga staza = ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a.staz);
}while(a.staz<0);

printf("\n\n\tVrednost boda je: ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%lf",&k);
}while(k<1);

if(a.staz!=0)
{
a.dohodak=a.koeficijent*k;
a.dohodak+=0.5*a.staz*a.dohodak;
}else{
a.dohodak=a.koeficijent*k;
a.dohodak=0.8 * a.dohodak;
}

printf("\n\n\n\tRadnik %s ima dohodak %.2f dinara.",


a.prezime_i_ime, a.dohodak );

gotoxy(1,25);
getch();
}

196
Izvedeni tipovi podataka često imaju dugačka imena, što zahteva mnogo pisanja i
nepreglednost koda. Da bi se ovaj problem rešio koristi se rezervisana reč typedef.

Primenom na strukture to je:

typedef struct ime_strukture {


Niz_deklaracija
} ime_tipa;

Primenimo li to na ovaj primer rešenje programa imalo bi sledeći izgled:

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include<ctype.h>

#define MAX 31

typedef struct radnik{


char prezime_i_ime[MAX];
double koeficijent;
int staz;
double dohodak;
} Tradnik; /* Sada je Tradnik novi tip podatka (izvedeni tip podatka). */

void main(void)
{
Tradnik a; /* Deklarise se promenljiva a koja predstavlja slozeni tip podatka, ali ga
prevodilac tretira kao jedan podatak koji je smesten u promenljivoj a. */
unsigned xu, yu;
double k;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("\t\tUNESITE PODATKE O RADNIKU:\n\n");


printf("\tIme i prezime: ");
gets(a.prezime_i_ime); /* Polju strukture se pristupa pomocu operatora tacka, stim sto je
od ranije poznato da se string unosi najcesce sa funkcijom
gets. */
printf("\tKoliki je koeficijenat: ");
xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%lf",&a.koeficijent);
}while(a.koeficijent<=0);

197
printf("\tGodine radnoga staza = ");
xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&a.staz);
}while(a.staz<0);

printf("\n\n\tVrednost boda je: ");


xu=wherex(), yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%lf",&k);
}while(k<1);

if(a.staz!=0)
{
a.dohodak=a.koeficijent*k;
a.dohodak+=0.5*a.staz*a.dohodak;
}else{
a.dohodak=a.koeficijent*k;
a.dohodak=0.8 * a.dohodak;
}

printf("\n\n\n\tRadnik %s ima dohodak %.2f dinara.",


a.prezime_i_ime, a.dohodak );
gotoxy(1,25);
getch();
}

Primer 2:
Napisati C program koji utvrđuje i na ekranu iscrtava (korišćenjem teorije
bioritma), skale fizičkog, intelektualnog i emocionalnog stanja tog dana. Dan se utvrđuje
korišćenjem strukture struct date za očitavanje sistemskog datuma. Bioritam se utvrđuje
na osnovu datumac rođenja po sledećoj formuli:
2 
y  sin(  ( d mod x)) gde je mod operator ostataka celobrojnog deljenja
x
U formuli je d broj dana od rođenja, a x može imati tri vrednosti x   23,28,33
23 - fizičko stanje,
28 - emocionalno stanje, i
33 - umno stanje

Bioritam se na ekranu prikazuje pomoću tri skale (fizička. emocionalna i


intelektualna) pri čemu je svaka skala obeležena drugom bojom i numerisana u
procentima (-100% do *100%). Datum rođenja se unosi u obliku stringa pri čemu su dan
mesec i godina razdvojeni separatorima (tačka, zarez ili prazno mesto).

198
Rešenje

#include<stdio.h>
#include<conio.h>
#include <string.h>
#include <stdlib.h>
#include<dos.h>
#include<math.h>

#define PI 3.141592654
#define ESC 27

/* Funkcija utvrdjuje ispravnost unesenog datuma u obliku stringa. Ako je datum ispravan
funkcija vraca 0, a u suprotnom 1. */

int pitdat(char *s, int saddan, int sadmes, int sadgod, int *dan, int *mes, int *god);

void main(void)
{
struct date sad; /* Novi tip podatka je struct date koji je nalazi u biblioteci DOS.H i sadrzi tri
pola dan, mesec i godinu u datom trenutku. */
/* Da se ne bi ispitivalo koji je mesec, formiran je niz m koji sadrzi dane po mesecima. */
int m[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int god,mes,dan,sdan,saddan,sadmes,sadgod,i,j;
float in,fiz,emo;
unsigned xu,yu;
char s[30];

textmode(3);
do{
sdan=0; /* Broj dana od datuma rodjenja do danasnjeg dana. */
clrscr();
getdate(&sad); /* Funkcija getdate ucitava sistemski datum i smesta u strukturnu
promenljivu sad. */
textcolor(0);
textbackground(15);
clrscr();
printf(" \n");
for(i=0;i<26;i++) printf(" \n");
gotoxy(1,1);

saddan=sad.da_day; /* U saddan upisuje se sadasnji dan. */


sadmes=sad.da_mon; /* U sadmes upisuje se sadasnji mesec. */
sadgod=sad.da_year; /* U sadgod upisuje se sadasnja godina. */

/* Unosi se datum rodjenja u obliku stringa s. Postupak unosa se ponavlja ako je datum
neispravno unesen.*/

printf("Datum rodjenja: ");


xu=wherex(), yu=wherey();

199
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
gets(s);
}while(!pitdat(s,saddan,sadmes,sadgod,&dan,&mes,&god));

/* Kada se trazi ukupan broj dana od rodjenja do danas razlikuju se dva slucaja. Godina
rodjenja se poklapa sa trenutnom godinom, ili ako to nije slucaj. */

sdan=0;
if(god==sadgod)
{
/* Sabira se broj dana od meseca rodjenja do predhodnog meseca. */
for(i=mes;i<sadmes;i++) sdan+=m[i-1];

/*Dodaje se jos jedan dan ako je obuhvacen februar mesec a godina prestupna. */
if(mes<=2&&(god%4==0||god%400==0)) sdan++;

/* Oduyima se broj dana u mesecu do dana rodjenja. */


sdan=sdan-dan+1;

/* Sabira se danasnji broj proteklih dana u mesecu. */


sdan+=saddan;
}else{

/* Sabira se broj dana od meseca rodjenja do kraja godine. */


for(i=mes;i<=12;i++)sdan+=m[i-1];

/*Dodaje se jos jedan dan ako je obuhvacen februar mesec a godina prestupna. */
if(mes>=2&&(god%4==0||god%400==0)) sdan++;

sdan=sdan-dan+1; /* Oduzima se dan rodjenja. */

/* Sabiraju se dani u proteklim godinama do sadasnje godine. */


for(i=god+1;i<sadgod;i++)
{
if(i%4==0 || i%400==0) sdan+=366;
else sdan+=365;
}

/* Dodaju se dani od pocetka godine do danasnjeg meseca. */


for(i=0;i<sadmes-1;i++) sdan+=m[i];

/*Dodaje se jos jedan dan ako je obuhvacen februar mesec a godina prestupna. */
if(sadmes>2&&(sadgod%4==0||sadgod%400==0)) sdan++;

/* Sabira se danasnji broj proteklih dana u mesecu. */


sdan+=saddan;
}

200
gotoxy(4,22); printf("\n\tIma %d dana.",sdan);

in =sin((2*PI)/33*(sdan%33)); /* Utvrdjuje se intelektualno stanje. */


emo=sin((2*PI)/28*(sdan%28)); /* Utvrdjuje se emocionalno stanje. */
fiz=sin((2*PI)/23*(sdan%23)); /* Utvrdjuje se fizicko stanje. */
gotoxy(4,24);

/* Prikazuje se u procentima parametri stanja na ekranu. */


printf("Intelektualni: %.2f%c Emocionalni: %.2f%c Fizicki: %.2f%c",
in*100,'%',emo*100,'%',fiz*100,'%');

/* Ako je stanje negativno, sabiranjem sa 1 i mnozenjem sa duzinom skale 30 dobija se


broj na osnovu koga ce se ciklusom dobiti prikaz stanja na skali. */

j=(1+in)*30;
textbackground(1); /* Postavlja se boja skale. */
gotoxy(2,10);printf("Intelektualni:");
for(i=0;i<j;i++)cprintf(" "); /* Crta se skala. */

j=(1+emo)*30;
textbackground(15); gotoxy(16,11);
printf("| | |");
textbackground(2);
gotoxy(4,12);printf("Emocionalni:");
for(i=0;i<j;i++)cprintf(" ");

j=(1+fiz)*30;
textbackground(15); gotoxy(16,13);
printf("| | |");
textbackground(4);
gotoxy(8,14);printf("Fizicki:");
for(i=0;i<j;i++)cprintf(" ");

textbackground(15);
gotoxy(16,15);
printf("| | |");
gotoxy(14,16);
printf("-100% 0 100%");

gotoxy(1,25);
}while(getch()!=ESC);
}

/* Funkcija pitdat utvrdjuje da li je datum rodjenja unesen u string s ispravan. Ako je ispravan
funkcija vraca 0, a u suprotnom vraca 1. */

int pitdat(char *s, int saddan, int sadmes, int sadgod, int *dan, int *mes, int *god)
{
char *pok;

201
/* Izmedju dana, meseca i godine rodjenja mora se nalaziti separator (tacka, zarez ili
prazno mesto). Funkcijom strto izdvajaju se delovi stringa. */

pok=strtok(s,":,. "); *dan=atoi(pok);


pok=strtok(NULL,":,. "); *mes=atoi(pok);
pok=strtok(NULL,":,. "); *god=atoi(pok);

/* Godina rodjenja ne sme biti veca od sadasnje godine, ili ako je jednaka mesec rodjenja
ne sme biti veci od trenutnog meseca, ili ako se godine i meseci poklapaju, tada dan
rodjenja ne sme biti veci od sadasnjeg dana. */

if(*god>sadgod) return 1;
if(*god==sadgod && *mes>sadmes) return 1;
if(*god==sadgod && *mes==sadmes && *dan>saddan) return 1;

/* Sada se proverava ispravnost broja dana u mesecu u odnosu na mesec. */


if(*god>0 && *god<2999)
{
if (((*mes==1 || *mes==3 || *mes==5
|| *mes==7 || *mes==8 || *mes==10
|| *mes==12) && (*dan < 32)) ||
((*mes==4 || *mes==6 || *mes==9
|| *mes==11) && (*dan < 31)) ||
((*mes==2) && (*dan<30) && (!(*god%4) && (*god%100) ||
((*mes==2) && (*dan<29))))) return 1;
}
return 0;
}

Test primer programa:

202
6.2. INICIJALIZACIJA STRUKTURE
NIZ STRUKTURA

Inicijalizacijom strukture obezbeđuje da svi članovi strukture imaju


definisanu početnu vrednost. Za numeričke tipove podataka uobičajno je dodeliti
vrednost nula, dok je kod stringovnih promenljivih uobičajno je da se funkcijom strcpy
koja se nalazi u string.h stringovnoj promenljivi upiše prazan string. Prazan string sadrži
samo znak kraja stringa '\0'. Kada član niza predstavlja pokazivač moramo ga postaviti
na vrednost NULL.
Na primer za strukturu radnik sa prošlog časa inicijalizacija imala bi sledeći izgled.

/* Definicija strukture radnik. */


struct radnik{
char prezime_i_ime[MAX];
unsigned starost;
unsigned staz;
} Tradnik;

/* Deklaracija strukturne promenljive a i b tipa Tradnik. */


Tradnik a, b;

/* Inicijalizacija strukturne promenljive a. */


strcpy(a.prezime_i_ime, ""); /* "" je prazan string. */
a.starost = 0;
a.staz = 0;

/* Naredbu dodele mozemo koristiti izmedju struktura. */


b = a;

Prilikom naredbe dodele vrši se automatsko kopiranje odgovarajućih polja jedne


strukture u drugu. U ovom slučaju vrednosti polja strukture a su prekopirane u strukturu
b. Ovim se skraćuje kod programa i ne mora se koristiti funkcija strcpy da bi se polje
koje predstavlja string prekopirao iz polja strukture a u polje strukture b.

Strukturna promenljiva se može inicijalizovati i prilikom deklaracije.


Tradnik a = {"", 0, 0};

Kada je programu potrebno koristiti više struktura istog tipa, logično je da


se tada koristi niz, pri čemu svaki član niza predstavlja strukturni tip podatka.

Ako se u ovom primeru hoće koristiti više radnika tada koristimo niz struktura.
Niz struktura se definiše na isti način kao bilo koji niz Svaki član niza je tipa strukture, a
u ovom primeru je to Tradnik.

203
Tradnik x[50], a; /* Ovde je a jedna strukturna promenljiva, a x predstavlja niz
struktura. */
unsigned i;

Inicijalizacija niza struktura vrši se kao inicijalizacija bilo kog niza. Prvo inicijalizujemo
strukturnu promenljivu a.

strcpy(a.prezime_i_ime, ""); /* "" je prazan string. */


a.starost = 0;
a.staz = 0;

a potom niz struktura pomoću ciklusa tako što svaki element niza dobija vrednost a, koja
je predhodno inicijalizovana.

for(i=0;i<50;i++) x[i]=a;

Prilikom pristupa odgovarajućem polju i-tog člana niza strukture pišemo:


x[i].starost = 35;

Prvo se pše indeks niza, a potom operator tačka da se pristupa članu strukture.

Primer 1:
Napisati C program koji omogućava unos n učenika n<31 sa podacima: ime do 15
karaktera, prezime do 15 karaktera i broj izostanaka. Prikazati spisak pet ucenika sa
najvećim brojem izostanaka sortiranih u opadajućem redosledu po broju izostanaka. Ako
dva ili više učenika imaju isti broj izostanaka drugi kriterijum je po abecednom
redosledu.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>

#define MAX 30

/* Definicija sablona strukture. */


typedef struct ucenik{
char ime[16];
char prezime[16];
unsigned izostanci;
} Tucenik;

/* Prototipovi funkcija. */
void brisi(unsigned xu, unsigned yu);
void unesistring(char s[], unsigned k);

204
void main(void)
{
Tucenik niz[MAX], a = {"","",0}, pom;
unsigned i, j, k, xn, yn, xu, yu;
int n;

/* Inicijalizacija niza struktura. */


for(i=0;i<MAX;i++) niz[i]=a;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

printf("Broj ucenika: ");


xn=wherex(),yn=wherey();
do{
gotoxy(xn,yn);
printf(" ");
gotoxy(xn,yn);
scanf("%d",&n);
}while(n<=0||n>MAX);

printf("\n\nUnesite podatke o ucenicima:\n\n");


xu=wherex(),yu=wherey();
for(i=0;i<n;i++)
{
brisi(xu,yu);
gotoxy(xu,yu);
printf(" %d UCENIK\n",i+1);
printf("Ime: ");
unesistring(niz[i].ime,15);
printf("\nPrezime: ");
unesistring(niz[i].prezime,15);
printf("\nBroj izostanaka = ");
scanf("%u",&niz[i].izostanci);
}

/* Sortiranje niza strukture kako je definisano tekstom zadatka. */

for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(niz[j].izostanci>=niz[i].izostanci)
{
if(niz[j].izostanci>niz[i].izostanci)
{
pom=niz[j];
niz[j]=niz[i];
niz[i]=pom;

205
}else{

if(strcmp(niz[j].prezime,niz[i].prezime)<0)
{
pom=niz[j];
niz[j]=niz[i];
niz[i]=pom;
}else{
if((strcmp(niz[j].prezime,niz[i].prezime)==0)&&
(strcmp(niz[j].ime,niz[i].ime)<0))
{
pom=niz[j];
niz[j]=niz[i];
niz[i]=pom;
}
}
}
}
}
}

/* Tabelarni prikaz resenja zadatka. */


printf("\n\nPREZIME\t\t\tIME\t\tIZOSTANCI\n");
for(i=1;i<=50;i++) printf("-");
printf("\n");

if(n<5) k=n;
else k=5;

for(i=0;i<k;i++)printf("%-15s\t\t%-15s\t%u\n", niz[i].prezime,niz[i].ime,niz[i].izostanci);
getch();
}

/* Funkcija brise deo ekrana koji je koriscen prilikom predhodnog unosa podataka vezanih
za odredjenog ucenika, a time je obezbedio isti prostor za unos sledeceg ucenika. */

void brisi(unsigned xu, unsigned yu)


{
unsigned i,j;

gotoxy(xu,yu);
for(i=1;i<=25-yu;i++)
{
for(j=1;j<=80-xu;j++) printf(" ");
}
}

206
/* Funkcija omogucava unos stringa koji sadrzi k slova abecede. */
void unesistring(char s[], unsigned k)
{
unsigned i;
char c;

for(i=0;i<k&&c!=13;)
{
if(isalpha(c=getch())) printf("%c",c),s[i]=c,i++;
}
s[i]='\0';
}

Primer 2:
Napisati C program koji učitava tekstualnu datoteku UCENIK.TXT koja u prvom
redu sadrži centrirano ispisan naziv odeljenja, sledi prazan red, pa spisak učenika sa
podacima, pri čemu se u jednom redu nalaze podaci o jednom učeniku.

Podaci o učenika su:


- Ime;
- Prezime;
- Ime oca; i
- Ocene iz predmeta.

Podaci od jednog učenika su razdvojeni sa blanko mesto, a ocene su spojene.


Oene mogu imati vrednosti od 0 – 5, pri čemu ocena 0 označava da učenik iz tog
predmeta nije ocenjen. Program treba da na osnovu učitanih podataka učenika formira niz
struktura, pri čemu je svaka struktura opisana sa poljima: Ime, Prezime, Ime oca, srednja
ocena i uspeh (odličan, vrlo dobar, dobar, dovolja, nedovoljan i neocenjen).
Ako je neocenjen u polju srednja_ocena pise broj predmeta iz kojih nije ocenjen, a
ako je nedovoljan u polju srednja_ocena piše broj nedovoljnih ocena.
Na ekranu u prvoj liniji centrirani ispis ocene za odeljenje pa naziv odeljenja,
prazan red, pa tabelarni prikaz uspeha u obliku.

Prezime Srednje slovo imena oca Ime Uspeh Prosečna ocena

Ako je učenik nedovoljan u polju prosečna ocena pisaće broj nedovoljnih ocena, a
ako je neocenjen broj neocenjenih predmeta. U računanje prosečne ocene odeljenja ne
računaju se oni učenici koji su nedovoljni ili neocenjeni.

Rešenje

#include <conio.h>
#include <stdio.h>
#include <string.h>

#define MAX 32

207
/*Definisanje strukture Tucenik. */
typedef struct ucenik{
char ime[15];
char prezime[15];
char imeoca[15];
double sr;
char uspeh [11];
}Tucenik;

void main(void)
{
/* Deklaracija promenljivih. */
FILE *dat;
Tucenik niz[31],a={"","","",0,""};
int i,j,k,l,pit1=0,pit2=0;
double sr;
char s1[7],ss[81],ssc[81],*pom;

textmode(64);
textattr(10);
clrscr();

for(i=0;i<MAX;i++) niz[i]=a;

if((dat=fopen("UCENIK.TXT","r"))==NULL)
{
printf("Datoteka se ne moze otvoriti");
getch();
return;
}

i=0,k=0;
while((fgets(ss,80,dat))!=NULL)
{
if(i==0)
{
/* Ako je prvi red izdvojice se naziv odeljenja */
for(j=0,k=0;ss[j]!='\n'&&ss[j]!='\0';j++)
{
if(ss[j]!=' '&&ss[j]!='\t') s1[k]=ss[j],k++,s1[k+1]='\0';
}
}
else{
/* Izdvajamo podatke za jednog ucenika. */
strcpy(ssc,ss);
pom=strtok(ssc," ");
strcpy(niz[i-1].ime,pom);
pom=strtok(NULL," ");
strcpy(niz[i-1].prezime,pom);
pom=strtok(NULL," ");
strcpy(niz[i-1].imeoca,pom);

208
pom=strtok(NULL," ");

/* Posmatraju se ocene pri cemu ako je ucenik nedovoljan promenljiva


pit2 imace vrednost 1, a u slucaju da je neocenjen promenljiva pit1 imace
vrednost 1. */

for(sr=0,j=0,pit1=0,pit2=0,k=0,l=0;j<strlen(pom)-1;j++)
{
sr+=(pom[j]-'0');
if(pom[j]=='0') pit1=1,k++;
if(pom[j]=='1') pit2=1,l++;
}
sr=sr/j;
niz[i-1].sr=sr;

if(sr>=1.5) strcpy(niz[i-1].uspeh,"DOVOLJAN");
if(sr>=2.5) strcpy(niz[i-1].uspeh,"DOBAR");
if(sr>=3.5) strcpy(niz[i-1].uspeh,"VRLO DOBAR");
if(sr>=4.5) strcpy(niz[i-1].uspeh,"ODLICAN");

/* Ako je ucenik zavrsio sa nedovoljnim umesto srednje ocene pisace


broj nedovoljnih ocenena. */

if(pit2==1)
{
strcpy(niz[i-1].uspeh,"NEDOVOLJAN");
niz[i-1].sr=l;
}

/* Ako je ucenik iz nekih predmeta neocenjen umesto srednje ocene


pisace broj predmeta iz kojih je neocenjen. */

if(pit1==1)
{
strcpy(niz[i-1].uspeh,"NEOCENJEN");
niz[i-1].sr=k;
}
}
i++;
}

/* Racuna se prosek odeljenja u koji se na racunaju proseci ucenika koji su nedovoljni ili
neocenjeni. */

i--,sr=0,k=0;
for(j=0;j<i;j++)
{
if(strcmp(niz[j].uspeh,"NEDOVOLJAN")!=0&&
strcmp(niz[j].uspeh,"NEOCENJEN")!=0) sr+=niz[j].sr,k++;
}
sr=sr/k;

209
/* Tabelarni prikaz ucenika sa ostvarenim uspehom. */
clrscr();
printf(" %s %.2lf\n\n",s1,sr);
printf("┌────────┬───────────┬────────────");
printf("─┬─────────────┬──────────────────┐\n");
printf("│ Prezime │ Sr. ime │ Ime │ Uspeh │ Prosecna ocena │\n");
printf("├────────────────┼───────────┼─────────");
printf("────┼─────────────┼──────────────────┤\n");

for(j=0;j<i;j++)
{
gotoxy(1,6+j), printf("│ %s",niz[j].prezime);
gotoxy(18,6+j), printf("│ %c",niz[j].imeoca[0]);
gotoxy(30,6+j), printf("│ %s",niz[j].ime);
gotoxy(44,6+j), printf("│ %s",niz[j].uspeh);
if(strcmp(niz[j].uspeh,"NEDOVOLJAN")!=0&&
strcmp(niz[j].uspeh,"NEOCENJEN")!=0)
gotoxy(58,6+j), printf("│ %.2lf",niz[j].sr);
else gotoxy(58,6+j),printf("│ %.0lf %sA",niz[j].sr,niz[j].uspeh);
gotoxy(77,6+j), printf("│\n");
}
printf("└────────────────┴───────────┴─────────");
printf("────┴─────────────┴──────────────────┘");
getch();
}

Test primer programa:


PRIMER.TXT
R31
Slobodan Prljevic Zdravko 54453554545545
Marko Novakovic Djura 221421232122
Darko Pejakovic Ranko 425554332344
Marijan Beg Andrija 555555555555
Andrea Pavlovic Zoran 243125121332

Izgled programa nakon startovanja::

210
6.3. STRUKTURE I FUNKCIJE

Osobine struktura su:


 Strukture su tipovi koje definiše programer.
 Podaci strukturnih tipova se smatraju pojedinačnim podacima, bez obzira
na njihovu složenost. To u stvari znači da se na određenim mestima
koriste kao prosti podaci.
 Podaci međusobno jednakih strukturnih tipova mogu međusobno da se
dodeljuju pomoću operatora za dodelu vrednosti. Time se celokupni
sadržaj izvorišnog podatka prekopira u odredišnu strukturnu
promenljivu polje po polje, ne smeta da se među poljima nalaze i nizovi
ili stringovi.
 Adresa strukturne promenljive može da se dobije adresnim operatorom &,
ali isto tako mogu da se deklarišu i promenljive koje su pokazivači na
strukture. Pristup poljima strukture preko pokazivačke promenljive
vrši se operatorom diferenciranja *.

Primer 1:
Definiši nov tip podatka Tucenik, sa poljima prezime (od maksimalno 30
karaktera) i brizostanaka. Potom deklariši promenljive a i b tipa Tucenik, kao i
pokazivač pok koji može da pokazuje na promenljive tipa Tucenik.

Rešenje:

typedef struct ucenik{


char ime_prezime[31];
unsigned brizostanaka;
} Tucenik;

Tucenik a, b, *pok=NULL;

a i b su strukturne promenljive, dok je pok pokazivač koji može da pokazuje samo


na strukturne promenljive tipa Tucenik. Pokazivačka promenljiva pok dobija vrednost
NULL koja znači da pokazivačka promenljiva trenutno ne pokazuje ni na jednu
strukturnu promenljivu tipa Tucenik.

pok=&a;

Inicijalizacija strukture se može izvršiti i pomoću pokazivake promenljive pok jer


ona sada sadrži adresu strukturne promenljive a.

strcpy((*pok).ime_prezime,"");
pok->brizostanaka=0;

211
Strukture i funkcije:
 Prosleđivanje člana strukture kao argumenta funkcije.
 Prosleđivanje strukture kao argumenta funkcije, i
 Prosleđivanje pokazivača na strukturu kao argumenta funkcije.

Prilikom prosleđivanja strukture kao argumenta funkcije, bez obzira na složenost,


smatra se jednim podatkom. Podrazumevani način prenošenja strukture u funkciju je
pomoću vrednosti. Na ovaj način se i niz smešta na stek. Iz istih razloga strukture moga
da budu i vrednosti funkcije. Pošto niz ne može da bude vrednost funkcije, ako je to baš
potrebno, može da se definiše struktura čije je jedino polje niz i da se definiše strktura
koja vraća upravo podatak tipa te strukture.
Pošto strukture mogu da budu jako velike preporučuje se da se one u funkciju
prosledđuju po referenci. Takođe radi efikasnosti preporučuje se da se za vrednost
funkcije umesto strukture koristi pokazivač na strukturu.

Primer 2:
Napisati C program koji primenom struktura omogućava unos dva datuma rođenja,
osobe A i osobe B. Struktura datuma je opisana sa godinom, mesecem i danom rođenja.
Program utvrđuje koja osoba je starija i za koliko dana.
Prilikom unosa osobe koristiti funkciju unos koja na osnovu oznake osobe (A ili B)
omogucava unos podataka o toj osobi i vraca istrukturu koja opisuje datu osobu.
Prilikom utvrdjivanja koja je osoba starija i za koliko dana koristiti funkciju razlika
koja vraca karakter (A ili B) koji opisuje koja je osoba starija, a prenosom po referenci i
podatak za koliko dana.

Rešenje

#include <stdio.h>
#include <conio.h>

/* Definicija sablona strukture. */


typedef struct datum{
unsigned godina;
unsigned mesec;
unsigned dan;
} Tdatum;

/* Prototipovi funkcija. */
Tdatum unos(char *s);
char razlika(Tdatum a, Tdatum b, int *raz);
unsigned zbir(Tdatum *x);

void main(void)
{
/* Deklaracija dve strukturne promenljive. Prva se odnosi na osobu A, a
druga na osobu B. */
Tdatum a,b;
int raz=0,star=0;

212
textmode(3);
textcolor(15);
textbackground(0);
clrscr();

a=unos("A"); /* Funkciji unos pomocu stringa prosledjuje se koja je osoba (A ili B). */
b=unos("B");

/* Funkcija razlika utvrdjuje razliku izmedju dva datuma i vraca karakter 'A' ako je osoba
A starija od osobe B, 'B' ako je osoba B starija od osobe A, ili '\0' ako su rodjene istog
datuma. */

star=razlika(a,b,&raz);
switch(star)
{
case 'A': printf("\n\n\tOsoba A je starija od osobe B za %d dana.",raz);
break;
case 'B': printf("\n\n\tOsoba B je starija od osobe A za %d dana.",raz);
break;
default: printf("Osobe A i B su rodjene istog dana.");
}

gotoxy(1,25);
getch();
}

/* Funkcija omogucava unos datuma rodjenja odredjene osobe A ili B, stim da se u stringu s
nalazi slovo A ili B. Funkcija vraca podatak tipa strukture. */
Tdatum unos(char *s)
{
Tdatum x;
unsigned xu,yu,k;
int pom;

printf("\n\n\tUnesite datum rodjenja osobe %s:\n",s);


printf("\tGodina: ");
xu=wherex(),yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&pom);
}while(pom<=1900||pom>2020);
x.godina=pom;

printf("\tMesec: ");
xu=wherex(),yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);

213
scanf("%d",&pom);
}while(pom<=0||pom>12);
x.mesec=pom;

printf("\tDan: ");
xu=wherex(),yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&pom); /* Kod funkcije scanf kao i za promenljive osnovnog tipa
mora se postavljati adresni operator .*/
switch(x.mesec)
{
case 1: case 3: case 5: case 7: case 8: case 12: case 10:
if(pom<=0 || pom>31) k=0;
else k=1;

break;
case 2: if(x.mesec % 4 == 0 || x.mesec % 400 == 0)
if(pom<=0 || pom>29) k=0;
else k=1;
else if(pom<=0 || pom>28) k=0;
else k=1;
break;
case 4: case 6: case 9: case 11: if(pom<=0 || pom>30) k=0;
else k=1;
}

}while(k==0);
x.dan=pom; /* Polju strukture pristupa se operatorom tacka. */

return x; /* Funkcija vraca kao vrednost promenljivu strukturnog tipa. */


}

/* Funkciju razlika koja vraca karakter (A ili B) koji opisuje koja je osoba starija, a
prenosom po referenci i podatak za koliko dana je starija. */
char razlika(Tdatum a, Tdatum b, int *raz)
{
unsigned s1, s2;

/* Izracunavamo ukupan broj dana osobe A od racunanja kalendara pa do rodjenja osobe A.


Priliko pozivanja funkcije gde se argumenti prosledjuju po referenci (prosledjuje se adresa
pokazivackoj promenljivi). */

s1=zbir(&a);

/* Izracunavamo ukupan broj dana osobe 'B' od racunanja kalendara pa do rodjenja osobe
'B'. */
s2=zbir(&b);

214
if(s1<s2)
{
*raz=s2-s1;
return 'A';
}
if(s2<s1)
{
*raz=s1-s2;
return 'B';
}
return '0';
}

/* Funkcija izracunavamo ukupan broj dana osobe od racunanja kalendara pa do njenog


rodjenja. */
unsigned zbir(Tdatum *x)
{
int i;
long int k=0;

/* U zagradi se naglasava da prvo diferenciranjem moramo doci do adrese strukturne


promenljive, pa tek onda operatorom tacka pristupiti odgovarajucem polju strukturne
promenljive. Prevoduilac ce prijaviti gresku jer su oba operatora istog prioriteta. */

for(i=1;i<=(*x).godina-1;i++)
{
if(i%4 == 0 || i%400==0) k+=366;
else k+=365;
}

for(i=1;i<=(*x).mesec-1;i++)
{
switch(i)
{
case 1: case 3: case 5: case 7: case 8: case 12: case 10: k+=31;
break;
case 2: if(i%4 == 0 || i%400==0) k+=29;
else k+=28;
break;
case 4: case 6: case 9: case 11: k+=30;
}
}

k+=x->dan; /* U primeru je umesto (*x).dan ekvivalentno sa x->dan, cime se skracuje


zapis. */

return k;
}

Primer 3:

215
Napisati C program koji korišćenjem funkcije unos omogućava unos napona i struje
na jednom potrošaču u kompleksnom obliku. Prototip funkcije unos je:

Tkomp unos(char c),

Karakter c može imati vrednosti 'U' ili 'I'. Ako ima vrednost 'U' unosiće se napon u
kompleksnom obliku, a ako ima vrednost 'I' unosiće se struja u kompleksnom obliku.
Funkcija vraća strukturu tipa Tkomp koja se sastoji od realnog i imaginarnog dela
kompleksnog broja.
Korišćenjem funkcije potrosac utvrđuje se prenosom po referenci impendasa
potrošača i prividna snaga u kompleksnom obliku tipa Tkomp.

Funkcija vraća:
1 - ako je potrošač induktivnog karaktera;
-1 – ako je potrošač kapacitivnog karaktera; ili
0 – ako potrošač nije induktivnog ni kapacitivnog karaktera.

Program ispisuje impedansu u kompleksnom obliku i prividnu snagu u


kompleksnom obliku, kao i tip potrošača: AKTIVAN, .INDUKTIVAN ili
KAPACITIVAN.

Rešenje

#include <stdio.h>
#include <conio.h>

/* Definise se struktura kompleksnog broja u algebarskom obliku. */


typedef struct komp{
float real;
float imag;
}Tkomp;

/* Prototipovi funkcija. */
Tkomp unos(char c);
int potrosac(Tkomp u, Tkomp i, Tkomp *z, Tkomp *S);

void main(void)
{
/* Deklarisu se promenljive za napon u, struju i, impedansu z i prividnu snagu S, koje se
predstavljaju u kompleksnom obliku te im je tip struktura kompleksnog broja Tkomp. */

Tkomp u, i, z, S;
int k;

textmode(3);
textbackground(15);
textcolor(0);
clrscr();

216
/* Unosi se napon u u kompleksnom obliku, a prosledjuje se karakter 'U' koji oznacava da
se unosi napon. */
printf("Unesite napon u kompleksnom obliku:\n");
u=unos('U');

/* Unosi se struja i u kompleksnom obliku, a prosledjuje se karakter 'I' koji oznacava da


se unosi struja. */
printf("\nUnesite struju u kompleksnom obliku:\n");
i=unos('I');

/* Poziva se funkcija potrosac koja po referenci izracunava impedansu, i prividnu snagu


potrosaca, a vraca broj koji nam simbolicno govori o tipu potrosaca. */
k=potrosac(u,i,&z,&S);

switch(k)
{
case 1: printf("\n\nPotrosac je induktivnog karaktera!!");
break;
case -1: printf("\n\nPotrosac je kapacitivnog karaktera!!");
break;
default: printf("\n\nPotrosac je cisto aktivan!!");
}

/* Prikazujemo impedansu u kompleksnom obliku. */


if(z.imag==0) printf("\n\nZ = %f",z.real);
else{
if(z.imag>0) printf("\n\nZ = %f + %fj",z.real,z.imag);
else printf("\n\nZ = %f - %fj",z.real,-(z.imag));
}

/* Prikazujemo prividnu snagu u kompleksnom obliku. */


if(S.imag==0) printf("\n\nS = %f",S.real);
else{
if(S.imag>0) printf("\n\nS = %f + %fj",S.real,S.imag);
else printf("\n\nS = %f - %fj",S.real,-(S.imag));
}

gotoxy(1,25);
getch();
}

/* Funkcija unos na osnovu karaktera c unosi i formira strukturu oblika kompleksnog broja
koja predstavlja napon ili struju. */

Tkomp unos(char c)
{
Tkomp pom;

if(c=='U')
{
printf("Re(U) = ");

217
scanf("%f",&pom.real);
printf("Im(U) = ");
scanf("%f",&pom.imag);
}else{
printf("Re(I) = ");
scanf("%f",&pom.real);
printf("Im(I) = ");
scanf("%f",&pom.imag);
}

/* Funkcija vraca uneseni podatak (napon ili struja) tipa Tkomp. */


return pom;
}

/* Funkcija potrosac prenosom po referenci izracunava impedansu, i prividnu snagu


potrosaca, a vraca broj koji nam simbolicno govori o tipu potrosaca. */

int potrosac(Tkomp u, Tkomp i, Tkomp *z, Tkomp *S)


{
/* Na osnovu izvedene formule za deljenje dva komplerksna broja, nastaju formule kojim
se izracunavaju realni imaginarni deo rezultujuceg kompleksnog broja. Derljenje se vrsi
jer je impedansa jednaka količniku napona i struje u kompleksnom obliku. */

(*z).real=(u.real*i.real+u.imag*i.imag)/(i.real*i.real+i.imag*i.imag);
(*z).imag=(u.imag*i.real-u.real*i.imag)/(i.real*i.real+i.imag*i.imag);

/* Prividna snaga se racuna kao kolicnik napona i konjugovane struje. Konjugovana


struja dobija se tako sto se promeni predznak kod imaginarnog dela. Izracunavanjem
proizvoda dva kompleksna broja dobicete formulu ciji realni i imaginarni deo moze da se
opise formulama. */

(*S).real= u.real*i.real+u.imag*i.imag;
(*S).imag= u.imag*i.real-u.real*i.imag;

/* Sada se na osnovu imaginarnog dela impedanse utvrdjuje tip potrosaca. Ako je njegova
vrednost pozitivna potrosac je induktivnog karaktera, ako je negativna potrosac je
kapacitivnog karaktera, a ako je jednaka nuli radi se o cisto aktivnom potrosacu. */

if((*z).imag<0) return -1;


else{
if((*z).imag>0) return 1;
else return 0;
}
}

218
6.4. RAD SA BINARNIM DATOTEKAMA

Prilikom podele datoteka u programskom jeziku C izvršena je podela na


tekstualne i binarne datoteke. Binarne datoteke najčešće imaju ekstenziju DAT. Binarna
datoteka se otvara funkcijom fopen, pri čemu se mod rb koristi za čitanje binarne
datoteke, a wb za upis u binarnu datoteku.

Na primer:
FILE *dat;
dat=fopen("PRIMER.DAT","rb");

Prilikom rada sa binarnim datotekama koriste se dve funkcije: fread (za učitavanje
podataka) i fwrite (za upis podataka) u binarnu datoteku.

Učitavanje podataka iz datoteke:

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

Funkcija fread čita iz datoteke na koju pokazuje pokazivač dat najviše br


podataka veličine vel bajtova i smešta u memoriju počev od pozicije niz.
Čitanje podataka počinje od pozicije gde je prethodni pristup datoteci završen.
Nakon završetka čitanja pozicionira se nakon poslednjeg pročitanog bajta.
Prilikom čitanja podataka mora se voditi računa o logičkoj strukturi datoteke, jer
će se u suprotnom čitati pogrešni podaci. Dužnost programera je da o tome vodi računa.
Vrednost funkcije je uspešan broj učitanih podataka.
Najčešće se prilikom učitavanja vrši učitavanje jednog podatka (podatak po
podatak). Podatak je uopšteno tipa strukture.

Upis podataka u datoteku:

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

Funkcija fwrite upisuje u datoteku na koju pokazuje pokazivač dat br podataka


veličine vel bajtova iz memorije počev od adrese niz.
Pisanje podataka u datoteci počinje gde je prethodni pristup datoteci završen.
Ako trenutna pozicija nije na kraju datoteke podaci se upisuju preko postojećih
podataka. Po završetku pisanja nastavlja se posle poslednjeg upisanog bajta.
Funkcija vraća broj prenetih podataka.

Primer 1:
Zadata je binarna datoteka SMENE.DAT. Datoteka se sastoji od binarnih reči, koje
predstavljajju podatke o jednodnevnom učinku smene..
Napisati C program koji na osnovu binarne datoteke o jednodnevnom učinku smene
daje po izboru korisnika: tabelarni prikaz učinka odgovarajuće smene i tabelarni

219
uporednidni prikaz učinka sih smena. U toku jednog dana rade četiri smene (1...4 smene),
tokom svake smene se broje proizvodi (do 50 000 komada). na 64 merna mesta.
Podaci su smešteni u 24 bitnu reč oblika:

0 - 15 bita - broj proizvoda


16 - 21 bita - broj mernog mesta
22 - 23 bita - broj smene

Binarna datoteka se sastoji od više podataka (za svaku smenu i merno mesto jedan
podatak, tj binarna reč), pri čemu je svaki podatak smešten u 24-bitnu reč.

Rešenje

#include <stdio.h>
#include <conio.h>

/* Definisanje novog tipa podatka Tmatrica. */


typedef unsigned TMatrica[4][64];

/* Prototipovi funkcija. */
void UcinakSmene(TMatrica JednUcinak);
void UporednaLista(TMatrica JednUcinak);
char OsnMeni();
char UcitajPodatke(TMatrica JednUcinak);
void Inicijalizacija(TMatrica JednUcinak);

void main (void)


{
char kraj=0;
TMatrica JednUcinak;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

/* Inicijalizacija matrice. */
Inicijalizacija(JednUcinak);

/* Ucitavanje podataka iz binarne datoteke u matricu. */


if(UcitajPodatke(JednUcinak))
{
do{
/* Izbor jedne od tri ponudjene opcije. */
switch(OsnMeni())
{
/* Ispisuje se ucinak jedne smene. */
case '1': UcinakSmene(JednUcinak);
break;

220
/* Prikazuje se uporedni prikaz smena. */
case '2': UporednaLista(JednUcinak);
break;
/* Izlazak iz programa. */
case '3': kraj=1;
}
} while (!kraj);
}
}

/* Funkcija inicijalizacija vrsi inicijalizaciju matrice. */


void Inicijalizacija(TMatrica JednUcinak)
{
unsigned i,j;

for (i=0;i<4;i++)
{
for (j=0;j<5;j++) JednUcinak[i][j]=0;
}
}

/* Funkcija UcitajPodatke ucitava podatke iz binarne datoteke i smesta ih u matricu. */


char UcitajPodatke(TMatrica JednUcinak)
{
/* Kako ce se u programu vrsiti shiftovanje na nivou bitova to se mora promenljiva temp,
gde se podaci smestaju iz datoteke i koja ce se shiftovati, deklarisati kao nenegativan
podatak, tj podatak tipa unsigned. */

unsigned i,j,BrKomada;
FILE *dat;
unsigned long temp;

/* Ucitavanje datoteke SMENE.DAT. */


if ((dat=fopen("SMENE.DAT","rb"))==NULL)
{
printf("\n\n NE POSTOJI DATOTEKA `SMENE.DAT`");
printf("\n\n Pritisnite bilo koji taster za izlazak iz programa..");
getch();
return 0;

}else{

/* Ucitavamo funkcijom fread jer je datoteka binarna, jednu po jednu rec, a kako
je rec duzine 24 bita = 3 bajta, ucitavamo stalno po 3 bajta iz datoteke. */

while(fread(&temp,3,1,dat))
{
/* Matrica se formira tako sto indekis i matrice pretstavlja broj smene,
indeks j pretstavlja broj mernog mesta, a vrednost matrice na poziciji i,j
pretstavlja broj proizvoda koje je i-ta smena napravila na j-tom mernom
mestu. */

221
i=(temp>>22) & 0x3 ;
j=(temp>>16) & 0x3f;
BrKomada=(temp & 0xffff);
JednUcinak[i][j]+=BrKomada;
}
fclose(dat);
return 1;
}
}

/* Funkcija OsnMeni iscrtava meni koji prikazuje ponudjene opcije I izbor jedne od ponudjenih
opcija. */
char OsnMeni(void)
{
char odg,i;

clrscr();
printf("\n\nProgram za ispisivanje ucinka fabrike.");
printf("\n\nIzaberite opciju prema njenom rednom broju.");
printf("\n---------------------------------------------");
printf("\n 1. Lista ucinka odredjene smene.");
printf("\n 2. Uporedna lista za sve smene.");
printf("\n 3. Kraj rada.");
printf("\n---------------------------------------------");
printf("\nVas izbor je (1-3) --> ");

i = wherex(); /* Kolona gde je kursor. */


do{
odg = getche();
/* Vraca kod tastera sa ehom, getch() bez eha. */
if (odg == '\r') /*Ako je odmah pritisnut Enter*/
{
gotoxy(i,wherey()); /*Vrati se gde si bio*/
printf("\a");
}else if (odg < '1' || odg > '5') printf("\b \b\a");
}while (odg < '1' || odg > '3');

return(odg);
}

/* Funkcija UcinakSmene omogucava da se vidi tabelarni prikaz ucinka jedne smene. */


void UcinakSmene(TMatrica JednUcinak)
{
unsigned short smena,j,i;
unsigned long suma=0;
char odg;

do{
/* Korisnik unosi broj smene za koju hoce da vidi tabelarni prikaz. */
clrscr();

222
do{
printf("Unesite smenu za koju zelite da vidite ucinak (1..4): ");
scanf("%i",&smena);
if((smena<1)||(smena>4))
printf("Uneli ste nepostojecu smenu!");
} while((smena<1)||(smena>4));

/* Tabelarni prikaz izabrane smene. */


clrscr();
printf(" Ucinak %i. smene",smena);
printf("\n-------------------------------------------------------");
for (j=0;j<5;j++)
{
printf("\n Merno mesto:%u Broj proizvoda: %u",
j+1,JednUcinak[smena-1][j]);
suma+=JednUcinak[smena-1][j];
}

printf("\n---------------------------------------------");
printf("\nUkupan broj proizvoda smene je: %lu\n\n\n",suma);
printf("\n---------------------------------------------");
printf("\nZelite li da pogledate jos neku smenu (D/N)?");

/* Omogucava se korisniku da ako hoce moze pogledati i ucinak neke druge ili
ponovno iste te smene. */

i = wherex();
do{
odg = getche();
if (odg!='D'&&odg!='d'&&odg!='N'&&odg!='n')
{
if (odg == '\r') gotoxy(i,wherey());
else printf("\b \b");
printf("\a");
}
}while(odg!='D'&&odg!='d'&&odg!='N'&&odg!='n');
} while (odg == 'D' || odg == 'd');
}

/* Uporedna lista ucinka sve cetiri smene. */


void UporednaLista(TMatrica JednUcinak)
{
unsigned long suma=0,sumasmena1=0,sumasmena2=0,
unsigned long sumasmena3=0,sumasmena4=0;
int j;

clrscr();
printf("Br. mer. I smena II smena III smena IV smena Ukupno za");
printf("\nmesta mer. mesto\n");
printf("--------------------------------------------------------------------");

223
for (j=0;j<5;j++)
{
sumasmena1+=JednUcinak[0][j];
sumasmena2+=JednUcinak[1][j];
sumasmena3+=JednUcinak[2][j];
sumasmena4+=JednUcinak[3][j];
suma=JednUcinak[0][j]+JednUcinak[1][j]+JednUcinak[2][j]+
JednUcinak[3][j];
printf("\n%-10u%-12u%-12u%-13u%-12u%-9lu",j+1, JednUcinak[0]
[j],JednUcinak[1][j],JednUcinak[2][j],
JednUcinak[3][j],suma);
}
printf("\n--------------------------------------------------------------------");

suma=sumasmena1+sumasmena2+sumasmena3+sumasmena4;
printf("\nUKUPNO %-12lu%-12lu%-13lu%-12lu%-9lu",
sumasmena1,sumasmena2,sumasmena3,sumasmena4,suma);
printf("\n\n Pritisnite bilo koji taster za nastavak programa..");
getch();
}

Test primer programa:

Binarnu datoteku jako je teško formirati u editoru teksta, već je to potrebno rešiti
programski. Iz tog razloga napisaćemo mali program koji omogućava formiranje binarne
datoteke SMENE.DAT koja će vam poslužiti za testiranje.

Primer 2:
Napisati C program koji omogućava formiranje datoteke SMENE.DAT koja će
nam poslužiti za testiranje prethodnog zadatka.

Rešenje

# include <stdio.h>
# include <conio.h>

#define MAX 20

224
void main (void)
{
FILE *dat;
long broj;
char pom;

/* Formira se niz gde ce svaki clan niza imati vrednost 0 ili 1. */


unsigned x[24];
long p,i,j,k;

/* Otvara se binarna datoteka za upis podataka. */


clrscr();
dat=fopen("SMENE.DAT","wb");

/* Unecemo MAX reci, pri cemu svaka rec je 24-bitna. */


printf("UNESITE %d BROJEVA U BINARNOM OBLIKU (24 BITA):\n\n",MAX);

for (i=0;i<MAX;i++)
{
printf("Unesite %d. broj ",i+1);
if(i<9) printf(" ");
for(j=0;j<24;j++)
{
do{
pom=getch();
}while(pom!='0'&&pom!='1');
printf("%c",pom);
x[j]=pom-48;
}

/* Pretvaramo iz binarnog u broj, a prilikom upisa on ce automatski biti upisan u


binarnom obliku. */

p=1,broj=0;
for (k=0;k<24;k++)
{
broj=broj+x[23-k]*p;
p=p*2;
}

/* Upisujemo rec u binarnu datoteku. */


fwrite(&broj,3,1,dat);

printf("\n");
}

fclose(dat);
}

225
6.5. FORMIRANJE HEDERA ZA RAD SA MIŠEM

Kreiraćemo heder sa imenom MIS.H kojeg ćemo koristiti kad god nam je u
programu potrebno koristiti miša. Nije potrebno znati kako funkcije rade ako hoćete
koristiti miša. Potrebno je samo znati šta radi koja funkcija i poznavati dobro strukturu
miša, tj tip podatka Tmiss koja je definisana u hederu MIS.H.

MIS.H

/* U hederu dos.h nalazi se struktura REGS I funkcija int86. */


#include <dos.h>
#include <stdio.h>
#include <conio.h>

/* Interapt 33H omogucava kacenje drajvera misa. Interapti se pisu u heksadecimalnom obliku*/

const MOUSE_INTR = 0x33;

/* Prototipovi funkcija. */
void mis(void);
int da_levod(void);
int da_desnod(void);
int citaj(void);
void kursor_uklj(void);
void kursor_isklj(void);
int reset(void);

/* Definicija strukture misa. */


struct Miss {
int instaliran; /* Indikator da li je mis instaliran. */
int x; /* Trenutna x koordinata kursora misa. */
int y; /* Trenutna y koordinata kursora misa. */
int starax; /* Pamti se predhodna x koordinata kursora misa. */
int staray; /* Pamti se trenutna y koordinata kursora misa. */
int vidljiv; /* Indikator da li se kursor misa vidi na ekranu. */
int levod; /* Indikator da li je pritisnut levi taster misa. */
int desnod; /* Indikator da li je pritisnut desni taster misa. */
} TMiss;

/* Funkcija mis omogucava da se instalira mis i podese pocetne vrednosti. */


void mis(void)
{
/* Ako promenljiva instaliran dobije vrednost 0 znak je da mis nije instaliran. */

TMiss.instaliran = reset();
TMiss.x = TMiss.y = TMiss.starax = TMiss.staray = -1;
TMiss.vidljiv = 0;
kursor_uklj();
}

226
/* Funkcija da_levo utvrdjuje da li je pritisnut levi taster misa. */
int da_levod(void)
{
union REGS r;

if(!TMiss.instaliran) return 1;

/* U akumulator se upisuje vrednost 3 i poziva se interapt 33h preko funkcije int68. */

r.x.ax = 3;
int86(MOUSE_INTR,&r,&r);

/* U registru BX zapisan je status tastera. Ako je njegova vrednost jednaka 1 znači da je


pritisnut levi taster misa. */

return r.x.bx & 1 ? 1 : 0;


}

/* Funkcija da_desno utvrdjuje da li je pritisnut desni taster misa. */


int da_desnod(void)
{
union REGS r;

if(!TMiss.instaliran) return 0;
r.x.ax = 3;
int86(MOUSE_INTR,&r,&r);

/* U registru BX zapisan je status tastera. Ako je njegova vrednost jednaka 2 znači da je


pritisnut desni taster misa. */

return r.x.bx & 2 ? 1 : 0;


}

/* Funkcija citaj vraca vrednost nula ako mis nije instaliran ili ako nije pritisnut niti jedan taster
misa a niti je mis pomeren na drugu poziciju. U suprotnom vraca vrednost jedan.*/

int citaj(void)
{
union REGS r;

if(!TMiss.instaliran) return 0;
r.x.ax = 3;
int86(MOUSE_INTR,&r,&r);

/* U startx i starty sacuvaju se predhodne pozicije misa. */


TMiss.starax = TMiss.x;
TMiss.staray = TMiss.y;

/* Koordinate misa se uvek zadaju kao da se radi o grafičkom režimu. Iz tih razloga vrši se
deljenje koordinata sa 8 kako bi se izvršilo pretvaranje u tekstualni režim. */

227
TMiss.x = r.x.cx/8+1;
TMiss.y = r.x.dx/8+1;
if(TMiss.levod == r.x.bx & 1 && TMiss.desnod == r.x.bx & 2 &&
TMiss.starax == TMiss.x && TMiss.staray == TMiss.y) return 0;
TMiss.levod = r.x.bx & 1 ? 1 : 0;
TMiss.desnod = r.x.bx & 2 ? 1 : 0;

return 1;
}

/* Poziv funkcije za prikazivanje kursora misa. */


void kursor_uklj(void)
{
union REGS r;

if(TMiss.vidljiv) return;

/* Mis se prikazuje tako što se u akumulatoru upiše vrednost 1 i pozove interapt 33h. */
r.x.ax = 1;
int86(MOUSE_INTR,&r,&r);

/* Promenljiva vidljiv ima vrednost 1 ako je mis vidljiv na ekranu, a 0 u suprotnom. */


TMiss.vidljiv = 1;
}

/* Funkcija onemogucava prikazivanje kursora misa. */


void kursor_isklj(void)
{
union REGS r;

if(!TMiss.vidljiv) return;

/* Mis se ne prikaziuje ako se u akumulator upiše vrednost 2 i pozove interapt 33h. */


r.x.ax = 2;
int86(MOUSE_INTR,&r,&r);

TMiss.vidljiv = 0;
}

/* Funkcija reset omogucava resetovanje misa. */


int reset(void)
{
union REGS r;
r.x.ax = 0;
int86(MOUSE_INTR,&r,&r);

return r.x.ax ? 1 : 0;
}

228
Primer:
Napisati C program koji omogućava demonstraciju rukovanja sa mišem u
programima pod DOS-om. Nakon pritiskanja levog tastera miša na tekućoj poziciji se
upisuje na ekranu vrednost 1, a ako se pritisne desni taster na ekranu se prikazuje broj 2.
Prilikom realizacije programa obavezno koristiti heder MIS:H. Iz programa se izlazi ako
se pritisne neki taster sa tastature.

Rešenje

#include <stdio.h>
#include <conio.h>
#include "mis.h"

void main(void)
{
textmode(3);
textcolor(15);
textbackground(0);
clrscr();

/* Iskljucujemo kursor. */
_setcursortype(_NOCURSOR);

/* Ukljucujemo misa u program. */


mis();

/* Stalno utvrdjujemo poziciju kursora misa i da li je pritisnut levi ili desni taster misa. */

while(citaj())
{

/* Ako je pritisnut levi taster misa levod imace vrednost 1. */


if(TMiss.levod)
{
/* Obavezno pre ispisivanja necega na ekranu iskljuciti kursor misa, jer
ako to ne uradite na poziciji gde se kursor trenutno nalazi nece biti nista
ispisano. */

kursor_isklj();
gotoxy(TMiss.x,TMiss.y);
textbackground(0);
cprintf("1");
TMiss.levod=0;

/* Nakon ispisivanja teksta potrebno je ponovno ukljuciti kursor misa. */

kursor_uklj();
}

229
/* Ako je pritisnut desni taster misa desnod imace vrednost 1. */
if(TMiss.desnod)
{
kursor_isklj();
textbackground(0);
gotoxy(TMiss.x,TMiss.y);
cprintf("2");
TMiss.desnod=0;
kursor_uklj();
}

if(kbhit())
{
/* Iz programa izlazimo kada se pritisne neki taster sa tastature. Te iz tih
razloga koristimo funkciju kbhit. Pre izlaska iz programa potrebno je
obavezno iskljuciti kursor misa. */

kursor_isklj();
return;
}
}

230
6.6. ZADACI IZ STRUKTURA, NIZOVA STRUKTURA I BINARNIH
DATOTEKA

Zadatak 1 (2)
Napisati C program koji omogućava unos dva ugla i izračunava njihov zbir.
Svaki ugao je okarakterisan sa poljima:

1) stepen (00-3600),
2) minut (0'-59'), i
3) sekund (0"-59")

Zadatak 2 (2)
Napisati C program koji korišćenjem funkcije dekupol prevodi tačku zadatu sa x i y
koordinatama Dekartovog koordinatnog sistema u polarni koordinatni sistem opisan sa
radijusom i uglom.

Zadatak 3 (2)
Napisati C program koji omogućava unos napona i struje pomoću stringova u
trigonometrijskom obliku: u (t )  U max cos( wt   ) i i (i )  Im ax  cos( wt   ) .
Program treba da predstavi struju i napon u algebarskom obliku, a potom da izračuna
impedansu potrošača.

Zadatak 4 (2)
Napisati C program koji izračunava obim poligona koji se zadaje sa nizom svojih
tačaka. Svaka tačka je opisana sa x i y koordinatom.

Zadatak 5 (2)
Napisati C program koji formira i na ekranu štampa tabelarni prikaz sledećeg
oblika:

R. Br. Reda Broj reci Broj samoglasnika Broj suglasnika


1 7 24 56
2 10 35 45 , itd

Naziv tekstualne datoteke uneti sa tastature ili iz komandne linije.

Zadatak 6 (3)
U Dekartovom koordinatnom sistemu zadat je skup od n, n<100 kružnica. Svaka
kružnica opisana je sa poljima: x-koordinata centra, y-koordinata centra i poluprečnikom.
Napisati C program koji pronalazi i na ekranu štampa one kružnice koje u sebi sadrže
najviše drugih kružnica.

231
Zadatak 7 (2)
U tekstualnoj datotecin POLIGON.TXT nalazi se u svakom redu dva podatka
razdvojena sa po jednim blanko mestom. Prvi podatak predstavlja x, a drugi y koordinatu
tačke konveksnog poligona. Ako se tačke u datoteci nalaze zapisane po redu koji
odgovara matematičkom smeru obilaska kroz poligon, napisati C program koji
izračunava pozivom funkcije teziste koordinate težišta poligona.
Težište poligona računa se po formulama:

1 n 1 n
xt    xi i yt    yi
n i 1 n i 1

Zadatak 8 (3)
Napisati C program koji omogućava unos razlomka u obliku strukture pod imenom
racionalni koja se sastoji od dva polja: brojilac i imenilac. Koristeći funkciju skrati
omogućiti da se razlomak dovede u oblik koji se ne može skratiti, i kao takav se štampa
na ekranu.

Zadatak 9 (3)
Napisati C program koji učitava niz struktura o uspehu učenika na prijemnom
ispitu, a zatim klasifikuje kandidate u tri kategorije A, B i C. Svaka struktura koja se
učitava sa ulaza sadrži dva polja: ime i poeni, a u obradi treba dodeliti i treće polje rang.
Kandidat je u rangu: A ako ima više od 80% od ukupnog broja bodova koji se može
osvojiti na ispiti, B ako ima više od 35%, ili C u suprotnom. Niz struktura se učitava iz
binarne datoteke čije ime se unosi sa tastature.

Zadatak 10 (3)
Napisati C program koji omogućava unos dva razlomka i pozivom odgovarajućih
funkcija izračuna i prikaže na ekranu njihov zbir, razliku, proizvod i količnik. Razlomak
je u obliku strukture pod imenom racionalni koja se sastoji od dva polja: brojilac i
imenilac.

Zadatak 11 (3)
Napisati C program koji omogućava učitavanje podataka iz najmanje jedne
tekstualne datoteke u niz struktura. U svakom redu tekstualne datoteke nalazi se Prezime,
Ime i broj bodova sa ispita za svakog studenta. Datoteke se unose iz komandne linije.
Niz struktura sortirati u opadajućem redosledu po broju bodova, a ukoliko više
kandidata ima isti broj bodova, drugi kriterijum je sortiranje u rastućem abecednom
redosledu. Obrađene podatke iz niza struktura upisati u novu tekstualnu datoteku.

Zadatak 12 (3)
Napisati C program koji učitava tekastualnu datoteku i formira niz struktura sa
poljima: reč i broj pojave te reči u datoteci, sortira niz struktura u opadajućem redosledu
po broju pojavljivanja reči u datoteci, a u slučaju da više reči ima isti broj pojavljivanja,
po abecedi. Na kraju štampati na ekranu tabelarni prikaz pojave reči u tekstualnoj
datoteci.

232
Zadatak 13 (3)
Formirati tekstualnu datoteku UCENICI.TXT pa u tu datoteku uneti podatke za n
učenika n<50, i to (prezime, ime, datum rođenja oblika dd.mm.gg, uspeh opisno izražen,
putnik Da ili Ne, i izostanci). U svakom redu nalaze se podaci o samo jednom učeniku.
Očitati datoteku i podatke smestiti u niz struktura. Strukturu sortirati po abecednom
redosledu i štampati je na ekranu.

Zadatak 14 (3)
Napisati C program za praćenje glasanja na muzičkom festivalu. Svaka pesma
dobija ocenu žirika (od 0 do 10) i ocenu publike (od 0 do 10). Program treba da omogući:
unos naziva pesme, naziv izvođača, broj osvojenih bodova, kao i izlistavanje rezultata po
opadajućem redosledu broja bodova

Zadatak 15 (3)
U tekstualnoj datotecin POLIGON.TXT nalazi se u svakom redu dva podatka
razdvojena sa po jednim blanko mestom. Prvi podatak predstavlja x, a drugi y koordinatu
tačke konveksnog poligona. Ako se tačke u datoteci nalaze zapisane po redu koji
odgovara matematičkom smeru obilaska kroz poligon, napisati C program koji
izračunava pozivom funkcije povrsina površinu poligona.
Površina trougla zadata sa koordinatama temena tačaka A(xa,ya), B(xb,yb) i
C(xc,yc) računa se po formulu:
1
P  xa  ( yb  yc )  xb  ( yc  ya)  xc  ( ya  yb)
2

Zadatak 16 (4)
Napisati C program koji formira niz struktura na osnovu tekstualne datoteke
IGRACI.TXT o takmičarima svetskog prvenstva u fudbalu tako da svaka struktura
takmičara sadrži sledeća polja: Prezime, Ime, Broj na dresu, Godine života, Ime
reprezentacije, Broj učešća na svetskim prvenstvima, Broj zlatnih, Broj srebrnih i Broj
bronzanih medalja.
Sortirati reprezentacije prema uspešnosti na svetskim prvenstvima i ispitati koja
reprezentacija ima najveću cenu na tržištu.

Zadatak 17 (4)
U datoteci RADNICI.TXT nalaze se podaci o radnicima neke firme, zapisani u
obliku:
broj radnika... prvi red
ime radnika1.. drugi red
godina staža... treći red
plata radnika... četvrti red
ime radnika2... peti red, itd.

Očitati podatke o radnicima pa sortirati radnike prema plati i po abecednom


redosledu ako imaju istu platu. Na svaku godinu staža dodaje se po 0,2% na platu
radnika. Tako sortirane rezultate ponovo smestiti u istu datoteku ne menjajući prvi red
datoteke.

233
Zadatak 18 (4)
Napisati C program za mesečnu evidenciju saobraćaja vozila preko mostova. Podaci
se nalaze u datoteci organizovanoj po 32-bitnim rečima jednog brojanja:

0 bit - bit parnog pariteta,


1 - 14 bita - broj vozila koja su tada prešla most,
15 - 19 - sat,
20 - 24 - dan,
25 - 28 - nesec, i
29 - 31 - šifra mosta.

Program treba da omogući sledeće:


 Učitavanje podataka barem iz jedne datoteke uz proveru informacija 0-tog
bita parnog pariteta,
 Prikaz tabele (mesec most i prosečan broj vozila po satima), i
 Određivanje šifre vozila koje je toga meseca najviše puta
prelazilo most.

Zadatak 19 (4)
Napisati C program koji omogućava evidenciju stanja bankovnih računa korisnika
u jednoj banci. Jedan račun se opisuje brojem računa, imenom i prezimenom vlasnika
računa, matičnim brojem vlasnika računa, stanjem računa. Program treba da omogući
pregled stanja računa za zadatog korisnika, izlistavanje svih računa koji su u minusu,
otvaranje novog računa za novog korisnika, kao i funkciju za prenos zadate svote sa
jednog na drugi račun u okviru banke. Jedan korisnik može imati samo jedan otvoreni
račun u banci. Obezbediti trajno čuvanje podataka u datoteci ACCOUNT.DAT.

Zadatak 20 (4)
Zadata je tektualna datoteka PROMENE.TXT u formatu: pr_sifra (dvanaest
cifara), pr_kolicina (pet celih i dva decimalna mesta), pr_cena (0 – ulaz, ili 1 - izlaz) i
pr_smer (sedam celih i dva decimalna mesta).
Napisati C program koji sekvencijalno čita datoteku PROMENE.TXT i formira niz
struktura sortiranu u rastućem redosledu šifre čiji elementi sadrže sledeća polja: st_sifra,
st_kolicina, st_cena i st_vrednost.

st _ kolicina   pr _ kolicina   pr _kolicina


za sve promenete za sve promenete
sifre sasmerom0 sifre sasmerom1

st_cena je najveća cena u svim strukturama promene za tu šifru.


st_vrednost = st_cena * st_kolicina

Na kraju štampati niz struktura u proizvoljnom formatu, ali tako, da se posle


štampanja poslednjeg elementa strukture odštampa ukupna vrednost sve robe u
magacinu.

234
Zadatak 21 (5)
Napisati C program za elektronsko vođenje školske biblioteke. Svaki član
biblioteke je okarakterisan sa:

1) Prezi
me i ime,
2) Člans
ki broj,
3) Adres
a stanovanja,
4) Razre
d,
5) Telefo
n, i
6) Broj
uzetih knjiga.

Program treba da omogući:

a) Upis novog člana, pri čemu automatski dobija članski broj,


b) Brisanje pojedinog člana iz biblioteke pod uslovom da je vratio sve knjige
koje je iz biblioteke zadužio,
c) Izmene pojedinih podataka o članu,
d) Ispis podataka o svim članovima po kriterijumu broja zaduženih knjiga,
e) Utvđivanje koji razred ima najviše neurednih korisnika biblioteke,
f) Na kraju školske godine prikaz svih članova četvrte godine koji nisu vratili
knjige, i
g) Automatso preimenovanje oznake svih odeljenja škole na početku školske
godine.

Zadatak 22 (5)
Napisati C program koji na osnovu unetog prirodnog broja n, 1<n<11 i formira
kvadratnu matricu A dimenzije nxn i inverznu matricu AINZ matrice A. Elementi
matrice A i AINZ su strukture koje se sastoje od dva polja: brojilac i imenilac.
Postupak za određivanje inverzne matrice je sledeći: Prvo se formira jedinična
matrica AINZ. Matrica je jedinična ako su svi elementi na glavnoj dijagonaliu jednaki
jedan. Sada se od matrice A formira jedinična matrica. Kod matrice se mogu izvršavati
sledeće transformacije: sabiranje jedne vrsta (kolone) sa drugom vrstom (kolonom),
množenje vrste (kolone) brojem različitim od nule ili množenjem jedne vrste (kolone)
brojem i dodavanjem drugoj vrsti (koloni). Sav postupak koji se radi sa vrstama
(kolonama) matrice A tako da ona postane jedinična raditi i sa vrstama (kolonama)
matrice AINZ. Kada nakon ovih postupaka matrica A postane jedinična tada će matrica
AINZ postati inverzna matrica matrice A.

235
Program omogućava štampanje inverzne matrice tako da elementi budu
predstavljeni u obliku prostih razlomaka (razlomaka koji se ne mogu skratiti).

Zadatak 23 (5)
Napisati C program kkoji primenom Gausovog postupka eliminacije u matričnom
obliku omogućava rešavanje sistema linearnih jednačina.

Gausov postupak eliminacije glasi:


Uopšteni sistem jednačina može se predstaviti u obliku:
a11  x1  a12  x 2  a13  x3  ...  a1n  x1n  c1
a 21  x1  a 22  x 2  a 23  x3  ...  a 2 n  x1n  c 2
.
.
.
a n1  x1  a n 2  x 2  a n3  x3  ...  a nn  x1n  c n

Sistem n jednačina sa n nepoznatih može se ekvivalentno predstaviti i u matričnoj


formi: A  X  C , pri čemu su A, X i C matrice.

 x1  c1 
 a11
a
a12 a13 . . . a1n  x  c 
. . . a 2 n   2  2
X C
a 22 a 23
A   21
 .

. . . . . 
 .  . 
 a n1 a2n a3n . . . a nn 
   
 xn  c n 
Rešenje matrične jednačine je dato u obliku: X  A 1  C gde je A-1 inverzna
matrica matrice A. Slično kao i u predhodnom zadatku potrebno je obezbediti da rešenja
budu u obliku razlomaka koji se ne mogu skratiti. Sistem jednačina nalazi se zapisan u
tekstualnoj datoteci čiji naziv sa putanjom se unosi sa tastature.

Zadatak 24 (5)
Napisati C program za vođenje takmičenja iz osnova elektrotehnike. Svaki
takmičar je opisan sa imenom i prezimenom, naziv škole, ime grada i broj osvojenih
poena. Na osnovu unetih podataka formira se lista takmičara. Na osnovu liste rezultata
formirati dve datoteke. U datoteku POBEDNICI.TXT upisati takmičare koji su se
plasirali na daljnje takmičenje (20% učesnika). U datoteku PLASMAN.TXT upisati
plasman škola učesnica na takmičenju po rezultatu (ukuopan broj bodova koje su
takmičari te škole ostvarili).
Omogućiti da se formirane datoteke mogu štampati na štampaču (77 linija 12
inčna dužina papira). Stranice moraju imati zaglavlje i numeraciju.

236
Zadatak 25 (5)
Napisati C program koji na osnovu učitane datoteke sa C programom i na ekranu
prikazuje sledeći tabelarni prikaz pojave naredbi selekcije if, if-else ili naredbi ciklusa
for, while ili do-while po redovima u datoteci, u obliku:

if1 while1 if2 do-while1 for1 if3...


10 23 12 34 55 56
10 30 60 38 55 58
nema 62 nema
else 62 else
Zadatak 26 (5)
Napisati C program za klasifikaciju uplata na račune banka/preduzeće. Svaka
uplata je okarakterisana sa: brojem računa (14 cifara – prvih pet označava SPP
poslovnicu a ostali su interni za datu poslovnicu), i uplaćenim iznosom Program treba da
prihvati sve uplate jednog dana iz date binarne datoteke i klasifikuje ih u tekstualne
datoteke SPP poslovnica tako da svaka SPP poslovnica za koju postoji barem jedna uplata
ima svoju tekstualnu datoteku pod nazivomm UPLxxxxx.TXT gde je xxxxx broj SPP
poslovnice iz broja računa. Jedna linija ove tekstualne datoteke sadrži devet internih
cifara iz broja računa, jedno prazno mesto i uplaćen iznos.
Sumarni izveštaj o klasifikaciji (5-to cifreni broj SPP poslovnice i ukupno uplaćen
iznos za tu poslovnicu) memorisati u tekstualnoj datoteci KLASUPL.TXT.

Zadatak 27 (5)
U tekstualnoj datoteci SOKOBAN.TXT nalaze se zapisane table koje je potrebno
preći od popularne video igrice SOKOBAN. Table su razdvojene sa jednim praznim
redom. Vrednosti polja table može imati jednu od sledećih vrednosti: 0 – hodnik kroz koji
se gura crvena kockica i gde se kursor može kretati, 1 – zid, 2 – cevena kockica koju
treba pregurati na neko od postavljenih mesta obeleženih sa crnom kockicom, 3 – crna
kockica ili mesto gde treba dogurati crvenu kockicu i 4 – kursor u obliku smeska kojim se
kroz hodnike krećete sa strelicama i možete gurati crvene kockice.
Broj crvenih kockica jednak je sa brojem crnih kockica. Kada se guranjem sve
crvene kockice postave na mesta gde se nalaze crne kockice uz zvučni signal prelazi se u
sledeći nivo. Kursor može gurati samo jednu kockicu u jednom smeru, a ako poguša
odjednom gurati njih više ili se pokuša gurati kockica a da je iza zid čuje se zvučni signal.
U slučaju da se pogrešilo tako da se ne može preći nivo sa SPACE se vraća na početak
tog nivoa. Ako se stisne ESC završava se igrica a od korisnika se traži ime kako bi se
podaci sačuvali u datoteci i time omogućilo da se prilikom ponovnog startovanja igrice
ne kreće od prve table već od one koju poslednji put nije pređena.

Zadatak 28 (5)
Napisati C program koji predstavlja poznatu igricu MINE stim da će se u ovom
slučaju igrica igrati sa tastaturom. Na samom početku programa pojavljuje se naslov sa
velikm slovima MINE koje su dobijene crtanjem kockica po kockica, a ispod toga meni

237
čija je prvobitna opcija označena crvenom bojom. Kroz meni se možete kretati sa
strelicama na gore i na dole. Sa leve strane nalazi se obaveštenje da se sa velikim slovom
L može dobiti lista 10 najboljih rezultata za dati nivo sa poljima ime igrača i vreme za
koje je igricu rešio, a ispod slovo S sa kojim se uključuje ili isključuje zvuk. U igrici
postoje nivoi: VERY EASY (25), EASY(40), NORMAL(55), HARD(70), VERY
HARD(85) i NIGHTMARKE(100), pri čemu u zagradi napisani broj označava broj
mina koje se na tabli nalaze.
Kada se izabere određeni nivo pritisne se ENTER formira se tabla za igru pri čemu
se a desne strane može videti vreme koje protiče dok traje igra. U gornjem levom uglu
nalazi se podatak koliko je zastavica ostalo. U gornjem desnom uglu nalazi se slovo S i
pored odgovarajuća poruka koja obaveštava šta će se desiti sa zvukom ako se unese
veliko slovo S.
Na sredini table nalazi se kursor sa kojim se strilicama može kretati po tabli. Sa
tasterom SPACE otvara polje, a sa tasterom ENTER postavlja zastavica u obliku znaka
uzvika, ako je na tom polju nema ili se ukida sa tog polja ako je ranije već postavljena.
Ako je zastavica postavljena na nekom polju to polje se nemože otvoriti. Kada se postavi
zastavica broj zastavica u gornjem levom uglu se automatski smanjuje za jedan.
U slučaju da se tabla reši sve zastavice će blinkovati i nakon pritisnutog tastera
ENTER ako je ostvareno vreme među prvih 10 pojaviće se lista najboljih sa imenom
Anonimus koje se može sa BACKSPACE izbrisati ili sa ENTER potvrditi.
U slučaju da se otvorilo polje gde postoji mina otvaraju se sva polja i mine koje su
obeležene sa crvenom zvezduicom će blinkovati. Ako se otvori polje gde nije mina
pojaviće se broj koji opisuje koliko mina to polje graniči, a ako je taj broj nula, broj se ne
prikazuje već se prikazuju svi najbliži brojevi koji nisu nule a nalaze se oko tog polja.
Nakon završetka igranja na odgovarajućoj tabli vračamo se u meni. Iz menija se
izlazi sa ESC.
Nema datoteke u kojoj se nalaze table sa nivoima već se table sa rasporedom mina
formiraju na slučajan način.

Zadatak 29 (5)
Napisati C program koji pretstavlja popularnu igricu ASOCIJACIJE iz muzičke
slagalice. Igrica je namenjena za dva igrača. U tekstualnoj datoteci u svakom redu nalazi
se po jedna reč. Reč ne sme da bude duža od 15 karaktera. Prva reč odnosi se na polje A1,
druga reč na polje A2, treća reč na polje A3, četvrta reč na polje A4, peta reč je rečenje
kolone A, šesta reč je polje B1, sedma reč je polje B2, osma reč je polje B3, deveta reč je
polje B4, deseta reč je rešenje kolone B, itd. Ima četiri kolone A, B, C i D. Poslednja reč
je rešenje asocijacije. U datoteci postoji više asocijacija. Asocijacije su razdvojene
praznim redom. Na slučajan način se bira asocijacija. Polja koje je pogodio igrač 1
iscrtavaju se crvenom bojom, a polja koje je pogodio igrač 2 iscrtavaju se tamnoplavom
bojom.
Postoji polje sa oznakom DALJE koje kada kliknete obaveštavate da igra sledeći
igrač. Igrica se igra sa mišem. Postoji polje KRAJ koje kada kliknete završavate igricu, i
iscrtava se rešenje asocijacije. Kada kliknete na polje za odgovor na kolonu ili konačno
rešenje, pojavljuju se zvezdice, ali broj zvezdica je uvek isti i ne zavisi od rešenja tog
polja. Ako igrač pogodi rešenje kolone cela kolona se iscrtava u njegovoj boji i za rešenje

238
dobija pet poena. Može otvarati sledeće polje ili kliknuti na DALJE čime omogućava da
polje otvara sledeći igrač. Igrač ne može da otvara polje za rešenje ako nije otvorio neko
ne otvoreno polje. Polje može otvarati iz bilo koje kolone.
Pogodak na konačno rešenje nosi 10 poena, pri čemu ako neka od kolona nisu
pogođena dobijaju se i poojeni (za svaku ne pogođenu kolonu po 5 poena) za te kolone.

Zadatak 30 (5)
Napisati C program koji pretstavlja igricu UKRŠTENICA. Prilikom startovanje
igrice unosi se ime tekstualnog fajla gde je zapisan format jedne ukrštenice. Na osnovu
tog formata iscrtava se prazna ukrštenica. Igrica se igra mišem ili tastaturom. Na osnovu
položaja kursora na donjim poljima (horizontalno, vertikalno) ispisuje se pitanje koje
odgovara odgovoru u toj vrsti ili koloni. Prilikom klika miša na neko polje na donjim
poljima se ispisuje horizontalno i vertikalno pitanje. Koje je horizontalno ili vertikalno
pitanje može se dobiti klikom na “polje sa pitanjem“. Kroz ukrštenicu može se kretati
strelicama. Unose se slova koja sde iscrtavaju žutom bojom.
Igrica se završava kada se klikne desim tasterom miša. Tada se dobijaju odgovori
na postavljena pitanja, pri čemu su slova crvene boje ako su na tim mestima bili pogrešni
odgovori, plave boje ako su bili tačni odgovori, ili žute boje ako korisnik na tim poljima
nije dao nikakav odgovor.
Na sledećoj strani dat je format tekstualne datoteke u kojoj je smeštena ukrštenica
sa pitanjima. Komentarima su data objašnjenja pravila po kojima je datoteka formirana.
Te komentare ne smete pisati u vašoj datoteci kada je budete formirali.
Format datoteke je predstavljen na sledećoj strani:

239
11*16 /* dimenzije ukrstenice */
`````%*b******** /* podaci o tome gde je koje slovo */
`````*promucuran /* ` oznacava sliku */
`````*tavan*tada /* * oznacava polje s pitanjima */
`````%*jad*bodar /* ... */
`````*ma*arekipo
%*%***onagar*ot*
*d*ivanapavlovic
*o*nepodesni*ero
*brak*kalkan*zar
*rec*almaata*ana
*ime*bistrica*ek
pitanja: /* jedan novi red (bilo sta u njemu) */
belgija@platina /* pitanja za polja su napisana */
levo-dole: kanadski pevac@pokazna zamenica /* redom, s leva na desno, i tako */
-@ostrvo u indijskom okeanu /* red po red. Prvo ide */
@ujedinjene nacije (skr.) /* horizontalno pitanje, pa znak"@", */
-@23. slovo azbuke /* pa vertikalno pitanje. Ako nema */

240
-@usce reke /* nekog od pitanja onda se samo */
-@komunikazija purem radija /* stavi "-" ili nesto slicno */
-@adaptacija
-@japanski grad na ostrvu honsu
dovitljiv@-
gornji deo kuce@-
u to vreme@stanovnik berlina
nevolja, nesreca@opticka naprava za jedno oko (mn.)
krepak, vedar, cio@poravnavati
mazurijum@-
grad u peruu@prijava visem sudu (lat.)
-@valjani
-@u drugom slucaju
-@period od sto godina
vrsta divljeg magarca@autonomna pokrajina
osnovna tarifa (skr.)@obim
-@lazni metak
dama u sahu (skr.)@-
nasa pop pevacica@-
kiseonik@-
koji nisu podesni, nepogodni@romulov brat
hercegovac@-
zajednica muza i zene@-
zabat na kuci (turc.)@pocetak azbuke
uzvicno-upitna recenica@-
deo recenice@-
glavni grad kazahstana@-
nasa voditeljka dmitrovic@amper
naziv@-
deo Novog Sada@-
enigmatski klub@-
format: /* jedan novi red */
05,07ù
06,07:
09,08:
00,07/

/* ù (u DOS-u izgleda kao ∙), oznacava razmak u vertikalnoj */


/* reci, na y=5 i x=7 koordinati */

/* : oznacava razmak u horizontalnoj reci, na tacki x=6 i y=7 */


/* : isto i za x=9 i y=8 */
/* "/" za strelicu na mestu y=0 i x

241
7. POGLAVLJE

DINAMIČKE STRUKTURE PODATAKA

242
7.1. DINAMIČKA DODELA MEMORIJE

Prilikom delaracije podataka u zoni podataka se odvaja potreban memorijski prostor


na osnovu tipa podataka. To znači da se u vreme prevođenja programa mora tačno znati
koliko ima podataka. U slučaju nizova mora se unapred rezervisati memorijski prostor za
smeštanje niza. To se obično radi tako što se deklariše niz sa očekivanim maksimalnim
brojem elemenata. To dovodi do nepotrebnog utroška memorije. Programski jezik C
dozvoljava da se u toku izvršenja programa od operativnog sistema traži dodeljivanje
memorijskog prostora

Definicija:
Deo memorije koji se dodeljuje u toku izvršavanja programa naziva se
dinamička zona memorije ili hip memorija.

Osobine dinamičkih podataka:


Podaci smešteni u dinamičkoj zoni memorije nazivaju se dinamički podaci.
Dinamiči podaci postoje sve dok ih programer eksplicitno ne uništi ili do završetka
programa kada se automatski uništavaju. Dinamički podaci nemaju svoje
indentifikatore već im se pristupa pomoću pokazivača iz zone podataka.

Upravljanje dinamičkim podacima vrši se pomoću funkcija malloc, calloc,


realloc i free koje se nalaze u biblioteci stdlib.h. U ovoj lekciji objasnićemo funkcije
malloc i free.
void *malloc(size_t size);

Funkcija malloc alocira size bajtova u dinamičkoj zoni memorije. Ako uspešno
obavi zadatak funkcija vraća generički pokazivač na alocirani prostor u memoriji.
Ako dođe do greške biće vraćena vrednost NULL.

void free(void *buffer);

Funkcija free oslobađa prethodno alociranu memoriju na čiju početnu adresu sadrži
pokazivač buffer. Pokazivač buffer dobio je adresu pozivom funkcije malloc, calloc ili
realloc.

Primer 1:
Napisati deo koda koji omogućava deklaraciju pokazivača na tip podataka Tucenik,
a potom formira objekat na koga taj pokazivač pokazuje. U slučaju da se objekat nije
mogao formirati prikazati poruku da nije bilo dovoljno memorije.

Rešenje:

Tucenik *pokazivac = NULL;

243
if(pokazivac = (Tucenik *) malloc(sizeof(Tucenik)) == NULL)
{
printf("Nije dobro alocirana memorija!! "),
return;
}
free(pokazivac);

Primer 2:
Napisati C program koji omogućava formiranje strukture radnik sa poljima:

1) Prezime i ime od maksimalno 30 karaktera;


2) Koeficijen za dato radno mesto; i
3) Godine radnog staža

Poznato je da je vrednost boda k dinara, a da se na svaku godinu radnoga staža


dohodak uvećava za 0.5%. Pripravnik je onaj radnik gde se za godine radnoga staža
unese broj 0 i ima 80% dohodak u odnosu na radnika sa obavljenim pripravničkim
stažom. Progam treba da ispiše koliki je dohodak radnika. Prilikom realizacije programa
koristiti dinamičku zonu memorije.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include<ctype.h>
#include <stdlib.h>

#define MAX 31

/* Definisanje strukture. */
typedef struct radnik{
char prezime_i_ime[MAX];
double koeficijent;
int staz;
double dohodak;
} Tradnik;

/* Sada je Tradnik novi tip podatka (izvedeni tip podatka). */

/* Prototipovi funkcija. */
Tradnik *unos(int startx,int starty);
void racunaj_dohodak(Tradnik **pok);
void ispis_dohotka(Tradnik *pok);

void main(void)
{
Tradnik *pok; /* Deklarise se promenljiva pok koja predstavlja pokazivac na slozeni tip
podatka Tradnik, i nalazi se u zoni podataka */

244
textmode(3);
textcolor(0);
textbackground(15);
clrscr();

printf("\t\tUNESITE PODATKE O RADNIKU:\n\n");


if((pok=unos(wherex(),wherey()))==NULL) return;

racunaj_dohodak(&pok);
ispis_dohotka(pok);

gotoxy(1,25);
getch();
}

/* Funkcija omogucava formiranje objekta i vraca pokazivac na taj objekat, kao i unos
podataka u objekat. */

Tradnik *unos(int startx,int starty)


{
Tradnik *pokazivac; /* pokazivac je promenljiva koja moze da sadrzi adresu podatka ili
objekta tipa Tradnik. */
double a;
int b;
unsigned xu,yu;

/* Radi sigurnosti potrebno je izvrsiti konverziju generickog pokazivaca u pokazivac tipa


Tradnik, pa tek tada izvrsiti dodelu adrese promenljivoj pokazivac. Ako promenljiva
pokazivac bude imala vrednost NULL znacice da se objekat nije formirao usled
nedostatka operativne memorije. Ovo ispitivanje potrebno je uvek vrsiti. */

if((pokazivac=(Tradnik *)malloc(sizeof(Tradnik)))==NULL)
{
printf("Nema dovoljno memorije!!");
return NULL;
}

strcpy(pokazivac->prezime_i_ime,"");
pokazivac->koeficijent=0;
pokazivac->staz=0;
pokazivac->dohodak=0;

gotoxy(startx,starty);
printf("\tIme i prezime: ");
gets(pokazivac->prezime_i_ime);
printf("\tKoliki je koeficijenat: ");
xu=wherex();
yu=wherey();

245
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%lf",&a);
}while(a<=0);
pokazivac->koeficijent=a;

printf("\tGodine radnoga staza = ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%d",&b);
}while(b<0);
pokazivac->staz=b;

/* Funkcija vraca adresu formiranog objekta. */


return pokazivac;
}

/* Funkcija racunaj_dohodak izracunava dohodak radnika. Podaci o radniku nalaze se u


objektu cija adresa se prosledjuje pokazivacu pok. */
void racunaj_dohodak(Tradnik **pok)
{
double k;
unsigned xu,yu;

printf("\n\n\tVrednost boda je: ");


xu=wherex();
yu=wherey();
do{
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
scanf("%lf",&k);
}while(k<1);

if((*pok)->staz!=0)
{
(*pok)->dohodak=(*pok)->koeficijent*k;
(*pok)->dohodak+=0.5*(*pok)->staz*(*pok)->dohodak;
}else{
(*pok)->dohodak=(*pok)->koeficijent*k;
(*pok)->dohodak=0.8 * (*pok)->dohodak;
}
}

246
/* Funkcija ispis_dohotka ispisuje dohodak koji je radnik ostvario i oslobadja prostor u
dinamickoj zoni memorije jer se objekat vise nece koristiti. */

void ispis_dohotka(Tradnik *pok)


{
printf("\n\n\n\tRadnik %s ima dohodak %.2f dinara.",
pok->prezime_i_ime, pok->dohodak );
free(pok);
}

Test primer programa:

247
7.2. JEDNOSTRUKO SPREGNUTA LISTA
Pojam i definicija, dodavanje elementa u listu

7.2.1. Kakva područja memorije priprema operativni sistem prilikom


započinjanja programa?
Operativni sistem priprema pet područja memorije:
- prostor za kod programa
- prostor podataka
- stek
- dinamička (hip) memorija
- registarska memorija

7.2.2. Šta je to pokazivač?


Pokazivač je promenljiva koja sadrži (pokazuje) adresu neke druge promenljive ili
objekta.

Na primer:
int a = 0, *pok = NULL;
pok=&a;

Zona podataka:
Pok a
CBD3 0

CBD3

7.2.3. Gde i kako se u programskom jeziku C formira objekat?


Objekat se nalazi u dinamičkoj zoni memorije, dok se promenljive nalaze u zoni
podataka. Objekat se u programskom jeziku C formira pomoću funkcije malloc:

pok=(Tcvor *)malloc(sizeof(Tcvor));

Funkcija malloc formira u dinamičkoj zoni objekat veličine (u bajtovima) koja


odgovara tipu podataka Tucenik, i adresu nakon formiranja upisuje u pokazivač pok.
Pokazivač pok se nalazi u zoni podataka.

248
Na primer:

Logička predstava Fizička predstava

Zona podataka

Dinamička zona

objekat

Kako se uništava objekat?


U programskom jeziku C objekat se uništava pomoću funkcije free.
Na primer:
free(pok);
pok=NULL;

Prilikom uništavanja objekta saopštava se operativnom sistemu da je taj prostor


memorije slobodan.

Kada programeri kažu da je nastupilo curenje memorije?


Programeri kažu da je nastupilo curenje memorije ako objekat nije uništen, а
nijedan pokazivač na njega ne pokazuje (ne sadrži) njegovu sdresu.

7.2.4. Šta је tо јеdnostruko spregnuta lista?


Јеdnostruko spregnuta lista је najjednostavnija struktura podataka која sе
аsastoji оd оbjekata međusobno povezanih (spregnutih) pokazivača, pri čemu svaki оd
čvorova pokazuje na svog sledbenika.
Listi sе pristupa preko јеnog spoljašnjeg pokazivača glava (nalazi sе u zoni
podataka) којi pokazuje na prvi čvor, а nije dео liste.
Poslednji čvor naziva sе repom liste. Оn nema svog sledbenika, tе njegov
pokazivač ima vrednost NULL.

249
Prikaz logičke i fizičke predstave јеdnostruko spregnute liste

Iz navedenog prikaza vidi se dа logički i fizički poredak nisu isti.

Како sе vrši definisanje čvora liste?


Definisanje čvora liste vrši sе gdе i definisanje struktura. Čvor liste је strukturni tip
podataka којi sе sastoji оd dva polja : informacionog sadržaja i pokazivača. Informacioni
sadržaj је uopšteno strukturni podatak којi predstavlja коrisni sadržaj čvora. Pokazivač је
polje које sadrži аdresu sledećeg čvora liste ili NULL ако је rep liste.
typedef struct cvor{
Tslog info;
struct cvor *sledeci;
}Tcvor ;
U ovom definisanju čvora liste:
Tslog - је тip podataka strukture којi је ranije definisan.
info - је polje које је тipa Tslog i sadrži u сеbi više polja која ćе dati korisne
informacije.
sledeci - је pokazivač којi је u stanju dа pokazuje nа оbjekat тipa Tcvor.

7.2.5. Како sе vrši inicijalizacija liste?


Јеdnostruko spregnutoj listi pristupa sе pomoću spoljašnjeg pokazivača glava. Ако
lista nema čvorova (nema liste) tada pokazivač glava ima vrednost NULL.
Inicijalizacijom jednostruko spregnute liste pokazivaču glava dodeljuje sе vrednost
NULL.

250
void inicijalizacijaliste(Tcvor **glava)
{
*glava = NULL;
}

7.2.6. Načini dodavanja novog elementa u jednostruko spregnutu listu


Jednostruko spregnuta lista najčešće sе formira dodavanjem novog čvora na
početak liste ili dodavanjem novog čvora na kraj liste.
Кoju tehniku primeniti zavisi оd ažuriranja liste. Kod ažuriranja liste
podrazumeva se traženje elementa u listi, brisanje elementa iz liste i modifikacija
(promena) informacionog sadržaja čvora liste.
Potrebno је da sе dо čvora liste što brže dođe, а dа bi sе tо desilo čvor liste
mora biti što bliži prvom čvoru liste, ili da је prvi čvor liste.

Dodavanje novog elementa nа početak liste


Коristiti sе каda је potrebno ažuriranje čvorova liste коji su poslednji uneseni.
Dodavanje novog čvora na početak liste је brže i еfikasnije оd dodavanja novog čvora nа
kraj liste.
void dodajnapocetakliste(Tcvor **glava)
{
Tcvor *novi = NULL;
novi = formcvor();
if(*glava==NULL) *glava=novi;
else{
novi -> sledeci=*glava;
*glava=novi;
}
}

Prilikom dodavanja elementa na početak liste mogu se razlučiti dva slučaja:


- Prvi slučaj je kada lista nema elemenata (prazna je), tj pokazivač glava
ima vrednost NULL.
- Drugi slučaj je kada lista sadrži barem jedan element.

Prvi slučaj:

251
Drugi slučaj:

REZIME

• Postoji značajna razlika između jednostruko spregnute liste i niza struktura.

252
• Kod nizova је isti logički i fizički poredak elemenata. Elementu sе pristupa
pomoću indeksa. Znači lak i brz pristup, što čini prednosti niza struktura u оdnosu
nа јеdnostruko spregnutu listu.
• Kod niza je potrebno аlocirati statički fiksan memorijski prostor којi sе
dimenzioniše prema maksimalno оčekivanom broju elemenata, što doprinosi
slabijem iskorišćenju memorijskog prostora. Takođe kod niza je neefikasno brisanje
i umetanje elemenata nа proizvoljnom mestu, јеr оni zahtevaju pomeranje
elemenata niza, dok se kod liste izvrši samo promena vrednosti pokazivača kojima
su čvorovi liste povezani.

7.3. JEDNOSTRUKO SPREGNUTA LISTA


Dodavanje novog elementa na kraj jednostruko spregnute liste,
Traženje elementa u jednostruko spregnutoj listi, i
Brisanje jednostruko spregnute liste
uz oslobađabje zauzete memorije

7.3.1. Dodavanje novog elementa na kraj jednostruko spregnute


liste
Коristiti sе каda је potrebno ažuriranje čvorova liste коji su prvi uneseni, tj
potrebno je zadržati hronološki redosled elemenata.

void dodajnakrajliste(Tcvor **glava)


{
Tcvor *novi, *tek;
tek=NULL;

novi = formcvor();
if(*glava==NULL) *glava=novi;
else{
tek=*glava
while(tek->sledeci!=NULL) tek=tek->sledeci;
tek -> sledeci=novi;
}
}

Razlikuju se dva slučaja. Prvi kada nema elemenata u listi i drugi kada ima
elemenata u listi. U prviom slučaju radi se isto kao i kod vezivanja na početak liste, samo
se povezuje pokazivač glava da pokazuje na novi element.

Prvi slučaj:

253
U drugom slučaju koriste se još jedan pomoćni pokazivač tek. Njegov zadatak je
da se prođe kroz listu tako da pokazivač tek na kraju po izlasku iz ciklusa pokazuje na
poslednji element u listi. Sada se uz pomoć pokazivača tek element lako vezuje na kraj
liste.
Drugi slučaj:

254
7.3.2. Traženje elementa u jednostruko spregnutoj listi
Traženje elementa u listi podrazumeva utvrđivanje da li neki elemenat liste ima
isti informacioni sadržaj kao i ključ (složeni podatak sa kojim se poredi).
Traženje elementa vrši se pomoću funkcije koja vraća adresu elementa u listi koji
ima isti informacionmi sadržaj kao i ključ, ili NULL ako nema takvog elementa u listi.
U listi samo jedan elemenat prilikom traženja poseduje takvo svojstvo. Funkciji
se po vrednosti prosleđuju pokazivač glava i ključ. Prosleđivanje po vrednosti se vrši iz
razloga što se vrednosti pokazivača glava neće promeniti, a ni ključ koji je tipa Tslog kao
i informacioni sadsržaj čvora liste.
Traženje se vrši pomoću pomoćnog pokazivača koji se postavlja na početku da
pokazuje na prvi element liste (gde i glava). Kroz listu se prolazi sa while ciklusom jer se
ne zna koliko lista ima elemenata. Ako se pronađe takav element pomoćni pokazivač tek
posedovaće adresu tog elementa liste, a u slučaju da se ne pronađe imaće vrednost
NULL.
Tcvor *trazi(Tcvor *glava, Tslog kljuc)
{
Tcvor *tek=glava;

while(tek!=NULL&&tek->info!=kljuc) tek=tek->sledeci;
if(tek==NULL) return NULL;
else return tek;
}
Prilikom traženja elementa u listi razlikuju se dva slučaja, Prvi da postoji element
liste koji ima isti informacioni sadržaj kao i ključ, i drugi da takvog elementa nema u listi.
Ključ može da bude podatak složenog tipa. U ovom primeru radi lakšeg praćenja ključ i
informacioni sadržaj su podaci osnovnog tipa int.

Prvi slučaj:
KLJUČ:15

255
Drugi slučaj:
KLJUČ:30

256
7.3.3. Brisanje liste i oslobađanje zauzete memorije
Prilikom rada sa dinamičkim strukturama podataka na kraju programa mora se
osloboditi zauzeta memorija u dinamičkoj zoni podataka (hip-a). To se u ovom slučaju
radi pomoću funkcije kojoj se prosleđuje pokazivač glava po referenci (jer će mu se
vrednost prilikom brisanja menjati).
Pri realizaciji koristi se pomoćni pokazivač tek, a brisanje se vrši sa početka liste
(onaj čijiu adresu sadrži pokazivač glava). Kada pokazivač glava bude imao vrednost
NULL znači da je lista obrisana iz memorije.

void brisanjeliste(Tcvor **glava)


{
Tcvor *tek=glava;

while(*glava!=NULL)
{
tek=*glava;
*glava=tek->sledeci;
free(tek);
}
}

U primeru posmatraćemo listu od tri elementa, pa moramo prilikom brisanja imati


tri iteracije.

Iteracija 1

257
Interacija 2

Iteracija 3

258
Primer:
Zadata je tekstualna datoteka BANKA.TXT koja sadrži podatke o štedišama jedne
banke. U svakom redu datoteke nalaze se podaci o jednom štediši banke u formatu:

Šifra#Prezime#Ime#Godine starosti#Stanje#Zaposlen(P,D,N)#prosečni dohodak

Šifra – indentifikacioni broj tekućeg računa;


Stanje – stanje tekućeg računa u trenutku podnošenja zahteva;
Zaposlen – u privatnom preduzeću (oznaka P), društvenom preduzeću (oznaka D)
ili nezaposled (oznaka N);
Prosečni dohodak – Prosečni lični dohodak u proteklih 12 meseci pre podnošenja
zahteva

U datoteci KREDITI.TXT nalaze se zahtevi za stambene kredite. Svaki red


datoteke sadrži podatke o jednom zahtevu u formatu: šifra#iznos.
Uslovi za dobijanje kredita su:
1) Da je štediša banke;
2) Podnosilac je stariji od 18 a mlađi od 65 godina starosti;
3) Zaposlen je u društvenom preduzeću;
4) Nema minus na tekućem računu banke; i
5) Mesečna rata kredita ne prelazi polovinu prosečnog ličnog dohotka.
Kredit se može dobiti na maksimalno 20 godina, ako je podnosilac zahteva mlađi
od 45 godina. U slučaju da je stariji od 45 godina, kredit se odobrava na broj godina do

259
65 godine života. Godišnja kamata u ovom trenutku za dobijanje stambenog kredita je
4.75% i zapišite je u simboličkoj konstanti KAMATA.
Napisati C program koji formira datoteke ODOBRENI.TXT (spisak osoba kojima
je kredit odobren) i NEODOBRENI.TXT (spisak osoba kojima kredit nije odobren).
Svaki red datoteke ODOBRENI.TXT je u formatu:
Šifra, Prezime, Ime, Na koliko godina je odobren kredit i Mesečna rata.
Svaki red datoteke NEODOBRENI.TXT je u formatu:
Šifra i Redni broj opcije (broj jedan) zbog koga kredit nije odobren) u slučaju da
podnosilac kredita nije štediša banke, ili Šifra, Prezime, Ime i Redni brojevi opcija zbog
kojih kredit nije odobren (međusobno odvojeni zarezima).

Rešenje

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

#define KAMATA 4.75

typedef struct zah{


char sifra[20];
double iznos;
}Tzah; /* Struktura zahteva, gde ce se upisivati podaci o osobi koja podnosi zahtev. */

typedef struct slog{


char sifra[20];
char prezime[30];
char ime[30];
char posao[2];
double stanje;
double pros;
unsigned god;
}Tslog; /* Struktura koja poseduje podatke o stedisama banke. */

typedef struct cvor{


Tslog info;
struct cvor *sled;
}Tcvor; /* Struktura cvora

/* Prototipovi funkcija. */
void inicijalizacija(Tcvor **glava); /* Inicijalizacija liste.. */
void smesti(Tcvor **glava, char *s); /* Upis podataka jednog stedise u listu. */
void dodajnapocetak(Tcvor **glava,Tcvor *novi); /* Dodavanje cvora na pocetak liste. */
void uradi(Tcvor *glava); /* Na osnovu podataka liste formira datoteke. */
void oslobodimemoriju(Tcvor **glava); /* Oslobadja memoriju koju je lista zauzela. */

void main(void)
{
FILE *dat;

260
Tcvor *glava;
char s[100];

textmode(3); textbackground(0); textcolor(15); clrscr();

if((dat=fopen("BANKA.TXT","r"))==NULL)
{
printf("\n\n\t\tDatoteka BANKA.TXT se ne moze otvoriti!!");
return;
}

inicijalizacija(&glava);

/* Ucitava se red po red iz datoteke i pozivanjem funkcije smesti podaci se upisuju u


objekat i uvezuju u listu. */
while(fgets(s,100,dat)!=NULL) smesti(&glava,s);
fclose(dat);

uradi(glava);
printf("\n\n\tPosao je uspesno obavljen!!");

/* Po zavrsetku programa obavezno obrisati listu iz memorije. */


oslobodimemoriju(&glava);
}

void inicijalizacija(Tcvor **glava)


{
*glava=NULL;
}

void smesti(Tcvor **glava, char *s)


{
char *pok=s;
Tcvor *novi;

novi=(Tcvor *)malloc(sizeof(Tcvor));
novi->sled=NULL;

/* Funkcijom strtok izdvajamo podatke iz formata stringa. */


pok=strtok(s,"#"); strcpy(novi->info.sifra,pok);
pok=strtok(NULL,"#"); strcpy(novi->info.prezime,pok);
pok=strtok(NULL,"#"); strcpy(novi->info.ime,pok);
pok=strtok(NULL,"#"); novi->info.god=atoi(pok);
pok=strtok(NULL,"#"); novi->info.stanje=atof(pok);
pok=strtok(NULL,"#"); strcpy(novi->info.posao,pok);
pok=strtok(NULL,"#"); novi->info.pros=atof(pok);

/* Formirani objekat se funkcijom dodajnapocetak uvezuje na pocetak liste. */


dodajnapocetak(&(*glava),novi);
}

261
void dodajnapocetak(Tcvor **glava,Tcvor *novi)
{
if(*glava==NULL) *glava=novi;
else novi->sled=*glava, *glava=novi;
}

void uradi(Tcvor *glava)


{
FILE *ul, *ne, *od;
char s[100], *pok=s, odgovor[10];
Tzah zah;
Tcvor *tek;
double rata;
unsigned god;

if((ul=fopen("KREDITI.TXT","r"))==NULL)
{
printf("\n\n\t\tDatoteka KREDITI.TXT se ne moze otvoriti!!");
return;
}

od=fopen("ODOBRENI.TXT","w");
ne=fopen("NEODOBRENI.TXT","w");

/* Ucitava se red po red iza datoteke. Pomocu funkcije strtok izdvoje se podaci i smestaju
u strukturu zahtev. */
while(fgets(s,100,ul)!=NULL)
{
strcpy(odgovor,"");
pok=strtok(s,"#");strcpy(zah.sifra,pok);
pok=strtok(NULL,"#"); zah.iznos=atof(pok);

/* Utvrdjuje se da li je podnosilac zahteva stedisa banke. */


tek=glava;
while(tek!=NULL&&strcmp(tek->info.sifra,zah.sifra)) tek=tek->sled;

/* Formira se string odgovor koji ce sadrzati redne brojeve opcija zbog kojih kredit
nije odobren. Ako nakon provere svih opcija string odgovor ostane prazan zahtev se
odobrava, a u suprotnom se ne odobrava. */
if(tek==NULL) strcat(odgovor,"1");
else{
if(tek->info.god<18 || tek->info.god>=65) strcat(odgovor,"2 ");
if(strcmp(tek->info.posao,"D")) strcat(odgovor,"3 ");
if(tek->info.stanje<0) strcat(odgovor,"4 ");
if(tek->info.god>=18&&tek->info.god<65&&!strcmp(tek->info.posao,"D"))
{
if(tek->info.god<45) god=20;
else god=65-tek->info.god;
rata=((zah.iznos/god)+(zah.iznos/god)*KAMATA/100)/12;
if(rata>tek->info.pros/2) strcat(odgovor,"5 ");
}

262
}
if(tek==NULL) fprintf(ne,"%-5s %s\n",zah.sifra,odgovor);
else{
if(strcmp(odgovor,"")) fprintf(ne,"%-5s %-15s %-15s\t%s\n",
tek->info.sifra,tek->info.prezime,tek->info.ime,odgovor);
else fprintf(od,"%-5s %-15s %-15s %d\t%.3f\n",
tek->info.sifra,tek->info.prezime,tek->info.ime,god,rata);
}
}
fclose(od); fclose(ne);
}

void oslobodimemoriju(Tcvor **glava)


{
Tcvor *tek;

while(*glava!=NULL)
{
tek=*glava;
*glava=(*glava)->sled;
tek->sled=NULL;
free(tek);
}
}
7.4. JEDNOSTRUKO SPREGNUTA LISTA
Brisanje elementa iz jednostruko spregnute liste
Formiranje sortirane jednostruko spregnute liste

7.4.1. Brisanje elementa iz jednostruko spregnute liste


Dinamička struktura podataka sadrži u svakom trenutku optimalan broj elemenata
čime se vrši ušteda memorije. Prilikom brisanja elementa iz liste oslobađa se zauzeta
memorija, tj operativnom sistemu se saopštava da oslobođeni deo memorije može
koristiti. Kako bi lista bila funkcionalna mora se izvršiti prelančavanje liste, odnosno
promena vrednosti pokazivača, čime se obezbeđuje ispravan logički poredak elemenata
liste.
Brisanje elementa liste uredićemo korišćenjem funkcije brisanjeelementa. Obrisaće
se samo jedan element liste koji ima isti informacioni sadržaj kao ključ traženja kljuc.
Pokazivač na početak liste mora se preneti po referenci jer se prilikom brisanja prvog
elementa liste vrednost pokazivača glava mora promeniti.

unsigned brisanjeelementa(Tcvor **glava, Tslog kljuc)


{
Tcvor *tek, *pret;
tek=pret=NULL;

tek= trazi(*glava,kljuc);
if(tek==NULL) return 0;

263
if(tek==*glava)
{
*glava=tek->sledeci;
tek->sledeci=NULL;
}else{
pret=*glava;
while(pret->sledeci!=tek) pret=pret->sledeci;
pret->sledeci=tek->sledeci;
tek->sledeci=NULL;
}
free(tek);

return 1;
}

Prilikom brisanja elementa liste razlikuju se dva slučaja:

Prvi slučaj:
Prvi slučaj je kada je element koji se briše prvi elemenat liste. Prilikom brisanja
elementa mora se prvo utvrditi da li elementa ima u listi, što se radi pomoću funkcije
traži koja je obrađena na prošlom času. Ako funkcija vrati vrednost NULL znak je da
elementa nema u listi, a u suprotnom pomoćni pokazivač tek dobija adresu pronađenog
elementa koga treba izbrisati iz liste. U prvom slušaju pokazivači tek i pret pokazuju gde
i pokazivač glava.

264
Drugi slučaj:
Drugi slučaj obuhvata varijante kada je element koji se briše nije prvi element
liste. Prilikom brisanja elementa mora se prvo utvrditi da li elementa ima u listi, što se
radi pomoću funkcije trazi koja je obrađena na prošlom času. Ako funkcija vrati vrednost
NULL znak je da elementa nema u listi, a u suprotnom pomoćni pokazivač tek dobija
adresu pronađenog elementa koga treba izbrisati iz liste. Kada smo našli elementa koga
treba izbrisati i njegovu adresu sadrži pokazivač tek, kako je lista jednostruko spregnuta
ne postoji pokazivač kojim bismo lako došli do elementa koji je logički predhodnik od
elementa koji se briše, moramo koristiti još jedan pomoćni pokazivač pok. Prolazimo
while ciklusom kroz listu sve dok pok ne dobije adresu predhodnika od elementa koji se
briše. Izvrši se prelančavanje liste i sa funkcijom free oslobodi memorija.

7.4.2. Formiranje sortirane jednostruko spregnute liste


Formiranje sortirane jednostruko spregnute liste ne znači da lista koja već postoji
sortira po nekom kriterijumu, već da se prilikom dodavanja novog elementa u listu,
element ulančava na onu poziciju koja obezbeđuje da lista stalno bude sortirana po
zadatom kriterijumu sortiranja.
Formiranje sortirane jednostruko spregnute liste može se uraditi na dva načina:
 Iterativnim postupkom, ili
 Rekurzivnim postupkom.

7.4.2.1. Formiranje sortirane jednostruko spregnute liste


iterativnim postupkom
Formiranje sortirane jednostruko spregnute liste iterativnim postupkom
(korišćenjem ciklusa) uradićemo pomoću funkcije formsortlistu. Funkciji se po referenci
mora proslediti pokazivač glava kako bi se moglo pristupiti listi, a prenos je po referenci
jer se novi cvor može uvezati na početak liste.
U okviru funkcije koriste se tri pomoćna lokalna pokazivača: novi, ispred i iza.
Pokazivač novi prihvatiće adresu novoformiranog objekta koga treba uvezati u listu.

265
Pokazivači iza i ispred koriste se u slučaju kada se element uvezuje negde u sredinu ili na
kraj liste. Ako se element uvezuje negde u sredinu liste, prvo se mora utvrditi pozicija
gde je element potrebno uvezati, tj pokazivač ispred pokazuje na čvor koji je ligički
sledeći u odnosu na onog koji se uvezuje, a pokazivač iza pokazuje na čvor koji je logički
prehodnik u odnosu na čvor koji se uvezuje. U slučaju da je potrebno uvezati čvor na kraj
liste, pokazivač ispred imaće vrednost NULL (jer nema logičkog sldbenika), a pokazivač
iza pokazivaće na poslednji element liste. Kada pokazivači iza i ispred sadrže potrebne
adrese, tada je lako izvršiti vezivanje novog elementa.

void formsortlistu(Tcvor **glava)


{
Tcvor *novi, *iza=NULL,* ispred=NULL;
novi= formcvor();

ispred=*glava;
while(ispred!=NULL&&novi->info.pod>ispred->info.pod)
{
iza=ispred;
ispred=ispred->sledeci;
}
novi->sledeci=ispred;
if(*glava==ispred) *glava=novi;
else iza->sledeci=novi;
}

U ovom primeru smatralo se da informacioni sadržaj čvora liste sadrži podatak pod
koji će učestvovati u ispunjavanju uslova kriterijuma sortiranja. Može više podataka
učestvovati u kriterijumima sortiranja, ali tada je potrebno modifikovati datu funkciju u
while uslovu. Iteratifni postupak formiranja jednostruko spregnute liste može se opisati
kroz četiri slučaja.

Prvi slučaj:
U prvom slučaju lista je prazna, te se novi čvor dodaje na početak liste.

Drugi slučaj:
U drugom slučaju postoji lista, a element koji se dodaje u listi treba da se uveže na
početak liste. U ovom slučaju while ciklus se nije izvršio ni jednom te pokazivač iza

266
pokazuje na prvi cvor liste, gde i pokazivač glava, a kako liste ima to im je vrednost
različita od NULL.

Treći slučaj:
U ovom slučaju čvor treba uvezati na kraj liste. To se zaključilo na osnovu vrednosti
pokazivača iza i ispred nakon završetka while ciklusa. Pokazivač iza pokazivaće na rep
liste, a pokazivač ispred imaće vrednost NUUL.

267
Četvrti slučaj:
U ovom slučaju nakon završetka while ciklusa pokazivači iza i ispred su različiti od
NULL, a to je znak da je novi element potrebno uvezati negde na sredinu liste (nije
početak, a nije ni kraj liste). Pokazivač ispred pokazivaće na čvor koji je logički
sledbenik u odnosu na element koji se uvezuje u listu, a pokazivač iza pokazivaće na čvor
koji je logički prethodnik u odnosu na element koji se uvezuje u listu.

7.4.2.2. Formiranje sortirane jednostruko spregnute liste


rekurzivnim postupkom

268
Rekurzivni postupak znači da je funkcija kojom se formira sortirana jednostruko
spregnuta lista rekurzivna (poziva sama sebe). Funkcija formsortlistrek je rekurzina i u
sebi poziva funkciju dodajnapocetakliste koja je malo modifikovana. Formiran je već
objekat koji treba da se uveže u listu a na njega pokazuje pokazivač novi.

void dodajnapocetakliste(Tcvor **glava, Tcvor *novi)


{
if(*glava==NULL) *glava=novi;
else{
novi -> sledeci=*glava;
*glava=novi;
}
}

void formsortlistrek(Tcvor **glava, Tcvor *novi)


{
if(*glava==NULL || (*glava)->info.pod>novi->info.pod)
dodajnapocetakliste(*glava, novi);
else formsortlistrek((*glava)->sledeci,novi);
}

Prilikom rekurzivne realizacije formiranja jednostruko spregnute liste u suštini se


vrši uvek dodavanje na početak liste, na koga pokazuje pokazivač glava koji se nalazi u
aktivacionom zapisu na STEK-u.

Prvi slučaj:
U prvom slučaju lista je prazna, te se novi element uvezuje na stvarni početak liste.
Izvrseno je prosledjivanje pokazivača glava po referenci na stek, te se prvi element liste
vezuje na početak liste

Drugi slučaj:
U drugom slučaju element se ne uvezuje na stvarni početak liste. Kako se poziva
rekurzivna funkcija, to će kada se zadovolje uslovi iskakanja iz rekurzije, pokazivač
glava iz poslednjeg aktivacionog zapisa pokazivati na logičkog sledbenika u odnosu na
element koga treba uvezati u listu. Znači da će se izvršiti uvezivanje na početak liste u
odnosu na pokazivač glava iz poslednjeg aktivacionog zapisa.

269
270
Nakon uvezivanja završava se poslednje pozvana rekurzivna funkcija, a kako
ispod nje nema naredbi završiće se prethodno pozvana rekurzivna funkcija, itd. Znači
brisaće se jedan po jedan aktivacioni zapisa sa steka.

271
Primer:
U tekstualnoj datoteci POLINOM.TXT nalaze se polinomi. Svaki red datoteke
sadrži jedan polinom. Polinom je opisan sa nizom uređenih parova
(a k , x k ), k  [1..n]  k  N  n  N . Nacrtati najjednostavniji i ujedno najefikasniji
strukturni dijagram (uz objašnjenje zašto baš on) i na osnovu njega napisati C program
koji na osnovu datoteke izračunava rezzultujući polinom, kao zbir svih polinoma koje
sadrži datoteka. Na kraj datoteke dodati liniju kojom se podvlači crta, a ispod crte
štampati i rezultujući polinom.

Rešenje

#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>

typedef struct cvor{


int ko;
int step;
struct cvor *sledeci;
}Tcvor;

void dodaj(Tcvor **glava, char *s);


void upis(Tcvor **glava,int ko,int step);
void ispis(Tcvor **glava,FILE *dat);

void main(void)
{
textmode(3);
textcolor(9);
textbackground(0);
clrscr();

Tcvor *glava=NULL;
FILE *dat;
char s[81];

if((dat=fopen("POLINOM.TXT","r+"))==NULL)
{
gotoxy(5,5);
printf("Ne moze otvoriti datoteku!");

272
}

/* Ucitava se red po red datoteke i vrsi sabiranje polinoma. Sabiranje vise polinoma vrsi
se ne polinom po polinom, vec clan po clan polinoma. Na ovaj nacin polinom ne mora
biti u datoteci sortiran po opadajucim vrednostima stepena. Rezultujuci polinom
predstavljace ce sortiranu jednostruko spregnutu listu po stepenima polinoma u
opadajucem redosledu. Svaci cvor liste predstavljace jedan clan polinoma. Funkcija dodaj
dobija string koji sadrzi jedan polinom, ali se lista formira tako sto se iz stringa izdvaja
clan po clan polinoma i ubacuje u listu ako takvog stepena nema, ili se sabira sa
odgovarajucim clanom koji ima isti stepen. */

while(fgets(s,80,dat)!=NULL) dodaj(&glava,s);

/* Ispisuje se rezultujuci polinom u datoteci. */


ispis(&glava,dat);
fclose(dat);

printf("\n\n\t\tPosao je obavljen!!");
getch();
}

void dodaj(Tcvor **glava, char *s)


{
char prvis[20],drugis[20];
int i,j,prvi=0,drugi=0,max;

max=strlen(s);
i=0;
while(i<max-2)
{
prvis[0]=drugis[0]='\0';
i++,j=0;
while((s[i]==','||s[i]=='('||s[i]==')')&&i<strlen(s)) i++;
while((s[i]!=',')&&i<strlen(s)) prvis[j]=s[i],i++,j++;
prvis[j]='\0';

/* Promenljiva prvi sadrzi koeficijent, a promenljiva drugi stepen jednog clana


polinoma. */

prvi=atoi(prvis);
j=0,i++;
while(s[i]!=')') drugis[j]=s[i],i++,j++;
drugis[j]='\0';
drugi=atoi(drugis);

/* Ako je koeficijent clana polinoma nula nece se promeniti rezultat. */


if(prvi!=0) upis(&(*glava),prvi,drugi);
}
}

void upis(Tcvor **glava,int ko,int step)

273
{
Tcvor *novi=NULL,*tek=*glava,*pret=*glava;
novi=(Tcvor *)malloc(sizeof(Tcvor));
novi->ko=ko;
novi->step=step;
novi->sledeci=NULL;

if(*glava==NULL) *glava=novi;
else{
/* Koristi se ista tehnika kao i kod formiranja sortirane liste. */
while((novi->step < tek->step )&&tek!=NULL) pret=tek, tek=tek->sledeci;

/* Ako postoji polinom sa istim stepenom sabiraju im se koeficijenti. */


if((novi->step == tek->step)&&tek!=NULL) tek->ko=tek->ko+novi->ko;
else{
/* Ako takvog stepena nema cvor se uvezuje u listu. */
novi->sledeci=tek;
if(tek==*glava) *glava=novi;
else pret->sledeci=novi;
}
}
}

void ispis(Tcvor **glava,FILE *dat)


{
Tcvor *tek=*glava;
int i=0;

/* Prvo se na kraju datoteke doda jedan red sa crticama, a ispod ispise SAB = */
fprintf(dat,"\n");
for(i=1;i<=39;i++) fprintf(dat,"-");
fprintf(dat,"\nSAB = ");

/* Rezultujuci polinom se nalazi u sortiranoj listi. Uzima se clan po clan polinoma i


ispisuje u istom formatu kao sto su i ostali polinomi u datoteci. Nakon upisa cvor liste se
brise. */

while(*glava!=NULL)
{
tek=*glava;
if((*glava)->ko!=0) fprintf(dat,"(%d,%d)",(*glava)->ko,(*glava)->step);
*glava=tek->sledeci;
tek->sledeci=NULL;
free(tek);
if(*glava!=NULL&&(*glava)->ko) fprintf(dat,",");
}
}

274
Test primer:

POLINOM.TXT (PRE STARTOVANJA PROGRAMA)

(2,5),(2,1),(3,0)
(1,4),(9,0)

POLINOM.TXT (POSLE STARTOVANJA PROGRAMA)

(2,5),(2,1),(3,0)
(1,4),(9,0)
---------------------------------------
SAB = (2,5),(1,4),(2,1),(12,0)

7.5. STEK
Realizacija stek-a pomoću niza
Realizacija stek-a pomoću jednostruko spregnute liste

Stek je poludinamička struktura podataka. Može se realizovati pomoću niza ili


jednostruko spregnute liste. Kod steka je dostupna samo poslednje dodata vrednost
(za koju se kaže da je na vrhu steka). Sa steka se uklanja poslednji dodani element.
Na steku su definisane dve operacije:
 dodavanje elementa na stek (push), i
 skidanje elementa sa steka (pop).

275
vrh

Prilikom realizacije steka jednostruko spregnutom listom,


info stek je opisan sa čvorovima liste i pokazvača na prvi čvor liste
koji se zove pokazivač na vrh steka. Funkcijom push novi
objekat se dodaje na stek dodavanjem na početak liste. Prilikom
info korišćenja funkcije pop funkcija fraća kao rezultat podatke sa
objekta koji je prvi član liste i briše prvi čvor liste uz oslobađanje
memorije koju je taj čvor zauzeo.
info
NULL

Primer 1:
Napisati C program koji vrši ažuriranje tekstualne datoteke REDOVI.TXT
primenom steka (ealizovanog pomoću niza). U svakom redu datoteke nalaze se podaci o
jednom učeniku. Nije potrebno obrađivati te podatke već treba datoteku ažurirati u
inverznom poretku po redovima.

Na primer:

REDOVI.TXT Preuređena datoteka REDOVI.TXT

Beg Marijan 5.00 Prljević Slobodan 4.50


Makan Dalibor 4.93 Savin Nikola 2.93
Savin Nikola 2.93 Makan Dalibor 4.93
Prljević Slobodan 4.50 Beg Marijan 5.00

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>

/* Definise se struktura Tredovi koja ima samo jedno polje. */


typedef struct redovi{
char s[81];
}Tredovi;

/* Prototipovi funkcija. */
unsigned push(FILE *dat, Tredovi niz[], int *n);
unsigned pop(FILE *dat, Tredovi niz[], int *n);

void main(void)
{

276
/* Deklaracija promenljivih. */
FILE *dat;
int vrh=0,i;
Tredovi niz[100]; /* Promenljiva niz je niz struktura. */

/* Inicijalizacija niza. */
for(i=0;i<100;i++) strcpy(niz[i].s,"");

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

/* Otvaranje datoteke za citanje. */


if((dat=fopen("REDOVI.TXT","r"))==NULL)
{
printf("Datoteka REDOVI.TXT se ne moze otvoriti!!");
getch();
return;
}

printf("Datoteka REDOVI.TXT je uspesno otvoren!!");

/* Smestanje datoteke na stek red po red funkcijom push. */


while(push(dat,niz,&vrh));
fclose(dat);

/* Datoteka se ponovno otvara sada za pisanje i time se predhodni sadrzaj datoteke brise.
*/

dat=fopen("REDOVI.TXT","w");

/* Uzimaju se podaci iz niza u suprotnom redosledu. */


while(pop(dat,niz,&vrh));

fclose(dat);
printf("\n\nU datoteku REDOVI.TXT upisani su redovi u obrnutom redosledu!!");

gotoxy(1,25);
getch();
}

/* Funkcija omogucava ucitavanje jednog reda iz datoteke i upisivanje u niz. Funkcija


vraca jedan ako je uspesno dodala element na stek ili 0 u suprotnom. */

unsigned push(FILE *dat, Tredovi niz[], int *vrh)


{
char s[81]="";

if(fgets(s,80,dat)!=NULL)

277
{
/* Potrebno je da poslednji karakter stringa bude '\n' da ne bi bilo iznenadjenja
prilikom formiranja nove datoteke. */

if(s[strlen(s)-1]!='\n') strcat(s,"\n");

/* Vrh steka predstavlja indeks vrh. */


strcpy(niz[*vrh].s,s);
(*vrh)++;

return 1;
}

return 0;
}

/* Funkcija pop omogucava uzimanje podatka sa steka i to samo onog koji je poslednji unet
na stek. Funkcija vraca 0 ako je stek prazan ili 1 u suprotnom. */
unsigned pop(FILE *dat, Tredovi niz[], int *n)
{

(*n)--;
if((*n)<0) return 0;

/* Upis reda u datoteku. */


fprintf(dat,"%s",niz[*n].s);

return 1;
}

Primer 2:
Napisati C program koji vrši ažuriranje tekstualne datoteke REDOVI.TXT
primenom steka (realizovanog pomoću jednostruko spregnute liste). U svakom redu
datoteke nalaze se podaci o jednom učeniku. Nije potrebno obrađivati te podatke već
treba datoteku ažurirati u inverznom poretku po redovima.

Na primer:

REDOVI.TXT Preuređena datoteka REDOVI.TXT

Beg Marijan 5.00 Prljević Slobodan 4.50


Makan Dalibor 4.93 Savin Nikola 2.93
Savin Nikola 2.93 Makan Dalibor 4.93
Prljević Slobodan 4.50 Beg Marijan 5.00

Rešenje

#include <stdio.h>

278
#include <conio.h>
#include <string.h>
#include <stdlib.h>

/* Definise se struktura Tredovi koja ima samo jedno polje. */


typedef struct cvor{
char s[81];
struct cvor *sledeci;
}Tcvor;

/* Prototipovi funkcija. */
unsigned push(FILE *dat, Tcvor **vrh);
unsigned pop(FILE *dat, Tcvor **vrh);

void main(void)
{

/* Deklaracija promenljivih. */
FILE *dat;
Tcvor *vrh=NULL, *glava=NULL;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

/* Otvaranje datoteke za citanje. */


if((dat=fopen("REDOVI.TXT","r"))==NULL)
{
printf("Datoteka REDOVI.TXT se ne moze otvoriti!!");
getch();
return;
}
printf("Datoteka REDOVI.TXT je uspesno otvoren!!");

/* Smestanje datoteke na stek red po red funkcijom push. */


while(push(dat,&glava));
fclose(dat);

/* Datoteka se ponovno otvara sada za pisanje i time se predhodni sadrzaj datoteke brise.
*/

dat=fopen("REDOVI.TXT","w");

/* Uzimaju se podaci sa pocetka liste. */


while(pop(dat,&vrh));

fclose(dat);
printf("\n\nU datoteku REDOVI.TXT upisani su redovi u obrnutom redosledu!!");

279
getch();
}

/* Funkcija omogucava ucitavanje jednog reda iz datoteke i upisivanje u niz. Funkcija


vraca jedan ako je uspesno dodala element na stek ili 0 u suprotnom. */
unsigned push(FILE *dat, Tcvor **vrh)
{
char s[81]="";
Tcvor *novi;

if(fgets(s,80,dat)!=NULL)
{
if(s[strlen(s)-1]!='\n') strcat(s,"\n");

novi=(Tcvor *)malloc(sizeof(Tcvor));
strcpy(novi->s,s);
novi->sledeci=NULL;

/* Vrh steka je vrh pokazivac na pocetak liste. */


if(*vrh == NULL) *vrh=novi;
else{
novi->sledeci=*vrh;
*vrh=novi;
}

return 1;
}
return 0;
}

/* Funkcija pop omogucava uzimanje podatka sa steka i to samo onog koji je poslednji unet
na stek. Funkcija vraca 0 ako je stek prazan ili 1 u suprotnom. */
unsigned pop(FILE *dat, Tcvor **vrh)
{
Tcvor *tek;

if(*vrh==NULL) return 0;

/* Upis reda u datoteku. */


fprintf(dat,"%s",(*vrh)->s);

/* Brise se prvi cvor iz liste i oslobadja zauzeta memorija. */


tek=*vrh;
*vrh=tek->sledeci;
tek->sledeci=NULL;
free(tek);

return 1;
}

280
Primer 3:
Zadata je tekstualna datoteka PRIMER.TXT. Korišćenjem dinamičke strukture podataka
STEK formirati izlaznu datoteku IZLAZ.TXT gde će biti zapisana datoteka PRIMER.TXT u
invernom poretku po pasusima. Između pasusa postoji prazan red.
Rešenje:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

/* Definisanje cvora steka. */


typedef struct stek{
char rec[3000];
struct stek *sled;
}Tcvor;

void push(Tcvor **vrh,char *s); /* Dodavanje cvora na stek. */


char *pop(Tcvor **vrh); /* Uzimanje podatka sa steka uz oslobadjanje zauzete memorije. */

void main(void)
{
FILE *dat;
Tcvor *vrh=NULL;
int br=0;
char s1[101]="",s[3000]="", *pok;

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

if((dat=fopen("PRIMER.TXT","r"))==NULL)
{
printf("\n\n\t\tDatoteka %s se ne moze otvoriti!!");
return;
}

/* Ucitava se red po red iz tekstualne datoteke. Ako je red prazan kraj je pasusa i
formirani string s se upisuje na sek. Promenljivom br brojimo koliko datoteka sadrzi
pasusa. Ako red nije prazan nadoveyuje se na kraj stringa s. */

while(fgets(s1,100,dat)!=NULL)
{
if(!strcmp(s1,"\n"))
{
br++;
push(&vrh,s);
printf("%s",vrh->rec);
getch(); clrscr(); strcpy(s,"");
}else strcat(s,s1);

281
}
fclose(dat);
/* Otvara se datoteka za pisanje i upisuju se pasusi sacuvani na steku. */
dat=fopen("IZL.TXT","w");
while((pok=pop(&vrh))!=NULL) fprintf(dat,"%s\n",pok), pok=NULL;
}

void push(Tcvor **vrh,char *s)


{
Tcvor *novi;

novi=(Tcvor *)malloc(sizeof(Tcvor));
strcpy(novi->rec,s); novi->sled=NULL;

if((*vrh)==NULL) *vrh=novi;
else{
novi->sled=*vrh;
*vrh=novi;
}
}

char *pop(Tcvor **vrh)


{
Tcvor *tek;
char *pok;

if(*vrh==NULL) return NULL;


tek=*vrh;
*vrh=(*vrh)->sled;
pok=tek->rec;
free(tek);

return pok;
}

7.6. STEK I REKURZIJA

Algoritamske tehnike mogu se podeliti u dve grupe: iterativnu i rekurzivnu.


Svaki problem može se rešiti iterativnom ili rekurzivnom tehnikom. Koja će se
tehnika primeniti zavisi od problema koji se rešava.
Jedan od tipičnih zadataka gde se rekurzija koristi je pretraživanje sa vraćanjem.
Primer korišćenja tehnike pretraživanje sa vraćanjem je lavirint, koji ima jedan ulaz, a
više izlaza, te je potrebno prikazati sve puteve izlaska iz lavirinta.

Primer:
U tekstualnoj datoteci LAVIRINT.TXT nalazi se mapa lavirinta. U prvom redu su
dimenzije matrice lavirinta, a u sledećim redovima je matrica lavirinta. Elemente lavirinta
čine brojevi od 0-3, čija su značenja:

282
0 - hodnik;
1 - zid;
2 - ulaz u lavirint; i
3 - izlaz iz lavirinta

Lavirint ima samo jedan ulaz koji se nalazi na krajevima matrice, i više izlaza koji
se nalaze takođe na krajevima matrice (prva vrsta, zadnja vrsta, prva kolona, zadnja
kolona). Potrebno je prikazati sve moguće puteve izlaska iz lavirinta. Sa pritiskom na bilo
koji taster prikazuje se sledeći put izlaska (sledeće rešenje).
Zadatak rešiti rekurzivnom tehnikom.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>

#define MAXX 70
#define MAXY 15

/* Prototipovi funkcija. */
void maska(int m[MAXX][MAXY], int *vr, int *kol, int *startx, int *starty, int *poci,
int *pocj);
void crtaj(int m[MAXX][MAXY], int vr, int kol, int startx, int starty);
void nadji(int m[MAXX][MAXY], int i, int j, int vr, int kol, int startx, int starty);
int moze(int m[MAXX][MAXY], int i, int j, int vr, int kol);
void pisi(int m[MAXX][MAXY], int vr, int kol, int startx, int starty);

void main(void)
{
/* Matrica lavirinta je m, vr je broj vrsta, kol je broj kolona, poci i pocj su indeksi u
matrici gde je ulaz, a startx i starty cine pocetnu poziciju na ekranu. */

int i,j,vr=0,kol=0,m[MAXX][MAXY],poci,pocj;
int startx=0,starty=0;

for(i=0;i<MAXX;i++)
{
for(j=0;j<MAXY;j++) m[i][j]=0;
}

textmode(3);
textcolor(15);
textbackground(15);

283
clrscr();
textcolor(4);
_setcursortype(_NOCURSOR);

gotoxy(36,2);
cprintf("LAVIRINT");

/* Crta se lavirint na ekranu. */


maska(m,&vr,&kol,&startx,&starty,&poci,&pocj);
textcolor(2);

/* Prikazuju se sva moguca resenja. */


nadji(m,poci,pocj,vr,kol,startx,starty);
}

/* Funkcija crta lavirint. Nema povratnu vrednost. Formira matricu ucitavanjem podataka iz
datoteke. */
void maska(int m[MAXX][MAXY], int *vr, int *kol, int *startx, int *starty,
int *poci, int *pocj)
{
FILE *dat;
char s[81],*pok;
int i,j;

if((dat=fopen("LAVIRINT.TXT","r"))==NULL)
{
gotoxy(35,12);
printf("Datoteka LAVIRINT.TXT se ne moze otvoriti!!");
return;
}

/* Ucitava se prvi red datoteke i utvrdjuje broj vrsta i kolona. */


fgets(s,80,dat);
pok=strtok(s," ");
*vr=atoi(pok);
pok=strtok(NULL,"\n");
*kol=atoi(pok);

/* Odredjuju se startne pozicije gornjeg ugla lavirinta tako da lavirint bude uvek na
sredini ekrana. */

*startx=41-3*(*kol)/2;
*starty=12-(*vr)/2;

/* Formira se matrica lavirinta ucitavanjem podataka iz datoteke. */


for(i=0;i<*vr;i++)
{
fgets(s,81,dat);
for(j=0;j<*kol;j++)
{
m[i][j]=s[j]-48;

284
if(m[i][j]==2) *poci=i, *pocj=j;
}
}
fclose(dat);

/* Pozova se funkcija crtaj koja na osnovu matrice lavirinta crta lavirint. */


crtaj(m,*vr,*kol,*startx,*starty);
}

/* Funkcija crtaj na osnovu matrice lavirinta prikazuje lavirint na ekranu. */


void crtaj(int m[MAXX][MAXY], int vr, int kol, int startx, int starty)
{
int i,j;

for(i=0;i<vr;i++)
{
gotoxy(startx,starty+i);
for(j=0;j<kol;j++)
{
if(m[i][j]==1)
{
textbackground(0);
textcolor(1);
cprintf("²²²");
}

if(m[i][j]==0)
{
textbackground(0);
textcolor(15);
cprintf(" ");
}
if(m[i][j]==2)
{
textbackground(0);
textcolor(2);
cprintf(" $ "); /* Sa karakterom $ oznacice se covek u lavirintu.
*/
}
if(m[i][j]==3)
{
textbackground(0);
textcolor(2);
cprintf("IZL");
}
}
}

285
/* Funkcija nadji je glavna funkcija jer utvrdjuje i prikazuje na ekranu sve puteve izlaska iz
lavirinta. Rekurzivna je funkcija, nema unutar lokalnih promenljivih kako se stek ne bi
opteretio.*/

void nadji(int m[MAXX][MAXY], int i, int j, int vr, int kol, int startx, int starty)
{
/* Ako se u matrici upise vrednost 4 znaci da je covek na toj poziciji bio. */
if(m[i][j]==0) m[i][j]=4;

/* Ako se nadje na granici lavirinta i tu je ujedno izlaz funkcijom pisi ispisuje se resenje.
*/

if((i==0||i==vr-1||j==0||j==kol-1)&&m[i][j]==3) pisi(m,vr,kol,startx,starty);
else{

/* Redom se proverava i pomera gde moze, te zbog rekurzije sa gornjim if-om


upisuje 4 da je tu bio ako je mogao da bude. */

if(moze(m,i+1,j,vr,kol)) nadji(m,i+1,j,vr,kol,startx,starty);
if(moze(m,i-1,j,vr,kol)) nadji(m,i-1,j,vr,kol,startx,starty);
if(moze(m,i,j+1,vr,kol)) nadji(m,i,j+1,vr,kol,startx,starty);
if(moze(m,i,j-1,vr,kol)) nadji(m,i,j-1,vr,kol,startx,starty);
}
/* Ako nije ulaz ili izlaz znaci da je bio po drugi put, to je taj deo puta slep i upisuje se 0
kao da tu i nije bio. */

if(m[i][j]!=2&&m[i][j]!=3) m[i][j]=0;
}

/* Funkcija moze utvrdjuje da li se covek moze naci na toj poziciji, te ako moze vraca 1 a u
suprotnom 0. */
int moze(int m[MAXX][MAXY], int i, int j, int vr, int kol)
{
return i>=0&&i<vr&&j>=0&&j<kol&&(m[i][j]==0||m[i][j]==3);
}

/* Funkcija pisi prikazuje nadjeni put izlaska iz lavirinta. */


void pisi(int m[MAXX][MAXY], int vr, int kol, int startx, int starty)
{
int i,j;

/* Prolazi se kroz matricu lavirinta i tamo gde se u matrici nalazi broj 4 znaci da je tu
covek bio te se ispisuje crveni $. */
for(i=0;i<vr;i++)
{
for(j=0;j<kol;j++)
{
if(m[i][j]==4)
{
gotoxy(startx+1+3*j,starty+i);

286
textcolor(4);
cprintf("$");
}
}
}
while(!kbhit()); /* Dok ne pritisnes taster gledaj resenje. */

/* Sada je potrebno izbrisati predhodno resenje. */


textbackground(0);
for(i=0;i<vr;i++)
{
for(j=0;j<kol;j++)
{
gotoxy(startx+1+3*j,starty+i);
if(m[i][j]==4) cprintf(" ");
}
}
getch();
}

7.7. DINAMIČKA STRUKTURA PODATAKA RED

Red je dinamička struktura podataka čija je struktura slična steku. Osnovna


razlika između ove dve strukture je što se redovi indentifikuju sa dva pokazivača:
glava koji pokazuje na logički prvi čvor liste i rep koji pokazuje na logički poslednji
čvor liste (rep liste). Kod steka elemenat se može uzimati i dodavati samo sa vrha
steka. Kod redova element se dodaje na kraj reda, a uzima sa vrha reda. Koristi se
kada je potrebno zadržati hronološki redosled unosa elemenata.

287
Za razliku od jednostruko spregnute liste omogućeno je lakše dodavanje elementa
na kraj liste. Prilikom dodavanja elementa na kraj jednostruko spregnute liste moralo se
sa pomoćnim pokazivačem doći do repa liste, prolaskom kroz celu listu, kako bi se
element vezao na kraj liste.

Primer 1:
Zadata je tekstualna datoteka RECI.TXT pri čemu se u svakom redu datoteke
nalazi tačno jedna reč. Jedna reč može se pojavljivati u više redova datoteke. Formirati
dinamičku strukturu podataka RED, a potom na osnovu nje formirati izlaznu datoteku
IZL.TXT pri čemu se u svakom redu datoteke nalazi po jedna reč i broj njenog
pojavljivanja u datoteci RECI.TXT.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>

typedef struct info{


char rec[30];
unsigned brojpojava;
}Tslog;

typedef struct cvor{


Tslog info;
struct cvor *sled;
}Tcvor;

void main(void)
{

288
FILE *dat;
Tcvor *glava=NULL, *rep=NULL, *novi, *tek;
char s[30];

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

if((dat=fopen("RECI.TXT","r"))==NULL)
{
printf("\n\n\t\tDatoteka se ne moze otvoriti!!");
return;
}

/* Ucitava se red po red iz datoteke. */


while(fgets(s,30,dat)!=NULL)
{
/* Ako je poslednji karakter '\n' brise se iz stringa, radi kasnijeg ispravnog
prikaza redova u datoteci. */
if(s[strlen(s)-1]=='\n') s[strlen(s)-1]='\0';

/* Utvrdjuje se da li takve reci ima u listi. */


tek=glava;
while(tek!=NULL&&strcmp(s,tek->info.rec)) tek=tek->sled;

/* Ako reci nema formira se novi cvor reda, a u suprotnom brojac reci se
povecava za jedan. */

if(tek==NULL)
{
novi=(Tcvor *)malloc(sizeof(Tcvor));
strcpy(novi->info.rec,s);
novi->info.brojpojava=1;
novi->sled=NULL;

if(glava==NULL) glava=novi, rep=novi;


else rep->sled=novi, rep=novi;
}else tek->info.brojpojava++;
}
fclose(dat);

/* Otvara se izlazna datoteka i podaci se iz reda upisuju u datoteku uz brisanje cvorova


reda i oslobadjanje zauzete memorije. */

dat=fopen("IZL.TXT","w");
tek=glava;

while(tek!=NULL)
{

289
fprintf(dat,"%s\t\t%d\n",tek->info.rec,tek->info.brojpojava);
tek=tek->sled;
free(glava);
glava=tek;
}
fclose(dat);

printf("\n\n\t\tPosao je obavljen!!");
getch();
}

Primer 2:
Zadata je tekstualna datoteka RACUNI.TXT. U svakom redu datoteke nalazi se po
jedan račun u formatu:

Šifra # Prezime # Ime # Uplata-isplata(U/I) # iznos uplate

U datoteci se može nalaziti više uplata i isplata sa istom šifrom. Na osnovu ulazne
datoteke formirati dinamičku strukturu podataka RED.
Nakon formiranja reda (ne može više članova reda imati istu šifru), izvršiti njegovo
sortiranje u rastućem redosledu, ali bez korišćenja dodatnih čvorova i objekata.
Na osnovu dinamičke strukture, formirati izlaznu datoteku IZRAC.TXT u kojoj će
biti prikazani podaci sortirani u rastućem redosledu po kriterijumu stanje na računu.

Rešenje

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

typedef struct slog{


char sifra[5];
char prezime[20];
char ime[20];
double iznos;
}Tslog;

typedef struct cvor{


Tslog info;
struct cvor *sled;
}Tcvor;

/* definisanje prototipova funkcija. */


void ubaci(Tcvor **glava, Tcvor **rep, char *s);
void uredi(Tcvor **glava, Tcvor **rep);
void formdat(Tcvor **glava, Tcvor **rep);

void main(void)

290
{
FILE *dat;
Tcvor *glava=NULL, *rep=NULL;
char s[100];

textmode(3);
textbackground(0);
textcolor(15);
clrscr();

if((dat=fopen("RACUNI.TXT","r"))==NULL)
{
printf("Datoteka RACUNI.TXT se ne moze otvoriti!!");
return;
}

/* Ucitava se red po red datoteke i uvezuje u red. */


while(fgets(s,100,dat)!=NULL) ubaci(&glava,&rep,s);
fclose(dat);

/* Vrsi se preuredjivanje reda tako da postane sortiran u opadajucem redosledu. */


uredi(&glava,&rep);

/* Formira se izlazna datoteka uz brisanje cvorova reda i oslobadjanje zauzete


memorije. */
formdat(&glava,&rep);

printf("\n\n\t\tPosao je obavljen!!");
getch();
}

void ubaci(Tcvor **glava, Tcvor **rep, char *s)


{
Tcvor *novi, *tek;
Tslog pom; /* Promenljiva pom je pomocna promenljiva i sluzi za privremeno smestanje
podataka jednog racuna. */
char *pok=s, ui[2];

/* Izdvajaju se podaci jednog racuna iz stringa. */


pok=strtok(s,"#"); strcpy(pom.sifra,pok);
pok=strtok(NULL,"#"); strcpy(pom.prezime,pok);
pok=strtok(NULL,"#"); strcpy(pom.ime,pok);
pok=strtok(NULL,"#"); strcpy(ui,pok);
pok=strtok(NULL,"#"); pom.iznos=atof(pok);

/* Utvrdjuje se da li postoji u listi takva sifra. */


tek=*glava;
while(tek!=NULL&&strcmp(tek->info.sifra,pom.sifra)) tek=tek->sled;

if(tek==NULL)

291
{
/* Ako sifra ne postoji, formira se objekat i uvezuje u red. */
novi=(Tcvor *)malloc(sizeof(Tcvor));
novi->info=pom;

/* Kako ranije nije bilo objekta sa takvom sifrom, u slucaju da je vrsena isplata,
stanje na njegovom racunu bice u minusu. */
if(!strcmp(ui,"I")) novi->info.iznos*=-1;
novi->sled=NULL;

/* Vrsi se uvezivanje cvora u red. */


if(*glava==NULL) *glava=novi, *rep=novi;
else (*rep)->sled=novi, *rep=novi;
}else{
/* Ako postoji takva sifra, nastaje promena stzanja racuna, pri čemu se prilikom
uplate stanje na racunu uvecava, a prilikom isplate umanjuje. */

if(!strcmp(ui,"U")) tek->info.iznos+=pom.iznos;
else tek->info.iznos-=pom.iznos;
}
}

void uredi(Tcvor **glava, Tcvor **rep)


{
Tcvor *glava1=NULL, *rep1=NULL, *pret, *tek;
double min;

/* Prevezivacemo pokazivace tako da ce nastati novi red. Pronalazimo u ciklusu cvor


reda koji ima najmanje stanje na racunu i njega uvezujemo u novi red, a izbacujemo bez
fizičkog brisanja iz starog reda. Kada stari red ne bude imao cvorova novonastali red bice
sortirani red u rastucem redosledu. */

while(*glava!=NULL)
{
/* Pomocu pokazivaca tek prolazimo kroz red, a nakon prolaska pokazivac pret
ce pokazivati na cvor sa najmanjim stanjem u redu. */

tek=pret=*glava;
min=tek->info.iznos;
while(tek!=NULL)
{
if(tek->info.iznos < min)
{
min=tek->info.iznos;
pret=tek;
}
tek=tek->sled;
}

/* Sada se taj cvor uvezuje u novi red, gde je pokazivac na prvi cvor glava1, a
pokazivac na rep rep1. */

292
if(glava1==NULL) glava1=pret, rep1=pret;
else rep1->sled=pret, rep1=pret;

/* Vrsi se izbacivanje cvora iz stare liste. Mogu se razdvojiti tri slucaja: Izbacuje
se prvi cvor reda, izbacuje se poslednji logicki cvor reda i izbacuje se cvor reda
koji nije logicki prvi a ni logicki poslednji cvor. */

if(pret==*glava)
{
/* Izbacuje se logicki prvi cvor reda. */
*glava=(*glava)->sled;
pret->sled=NULL;

}else{
/* Izbacuje se logicki poslednji cvor reda. */
if(pret==*rep)
{
*rep=*glava;
while((*rep)->sled!=pret) *rep=(*rep)->sled;
(*rep)->sled=NULL;
}else{
/* Izbacuje se cvor reda koji nije logicki prvi niti logicki
poslednji cvor reda. */

tek=*glava;
while(tek->sled!=pret) tek=tek->sled;
tek->sled=pret->sled;
pret->sled=NULL;
}
}
}

/* Sada postoji samo novi red, te je potrebno pokazivace koji spolja opisuju red promeniti
tako da ispravno pokazuju na prvi, odnosno poslednji cvor reda. */

*glava=glava1, *rep=rep1;
}

void formdat(Tcvor **glava, Tcvor **rep)


{
FILE *dat;
Tcvor *tek;

/* Prolazi se kroz red i vrsi upisivanje podataka u izlaznu datoteku uz oslobadjanje


zauzete memorije. */
dat=fopen("IZRAC.TXT","w");

tek=*glava;
while(tek!=NULL)
{

293
fprintf(dat,"%5s%20s%20s\t%10.3f\n",
tek->info.sifra,tek->info.prezime,tek->info.ime,tek->info.iznos);
*glava=tek->sled;
tek->sled=NULL;
free(tek);
tek=*glava;
}
*rep=NULL;
}

Test programa:

RACUNI.TXT

12#Maric#Mirko#U#4000.00
123#Petrovic#Milos#I#1500.00
12#Maric#Mirko#I#2000.00
123#Petrovic#Milos#U#1000.00
21#Kozic#Luka#U#10000.00
18#Markovic#Milos#I#5000.00

IZRAC.TXT

18 Markovic Milos -5000.000


123 Petrovic Milos -500.000
12 Maric Mirko 2000.000
21 Kozic Luka 10000.000

7.8. DINAMIČKA STRUKTURA PODATAKA


DVOSTRUKO SPREGNUTA LISTA

294
Često je potrebno od jednog čvora liste doći do njegovog logičkog predhodnika.
Kod jednostruko spregnute liste bilo bi potrebno preći sve članove liste od prvog čvora
do predhodnika. Zbog toga je korisno da svaki čvor, pored pokazivača na sledeći čvor,
poseduje i pokazivač na predhodni čvor liste. Kada čvor liste poseduje dva pokazivača,
jedan na predhodni, a drugi na sledeći čvor liste, kažemo da je u pitanju dvostruko
spregnuta lista.
Kod dvostruko spregnute liste jako je jednostavno kretati se kroz listu u jednom i
drugom smeru. Dvostruko spregnuta lista poseduje i dva spoljašnja pokazivača,
pokazivač na prvi čvor liste za prolazak s leva u desnu i pokazivač na poslednji čvor liste
za prolazak s desna na levo.
Prilikom umetanja ili brisanja čvora liste nije potrebno posedovati i dodatne
pokazivače. Prilikom umetanja novog čvora u listu, osim pokazivača koji pokazuje na
objekat koji se umeće u listu i jednog koji pokazuje na čvor liste ispred (ili iza) koga
treba umetnuti novi čvor, nisu potrebni dodatni pokazivači. Prilikom brisanja potrebno je
imati samo pokazivač na čvor koji treba da se izbrise iz liste.
.

info info info info


NULL
NULL

poc kraj

Primer 1:
Zadata je kestualna datoteka BROJEVI.TXT koa u svakom redu sadrži po jedan
racionalan broj. Na osnovu sadržaja datoteke formirati dvostruko spregnutu listu.
Čvor liste je definisan na sledeći način:

typedef struct cvor{


int broj;
unsigned brojpojava;
struct cvor *sled;
struct cvor *pret;
}Tcvor;

Polje brojpojava predstavlja broj pojavljivanja datog broja u datoteci. Na osnovu


dvostruko spregnute liste formirati izlazne tekstualne datoteke RAS.TXT i OPA.TXT.
Datoteka RAS.TXT sadrži brojeve sortirane u rastućem redosledu. Datotek OPA.TXT
sadrži date brojeve sortirane u opadajućem redosledu.
Svaki red datoteka RAS.TXT i OPA.TXT u jednom redu sadrže tačno jedan broj.

Rešenje

#include <stdio.h>

295
#include <conio.h>
#include <stdlib.h>

typedef struct cvor{


int br;
unsigned brpojava;
struct cvor *sled;
struct cvor *pret;
}Tcvor;

void main(void)
{
FILE *dat;
Tcvor *poc=NULL, *kraj=NULL, *novi, *tek;
char s[30];
int i;

textmode(3);
textcolor(15);
textbackground(0);
clrscr();

if((dat=fopen("BROJEVI.TXT","r"))==NULL)
{
printf("\n\n\t\tDatoteka BROJEVI.TXT se ne moze otvoriti!!");
return;
}

while(fgets(s,30,dat)!=NULL)
{
if(poc==NULL)
{
novi=(Tcvor *)malloc(sizeof(Tcvor));
novi->sled=NULL;
novi->pret=NULL;
novi->brpojava=1;
novi->br=atoi(s);
poc=novi;
kraj=novi;
}else{
tek=poc;
while(tek!=NULL&&tek->br>=atoi(s)) tek=tek->sled;

if(tek!=NULL)
{
if(tek->br==atoi(s)) tek->brpojava++;
else{
novi=(Tcvor *)malloc(sizeof(Tcvor));
novi->brpojava=1;
novi->br=atoi(s);
if(tek==poc)

296
{
novi->sled=tek;
tek->pret=novi;
poc=novi, novi->pret=NULL;
}else{
novi->sled=tek;
novi->pret=tek->pret;
tek->pret->sled=novi;
tek->pret=novi;
}
}
}else{
novi=(Tcvor *)malloc(sizeof(Tcvor));
novi->sled=NULL;
novi->brpojava=1;
novi->br=atoi(s);
novi->pret=kraj;
kraj->sled=novi;
kraj=novi;
}
}
}
fclose(dat);

dat=fopen("OPA.TXT","w");
tek=poc;
while(tek!=NULL)
{
for(i=1;i<=tek->brpojava;i++) fprintf(dat,"%d\n",tek->br);
tek=tek->sled;
}
fclose(dat);

dat=fopen("RAS.TXT","w");
tek=kraj;
while(tek!=NULL)
{
for(i=1;i<=tek->brpojava;i++) fprintf(dat,"%d\n",tek->br);
tek=tek->pret;
free(kraj);
kraj=tek;
}
fclose(dat);

printf("\n\n\tPosao obavljen!!");
getch();
}

Primer 2:

297
Zadate su tri binarne datoteke UCENIK.DAT, ISPITI.DAT i POLAGANJE.DAT.
Datoteka UCENIK.DAT je u formatu: evidencioni broj (unsigned), ime i prezime (od
maksimalno 30 karaktera). Datoteka ISPITI.DAT je u formatu: šifra ispita (unsigned) i
naziv ispita od maksimalno 50 karaktera. Datoteka POLAGANJE.DAT je u formatu:
evidencioni broj (unsigned), šifra ispita (unsigned) datum ispita (u obliku dd.mm.gggg) i
ocena (unsigned).
Datoteka POLAGANJE.DAT služi za čuvanje podataka o polaganju svih
vandrednih učenika za bilo koje ispite u nekom proizvoljnom vremenskom periodu.
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program koji za izabranog studenta na osnovu
evidencionog broja štampa na ekranu tabelarni prikaz položenih ispita. U svakom redu po
jedan ispit: Redni broj ispita, Šifra i naziv ispita, Datum polaganja ispita i ocena.
Program ne vrši kontrolu podataka iz binarnih datoteka, jer se smatra da su podaci
ispravni.

Rešenje

U programu je koriscena dinamicka struktura podataka multilista. Formirana je


jednostruko spregnuta lista ciji cvorovi osim informacionog sadrzaja poseduju i dva
pokazivaca: pokazivac na naredni cvor jednostruko spregnute liste i pokazivac na prvi
cvor liste koja izbija iz glavne liste. Glavna lista sadrzi podatke o vandrednim ucenicima.
Liste koje iz datog čvora liste ucenika izbijaju sadrze podatke o polozenim ispitima tog
ucenika. Svaki cvor tih lista odnosi se na podatke vezane za polozeni ispit datog ucenika.

#include<stdio.h>
#include<conio.h>
#include<alloc.h>

#define ESC 27

typedef struct{
unsigned evbroj;
char ime_prezime[30];
}Tucenik; /* Struktura vanrednog ucenika. */

typedef struct{
unsigned evbroj;
unsigned sifra;
char datum[12];
unsigned ocena;
}Tpolaganje; /* Struktura polozenog ispita. */

typedef struct cvorp2{


Tpolaganje info;
struct cvorp2 *dole;
}Tcvorp2; /* Struktura cvora polozenog ispita. */

typedef struct cvorp1{


Tucenik info;

298
struct cvorp1 *sledeci;
struct cvorp2 *dole;
}Tcvorp1; /* Struktura cvora vandrednog ucenika. */

typedef struct{
unsigned sifra;
char naziv[30];
}Tispit; /* Struktura ispita. */

int unos_ceo(void); /* Funkcija omogucava unos celog broja uz kontrolu, a sa ESC se prekida
formiranje broja i vraca vrednost -1 sto oznacava da broj nije formiran. Kraj formiranja broja je
pritisak na taster ENTER. */

Tcvorp1 *trazi(Tcvorp1 *tek,unsigned evbroj); /* Trazi se ucenik na osnovu evidencionog broja.


*/

void main(void)
{
FILE *polaganje,*ucenik,*ispit;
Tcvorp1 *glava;
Tcvorp1 *novi=NULL,*tek=NULL,*pret=NULL;
Tcvorp2 *novi2=NULL,*tek2=NULL,*pret2=NULL;
Tucenik s;
Tpolaganje p;
Tispit t;
char c;
int i, evbroj, kon;

textmode(3);
textbackground(15);
textcolor(1);

do{
clrscr();
cprintf(" Polozeni ispiti za ucenika ");
cprintf(" Ev. broj:");
textbackground(2);
cprintf(" ");
textbackground(15);
cprintf(" Ime i prezime:");
textbackground(2);
cprintf(" ");
textbackground(15);
cprintf(" ");
textbackground(4);
cprintf(" R.br Ispit Datum Ocena ");
textbackground(15);
gotoxy(21,2);
textbackground(2);
/* Unosi se evidencionalni broj ucenika. */
evbroj=unos_ceo();

299
if(evbroj==-1) return;
textbackground(15);
glava=NULL;
ucenik=fopen("UCENIK.DAT","r+b");

/* Ucitavaju se podaci o ucenicima iz binarne datoteke. */


while(fread(&s,sizeof(s),1,ucenik))
{
/* Formira se cvor o uceniku. */
if(s.evbroj==evbroj) gotoxy(48,2),puts(s.ime_prezime);
novi=(Tcvorp1*)malloc(sizeof(Tcvorp1));
novi->sledeci=NULL;
novi->dole=NULL;
novi->info=s;

/* Vrsi se uvezivanje cvora na kraj liste. */


if(glava==NULL) glava=novi;
else{
tek=pret=glava;
while(tek!=NULL) pret=tek, tek=tek->sledeci;
pret->sledeci=novi;
}
}
fclose(ucenik);

/* Otvara se datoteka sa polozenim ispitima. */


polaganje=fopen("POLAGANJE.DAT","r+b");
while(fread(&p,sizeof(p),1,polaganje))
{
/* Formira se cvor o polozenom ispitu. */
novi2=(Tcvorp2*)malloc(sizeof(Tcvorp2));
novi2->dole=NULL;
novi2->info=p;

/* Vrsi se uvezivanje cvora na kraj liste polozenih ispita. */


tek=glava;
while(tek!=NULL)
{
/* Pronalazi se ucenik sa istim evidencionim brojem. */
if(novi2->info.evbroj==tek->info.evbroj)
{
if(tek->dole==NULL) tek->dole=novi2;
else{

/* Prolazimo kroz listu polozenih ispita.


Moramo koristiti pokazivace tek2 i pret2 koji
mogu da pokazuju na cvorove polozenih ispita.
Sttruktura cvora polozenog ispita i struktura
cvora ucenik su razliciti. Vezivanje cvora se vrsi
na kraj liste.*/

300
tek2=pret2=tek->dole;
while(tek2!=NULL)
{
pret2=tek2;
tek2=tek2->dole;
}
pret2->dole=novi2;
}
}
tek=tek->sledeci;
}
}
fclose(polaganje);

i=0;
tek=glava;
printf("\n\n");
tek=trazi(tek,evbroj); /* Trazi se ucenik na osnovu evedencionog broja. */

ispit=fopen("ISPIT.DAT","r+b");
if(tek!=NULL)
{
pret2=tek->dole;
while(pret2!=NULL)
{
i++;
printf(" %d %u %s %u\n",
i,pret2->info.sifra,pret2->info.datum,pret2->info.ocena);

/* Pozicioniramo se na pocetak datoteke ispiti i trazimo naziv


ispita koji odgovara datoj sifri. */
fseek(ispit,0,SEEK_SET);
kon=1;
while(fread(&t,sizeof(t),1,ispit))
{
if(t.sifra==pret2->info.sifra && kon==1)
{
gotoxy(19,4+i);
puts(t.naziv);
kon=0;
}
}
pret2=pret2->dole;
}
}else{
gotoxy(23,13);
printf(" Zadati kriterijumi nisu pronadjeni");
gotoxy(23,14);
printf("Za izlazak iz programa pritisni 'ESC'");
}

301
fclose(ispit);
c=getch();
}while(c!=ESC);
}

/* Funkcija unos_ceo omogucava unos celog broja. */


int unos_ceo(void)
{
unsigned xu, yu;
char c;
int x, pom=1;

/* Sa unosom broja pocinjemo od trenutne pozicije na ekranu. */


xu=wherex();
yu=wherey();

x=0;
do{
c=getch();
if(c==ESC) return -1;

/* U slucaju da je predznak negativan promenljiva pom dobija vrednost -1. */


if(c=='-'&&x==0) pom=-1, putch(c);

/* Cifra je ako je karakter veci od 48 a manji od 57, jer su to redni brojevi koji
odgovaraju decimalnim ciframa iy ASCII tabele. Prva cifra ne moye da bude 0.*/
if((c>48&&c<=57)||(c==48&&x!=0))
{
x=x*10+c-48;
putch(c);
}

/* Znajuci da ako broj predje granicu 32767 automatski


postaje negativan, utvrdjujemo da li se to desilo I usled
prekoracenja vracamo korisnika na ponovni unos. */
if(x<0)
{
x=0;
pom=1;
gotoxy(xu,yu);
printf(" ");
gotoxy(xu,yu);
}
}while(c!='\r' || x==0);

/* Vracamo dobijeni broj pomnozen sa zapamcenim predznakom. */


return x*pom;
}

/* Funkcija trazi trazi ucenika u listi ucenika na osnovu evidencionalnog broja. */


Tcvorp1 *trazi(Tcvorp1 *tek,unsigned evbroj)

302
{
while(tek!=NULL&&(tek->info.evbroj)!=evbroj) tek=tek->sledeci;
if(tek==NULL)
{
return NULL;
}else{
return tek;
}
}

Test primer programa:

Primer 3:
Tekstualna datoteka LETOVI.TXT sadrži spisak svih avionskih linija jedne avio
kompanije. Svaka linija teksta sadrži sledeća polja: broj leta, ime grada iz kojeg avion
poleće, ime grada do koga avion leti i cenu leta, pri čemu su pojedina polja razdvojena sa
znakom #:
broj leta # poletni grad # odredišni grad # cena leta

Može postojati više letova čiji poletni grad je isti. Takođe može postojati više letova
sa istim odredišnim gradom.
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program koji omogućava:

 Ispisivanje letova ove avio kompanije, sortirane po gradovima iz koje avion


poleće. Svaki ispis treba da sadrži: ime grada iz kojeg avion poleće, ime
odredišnog grada, broj leta i cenu leta.
 Za zadati grad, ispisuje brojeve svih linija koje kreću iz tog grada, kao i
odredište svake od tih linija.
 Za zadate gradove A i B odrediti broj direktnog leta i cenu leta od grada A
do grada B ako takav let postoji, i

303
 Za zadate gradove A i B odrediti niz letova kojima se stiže iz grada A do
grada B sa minimalnim brojem sletanja, kao i ukupnu cenu ovakvog leta.
U analizu dolazi maksimalno tri sletanja.

Rešenje

U programu je koriscena dinamicka struktura podataka multilista. Formirana je


jednostruko spregnuta lista ciji cvorovi osim informacionog sadrzaja poseduju i dva
pokazivaca: pokazivac na naredni cvor jednostruko spregnute liste i pokazivac na prvi
cvor liste odredisnih gradova. Iz svako grada odakle se polece izbija lista koja sadrzi
cvorove koji opisuju odredisne gradove do kojih postoji direktan let od tog poletnog
grada.

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>

typedef struct cvor{


char grad[20];
int cena,broj;
struct cvor *sledeci, *dalje;
}Tcvor;

/*Funkcija trazi objekat u glavnoj listi za grad poletanja*/


Tcvor *trazi(Tcvor *glava, char kljuc[]);

/*funkcija trazi grad sletanja u listi grada poletanja*/


Tcvor *trazikroz(Tcvor *glava, char kljuc[]);

void main(void)
{
Tcvor *glava,*pok,*pret,*tek,*taj,*p1,*p2,*p3,*p4,*p5;
int i,j,broj,cena,a,x,y,x1,y1,pomx,pomy,pomx1,pomy1,kon;
FILE *dat;
char pom[70],iz[20],u[20],br[5],cn[5];

glava=NULL;

textmode(3);
textcolor(BLUE);
textbackground(WHITE);
clrscr();

if((dat=fopen("letovi.txt","r"))==NULL)
{
printf("\n\tDatoteka se ne moze otvoriti!!!");
return;
}else{

304
while(fgets(pom,80,dat)) /*Ucitavanje reda datoteke u sring pom*/
{
/* Izdvajanje podataka iz stringa pom*/
i=0,j=0;
while(pom[i]!='#') br[j]=pom[i], i++, j++;
br[j]='\0', i++, j=0;

while(pom[i]!='#') iz[j]=pom[i], i++, j++;


iz[j]='\0', i++, j=0;
while(pom[i]!='#') u[j]=pom[i], i++, j++;
u[j]='\0', i++, j=0;

while(pom[i]!='\n') cn[j]=pom[i], i++, j++;


cn[j]='\0', i++, j=0;

/*Pretvara stringove u celobrojne podatke*/


broj=atoi(br);
cena=atoi(cn);

/*Ako lista ne postoji*/


if(glava==NULL)
{
/* Formirati cvor sa poletnim grad. */
glava=(Tcvor*)malloc(sizeof(Tcvor));

strcpy(glava->grad,iz);
glava->sledeci=NULL;

/* Formirati cvor sa odredisnim gradom. */


glava->dalje=(Tcvor*)malloc(sizeof(Tcvor));
pok=glava->dalje;
strcpy(pok->grad,u);
pok->broj=broj;
pok->cena=cena;
pok->dalje=NULL;
}else{

/*Ako lista postoji, trazi u glavnoj listi grad poletanja*/


taj=trazi(glava,iz);

if(taj==NULL)
{
/* Takvog poletnog grada nema. Formirati cvor na kraju liste
Poletnih gradova. */
tek=pret=glava;
while(tek!=NULL) pret=tek, tek=tek->sledeci;

pret->sledeci=(Tcvor*)malloc(sizeof(Tcvor));
pok=pret->sledeci;
strcpy(pok->grad,iz);
pok->sledeci=NULL;

305
/* Upisati prvi odredisni grad direktnog leta. */
pok->dalje=(Tcvor*)malloc(sizeof(Tcvor));
pok=pok->dalje;
strcpy(pok->grad,u);
pok->broj=broj;
pok->cena=cena;
pok->dalje=NULL;
}else{
/* Postoji takav poletni grad. Prolazimo kroz listu odredisnih
gradova i formiramo novi cvor na kraju liste. */

pret=tek=taj;
while(tek!=NULL) pret=tek, tek=tek->dalje;
pret->dalje=(Tcvor*)malloc(sizeof(Tcvor));
pok=pret->dalje;
pok->dalje=NULL;
strcpy(pok->grad,u);
pok->broj=broj;
pok->cena=cena;
}
}
}

i=0;
/*Pocetak while ciklusa za ponavljanje celokupnog menija*/
while(a!=5)
{
delay(100);
if(i!=0) getch();

if(i==0) i++;
clrscr();
textcolor(BLUE);
textbackground(WHITE);
clrscr();
printf("\n\n\n\n\n\n\n ");
textcolor(BLUE);
cprintf("- O P C I J E -");
printf("\n 1-Svi letovi kompanije\n 2-Letovi iz grada");
printf("\n 3-Trazenje direktnog leta\n 4-Letovi sa vise sletanja\n 5-I Z L A Z");
printf("\n O P C I J A: ");
textbackground(RED);
x=wherex(), y=wherey();
cprintf(" ");

/*Unos opcije*/
do{
gotoxy(x+1,y);

306
a=getche()-48;
}while(a<=0&&a>5);

/*Selekcija vrednosti a*/


switch(a)
{
case 1: pok=glava;
printf("\n\t");
gotoxy(35,3);
cprintf(" L E T");
cprintf(" broj leta"),x=wherex()-5,y=wherey();
cprintf(" cena leta"),x1=wherex()-6,y1=wherey();
y++,y1++,i=4;

while(pok!=NULL)
{
strcpy(iz,pok->grad);
tek=pok->dalje;
while(tek!=NULL)
{
gotoxy(35,i++);
printf("%s - %s",iz,tek->grad);
gotoxy(x,y++),printf("%d",tek->broj);
gotoxy(x1,y1++),printf("%d",tek->cena);
tek=tek->dalje;
}
pok=pok->sledeci;
}
break;
case 2: printf("\n\n\tGrad: ");
scanf("%s",&iz);
pok=trazi(glava,iz);
gotoxy(30,3);
cprintf(" L E T");
cprintf(" broj leta"),x=wherex()-5,y=wherey();
cprintf(" cena leta"),x1=wherex()-5,y1=wherey();
y++,y1++;

tek=pok->dalje; i=4;
while(tek!=NULL)
{
gotoxy(30,i++);
printf("%s - %s",iz,tek->grad);
gotoxy(x,y++),printf("%d",tek->broj);
gotoxy(x1,y1++),printf("%d",tek->cena);
tek=tek->dalje;
}
break;
case 3: printf("\n\n\tPoletanje: ");
scanf("%s",&iz);
printf("\tSletanje: ");

307
scanf("%s",&u);
pok=trazi(glava,iz);
tek=trazikroz(pok,u);
gotoxy(30,3);
cprintf(" L E T");
cprintf(" broj leta"),x=wherex()-5,y=wherey();
cprintf(" cena leta"),x1=wherex()-6,y1=wherey();
y++,y1++;

if(tek==NULL)
{
gotoxy(30,4);
printf(" ---------N E M A L E T O V A--------");
}else{
gotoxy(30,4);
printf("%s - %s",iz,tek->grad);
gotoxy(x,y),printf("%d",tek->broj);
gotoxy(x1,y1++),printf("%d",tek->cena);
}
break;
case 4: printf("\n\n\tPoletanje: ");
scanf("%s",&iz);
printf("\tSletanje: ");
scanf("%s",&u);

if(strcmp(iz,u))
{
gotoxy(30,i=3);

/*Ispitivanje da li postoji direktan let*/


gotoxy(30,i++);
cprintf(" L E T");
cprintf(" broj leta"),x=wherex()-5,y=wherey();
cprintf(" cena leta "),x1=wherex()-6,y1=wherey();
y++,y1++;

/*Funkcije trazi i trazikroz ce se pozivati maksimalno onoliko


puta koliko postoji gradova u glavnoj listi*/
p1=trazi(glava,iz);
p2=trazikroz(p1->dalje,u);
if(p2!=NULL)
{
gotoxy(30,y++);
printf("%s - %s",iz,p2->grad);
gotoxy(x,y-1),printf("%d",p2->broj);
gotoxy(x1,y1++),printf("%d",p2->cena);
}else{
gotoxy(30,y++);
printf("-----N E M A D I R E K T N I H L E T O V A----");
gotoxy(30,y+=2);

308
/*Ispitivanje da li postoji let sa jednim sletanjem*/
gotoxy(30,y++);
cprintf(" L E T");
cprintf(" broj leta"),
pomx=x=wherex()-5,pomy=y=wherey();
cprintf(" cena leta "),
pomx1=x1=wherex()-6,pomy1=y1=wherey();
y++,y1++;
p2=p1->dalje;
kon=0;
while(p2!=NULL)
{
p3=trazikroz(trazi(glava,p2->grad)->dalje,u);
if(p3!=NULL)
{
kon=1;
gotoxy(30,y++);
printf("%s - %s",iz,p2->grad);
gotoxy(x,y-1);
printf("%d",p2->broj);
gotoxy(x1,y1++);
printf("%d",p2->cena);
gotoxy(30,y++);
printf("%s - %s",p2->grad,p3->grad);
gotoxy(x,y-1),printf("%d",p3->broj);
gotoxy(x1,y1++);
printf("%d",p3->cena);
gotoxy(30,y++);
printf("------------------");
y1++;
gotoxy(30,y++);
printf("Ukupna cena: ");
printf("%d",p2->cena+p3->cena);
y1++;
}
p2=p2->dalje;
}
gotoxy(30,y+=2);

if(kon==0)
{
x=pomx, y=pomy+1, x1=pomx1, y1=pomy1+1;
/*Proveravanje da li postoji let sa dva sletanja*/
p2=p1->dalje;
while(p2!=NULL)
{
/* Trazimo grad sa prvim sletanjem. */
p3=trazi(glava,p2->grad);
while(p3!=NULL)
{
p3=p3->dalje;

309
/* Trazimo grad sa drugim sletanjem. */
p4=trazikroz(trazi(glava,p3->grad)->dalje,u);
if(p4!=NULL)
{
kon=2;
gotoxy(30,y++); printf("%s - %s",iz,p2->grad);
gotoxy(x,y-1); printf("%d",p2->broj);
gotoxy(x1,y1++); printf("%d",p2->cena);
gotoxy(30,y++);
printf("%s - %s",p2->grad,p3->grad);
gotoxy(x,y-1),printf("%d",p3->broj);
gotoxy(x1,y1++); printf("%d",p3->cena);
gotoxy(30,y++);
printf("%s - %s",p3->grad,p4->grad);
gotoxy(x,y-1),printf("%d",p4->broj);
gotoxy(x1,y1++); printf("%d",p4->cena);
gotoxy(30,y++),printf("-----------------"),y1++;
gotoxy(30,y++); printf("Ukupna cena: "),y1++;
printf("%d",p2->cena+p3->cena+p4->cena);
}
p3=p3->dalje;
}
p2=p2->dalje;
}
}
/*Ako je p4=0 ne postoje letovi sa vise sletanja*/
if(kon==0)
{
gotoxy(30,y++);
printf("Nema sa manje od 3 sletanja u tom pravcu!");
}else{
gotoxy(45,6);
printf("LETOVI SA %d SLETANJA",kon);
gotoxy(1,25);
}
}
}
break;
}
}
}
}
Tcvor *trazi(Tcvor *glava, char kljuc[])
{
Tcvor *pot=glava;
while(pot!=NULL&&strcmp(pot->grad,kljuc)) pot=pot->sledeci;
return pot;
}

Tcvor *trazikroz(Tcvor *glava, char kljuc[])


{

310
Tcvor *pol;
pol=glava;
while(pol!=NULL&&strcmp(pol->grad,kljuc)) pol=pol->dalje;
return pol;
}

Test primer programa:

7.9. ZADACI IZ DINAMIČKIH STRUKTURA PODATAKA

311
Zadatak 1 (2)
Zadata je tekstualna datoteka TEKST.TXT. Nacrtati najjednostavniji i ujedno
najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i na osnovu njega napisati
C program koji modifikuje datoteku TEKST.TXT tako što se polazna datoteka
transformiše u datoteku čiji su redovi ispisani u obrnutom poretku.

Zadatak 2 (2)
U tekstualnoj datoteci SPISAK.TXT nalazi se spisak građana gde je u jednoj liniji
teksta prezime, ime i težina. Podaci su razdvojeni sa praznim mestima i/ili tabulatorima.
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program koji brzo daje odgovor na upit težina
za zadatog građanina.

Zadatak 3 (2)
U tekstualnoj datoteci čiji se naziv unosi sa tastature postoji dva reda zapisa, pri
čemu se prvi red odnosi na prvi polinom P, a drugi red na drugi polinom Q. Polinom je
opisan sa nizom uređenih parova (a k , x ), k  [1..n]  k  N  n  N . Nacrtati
k

najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i
na osnovu njega napisati C program koji na osnovu datoteke izračunava i u trećem redu
ispisuje polinom R u formati koji je gore naveden, pri čemu je R = P+Q.

Zadatak 4 (2)
Zadata je tekstualna datoteka IMENA.TXT u kojoj se u svakom redu nalazi tačno
jedno ime i prezime međusobno razdvojeni blanko mestima i/ili tabulatorima. Nacrtati
najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i
na osnovu njega napisati C program koji na ekranu i u datoteci IZVESTAJ.TXT štampa
izveštaj sledećeg izgleda:

R. Br. Prezime Broj pojava


1 Arsic 12
2 Bajic 3
3 Dragas 10, itd ...

Izveštaj je sortiran po abecednom redosledu.

Zadatak 5 (2)
Zadata je tekstualna datoteka BROJEVI.TXT koja u svakom redu sadrži uopšteno
jedan realan podatak Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram
(uz objašnjenje zašto baš on) i na osnovu njega napisati C program koji iz datoteke briše
one brojeve koji su negativni i imaju vrednost veću od srednje vrednosti brojeva iz
datoteke. Za izračunavanje srednje vrednosti koristiti funkciju srednjavrednost čiji je
prototip: double srednjavrednost(Tcvor **glava); gde je glava pokazivač na prvi
elemenat liste.

Zadatak 6 (2)

312
Zadata je tekstualna datoteka BROJEVI.TXT koja u svakom redu sadrži uopšteno
jedan realan podatak Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram
(uz objašnjenje zašto baš on) i na osnovu njega napisati C program koji preuređuje
datoteku tako da se prvo ispisuju negativni brojevi sortirani u opadajućem redosledu, a
potom pozitivni brojevi sortirani u rastućem redosledu. U svakom redu nalazi se samo
jedan broj.

Zadatak 7 (2)
Zadata je tekstualna datoteka SPISAK.TXT koja sadrži spisak imena i prezimena.
U svakom redu datoteke nalazi se tačno jedno ime i prezime međusobno razdvojeni
prazninama i/ili tabulatorima. Datoteka je sortirana po abecednom kriterijumu. U datoteci
BRISI.TXT nalazi se u istom formatu kao u datoteci SPISAK.TXT spisak imena i
prezimena koje treba izbaciti iz datoteke SPISAK.TXT. Nacrtati najjednostavniji i
ujedno najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i na osnovu njega
napisati C program koji efikasno rešava dati problem.

Zadatak 8 (3)
Binarna datoteka KRUGOVI.DAT je formata: x (double), y (double) i r (double).
Sa x i y označen je centar kruga a r je poluprečnik kruga. Nacrtati najjednostavniji i
ujedno najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i na osnovu njega
napisati C program koji iz datoteke izbacuje sve one krugove koji se nalaze unutar
krugova sa najvećim poluprečnicima.

Zadatak 9 (3)
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program za vođenje evidencije robe neke
tehničke prodavnice. Roba je okarakterisana: nazivom (do 30 karaktera), šifrom (do 15
karaktera), količinom u magacinu i cenom po komadu.

Program treba da omogući sledeće funkcije:


1) Unos nove robe;
2) Brisanje robe iz evidencije (ako je količina te robe 0);
3) Promena cene robe (pojedinačno ili linearno za svu robu);
4) Prikaz podataka po šifri za zadatu robu;
5) Trajno čuvanje podataka o robi u binarnoj datoteci ROBA.DAT.

Zadatak 10 (3)
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program za praćenje glasanja na muzičkom
festivalu. Svaka pesma dobija ocenu žirija od 0 do 10 i ocenu publike od 0 do 10.
Program treba da omogući unos naziva pesme, naziv izvođača, broj osvojenih bodova,
kao i izlistavanje rezultata po opadajućem redosledu broja bodova.

Zadatak 11 (3)

313
Zadata je tekstualna datoteka TEKST.TXT. Nacrtati najjednostavniji i ujedno
najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i na osnovu njega napisati
C program koji modifikuje datoteku TEKST.TXT tako što se polazna datoteka
transformiše u datoteku čije su rečenice ispisane u obrnutom poretku.

Zadatak 12 (3)
Data je binarna datoteka čije ime se unosi sa tastature u formatu: oznaka (string od
6 karaktera), količina (float) i datum (string oblika dd.mm.gggg). Oznaka predstavlja
uređaj koji proizvodi neki proizvod. Količina predstavlja proizvedenu količinu na tom
uređaju u toku dana koji je označen sa datum. Nacrtati najjednostavniji i ujedno
najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i napisati C program koji
sekvencijalno učitava binarnu datoteku i na osnovu nje formira tekstualnu datoteku sa
isim imenom kao i ulazna datoteka uz ekstenziju TXT. U izlaznu datoteku ulaze samo
one oznake koje su imale najveću količinu. U svakom redu datoteke nalaze se podaci
oblika (oznaka, količina i datum) razdvojenih sa jednim tabulatorom.

Zadatak 13 (3)
Zadata je binarna datoteka PROMENE.DAT u formatu: pr_sifra (unsigned),
pr_kolicina (float), pr_cena (unsigned) i pr_smer (float).
Napisati C program koji sekvencijalno čita datoteku PROMENE.DAT i formira
najjednostavniju i ujedno najefikasniju strukturu. Objekat strukture poseduje polja:
st_sifra, st_kolicina, st_cena i st_vrednost.

st _ kolicina   pr _ kolicina   pr _kolicina


za sve promenete za sve promenete
sifre sasmerom0 sifre sasmerom1

st_cena je najveća cena u svim strukturama promene za tu šifru.


st_vrednost = st_cena * st_kolicina

Na kraju štampati niz struktura u proizvoljnom formatu, ali tako, da se posle


štampanja poslednjeg elementa strukture odštampa ukupna vrednost sve robe u
magacinu.

Zadatak 14 (3)
U tekstualnoj datoteci TELEFONI.TXT u svakom redu nalazi se zapisan po tačno
jedan broj telefona (između brojeva mogu postojati praznine, tabulatori i crtice). Korisnik
je dobio ogroman telefonski račun te od pošte zatraži da za dati mesec dobije izveštaj
telefonskih poziva. Pošta molbu ne prihvati (vlasnik telefona nije u zemlji), ali mu
drugarica iz pošte prosledi binarnu datoteku naziva prezime (ime datoteke) i ekstenzija
DAT. Format datoteke je: broj telefona (string og maksimalno 15 karaktera) i broj
impulsa (unsigned).
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program koji će utvrditi da li postoji neki
sumnjivi brojevi telefona i da se utvrdi sa kojim telefonskim brojevima je napravljen
najveći broj impulsa datog meseca.

314
Zadatak 15 (4)
U datotekama MATRICAxx.TXT nalaze se veoma velike matrice. Oznaka xx je
broj (01,02,...,10,...) datoteke. Svaki red datoteke sastoji se od tri podatka (vrsta, kolona i
vrednost na toj poziciji) međusobno razdvojeni sa po jedniim praznim mestom. Matrica
je “retka“, tj. mnogo njenih elemenata ima vrednost nula. Nacrtati najjednostavniji i
ujedno najefikasniji strukturni dijagram sa što manje elemenata (uz objašnjenje zašto baš
on) i na osnovu njega napisati C program koji sekvencijalno učitava tekstualne datoteke,
formira odgovarajuću strikturu i na osnovu nje izlazne matrice IZLAZxx.TXT koje
pretstavljaju rezultujuće matrice zapisane u formatu ulaznih matrica. Svaka datoteka
IZLAZxx.TXT sadržaće po jednu matricu koja je nastala kao rezultat zbira matrica istih
dimenzija (jer se matrice mogu sabrati ako imaju jednak broj vrsta i kolona).

Zadatak 16 (4)
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program koji automatizuje finalno takmičenje
u streljaštvu n kome učestvuje 10 finalnih strelaca, najboljih po plasmanu iz
predtakmičenja. Svaki strelac ima 10 hitaca koji se ocenjuju u opsegu od 0.0 do 11.0
bodova. Svaki strelac je okarakterisan sledećim atributima: takmičarski broj, ime i
prezime, broj bodova iz predtakmičenja i bodovima finalnih hitaca. Program treba da
omogući sledeće funkcije:

1) Unos opštih podataka o akmičaru (prva tri atributa), tj. prijavljivanje;


2) Unos bodova svakog takmičara po obavljenom hicu. Prvi unos treba
automatski da zabrani prijavljivanje takmičara;
3) Lista takmičara uređena po rastućem ukupnom broju bodova u obliku tabele
sa 13 kolona: Takm. broj, Prezime i ime, Hitac1, Hitac2,...,Hitac10 i
Ukupno; i
4) Podatke čuvati u binarnoj datoteci čiji naziv unosi korisnik sa tastature.

Zadatak 17 (4)
Data je tekstualna datoteka čiji naziv se unosi sa tastature. Nacrtati najjednostavniji
i ujedno najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i na osnovu njega
napisati C program koji na osnovu unesene reči utvrđuje koliko se ta reč pojavljuje u
datoteci i u kojim sve redovima se nalazi i koliko puta.

Zadatak 18 (4)
Datoteka DELOVI.DAT sadrži podatke o delovima automobila u formatu: šifra
dela, naziv dela, marku automobila za koji je namenjen i cenu dela. Nacrtati
najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje zašto baš on) i
na osnovu njega napisati C program koji za zadati automobil izlistava sve njegove
raspoložive delove automobila, i da se za zadati deo izlistaju sve marke automobila za
koji je deo namenjen.
Potrebno je realizovati postupke za postavljanje dva navedena upita i postupke za
dodavanje novog i uklanjanje postojećeg dela iz strukture.

315
Zadatak 19 (4)
U tekstualnoj datoteci čiji naziv se unosi sa tastature nalaze se podaci: prezime, ime,
prosečna ocena, broj opravdanih izostanaka i broj neopravdanih izostanaka. Podaci su
razdvojeni sa po jednim praznim mestom. Nacrtati najjednostavniji i ujedno najefikasniji
strukturni dijagram (uz objašnjenje zašto baš on) i na osnovu njega napisati C program
koji daje prikaz podataka po sledečim kriterijumima:
 Rastući poredak po prosečnoj oceni, a drugi kriterijum sortiranja je
alfanumerički poredak po prezimenu i imenu učenika; i
 Opadajući poredak po broju neopravdanih izostanaka, drugi kriterijum je
veći broj izostanaka, a treći kriterijum je alfanumerički kriterijum po
prezimenu i imenu učenika.

Zadatak 20 (4)
Zadate se tri tekstualne datoteke POREZI.TXT, ROBA.TXT i PRODAJA.TXT.
U datoteci POREZI.TXT u svakom redu nalazi se tri podatka međusobno
razdvojena sa jednim praznim mestom: šifra poreza (dve cifre), stopa saveznog poreza
(tri cela i dva decimalna mesta) i republička stopa poreza (tri cela i dva decimalna mesta).
U datoteci ROBA.TXT u svakom redu nalazi se tri podatka međusobno razdvojena
sa jednim praznim mestom: šifra robe (12 cifara), cena robe (pet celih i dva decimalna
mesta) i šifra poreza kojem podleže ta roba (dve cifre).
U datoteci PRODAJA.TXT u svakom redu nalazi se tri podatka međusobno
razdvojena sa jednim praznim mestom: šifra robe koja je prodata (12 cifara), datum kada
je roba prodata u formatu dd.mm.gggg i količina te robe prodate tog datuma (tri cela i dva
decimalna mesta)
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program koji izračunava proseke obaveza za
zadati period i štampa izveštaj sledećeg izgleda:

R.BR. SIFRA POREZA SAVEZNI POREZ REPUBLICKI POREZ


1 xx xxxxxxx.xx xxxxxxx.xx
2 xx xxxxxxx.xx xxxxxxx.xx
3 xx xxxxxxx.xx xxxxxxx.xx, itd...

Zadatak 21 (4)
Data je tekstualna datoteka BANKA.TXT koja u svakom redu sadži tri podatka
međusobno razvojena sa po jednim praznim mestom: račun (xxx – xxx – xxx), smer (ima
vrednost 1 ako je uplata ili 0 ako je isplata) i iznos (realan broj na dve decimale). Napisati
C program koji sekvencijalno čita datoteku BANKA.TXT i formira dvostruko spregnutu
listu na sledeći način:
 Ako smo pročitali podatke jednog objekta čiji atribut račun nije u listi,
uvežite ga na kraj.

316
 Ako smo pročitali podatke jednog objekta čiji atribut račun se nalazi u listi,
uvezati ga iza poslednjeg čvora sa tim računom.
Koristeći se sadržajem liste, odštanpati sledeći izveštaj:

RACUN ZBIR
xxx – xxx – xxx xxxxxxx.xx
xxx – xxx – xxx xxxxxxx.xx
xxx – xxx – xxx xxxxxxx.xx, itd...

Zadatak 22 (4)
Data je binarna datoteka TEKST.DAT koja je formatizovana sa podacima koji se
sastoje od dva polja: šifra (8 cifara, a u datoteci se može nalaziti više podataka sa istom
šifrom) i ekst (string od 20 karaktera).
Napisati C program koji sekvencijalno čita datoeku i formira jednostruko spregnutu
listu sortiranu u rastućem redosledu šifre, tako da su svi duplikati jedne šifre vezani u
listu čiji je početak u sortiranoj listi. Ta lista duplikata treba da je formirana po principu
umetanja na poslednje mesto u listi.
Na kraju odštampati izveštaj sledećeg izgleda:

SIFRA TEKST NAPOMENA


xxxxxxxx xxxxxxxxxxxxxxxxxxxx IMA DUPLIKATE
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx

xxxxxxxx xxxxxxxxxxxxxxxxxxxx IMA DUPLIKATE


xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx

xxxxxxxx xxxxxxxxxxxxxxxxxxxx NEMA DUPLIKATE

xxxxxxxx xxxxxxxxxxxxxxxxxxxx IMA DUPLIKATE


xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx, itd...

Zadatak 23 (5)
Date su binarne datoteke GRADJANI.DAT i RACUNI.DAT. Datoteka
GRADJANI.DAT je formata: prezime i ime građanina (do 40 karaktera), JMBG (13
karaktera) i dažbine koje građanin treba da plati. Datoteka RACUNI.DAT sadrži podatke
o žiro i tekućim računima građana i to: JMBG, broj računa i stanje na računu. Jedan
građanin može da ima više žiro ili tekućih računa, a može uopšte da nema računa.
Program treba da formira sledeću strukturu:

317
Lista građana dodavanjem na početak;
Lista računa za svakog građanina u listi građana;
Iz tako dobijene strukture izvršiti izbacivanje građana koji imaju više novca na
računima, nego što je iznos njihovih dažbina; i
Smeštanje ostataka liste u tekstualnu datoteku DUZNICI.TXT, pri čemu svaki red
datoteke sadrži podatke: ime, prezime, JMBG i iznos duga. Podaci su razdvojeni sa
jednim praznim mestom.

Zadatak 24 (5)
U Sremskim Karlovcima svake godine održavaju se dani vina. Ove godine rešeno je
da se putem SMS poruka izvrši takmičenje. Poruke se upisuju u datoteku
PORUKE.TXT. Svaki red datoteke sadrži jednu poruku u formatu:

Šifra vina # Broj mobilnog telefona # Ocena (1..5)

U datoteci TAKMICARI.TXT nalaze se prijavljeni takmičari, pri čemu svaki red


datoteke sadrži podatke jednog takmičara, u formatu:

Šifra # Naziv vina

Ucitati podatke iz datoteka i formirati najjednostavniju i ujedno najefikasniju


dinamičku strukturu podataka, kojom će se najefikasije utvrditi rang lista vina. Rang lista
se formira u izlaznoj datoteci POBEDNICI.TXT.

Pravila ocenjivanja:
 Odbacuju se poruke sa neispravnom šifrom vina;
 Odbacuju se poruke sa neispravnom ocenom;
 Za jednu šifru vina sa jednog mobilnog telefona prihvataju se maksimalno
prve tri poruke.

Izlazna datoteka je sortirana u opadajućem redosledu: Prvi kriterijum sortiranja je


broj glasova, a drugi prosečna ocena.
Svaki red izlazne datoteke odnosi se na jedno vino i zapis je u formatu:

Šifra # Naziv vina # Prosečna ocena # Broj osvojenih glasova

Zadatak 25 (5)
Mali Perica je počeo da skija. Perica je egzibicionista i ne skija po stazama, već
skija kako stigne. Zbog toga, služba spasavanja je rešila da napravi program koji će
simulirati kretanje Perice od početne pozicije do cilja. Program prikazuje sva moguća
rešenja. Mapa terena se nalazi u datoteci MAPA.TXT. Prvi red datoteke čine dva broja
(broj vrsta i broj kolona mape) međusobno razdvojena blanko mestima. U narednim
redovima nalazi se mapa terena pri čemu su elementi mape (predstavlja visinu terena)
razdvojeni praznim mestima. Ispod mape terena nalazi se red u kome su dva broja
međusobno razdvojeni praznim mestima koji označavaju startno mesto od koje Perica
počinje da skija.

318
Perica se spušta samo u pravcu jedne koordinate (ne dijagonalno), i to isključivo sa
mesta koje ima veću visinu na mesto niže visine. Potencijalni cilj su ona mesta koja na
mapi imaju najmanju visinu.

Zadatak 26 (5)
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program za elektronsko vođenje školske
biblioteke. Svaki član biblioteke je okarakterisan sa:

7) Prezi
me i ime,
8) Člans
ki broj,
9) Adres
a stanovanja,
10) Razre
d,
11) Telefo
n, i
12) Broj
uzetih knjiga.

Program treba da omogući:

h) Upis novog člana, pri čemu automatski dobija članski broj,


i) Brisanje pojedinog člana iz biblioteke pod uslovom da je vratio sve knjige
koje je iz biblioteke zadužio,
j) Izmene pojedinih podataka o članu,
k) Ispis podataka o svim članovima po kriterijumu broja zaduženih knjiga,
l) Utvđivanje koji razred ima najviše neurednih korisnika biblioteke,
m) Na kraju školske godine prikaz svih članova četvrte godine koji nisu vratili
knjige, i
n) Automatso preimenovanje oznake svih odeljenja škole na početku školske
godine.

Program treba da obezbedi trajno čuvanje podataka u tekstualnoj datoteci


BIBLIOTEKA.TXT.

Zadatak 27 (5)
Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje
zašto baš on) i na osnovu njega napisati C program koji prihvata podatke o posetiocima
nekog preduzeća gde je svaki posetioc okarakterisan sa: prezimenom i imenom (do 30
karaktera), JMBG (13 karaktera) i vremenom ulaska i napuštanja preduzeća.

Program treba da omogući sledeće funkcije:

319
1. Unos podataka o posetiocu pri ulasku i izlasku iz preduzeća;
2. Prikaz svih podataka o posetama za datog zaposlenog, tabela sa kolonama:
ULAZAK, IZLAZAK, PREZIME I IME;
3. Prikaz svih poseta koji još nisu izašli iz preduzeća, tabela sa kolonama:
ULAZAK, PREZIME I IME, POSETA ZA;
4. Prikazati na ekranu ime i prezime najvećeg zabušanta. Najveći zabušant je
onaj radnik koji je najveći interval vremena proveo u razgovoru sa svojim
posetiocima. U slučaju da je njih više imalo isti maksimalni vremenski
interval trajanja posete, najveći zabušant postaje onaj radnik koga je u toku
dana posetilo najviše posetilaca.
5. Trajnjo čuvanje podataka o svim posetama u tekstualnoj datoteci pod
nazivom PORTddmmgg.TXT gde je dd – dan, mm – mesec, a gg – godina
evidencije.

Zadatak 28 (5)
Date su tekstualne datoteke PROIZVODI.TXT, AUTOMOBILI.TXT i
KUPCI.TXT koje sadrže podatke o proizvođačima automobila i kupcima jedne auto
kuće. Datoteke sadrže sledeće podatke:

PROIZVODI.TXT
 Naziv proizvođača automobila (od maksimalno 40 karaktera);
 Mesto (od maksimalno 20 karaktera).

AUTOMOBILI.TXT
 Tip automobila (od maksimalno 30 karaktera);
 Naziv proizvođača (od maksimalno 40 karaktera);
 Cena (od maksimalno 10 karaktera); i
 Količina na lageru (od maksimalno 5 karaktera)

KUPCI.TXT
 Ime kupca (od maksimalno 30 karaktera);
 Tip automobila (od maksimalno 30 karaktera); i
 Već uplaćeni iznos (od maksimalno 10 karaktera).

Nacrtati najjednostavniji i ujedno najefikasniji strukturni dijagram (uz objašnjenje


zašto baš on) i na osnovu njega napisati C program koji omogućava kreiranje sledećih
izveštaja:
1) Spisak svih tipova automobila iz programa ove auto kuće. Za svaki tip
automobila potrebno je navesti sledeće podatke: proizvođač, sedište
proizvođača, cena automobila, broj prodatih automobila (broj kupaca tog
tipa automobila) i ukupan broj automobila na lageru.

2) Spisak svih kupaca. Za svakog kupca navesti spisak svih automobila koje
kupuje, ukupno uplaćen iznos kao i ukupan iznos koji duguje auto kući.

320
Zadatak 29 (5)
U tekstualnoj datoteci BEGUNAC.TXT nalazi se mapa zamka. Na ulazu u zamak
nalazi se begunac. Postoji više puteva u zamku kojim je begunac mogao pobeći policiji,
kao i više izlaza iz zamka. U samom zamku na jednom mestu policija je postavila zasedu.

Mapa zamka sastoji se od brojeva čije vrednosti mogu biti:


1 – Zid zamka;
2 – Hodnik u zamku;
3 – Mesto gde se nalazi policija; i
4 – Položaj begunca.

Program treba da utvrdi kolika je verovatnoća da će begunac pobeći iz zamka.


U datoteci POBEGAO.TXT upisati koordinate kretanja begunca da bi pobegao
iz zamka. Potrebno je u datoteci upisati sve putanje kojima je begunac mogao pobeći iz
zamka. Putanju čine redni brojevi koji opisuju položaj elementa u matrici.
Na ekranu prikazati najoptimalniji put izlaska iz zamka. Najoptimalniji put
izlaska iz zamka je onaj koji ima najmanje polja koji pretstavljaju hodnik i ujedno
najmanje promene smera kretanja.
Program treba da pomogne policiji u postavljanju još jedne zasede, a koji je
udaljen više od tri polja (koga čine hodnik ili zid), a postavlja se na polje gde je hodnik,
tako da begunac bude sigurno uhvaćen.
Prikazati simulaciju kretanja begunca, prilikom bežanja kroz zamak. Nakon svakog
prikaza prolaska do izlaza, za nastavak pritisnuti taster SPACE. Ako je moguće sa 100%
sigurnosti uhvatiti begunca, prikazati položaj druge policijske zasede, na iscrtanom
zamku

Zadatak 30 (5)
Napisati C program koji predstavlja igricu "milioner". U datoteci PITANJA.TXT
nalaze se pitanja na koje igrac daje odgovor. Svako pitanje je odgovarajuće težine.
Između formata zapisa pitanja nalazi se prazan red. Format zapisa pitanja prostire se
u ŽŽ reda. Prvi red sadrži broj koji predstavlja težinu pitanja i samo pitanje, razdvojeni
znakom #. U naredna četiri reda nalaze se ponuđeni odgovori (A, B, C i D). U narednom
redu nalaze se četiri cifre razdvojene praznim mestima, koje predstavljaju procente.
U poslednjem redu formata pitanja nalazi se redni broj tacnog odgovora.
Pri startovanju igrice na ekranu se nalaze opcije sa iznosom novca koju ce dobiti
ukoliko odgovori tačno na postavljeno pitanje. Svaka naredna opcija nosi više novca i
ima veću težinu pitanja. Opcija na kojoj se trenutno nalazi igrac je crvene boje, dok su
sve ostale plave boje. Sa desne strane od postavljene opcije nalazi se postavljeno pitanje,
a ispod njega poneđena četiri odgovora (ispred odgovora je slovo A..D). Igrac može
pritiskom na odgovarajuće slovo dati odgovor ili zatražiti pomoć. Ako da odgovor na
pitanje pritiskom na odgovarajuće slovo, računar mu saopštava da li je odgovor tačan te
ako jeste može odgovarati na sledeće pitanje veće težine i saopštava mu se koliko ima
trenutno novca. Ako je odgovorio pogrešno kraj je igre. Igraču su na raspolaganju i tri
pomoći: pomoć računara1 (brišu se dva od četiri ponuđena odgovora), pomoć računara2
(briše se jedno od četiri ponuđena odgovora) i pomoć prijatelja (na osnovu četiri učitana
broja koja su predstavljala procente, prikazuju se procentualna zastupljenost odgovora A,

321
B, C i D od strane puublike). Pomoći su numerisane sa brojevima 1, 2 i 3. Igrač u toku
igre može ako hoće iskoristiti ponuđene pomoći, ali svaku pomoć samio jednom u toku
cele igre.
Igra se može u toku trajanja programa igrati više puta, ali se ne smeju ponavljati
pitanja od predhodnih odigranih partija.

322

You might also like