/*

datoteke_txt_i_bin_-_lista_sa_string_string_int_float_v2.c

    Datoteke i liste:

Kreira listu iz niza struktura niz_struktura[].

Struktura ime_strukture sadrzi: string, string, integer i float.

Cvorovi liste Lista sadrze: string, string, int, float.

Upis liste u bin datoteku.

Citanje liste iz bin datoteke.

Upis liste u txt datoteku.

Citanje liste iz txt datoteke.

Sortiranje liste po jednom i dva kriterijuma.

*/

#include <stdio.h>
#include<stdlib.h>
#include <string.h>                         // zbog strcpy()

#define MAX_SIZE 100                        // niz moze imati najvise MAX_SIZE elemenata
#define TEKST_SIZE 30                       // string moze imati najvise TEKST_SIZE karaktera


struct ime_strukture{                       // struktura ime_strukture
                      char  ime[TEKST_SIZE];    // ima svoj sadrzaj string, string, int, float
                      char  prezime[TEKST_SIZE];
                      int   brojInt;
                      float brojFloat;
                    };

// deklaracija sluzi samo da ne bismo svuda pisali struct ime_strukture, vec samo IME_STRUKTURE
typedef struct ime_strukture IME_STRUKTURE;

// niz_struktura je niz od MAX_SIZE struktura IME_STRUKTURE
typedef IME_STRUKTURE niz_struktura[MAX_SIZE];

struct cvor{                                // struktura cvor, to je jedan element liste.
             IME_STRUKTURE podatak;         // Sadrzaj cvora, jedna struktura ime_strukture podatak
             struct cvor *sledeci;          // i pointer na sledeceg clana liste
           };

// deklaracija sluzi samo da ne bismo svuda pisali struct cvor, vec samo CVOR
typedef struct cvor CVOR;

// PCVOR lista koja se sastoji od elemenata CVOR
typedef CVOR* PCVOR;


void prikazi_niz_struktura( char tekst[], IME_STRUKTURE niz[], int brClanova )
{
    int i;

    printf("\n\n %s \n",tekst);             // prikazuje opis liste

    for(i=0;i<brClanova;i++) {

        printf("\n | %-6s %-8s %5d %6.2f | \n",
               niz[i].ime,
               niz[i].prezime,
               niz[i].brojInt,
               niz[i].brojFloat );
    }
}


// Prikazuje opis liste i sadrzaj cvorova liste glava.
// Bez pomocnog cvora tekuci jer glava nece biti promenjena
// jer nije predata sa adresom (PCVOR *glava).
void prikazi_listu (char tekst[],PCVOR glava) {

    printf("\n\n %s \n",tekst);             // prikazuje opis liste

    if(glava == NULL)                       // ako nema cvorova u listi ispisuje: prazna
        printf("\n prazna. \n");
    else
         while(glava != NULL) {             // od pocetka do kraja liste
            printf("\n | %-6s %-8s %5d %6.2f \t adresa sledeceg %p | \n",
                   glava->podatak.ime,
                   glava->podatak.prezime,
                   glava->podatak.brojInt,
                   glava->podatak.brojFloat,
                   glava->sledeci );
            glava = glava->sledeci;         // idemo na sledeci cvor liste
    }
}


// Na kraj liste glava dodaje vec napravljeni novi cvor
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
// Dobija se isti redosled cvorova u odnosu na niz.
void dodaj_na_kraj (PCVOR *glava, PCVOR *rep, PCVOR novi)
{
    if(*glava == NULL) {                    // ako je lista prazna
        *rep = novi;                        // i rep i glava su taj novi cvor
        *glava = novi;
    } else {                                // ako lista nije prazna
        (*rep)->sledeci = novi;             // sledeci od starog repa je taj novi
        *rep = novi;                        // novi rep je taj novi
    }
}


