/*
4._zadatak_Ispit_jul_2017_v3.c 13.03.2018.
Ova verzija radi sa razlicitim brojem polozenih ispita po studentu.
4. zadatak Ispit jul 2017
U svakoj liniji tekstualne ulazne datoteke studenti.txt.
nalaze se podaci o studentima i podaci o polozenim ispitima.
Svaka linija u ovoj ulaznoj datoteci se sastoji od vise kolona
koje su medjusobno odvojene znakom tackazarez (;).
U prvoj koloni se nalazi ime i prezime studenta (maksimalan broj karaktera je 50).
U drugoj koloni se nalazi broj indeksa studenta (maksimalan broj karaktera je 9).
Potom slede podaci o polozenim ispitima.
Za svaki ispit cuvaju se podaci o sifri ispita (maksimalan broj karaktera je 6)
i oceni sa tog ispita (ocene su u intervalu od 6 do 10).
Prebaciti podatke iz tekstualne datoteke studenti.txt u jednostruko spregnutu listu.
(20 poena)
Sortirati ovu listu (u opadajucem redosledu prema prosecnoj oceni)
i prikazati njen sadrzaj. (15 poena)
Prikaz jedne linije ulazne datoteke:
Marko Markovic;0001/2016;P1;8;OIKT;9;UIS;6;
*/
// Moramo prvo formirati cvor liste i onda njega ubaciti na kraj liste
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> // zbog atoi()
#define SIZE_IME 51 // za jedan vise zbog '\0' na kraju stringa
#define SIZE_BRINDEKSA 10 // za jedan vise zbog '\0' na kraju stringa
#define SIZE_SIFRAISPITA 7 // za jedan vise zbog '\0' na kraju stringa
#define MAX_BRISPITA 50 // 50 ispita tokom studiranja
#define MAX_SIZETEKST 600 // SifraIspita + ; + ocena = 8 + ; + 2 = 11+1=12 . 12 * 50 = 600
typedef struct student STUDENT;
struct student{
char ImeIPrezime[SIZE_IME];
char BrojIndeksa[SIZE_BRINDEKSA];
char SifraIspita[MAX_BRISPITA][SIZE_SIFRAISPITA];
int ocena[MAX_BRISPITA];
float ProsecnaOcena; // ovo je dodato u listu zbog sortiranja po prosecnoj oceni
int BrojPolozenihIspita; // takodje
};
typedef struct cvor CVOR;
typedef CVOR* PCVOR;
struct cvor{
STUDENT podatak;
PCVOR sledeci;
};
// Prikazuje sadrzaj cvorova liste glava
void prikazi_listu(char *tekst, PCVOR glava)
{
int i;
printf("\n%s\n",tekst);
if(glava == NULL) {
printf(" prazna. \n");
} else {
while(glava) {
printf("\n | %-14s %10s ",
glava->podatak.ImeIPrezime,
glava->podatak.BrojIndeksa );
for( i=0; i < glava->podatak.BrojPolozenihIspita; i++ ){
printf(" %4s %2d ",
glava->podatak.SifraIspita[i],
glava->podatak.ocena[i]);
}
printf(" %5.2f %2d | \n",
glava->podatak.ProsecnaOcena,
glava->podatak.BrojPolozenihIspita );
glava = glava->sledeci;
}
}
printf("\n");
}
// 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
}
}
// 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;
}
// Sortiranje liste
void sortiraj_listu_po_float_prosecna_ocena_opadajuce( 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.ProsecnaOcena > j->podatak.ProsecnaOcena ) // 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)
{
FILE *fp;
PCVOR novi = NULL; // pocetne vrednosti su obavezno NULL
PCVOR glava = NULL;
PCVOR rep = NULL;
int i, k, duzina; // j je indeks za tekst2
int ZbirOcenaJednogStudenta;
char ImeUlaznogFajla[] = "studenti.txt";
char tekst[MAX_SIZETEKST];
char tekst2[SIZE_SIFRAISPITA];
char ch;
fp=fopen(ImeUlaznogFajla,"r"); // Otvaramo ulazni txt fajl za citanje
if(fp == NULL){
printf("\n Greska pri otvaranju ulaznog fajla \"%s\". \n",ImeUlaznogFajla);
exit(1);
}
// Marko Markovic;0001/2016;P1;8;OIKT;9;UIS;6;
// Od pocetka do kraja fajla ucitavamo jedan po jedan podatak i smestamo ga u listu
while ( 1 ) { // prva beskonacna petlja koja se prekida sa break
novi = (PCVOR)malloc(sizeof(CVOR)); // rezervisemo memoriju za cvor novi
if(novi == NULL) {
printf("\n Greska pri rezervisanju memorije za novi cvor ! \n");
exit(1);
}
ZbirOcenaJednogStudenta=0; // resetujemo ZbirOcenaJednogStudenta
// Ucitavamo iz reda ImeIPrezime i BrojIndeksa uz proveru da li smo stigli do kraja fajla
// format za ucitavanje "%[^;]" znaci da ucitavamo dok ne naidjemo na tackazarez !!!
// format za ucitavanje "%*c" ucitava BILO KOJI znak iz datoteke, ali ga nigdje ne zapisuje !!!
if( fscanf(fp,"%[^;]%*c%[^;]%*c",
novi->podatak.ImeIPrezime,
novi->podatak.BrojIndeksa ) == EOF )
break;
// printf("\n|%s|\n",novi->podatak.ImeIPrezime);
// printf("\n|%s|\n",novi->podatak.BrojIndeksa);
novi->podatak.BrojPolozenihIspita=0; // resetujemo brojac polozenih ispita
// Mi jos ne znamo broj polozenih predmeta (promenljiv je) i moramo da ga odredimo.
// Do sada smo ucitali ImeIPrezime i BrojIndeksa.
// Sada cemo, do kraja reda ili do kraja fajla,
// ucitavati parove SifraIspita i ocena.
// Podatak ocena cemo ucitavati u tekst2,
// pa tekst2 pretvoriti u float i dodeliti cvoru novi
while ( 2 ) { // druga beskonacna petlja koja se prekida sa break
if( fscanf(fp,"%[^;]%*c%[^;]%*c",
novi->podatak.SifraIspita[novi->podatak.BrojPolozenihIspita],
tekst2 ) == EOF )
break;
novi->podatak.ocena[novi->podatak.BrojPolozenihIspita] = atoi(tekst2);
// printf("\n novi->podatak.SifraIspita = %s \n",novi->podatak.SifraIspita[novi->podatak.BrojPolozenihIspita]);
// printf("\n novi->podatak.ocena = %d \n",novi->podatak.ocena[novi->podatak.BrojPolozenihIspita]);
ZbirOcenaJednogStudenta += novi->podatak.ocena[novi->podatak.BrojPolozenihIspita];
// printf("\n ZbirOcenaJednogStudenta = %d \n", ZbirOcenaJednogStudenta );
novi->podatak.BrojPolozenihIspita++; // brojimo polozene predmete
// printf("\n novi->podatak.BrojPolozenihIspita = %d \n",novi->podatak.BrojPolozenihIspita );
// provera da li smo stigli do kraja reda
if ( (ch=fgetc(fp)) == '\n' ) {
// printf("\n *** Prekidamo drugu beskonacnu while(1) petlju\n");
break; // prekidamo drugu beskonacnu while(1) petlju
} else {
ungetc( ch, fp ); // vracamo ch u fajl
}
} // while ( 2 ) { // druga beskonacna petlja koja se prekida sa break
// Sada konacno imamo broj polozenih ispita za tog jednog studenta.
// Racunamo prosecnu ocenu tog jednog studenta:
novi->podatak.ProsecnaOcena = (float)ZbirOcenaJednogStudenta / (float)novi->podatak.BrojPolozenihIspita;
novi->sledeci=NULL; // Obavezno jer je to novi cvor.
dodaj_na_kraj(&glava,&rep,novi);
} // while ( 1 ) { // prva beskonacna petlja koja se prekida sa break
prikazi_listu(" Lista je: ",glava);
//Sortiranje neopadajuce po prosecnim ocenama
sortiraj_listu_po_float_prosecna_ocena_opadajuce(&glava);
prikazi_listu(" Lista sortirana opadajuce po prosecnim ocenama je: ",glava);
fclose(fp);
printf("\n\n\n");
system("PAUSE");
return 0;
}