Professional Documents
Culture Documents
LABORATORIJSKE VJEBE
LV10
Strukture podataka i dinamika
alokacija memorije
Do sada smo u vie vjebi pokrili rad sa strukturama, njihovo kreiranje, prosljeivanje preko
pokazivaa funkcijama, upisivanje u datoteku i itanje iz datoteke te openito svrhu
struktura podataka i rad s njima.
U ovoj vjebi obradit emo kako se moe dinamiki alocirati memorija za spremanje
strukture podataka te koja je svrha toga. Potrebna e biti predznanja iz prethodnih vjebi
gdje smo obradili rad sa strukturama te vjebi gdje se obraivala dinamika alokacija
memorije.
2 DINAMIKA ALOKACIJA MEMORIJE ZA STRUKTURU
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int n = 100;
char orig[] = "Ovo je string koji cemo kopirati u dinamicki alocirani";
char *p;
p = (char*)malloc(n*sizeof(char));
strcpy(p,orig);
puts(orig);
puts(p);
return 0;
}
Funkcija koja u gornjem primjeru stvarno alocira memoriju za ovo polje je funkcija malloc,
kojoj moramo predati koliki broj byteova elimo alocirati, a ona nam vraa adresu u
memoriji raunala na kojoj je taj eljeni broj byteova alociran, ili NULL ako nije uspjela
alokacija.
Kada elimo dinamiki alocirati memoriju za strukturu, koristit emo istu funkciju kao i kod
osnovnih tipova podataka, razlika je jedino u castanju rezultata poziva funkcije. Budui da
funkcija malloc vraa pokaziva tipa void (to znai da vraa samo adresu, a ne zna koji tip
podataka e biti spremljen na toj adresi) mi moramo eksplicitno, kao u gornjem primjeru,
castati tu adresu na tip podatka za koji smo alocirali memoriju. Budui da smo alocirali
memoriju za tip podatka char, moramo adresu eksplicitno castati na pokaziva na char,
prije nego adresu pridijelimo pokazivau.
Na isti nain emo castati i adresu koju nam vrati malloc pri alokaciji memorije za
strukturu:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
Tocka t= { 3.0, 2.0, 1.0 };
Tocka *d;
d = (Tocka*)malloc(sizeof(Tocka));
d->x = t.x;
d->y = t.y;
d->z = t.z;
free(d);
return 0;
}
U ovom primjeru vidimo kako je deklarirana struktura struct tocka kojoj kao tipu podatka
dali ime Tocka. Tako pri alokaciji memorije moramo castati adresu koju vrati malloc na
pokaziva na tip podatka Tocka. Vidimo da kao i u prijanjim vjebama, kada pristupamo
elementima strukture preko pokazivaa, moramo koristiti operator strjelicu.
Takoer, mogua je alokacija memorije za polje struktura, gdje je ponovno sintaksa same
alokacije jako slina prijanjim primjerima:
int main(void)
{
int n=10;
Tocka *polje;
polje = (Tocka*)malloc( n * sizeof(Tocka) );
for (int i = 0; i < n; i++) {
scanf("%f%f%f", &polje[i].x, &polje[i].y, &polje[i].z);
printf("-->%f %f %f<--\n", polje[i].x, polje[i].y, polje[i].z);
}
free(polje);
return 0;
}
Primijetimo kako se u ovom sluaju sintaksa alokacije jako malo mijenja, jedina promjena je
broj elemenata kojim mnoimo sizeof funkciju. Ponovimo, to je zato to funkcija sizeof
vraa veliinu u bajtima odreenog tipa podatka (u ovom sluaju strukture Tocka), te tu
veliinu mnoimo s brojem elemenata koje e polje imati. Takoer, bitno je naglasiti kako u
ovom sluaju lanovima strukture pristupamo s operatorom toka, jer operacijom
pristupanja elementu polja odraujemo dereferenciranje pokazivaa polje, pa je rezultat te
operacije struktura, a ne adresa. Bitno je pripaziti kada se kako pristupa kojem elementu.
#include <stdio.h>
#include <stdlib.h>
typedef struct tocka {
int x;
int y;
int z;
} Tocka;
int main(void)
{
Tocka a={1,2,3}, b={2,3,4};
Tocka p;
Tocka *q;
Rezultat izvoenja:
static add:
rezultat: 3, 5, 7; adresa: 0x7ffeb2d61ea0
rezultat: 3, 5, 7; adresa: 0x7ffeb2d61ea0
dynamic add:
rezultat: 3, 5, 7; adresa: 0x97c010
rezultat: 3, 5, 7; adresa: 0x97c030
Pogledajmo nasuprot nje funkciju dynamic_add. Ova funkcija vraa adresu strukture koja
e sadravati rezultat izvoenja. Za razliku od prole funkcije, kada je funkcija vraala kopiju
podataka, ova funkcija vraa adresu gdje se u memoriji nalaze podaci. Specifinost ove
funkcije u odnosu na funkcije koje smo do sada obraivali je u injenici da ova funkcija
alocira memoriju za rezultat koji vraa. U ovoj funkciji se takoer kreira lokalna varijabla res
koja e u ovom sluaju sadravati adresu gdje je u memoriji alocirano mjesto za spremanje
rezultata zbrajanja. Ovdje je bitno naglasiti kako je varijabla res i u ovom sluaju lokalna
varijabla, te se nakon zavretka izvravanja ove funkcije ona brie. Ipak, ono to je jako
razliito od prethodnog primjera je injenica da je ova varijabla pokaziva, a kako je
memorija za strukturu na koju pokazuje alocirana dinamiki, nakon zavretka izvoenja ove
funkcije ona se nee dealocirati. Pri ponovnom pozivu ove funkcije alocirat e se novo
memorijsko mjesto za spremanje strukture, te e se vratiti adresa gdje se u memoriji nalazi
ta nova alokacija.
To moemo vidjeti u ispisu gornjeg primjera, gdje se nakon izvoenja svakog od poziva
funkcija ispisuje adresa gdje se u memoriji nalazi taj podatak. Vidimo kako dva uzastopna
poziva funkcije static_add spremaju rezultat na istu adresu, dok dva uzastopna poziva
funkcije dynamic_add spremaju rezultat na razliite adrese. Takoer je bitno naglasiti da
drugim pozivom funkcije dynamic_add prepisuje se adresa spremljena u pokazivau q, ali
se alocirana memorija ne oslobaa i podaci ostaju zapisani u memoriji. Ova memorija moe
se osloboditi samo pozivom funkcije free. Kako e sada u pokazivau q biti spremljena
adresa nove strukture, prethodna memorijska adresa je nepovratno izgubljena. Vie nije
mogue doi do podataka koji su spremljeni na toj memorijskoj adresi, jer vie niti jedna
varijabla u programu ne pamti tu adresu, ali ti podaci i dalje postoje i zauzimaju memoriju.
Ukoliko bi takav postupak ponovili puno puta, rezultat bi bio velik broj memorijskih lokacija
koje je na program zatraio od operacijskog sustava i zauzeo, ali ih vie ne moe osloboditi
jer vie ne zna adrese tih memorijskih lokacija i ne moe ih osloboditi.
Ovakav sluaj naziva se curenje memorije (eng. Memory leak), te predstavlja velik problem
pri radu s pokazivaima i dinamikom alokacijom memorije. Operacijski sustav takoer ne
zna koje memorijske adrese smije osloboditi dok mu to eksplicitno ne javi program, jer
operacijski sustav pamti sve memorijske adrese koje su dodijeljene nekom programu, ali ne
provjerava koristi li taj program te memorijske lokacije ili ne (jer to ni nije u nadlenosti
operacijskog sustava). Tako zauzeta memorija moe se osloboditi jedino tako to e
operacijski sustav prekinuti izvoenje programa, te samim time osloboditi sve resurse koje
je program zauzeo. Ovaj problem je neprimjetan kod ovako malih programa kao to je
gornji primjer, ali je ovaj problem vrlo est u svim kompleksnijim programima pisanim u C i
C++ jezicima, a pogotovo u programima koji moraju raditi due vrijeme i zauzimaju puno
memorije (web serveri, baze podataka, raunalne igre) te predstavljaju vrlo est razlog
ruenja programa i usporavanja cijelog sustava.
Posao je programera pobrinuti se da su sve dinamiki zauzete memorijske lokacije (bile ono
strukture ili osnovni tipovi podataka) osloboene pozivom naredbe free nakon to
programu vie nisu potrebne.
U naem primjeru to bi izveli dodavanjem naredbe free(q) prije ponovnog poziva funkcije
dynamic_add.
q = dynamic_add(a, b);
printf("rezultat: %d, %d, %d; adresa: %p \n", q->x, q->y, q->z, q);
free(q);
q = dynamic_add(a, b);
2.2 POKAZIVA NA STRUKTURU KAO LAN STRUKTURE
Do sada smo spominjali pokazivae na strukture koji su bili lanovi neke druge strukture.
Primjer iz prolih vjebi je bio onaj s tokama i trokutima. Ipak, do sada nismo imali primjer
gdje je lan strukture bio pokaziva na strukturu istog tipa. Bitno je jo jednom napomenuti
kako lan strukture ne moe biti istog tipa kao i struktura:
struct kupac {
char ime[100];
struct kupac next; //nemogue
} prvi;
Ipak, lan strukture moe biti pokaziva na isti tip podatka kao to je i sama struktura:
struct kupac {
char ime[100];
struct kupac *next; //mogue
} prvi;
struct kupac {
char *ime;
int id;
struct kupac *next;
};
int main(void) {
struct kupac prvi;
struct kupac *novi;
char buff[] = "Petar Kresimir Cetvrti";
char buff2[]= "Zvonimir Zadnji";
prvi.next = novi;
puts( prvi.ime);
puts( prvi.next->ime);
printf("adresa prvog: %p\n", &prvi);
printf("adresa novog: %p\n", prvi.next);
printf("adresa slijedeeg: %p\n", prvi.next->next);
return 0;
}
Definirali smo strukturnu varijablu tipa kupac naziva prvi i pokaziva na strukturu tipa
kupac naziva novi. Budui da je prvi strukturna varijabla, za nju je memorija ve alocirana i
ne moe se mijenjati lokacija gdje se u memoriji sprema. Isto tako, kada spremamo podatke
u varijablu prvi njegovim elementima pristupamo s operatorom toka. Primijetimo kako
struktura kupac ima lanove ime, id i next, gdje je ime pokaziva na polje znakova, id je
cjelobrojna vrijednost, dok je next pokaziva na strukturu tipa kupac. Zbog toga pri
upisivanju imena u strukturu moramo koristiti naredbu strcpy() kako bi mogli upisati ime
kupca. Naravno, prvo je potrebno alocirati memoriju za ime, to inimo funkcijom malloc na
ve poznati nain. Adresu na koju pokazuje next postavljamo na NULL, to oznaava da je
varijabla prvi i prvi i zadnji lan liste kupaca.
Nakon toga alociramo memoriju za novu strukturu tipa kupac, iju adresu spremamo u
pokaziva novi. Na isti nain kao i do sada postavljamo podatke u strukturu na koju
pokazuje novi. Postavljanjem vrijednosti prvi.next na adresu koja je spremljena u
pokazivau novi, uspjeno smo kreirali povezanu listu. Sada podacima spremljenim u
novostvorenoj strukturi osim preko pokazivaa novi moemo pristupiti i preko varijable
prvi.
Prema rezultatu ispisa vidimo na kojim su adresama spremljene strukture. Vidimo kako je
adresa spremljena u pokazivau next druge strukture jednaka NULL, to znai da je taj
element liste posljednji u listi.
Bitno je naglasiti da se ovako povezanoj listi ne moe direktno pristupiti i-tom elementu
liste, jer ne znamo njegovu lokaciju. Svaki element liste je dinamiki alociran i elementi liste
su 'razbacani' po memoriji. Zbog toga kada elimo pristupiti bilo kojem elementu liste,
moramo prolaziti kroz sve elemente liste od prvog elementa. Pogledajmo slijedei kod:
Prema tome, kada elimo dodati novi element u listu, dinamiki emo alocirati memoriju za
taj element, te emo njegovu adresu spremiti u pokaziva next unutar zadnjeg elementa u
listi. Kako bi mogli jednostavno dodavati elemente u listu, moemo napisati funkciju koja e
nam omoguiti dodavanje novog elementa na kraj liste.
U ovom sluaju definirali smo dvije funkcije koje e proi kroz listu, testirati svaki element
prema nekom odreenom uvjetu, te vratiti adresu elementa liste ukoliko odgovara uvjetu,
a NULL ako ne odgovara uvjetu. Ovdje imamo dva uvjeta koja testiramo: je li id trenutno
gledanog elementa liste jednak predanom id-u, te je li ime trenutno gledanog elementa
liste jednako predanom imenu.
Primjer 1.
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 struct kupac {
6 char *ime;
7 int id;
8 struct kupac *next;
9 };
10
11 char* read_name() {
12 int i;
13 char *name;
14 char buff[100];
15 fgets(buff, 100, stdin);
16 for ( i=0; buff[i] != '\n'; i++) {} //prazan for da se dodje na kraj polja
17 buff[i] = '\0';
18 name = (char*) malloc( strlen(buff) * sizeof(char) );
19 strcpy(name, buff);
20 return name;
21 }
22
23 struct kupac* init_list() {
24 struct kupac *novi = (struct kupac*) malloc(sizeof(struct kupac));
25 novi->ime = NULL;
26 novi->next = NULL;
27 return novi;
28 }
29
30 struct kupac* find_by_name(struct kupac *prvi, char *name) {
31 struct kupac *iter;
32 for( iter=prvi; iter != NULL; iter=iter->next) {
33 if( strcmp(iter->ime, name) == 0 )
34 return iter;
35 }
36 return NULL;
37 }
38
39 struct kupac* find_by_id(struct kupac *prvi, int id) {
40 struct kupac *iter;
41 for( iter=prvi; iter != NULL; iter=iter->next) {
42 if( iter->id == id )
43 return iter;
44 }
45 return NULL;
46 }
47
48 void append(struct kupac *prvi) {
49 puts("Dodavanje novog kupca");
50 struct kupac *novi = NULL;
51 struct kupac *iter = NULL;
52 if(prvi->ime == NULL) { //prazna lista
53 //ucitaj podatke i postavi next zadnjeg elementa na NULL
54 printf("ime: ");
55 prvi->ime = read_name();
56 printf("id: ");
57 scanf("%d", &prvi->id);
58 getchar();
59 prvi->next = NULL;
60 }
61 else { //pronadji kraj liste
62 novi = (struct kupac*) malloc(sizeof(struct kupac));
63 for (iter = prvi; iter->next != NULL; iter = iter->next) {}; //prazan for
64 //postavi zadnji element liste na novi
65 iter->next = novi;
66 //ucitaj podatke i postavi next zadnjeg elementa na NULL
67 printf("ime: ");
68 novi->ime = read_name();
69 printf("id: ");
70 scanf("%d", &novi->id);
71 getchar();
72 novi->next = NULL;
73 }
74 }
75
76 int main(void) {
77 struct kupac *prvi = init_list();
78 struct kupac *iter = NULL;
79 int n = 5;
80 int i;
81
82 for (i = 0; i < n; i++) {
83 append(prvi);
84 }
85
86 for( iter=prvi; iter != NULL; iter=iter->next) {
87 puts(iter->ime);
88 }
89
90 while(1) {
91 char b[100];
92 gets(b);
93
94 iter = find_by_name(prvi, b);
95 if( iter != NULL )
96 printf(" Nadjen %s \n", iter->ime);
97 else
98 printf(" Nije nadjen! \n");
99 }
100 return 0;
101 }
Kratko obrazloenje [Primjer 1]: U funkciji main za prvi element liste pozivamo funkciju
init_list(), iji je zadatak alocirati memoriju za prvi element liste i njegove lanove
postaviti na NULL. Razlog tome je jer u funkciji append() na nain opisan u prethodnom
potpoglavlju testiramo je li lista prazna ili nije. Jo jedna posebnost je funkcija
read_name(), koja vraa adresu polja u koje je spremljeno ime. Funkcija omoguuje upis
imena, te budui da koristi funkciju fgets(stdin) koja upisuje i '\n' u polje ona brie taj
'\n' iz polja, dinamiki alocira memoriju za upisani tekst, kopira ga u dinamiki alociranu
memoriju te adresu te memorije vraa kao rezultat. Zato se u pokaziva ime elementa liste
jednostavno spremi povratni rezultat te funkcije, koji je adresa upisanog stringa.
Primjer 2. Zamislimo kako elimo napisati program koji e pronai dvije najvie toke i
izraunati njihovu udaljenost. Znamo kako je udaljenost u trodimenzionalnom prostoru
izmeu dvije toke definirana slijedeom formulom:
= (2 1 )2 + (2 1 )2 + (2 1 )2
Zadatak: Napisati program koji e omoguiti unos prirodnog broja n koji predstavlja broj
toaka, a nakon njega unos n toaka u polje struktura tocke. Broj n nije ogranien (osim
veliinom tipa podatka int i dostupnom memorijom raunala). Dinamiki alocirajte memoriju
za upis toaka. Pretpostavite kako upisane toke predstavljaju toke terena u 3d prostoru.
Pronai i na ekran ispisati udaljenost dva najvia vrha tog terena.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4
5 typedef struct tocka {
6 float x;
7 float y;
8 float z;
9 } Tocka;
10
11 void inputData(Tocka *tocke, int n) {
12 int i;
13 for (i = 0; i < n; i++) {
14 printf("Upisi x, y i z za %d tocku: ", i+1);
15 scanf("%f%f%f", &tocke[i].x, &tocke[i].y, &tocke[i].z);
16 }
17 }
18
19 void findTopTwo(Tocka *p, int n, Tocka *max[]) {
20 int i;
21 max[0] = &p[0];
22 max[1] = &p[1];
23 for (i = 2; i < n; i++) {
24 if(max[0]->z < p[i].z || max[1]->z < p[i].z) {
25 if(max[0]->z < max[1]->z)
26 max[0] = &p[i];
27 else
28 max[1] = &p[i];
29 }
30 }
31 }
32
33 float len3d(Tocka *p1, Tocka *p2) {
34 return sqrt( pow(p2->x - p1->x, 2) + pow(p2->y - p1->y,2) + pow(p2->z - p1->z,
2));
35 }
36
37 void printTocka(Tocka *p) {
38 printf("%.2f, %.2f, %.2f \n", p->x, p->y, p->z);
39 }
40
41 int main(void) {
42 Tocka *tocke;
43 Tocka *max[2];
44 int n;
45 float D;
46
47 printf("Upisi broj tocaka: ");
48 scanf("%d", &n);
49 tocke = (Tocka *) malloc ( n * sizeof(Tocka));
50 inputData(tocke, n);
51
52 for (int i = 0; i < n; i++) {
53 printf("%.2f %.2f %.2f\n", tocke[i].x, tocke[i].y, tocke[i].z);
54 }
55
56 findTopTwo(tocke, n, max);
57
58 D = len3d(max[0], max[1]);
59
60 printf("Udaljenost najvisih vrhova je %.2f\n", D);
61 printf("a njihove koordinate su:\n");
62 printTocka(max[0]);
63 printTocka(max[1]);
64 return 0;
65 }
Kratko obrazloenje [Primjer 2]: U ovom zadatku definirano je nekoliko osnovnih funkcija
koje sadre funkcionalnost programa.
Funkcija inputData prima kao argument pokaziva na dinamiki alocirano polje struktura
tipa Tocka i broj toaka koje treba upisati, a zadatak koji obavlja je upis koordinata toaka u
predano polje struktura tipa Tocka.
Funkcija findTopTwo prima kao argumente polje struktura tipa Tocka, broj elemenata u
polju, te pokaziva na polje pokazivaa tipa Tocka. Funkcija ne vraa nikakvu vrijednost.
Zadatak funkcije je pronai u predanom polju toaka dvije toke koje imaju najviu
vrijednost Z koordinate, te njihove adrese spremiti u polje pokazivaa na strukturu Tocka,
koje je predano kao trei parametar. Ovakav pristup koristimo jer nije mogue iz funkcije
vratiti vie od jednog podatka, a u naem sluaju elimo vratiti dvije adrese koje
predstavljaju lokacije dvije najvie toke. Kako ne moemo odjednom vratiti dvije adrese,
koristimo pristup u kojem emo predati funkciji polje pokazivaa, te emo direktno u njega
spremiti adrese najviih toaka. Mogue je primijetiti kako bi se ovakav pristup mogao lako
generalizirati tako to e traiti proizvoljan broj najviih toaka (za razliku od dvije u
trenutnom sluaju), gdje bi se taj broj toaka koji se trai trebao predati kao etvrti
argument funkciji.
Funkcija len3d prima adrese dvije toke u memoriji, a vraa vrijednost koja predstavlja
udaljenost te dvije toke.
Funkcija printTocka prima adresu toke koju treba ispisati, a ne vraa nikakvu vrijednost
ve ispisuje koordinate toke na ekran.
Unutar main funkcije se uitava podatak koliko toaka treba upisati, te se alocira memorija
za toliko toaka. Za ostale funkcionalnosti samo se pozivaju gore navedene funkcije.
Primjer 3. Zamislimo kako elimo napisati program koji e pronai koji od trokuta ima
najveu udaljenost od ishodita koordinatnog sustava. Znamo kako je udaljenost u
trodimenzionalnom prostoru izmeu dvije toke definirana slijedeom formulom:
= (2 1 )2 + (2 1 )2 + (2 1 )2
= 2 + 2 + 2
Zadatak: Napisati program koji e omoguiti uitavanje N toaka u polje struktura tipa tocka i
N trokuta u polje struktura tipa trokut. Program treba pronai trokut koji je najudaljeniji od
ishodita. Za mjeru udaljenosti trokuta uzeti prosjenu udaljenost njegovih toaka:
(1 +2 +3 )
= 3
.
1 #include <stdio.h>
2 #include <math.h>
3 #include <stdlib.h>
4
5 typedef struct tocka {
6 float x;
7 float y;
8 float z;
9 } Tocka;
10 typedef struct trokut {
11 struct tocka *t1;
12 struct tocka *t2;
13 struct tocka *t3;
14 } Trokut;
15
16 void inputData(Tocka *p, Trokut *t, int n, int m) {
17 int i;
18 int ind1, ind2, ind3;
19
20 for (i = 0; i < n; i++) {
21 printf("Upisi x, y i z za %d tocku: ", i);
22 scanf("%f%f%f", &p[i].x, &p[i].y, &p[i].z);
23 }
24 for (i = 0; i < m; i++) {
25 printf("Upisi indexe tocaka za %d trokut: ", i);
26 scanf("%d%d%d", &ind1, &ind2, &ind3);
27 t[i].t1 = &p[ind1];
28 t[i].t2 = &p[ind2];
29 t[i].t3 = &p[ind3];
30 }
31 }
32
33 float len3d(Tocka p) {
34 return sqrt( p.x*p.x + p.y*p.y + p.z*p.z);
35 }
36
37 float distTrokut(Trokut t) {
38 float D = 0.0;
39 D = len3d(*t.t1) + len3d(*t.t2) + len3d(*t.t3);
40 D /= 3;
41 return D;
42 }
43
44 int main(void)
45 {
46 Tocka *tocke;
47 Trokut *trokuti;
48 Trokut *max;
49 int i, n, m;
50 float Dtrenutni=0, Dmax=0;
51
52 printf("Upisi broj tocaka: ");
53 scanf("%d", &n);
54 tocke = (Tocka *) malloc ( n * sizeof(Tocka));
55
56
57 printf("Upisi broj trokuta: ");
58 scanf("%d", &m);
59 trokuti = (Trokut *) malloc ( m * sizeof(Trokut));
60
61
62 inputData(tocke, trokuti, n, m);
63
64 for (i = 0; i < m; i++) {
65 Dtrenutni = distTrokut(trokuti[i]);
66 if (Dtrenutni > Dmax)
67 {
68 Dmax = Dtrenutni;
69 max = &trokuti[i];
70 }
71 }
72
73 printf("Najudaljeniji trokut je udaljen %.2f od ishodita,\n", Dmax);
74 printf("a njegove koordinate su:\n");
75 printf("(%.2f, %.2f, %.2f)\n", max->t1->x, max->t1->y, max->t1->z);
76 printf("(%.2f, %.2f, %.2f)\n", max->t2->x, max->t2->y, max->t2->z);
77 printf("(%.2f, %.2f, %.2f)\n", max->t3->x, max->t3->y, max->t3->z);
78
79 return 0;
80 }
Kratko obrazloenje [Primjer 3]: Program prvo nudi unos n toaka, a zatim unos N trokuta
definiranih tim tokama. Ovaj unos se obavlja pozivom funkcije inputData, kojoj se
predaju polja gdje e se spremati toke i trokuti, te broj n koji govori koliko toaka i trokuta
treba uitati.
U funkciji len3d rauna se udaljenost pojedine toke od ishodita. Funkcija prima kao
parametar strukturu, a ne pokaziva na strukturu. Kao i u gornjem primjeru, budui da je
povratna vrijednost float, ovakav ulazni argument u funkciju nema nekih nedostataka.
Pri rjeavanju zadataka potrebno je ispisati rezultate u tono odreenom formatu. Budui
da sustav automatski provjerava ispravnost rjeenja, sustav oekuje tekst REZULTATI: u
jednom redu, a nakon njega tono formatiran ispis rezultata na nain koji e biti naveden u
tekstu zadatka. Sav tekst koji se ispie prije teksta REZULTATI: sustav e ignorirati, kao i sav
tekst koji se ispie nakon oekivanog izlaza.
Zadatke je potrebno predati preko aktivnosti na Loomenu u koju e Vas uputiti nastavnici
na vjebama.