// Kreira cvor novi od jedne strukture jedna_struktura, sledeci mu je NULL
void napravi_novi_cvor_od_strukture( PCVOR *novi, IME_STRUKTURE jedna_struktura )
{
    *novi = (PCVOR)malloc(sizeof(CVOR));    // rezervisemo memoriju za cvor novi

    if(*novi == NULL) {                     // obrada eventualne greske pri rezervisanju memorije
        printf("\n Greska pri rezervisanju memorije! \n");
        exit(1);                            // prekidamo program
    }

    strcpy( (*novi)->podatak.ime, jedna_struktura.ime );            // sa stringovima mora strcpy()
    strcpy( (*novi)->podatak.prezime, jedna_struktura.prezime );    // sa stringovima mora strcpy()
    (*novi)->podatak.brojInt = jedna_struktura.brojInt;
    (*novi)->podatak.brojFloat = jedna_struktura.brojFloat;
    (*novi)->sledeci = NULL;                // za sada cvor novi ne pokazuje na sledeci cvor
}


// Kreira listu glava od nizova koji imaju brClanova
void kreiraj_listu_od_niza_struktura ( PCVOR *glava, PCVOR *rep,
                                       IME_STRUKTURE niz[], int brClanova )
{
    PCVOR novi; // samo je deklarisan, memorija za njega bice rezervisana u funkciji napravi_novi_cvor_od_strukture()
    int i;

    for(i=0;i<brClanova;i++){
        napravi_novi_cvor_od_strukture( &novi, niz[i] );
        dodaj_na_kraj(glava,rep,novi);      // dodajemo na kraj da bi u listi bio isti redosled kao u niz tj. strukturi
    }
}


// Brise celu listu glava.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void obrisi_celu_listu (PCVOR *glava)
{
    PCVOR pom;

    while( ( pom = *glava ) != NULL ){      // dok glava postoji, brisemo glavu

        pom = *glava;                       // pocetni cvor glava pamtimo u pom zbog oslobadjanja memorije
        *glava = (*glava)->sledeci;         // drugi cvor postaje prvi, tj. novi prvi cvor glava postaje njegov (bivsi) sledeci cvor
        free(pom);                          // oslobadjamo memoriju koja je bila rezervisana za pom
    }                                       // (tu smo bili zapamtili bivsi prvi cvor glava)
}


// Brise prvi cvor liste glava
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void obrisi_prvi_cvor (PCVOR *glava){
    PCVOR pom;

    if( *glava == NULL ){                   // ako nema cvorova u listi tj. ako je lista prazna
        printf("\n\n Lista je prazna! Nema cvorova za brisanje ! \n\n");
        system("PAUSE");
    }
    else{                                   // ako ima cvorova u listi tj. ako lista nije prazna
        pom = *glava;                       // pocetni cvor glava pamtimo u pom zbog oslobadjanja memorije
        *glava = (*glava)->sledeci;         // drugi cvor postaje prvi, tj. novi prvi cvor glava postaje njegov (bivsi) sledeci cvor
        free(pom);                          // oslobadjamo memoriju koja je bila rezervisana za pom
    }                                       // (tu smo bili zapamtili bivsi prvi cvor glava)
}


// Brise poslednji cvor liste glava tj. brise rep.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void obrisi_poslednji_cvor (PCVOR *glava)
{
    PCVOR pom, poslednji;                   // pomocni cvorovi

    poslednji = (PCVOR)malloc(sizeof(CVOR));// rezervisemo memoriju za poslednji, njega na kraju brisemo
    if(poslednji == NULL){                  // obrada eventualne greske pri rezervisanju memorije
        printf("\n Neuspelo rezervisanje memorije. \n");
        exit(1);
    }

    pom = *glava;                           // glavu pamtimo u cvoru pom (cuvamo glavu da je ne bi promenili)

    while( pom->sledeci->sledeci )          // idemo do PRETPOSLEDNJEG cvora  !!! CAKA !!!
        pom = pom->sledeci;                 // krecemo se po listi

    poslednji = pom->sledeci;               // poslednji cvor je sada bivsi pretposlednji cvor
    pom->sledeci = NULL;                    // i on pokazuje na NULL (jer je sada postao poslednji cvor)
    free(poslednji);                        // brisemo bivsi poslednji cvor
}


