Zadatak „Cena pizze u svetu”

Section author: Petar Marić <petarmaric@uns.ac.rs>

Iz zadate ulazne datoteke učitati podatke u jednostruko spregnutu listu, gde struktura pizza_st sadrži sledeća polja:

  • Cena (prirodan broj)
  • Skraćena oznaka države (jedna reč, tačno 3 karaktera)
  • Skraćena oznaka grada (jedna reč, tačno 2 karaktera)
  • Naziv pizze (jedna reč, do 20 karaktera)

Naravno, struktura pizza_st sadrži i polja potrebna za pravilno formiranje jednostruko spregnute liste.

Na osnovu zadate oznake države drzava i naziva pizze naziv_pizze iz formirane liste upisati podatke u zadatu izlaznu datoteku, u sledećem rasporedu polja strukture pizza_st:

  • Cena (koristiti "%4d" format specifikator)
  • Skraćena oznaka države
  • Skraćena oznaka grada
  • Naziv pizze

i potom u istu izlaznu datoteku upisati informaciju koja je prosečna cena pizze (zaokružena na 2 decimale) za zadatu državu i vrstu pizze.

Primer poziva:

./zad SRB Capricciosa pizze.txt analiza.txt

sa drzava=SRB, naziv_pizze=Capricciosa i zadatim ulazom u datoteci pizze.txt:

 503 SRB NS Capricciosa
 530 SRB NS Madjarica
1270 SRB NS Prosciutto
 990 ITA NA Margharita
1020 ITA NA Capricciosa
1120 ITA NA Prosciutto
 540 SRB BG Capricciosa
 620 SRB BG Madjarica
 320 USA NY YankeeSlice

i očekivanim izlazom u datoteci analiza.txt:

 503 SRB NS Capricciosa
 530 SRB NS Madjarica
1270 SRB NS Prosciutto
 990 ITA NA Margharita
1020 ITA NA Capricciosa
1120 ITA NA Prosciutto
 540 SRB BG Capricciosa
 620 SRB BG Madjarica
 320 USA NY YankeeSlice

avg = 521.50

Primer poziva kada pizza sa zadatim kriterijumima ne postoji:

./zad SRB Margharita ns_pizze.txt analiza.txt

sa drzava=SRB, vrsta_pizze=Margharita i zadatim ulazom u datoteci ns_pizze.txt:

 530 SRB NS Madjarica
1270 SRB NS Prosciutto
 510 SRB NS Capricciosa

i očekivanim izlazom u datoteci analiza.txt:

 530 SRB NS Madjarica
1270 SRB NS Prosciutto
 510 SRB NS Capricciosa

NOT FOUND!

Primer rešenja

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_DRZAVA 3+1
#define MAX_GRAD 2+1
#define MAX_NAZIV 20+1

#define ERROR_MAGIC_NUM -666.999

typedef struct pizza_st {
    int cena;
    char drzava[MAX_DRZAVA];
    char grad[MAX_GRAD];
    char naziv[MAX_NAZIV];
    struct pizza_st *next;
} PIZZA;

void init_list(PIZZA **head) {
    *head = NULL;
}

void add_to_list(PIZZA *new, PIZZA **head) {
    if(*head == NULL) { // list is empty
        *head = new;
        return;
    }

    add_to_list(new, &((*head)->next));
}

PIZZA *create_new_item(int cena, char drzava[], char grad[], char naziv[]) {
    PIZZA *new = (PIZZA *)malloc(sizeof(PIZZA));
    if (new == NULL) {
        printf("Not enough RAM!\n");
        exit(21);
    }

    new->cena = cena;
    strcpy(new->drzava, drzava);
    strcpy(new->grad, grad);
    strcpy(new->naziv, naziv);

    new->next = NULL;

    return new;
}

void read_list_from(FILE *in, PIZZA **head) {
    int cena;
    char drzava[MAX_DRZAVA];
    char grad[MAX_GRAD];
    char naziv[MAX_NAZIV];

    while(fscanf(in, "%d %s %s %s", &cena, drzava, grad, naziv) != EOF) {
        PIZZA *new = create_new_item(cena, drzava, grad, naziv);
        add_to_list(new, head);
    }
}

void save_item_to(FILE *out, PIZZA *x) {
    fprintf(
        out, "%4d %s %s %s\n",
        x->cena, x->drzava, x->grad, x->naziv
    );
}

void save_list_to(FILE *out, PIZZA *head) {
    if(head != NULL) {
        save_item_to(out, head);
        save_list_to(out, head->next);
    }
}

void destroy_list(PIZZA **head) {
    if(*head != NULL) {
        destroy_list(&((*head)->next));
        free(*head);
        *head = NULL;
    }
}

FILE *safe_fopen(char *filename, char *mode, int error_code) {
    FILE *fp = fopen(filename, mode);
    if (fp == NULL) {
        printf("Can't open '%s'!\n", filename);
        exit(error_code);
    }
    return fp;
}

int count_pizza(PIZZA *head, char drzava[], char naziv[]) {
    int count = 0;

    while(head != NULL) {
        if (strcmp(head->drzava, drzava) == 0 &&
            strcmp(head->naziv, naziv) == 0) {
            count++;
        }

        head = head->next;
    }

    return count;
}

int sum_pizza(PIZZA *head, char drzava[], char naziv[]) {
    int sum = 0;

    while(head != NULL) {
        if (strcmp(head->drzava, drzava) == 0 &&
            strcmp(head->naziv, naziv) == 0) {
            sum += head->cena;
        }

        head = head->next;
    }

    return sum;
}

double avg_pizza(PIZZA *head, char drzava[], char naziv[]) {
    double count = count_pizza(head, drzava, naziv);
    if (count == 0) {
        return ERROR_MAGIC_NUM;
    } else {
        return sum_pizza(head, drzava, naziv) / count;
    }
}

int main(int arg_num, char *args[]) {
    if (arg_num != 5) {
        printf("USAGE: %s DRZAVA NAZIV IN_FILENAME OUT_FILENAME\n", args[0]);
        exit(11);
    }

    char *drzava = args[1];
    char *naziv = args[2];
    char *in_filename = args[3];
    char *out_filename = args[4];

    FILE *in  = safe_fopen(in_filename,  "r", 1);
    FILE *out = safe_fopen(out_filename, "w", 2);

    PIZZA *head;
    init_list(&head);

    read_list_from(in, &head);
    save_list_to(out, head);

    double avg = avg_pizza(head, drzava, naziv);
    if (avg == ERROR_MAGIC_NUM) {
        fprintf(out, "\nNOT FOUND!\n");
    } else {
        fprintf(out, "\navg = %.2lf\n", avg);
    }

    destroy_list(&head);

    fclose(in);
    fclose(out);

    return 0;
}