// U binarnu datoteku ImeDatoteke upisuje listu glava.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void upisi_listu_u_bin_datoteku (char ImeDatoteke[],PCVOR glava)
{
    FILE *p_fajl;
    PCVOR tek = glava;                      // da glava ne bi bila promenjena, cuvamo glavu

    p_fajl = fopen(ImeDatoteke, "wb");      // otvaramo izlaznu binarnu datoteku za pisanje

    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju izlaznog bin fajla ! \n");
        exit(1);                            // napustamo program
    }

    while( tek ){                           // od pocetka do kraja liste

//        prikazi_jedan_cvor(tek);            // prikazuje samo jedan cvor, tek

        fwrite(tek, sizeof(CVOR), 1, p_fajl); // ceo jedan cvor tek odjednom upisujemo u datoteku
                                            // Ovde se menja tek (zato nismo radili sa glava) :
        tek = tek->sledeci;                 // idemo na sledeci cvor
    }
    fclose(p_fajl);                         // zatvaramo izlaznu bin datoteku
}


// Ucitava listu glava iz binarne datoteke ImeDatoteke.
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
void ucitaj_listu_iz_bin_datoteke (char ImeDatoteke[],PCVOR *glava,PCVOR *rep)
{
    FILE *p_fajl;
    PCVOR novi; // samo je deklarisan, memorija za njega bice rezervisana kasnije u ovoj funkciji

    p_fajl = fopen(ImeDatoteke, "rb");      // otvaramo ulaznu binarnu datoteku za citanje

    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju ulaznog bin fajla ! \n");
        exit(1);                            // napustamo program
    }
                                            // ucitavamo jedan po jedan cvor liste iz bin datoteke
    while( 1 ) {                            // beskonacna petlja koja se prekida sa break

        novi = (PCVOR)malloc(sizeof(CVOR)); // rezervisemo memoriju za cvor novi

        if(novi == NULL) {                  // obrada eventualne greske pri rezervisanju memorije
            printf("\n Greska pri rezervisanju memorije! \n");
            exit(1);                        // prekidamo program
        }

        fread(novi,sizeof(CVOR),1,p_fajl);  // u cvor novi ucitavamo ceo jedan cvor iz bin datoteke
                                            // funkciju feof() pozivamo obavezno tek nakon pokusaja citanja sa fread() !
        if( feof(p_fajl) )                  // ako smo stigli do kraja bin datoteke
            break;                          // prekidamo while petlju

//        prikazi_jedan_cvor(novi);           // prikazuje samo jedan cvor, novi

        dodaj_na_kraj(glava,rep,novi);      // dodajemo cvor novi na kraj liste da bi se ocuvao redosled kao u nizovima
    }
    fclose(p_fajl);                         // zatvaramo ulaznu bin datoteku
}


// U txt datoteku ImeDatoteke upisuje listu glava.
void upisi_listu_u_txt_datoteku (char ImeDatoteke[],PCVOR glava)
{
    FILE *p_fajl;

    p_fajl = fopen(ImeDatoteke, "w");       // otvaramo izlaznu txt datoteku za pisanje
    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju izlaznog txt fajla ! \n");
        exit(1);
    }

    while(glava){                           // od pocetka do kraja liste glava

        // fprintf(u sta, format, sta)
        // fprintf() vraca broj upisanih elemenata. Ako je greska, vraca negativan broj.
        // Upis mora u ovom formatu, ne moze sa %-6s ili sa %6.2f   !!!
        fprintf(p_fajl, "%6s %8s %5d %f \n",
                glava->podatak.ime,
                glava->podatak.prezime,
                glava->podatak.brojInt,     // nema potrebe da upisujemo pokazivac na sledeci cvor
                glava->podatak.brojFloat ); // jer ce se on biti formiran pri dodavanju cvora u listu

        // ovde se glava menja, ali nije preneta kao pointer tako da ne treba da je cuvamo u cvoru pom
        glava = glava->sledeci;             // idemo na sledeci cvor
    }
    fclose(p_fajl);                         // zatvaramo izlaznu txt datoteku
}


// Iz txt datoteke ImeDatoteke ucitava listu glava.
void ucitaj_listu_iz_txt_datoteke(char ImeDatoteke[],PCVOR *glava,PCVOR *rep)
{
    FILE *p_fajl;                           // deklaracija pointera na fajl
    PCVOR novi; // samo je deklarisan, memorija za njega bice kasnije rezervisana u petlji while

    p_fajl = fopen(ImeDatoteke, "r");       // otvaramo ulaznu txt datoteku za citanje
    if( p_fajl == NULL ) {                  // obrada eventualne greske pri otvaranju fajla
        printf("\n Greska pri otvaranju ulaznog txt fajla %s ! \n", ImeDatoteke);
        exit(1);
    }

    // fscanf(odakle, format, adrese u sta),
    // fscanf() vraca broj ucitanih elemenata ili EOF na kraju fajla.
    // Ucitavamo jedan po jedan red iz txt fajla U ISTOM FORMATU u kojem smo je upisali u txt fajl:
    while ( 1 ) {                           // beskonacna petlja koja se prekida sa break

        novi = (PCVOR)malloc(sizeof(CVOR)); // rezervisemo memoriju za cvor novi
        if(novi == NULL) {                  // obrada eventualne greske pri rezervisanju memorije
            printf("\n Greska pri rezervisanju memorije! \n");
            exit(1);                        // izlazimo iz programa
        }

        // Ucitavamo jedan red iz ulaznog txt fajla U ISTOM FORMATU u kojem je upisan u txt fajl:
        fscanf(p_fajl, "%6s %8s %5d %f \n",
                    novi->podatak.ime,      // NE TREBA & (ADRESA)  !!!
                    novi->podatak.prezime,  // NE TREBA & (ADRESA)  !!!
                    &(novi->podatak.brojInt),
                    &(novi->podatak.brojFloat) );

        novi->sledeci = NULL;               // za sada, za svaki slucaj

//        prikazi_jedan_cvor(novi);           // prikazuje samo jedan cvor, novi

        dodaj_na_kraj(glava,rep,novi);      // dodajemo cvor novi na kraj liste da bi se ocuvao redosled kao u nizovima

        if (feof(p_fajl))                   // Ukoliko smo dosli do kraja datoteke, prekidamo while(1) petlju
            break;
    }
    fclose(p_fajl);                         // zatvaramo ulaznu txt datoteku
}


// SORTIRANJE LISTE


// Medjusobno zamenjuje sadrzaje dva cvora i,j.
// To je pomocna funkcija za funkcije sortiranja.
void zameni_medjusobno_sadrzaje_cvorova( PCVOR *i, PCVOR *j)
{                                           // argumenti su pointeri jer funkcija menja cvorove i,j.
    PCVOR mem;                              // deklaracija pomocnog cvora liste

    mem = (PCVOR)malloc(sizeof(CVOR));      // rezervisemo memoriju za cvor mem

    if(mem == NULL) {                       // obrada eventualne greske pri rezervisanju memorije
        printf("\n Greska pri rezervisanju memorije za cvor mem ! \n");
        exit(1);                            // prekidamo program
    }

    mem->podatak = (*i)->podatak;           // zamena sadrzaja dva cvora
    (*i)->podatak = (*j)->podatak;
    (*j)->podatak = mem->podatak;
}


// Sortira neopadajuce listu glava neopadajuce po imenima premestanjem sadrzaja cvorova.
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
void sortiraj_listu_neopadajuce_po_ime(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)
                                                    // ==  1 za nerastuci (obrnuti) redosled sortiranja
            if( strcmp(i->podatak.ime, j->podatak.ime) == -1 )      // KRITERIJUM SORTIRANJA !
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove
}


// Sortira neopadajuce listu glava po prezimenima
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
void sortiraj_listu_neopadajuce_po_prezime(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)
                                                            // ==  1 za nerastuci (obrnuti) redosled sortiranja
            if( strcmp(i->podatak.prezime, j->podatak.prezime) == -1 )      // KRITERIJUM SORTIRANJA !
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove
}


// Sortira neopadajuce listu glava po brojInt
void sortiraj_listu_neopadajuce_po_brojInt(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)
                                // > za nerastuci (obrnuti) redosled sortiranja
            if( i->podatak.brojInt < j->podatak.brojInt )       // KRITERIJUM SORTIRANJA !
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove
}


// Sortira neopadajuce listu glava po brojFloat
void sortiraj_listu_neopadajuce_po_brojFloat(PCVOR *glava)
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)
                                  // > za nerastuci (obrnuti) redosled sortiranja
            if( i->podatak.brojFloat < j->podatak.brojFloat )       // KRITERIJUM SORTIRANJA !
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove
}


// Sortira listu neopadajuce po prezimenima,
// a zatim u okviru istih prezimena sortira listu neopadajuce po imenima.
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
void sortiraj_listu_neopadajuce_po_prezimenima_imenima( PCVOR *glava )
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    // Prvo sortiramo po 1. kriterijumu sortiranja, po prezimenima
    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)
                                                            // ==  1 za nerastuci (obrnuti) redosled sortiranja
            if( strcmp(i->podatak.prezime, j->podatak.prezime) == -1 )      // 1. KRITERIJUM SORTIRANJA !
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove

//    prikazi_listu(" Lista je sada sortirana po prezimenima.", *glava);

    // Zatim ponovo sortiramo celu listu.
    // Ako su prezimena ista, sortiramo ih po imenima tj. 2. kriterijumu sortiranja.
    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)

            if( strcmp(i->podatak.prezime, j->podatak.prezime) == 0 )   // ako su prezimena ista
                                                        // ==  1 za nerastuci (obrnuti) redosled sortiranja
                if( strcmp(i->podatak.ime, j->podatak.ime) == -1 )      // 2. KRITERIJUM SORTIRANJA !
                    // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                    zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove
}


// Sortira listu neopadajuce po brojInt (godistima),
// a zatim u okviru istih brojInt (godista) sortira listu neopadajuce po brojFloat (proseku ocena).
// strcmp(a,b) uporedjuje stringove a i b i vraca:  ( CoMPare )
//      -1 za a<b
//      0 za a=b
//      1 za a>b
void sortiraj_listu_neopadajuce_po_brojInt_brojFloat( PCVOR *glava )
{
    PCVOR i,j;                              // pomocni cvorovi za sortiranje

    // Prvo sortiramo po 1. kriterijumu sortiranja, po brojInt
    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)
                                // < za nerastuci (obrnuti) redosled sortiranja
            if( i->podatak.brojInt > j->podatak.brojInt )       // 1. KRITERIJUM SORTIRANJA !
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove

//    prikazi_listu(" Lista je sada sortirana po godistima.", *glava);

    // Zatim ponovo sortiramo celu listu.
    // Ako su godista ista, sortiramo ih po proseku ocena tj. 2. kriterijumu sortiranja.
    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)

            if( i->podatak.brojInt == j->podatak.brojInt )  // ako su godista ista
                                      // < za nerastuci (obrnuti) redosled sortiranja
                if( i->podatak.brojFloat > j->podatak.brojFloat )       // 2. KRITERIJUM SORTIRANJA !
                    // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                    zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove
}




int main (void)
{
                                    // niz_struktura[] od 100 struktura IME_STRUKTURE
    IME_STRUKTURE niz_struktura[] = {
                                        { "Ivana",  "Milicev",  1997,   10.00 },
                                        { "Pera",   "Peric",    1992,    8.45 },
                                        { "Sava",   "Milicev",  1996,    7.12 },
                                        { "Mika",   "Mikic",    1996,    7.23 },
                                        { "Laza",   "Lazic",    1997,    7.34 },
                                        { "Danica", "Milicev",  1996,    7.56 },
                                        { "Dule",   "Lazic",    1995,    9.45 },
                                        { "Ceca",   "Milicev",  1996,    7.23 },
                                        { "Marija", "Milicev",  1997,    8.34 },
                                        { "Dragan", "Peric",    1995,    6.58 },
                                        { "Dragan", "Milicev",  1983,    6.78 },
                                    };

    int n;                                  // broj struktura u niz_struktura
    PCVOR Lista = NULL;                     // lista
    PCVOR rep = NULL;                       // rep liste


    n = sizeof(niz_struktura) / sizeof(IME_STRUKTURE);
    printf("\n n = %2d \n",n);              // broj struktura u niz_struktura

    printf("\n sizeof(IME_STRUKTURE)  = %2d \n",sizeof(IME_STRUKTURE)); // prikaz velicine memorije za IME_STRUKTURE
    printf("\n sizeof(niz_struktura)  = %2d \n",sizeof(niz_struktura)); // prikaz velicine memorije za niz_struktura

    printf("\n n x sizeof(IME_STRUKTURE) = sizeof(niz_struktura) \n");  // proracun velicine memorije za niz_struktura
    printf("\n %d x \t %d  \t\t   =  \t %d \n\n",
                n, sizeof(IME_STRUKTURE), sizeof(niz_struktura) );

    printf("\n sizeof(CVOR)  = %2d \n",sizeof(CVOR));   // prikaz velicine memorije za CVOR
    printf("\n sizeof(PCVOR) = %2d \n",sizeof(PCVOR));  // prikaz velicine memorije za PCVOR

    // Prikazujemo niz_struktura koji se sastoji od n struktura IME_STRUKTURE
    prikazi_niz_struktura("Niz struktura je: ", niz_struktura, n);

    // Formiramo listu od niza struktura.
    // U funkciji se menja lista i zato su argumenti adrese.
    kreiraj_listu_od_niza_struktura ( &Lista, &rep, niz_struktura, n );

    prikazi_listu( "Lista je: ", Lista );


// Binarna datoteka:

    // Listu upisujemo u bin datoteku, ne treba adresa jer se lista samo cita
    printf("\n\n Listu upisujemo u bin datoteku. \n");
    upisi_listu_u_bin_datoteku("Lista.bin",Lista);

    // Brisemo celu listu, dajemo adresu jer se vrsi promena liste
    printf("\n\n Brisemo celu listu (upisana je u bin datoteku). \n");
    obrisi_celu_listu(&Lista);

    prikazi_listu("Lista nakon brisanja je: ",Lista);

    // Listu ucitavamo iz bin datoteke, dajemo adrese jer se vrsi promena liste
    printf("\n\n Listu ucitavamo iz bin datoteke. \n");
    ucitaj_listu_iz_bin_datoteke("Lista.bin",&Lista,&rep);

    // prikazujemo listu ucitanu iz bin datoteke, ne treba adresa jer se lista samo cita
    prikazi_listu("Lista iz bin datoteke je: ",Lista);


// Tekstualna datoteka:

    // Listu upisujemo u txt datoteku, ne treba adresa jer se lista samo cita
    printf("\n\n Listu upisujemo u txt datoteku. \n");
    upisi_listu_u_txt_datoteku("Lista.txt",Lista);

    // Brisemo celu listu, dajemo adresu jer se vrsi promena liste
    printf("\n\n Brisemo celu listu (upisana je u txt datoteku). \n");
    obrisi_celu_listu(&Lista);

    prikazi_listu("Lista nakon brisanja je: ",Lista);

    // Listu ucitavamo iz txt datoteke, dajemo adrese jer se vrsi promena liste
    printf("\n\n Listu ucitavamo iz txt datoteke. \n");
    ucitaj_listu_iz_txt_datoteke("Lista.txt",&Lista,&rep);

    // prikazujemo listu ucitanu iz txt datoteke, ne treba adresa jer se lista samo cita
    prikazi_listu("Lista iz txt datoteke je: ",Lista);


// Sortiranja liste
    printf("\n\n\n Sortiranja liste: \n");

    // Sortiramo listu neopadajuce po imenima
    sortiraj_listu_neopadajuce_po_ime(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po imenima je: ",Lista);

    // Sortiramo listu neopadajuce po prezimenima
    sortiraj_listu_neopadajuce_po_prezime(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po prezimenima je: ",Lista);

    // Sortiramo listu neopadajuce po brojInt
    sortiraj_listu_neopadajuce_po_brojInt(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po brojInt je: ",Lista);

    // Sortiramo listu neopadajuce po brojFloat
    sortiraj_listu_neopadajuce_po_brojFloat(&Lista);
    prikazi_listu("Lista sortirana neopadajuce po brojFloat je: ",Lista);



    // Sortiramo listu neopadajuce po prezimenima,
    // a zatim u okviru istih prezimena sortiramo listu neopadajuce po imenima
    sortiraj_listu_neopadajuce_po_prezimenima_imenima(&Lista);
    prikazi_listu("Lista sortirana neop. po prezimenima i zatim u okviru prezimena po imenima: ",Lista);

    // Sortiramo listu neopadajuce po brojInt,
    // a zatim u okviru istih brojInt sortiramo listu neopadajuce po broFLoat
    sortiraj_listu_neopadajuce_po_brojInt_brojFloat(&Lista);
    prikazi_listu("Lista sortirana neop. po godistima i zatim u okviru godista po proseku: ",Lista);



/*
    // brisanje napravljenih datoteka
    remove("Lista.txt");
    remove("Lista.bin");
*/


    printf("\n\n\n");
    system("PAUSE");
    return 0;
}