#include #include #include #define VSE #define DELKA_BUFFERU 10000 #define DELKA_NAZVU 32 /* Od 85 to je vynulované. Jinak lze nulovat pomoci funkce memset nebo bzero. */ #define SEPARATORY ";\t\n" #define VSTUPNI_SOUBOR "veci.txt" #define VYSTUPNI_SOUBOR "veci_vystup.txt" #define VYSTUPNI_SOUBOR_BIN "veci_vystup.bin" typedef struct { char nazev[DELKA_NAZVU]; int cena; char *poznamka; } VEC; char *alokuj(int delka) { char *p_c; if ((p_c = (char *) calloc(delka, sizeof(char))) == NULL) { /* Funkce calloc na rozdil od malloc inicializuje reterce na nulu. */ printf("Malo pameti!\n"); return NULL; } else { return p_c; } } void nacti(char *jmeno_souboru, int *p_pocet, VEC **p_vec) { FILE *fr; char buffer_radku[DELKA_BUFFERU]; char *cislo_string; if ((fr = fopen(jmeno_souboru, "r")) == NULL) { printf("Soubor %s se nepodaril otevrit.\n", jmeno_souboru); exit(1); } while (fgets(buffer_radku, DELKA_BUFFERU, fr) != NULL) { cislo_string = strtok(buffer_radku, SEPARATORY); if (cislo_string != NULL) { (*p_pocet)++; } } if (*p_pocet == 0) { printf("V souboru %s neni ani jeden radek s daty.\n", jmeno_souboru); exit(1); } if ((*p_vec = (VEC *) malloc(*p_pocet * sizeof(VEC))) == NULL) { printf("Malo pameti!\n"); exit(1); } fclose(fr); if ((fr = fopen(jmeno_souboru, "r")) == NULL) { printf("Soubor %s se nepodaril otevrit.\n", jmeno_souboru); exit(1); } *p_pocet = 0; while (fgets(buffer_radku, DELKA_BUFFERU, fr) != NULL) { cislo_string = strtok(buffer_radku, SEPARATORY); if (cislo_string != NULL) { /* memset((*p_vec + *p_pocet)->nazev, '\0', DELKA_NAZVU); Chybi-li tento prikaz a DELKA_NAZVU < 85, tak je v binárním souboru stary obsah pameti v nevyuzite casti polozky "nazev". */ strcpy((*p_vec + *p_pocet)->nazev, cislo_string); cislo_string = strtok(NULL, SEPARATORY); if (cislo_string != NULL) { sscanf(cislo_string, "%d", &(*p_vec + *p_pocet)->cena); } (*p_vec + *p_pocet)->poznamka = NULL; cislo_string = strtok(NULL, SEPARATORY); if (cislo_string != NULL) { (*p_vec + *p_pocet)->poznamka = alokuj(strlen(cislo_string) + 1); if ((*p_vec + *p_pocet)->poznamka != NULL) { strcpy((*p_vec + *p_pocet)->poznamka, cislo_string); } } (*p_pocet)++; } } fclose(fr); } void zapis(char *jmeno_souboru, int pocet, VEC *p_vec) { FILE *fw; int i; fw = fopen(jmeno_souboru, "w"); for (i = 0; i < pocet; i++) { fprintf(fw, "%s;\t%d;\t%s\n", (p_vec + i)->nazev, (p_vec + i)->cena, (p_vec + i)->poznamka); } fclose(fw); } void zapis_bin(char *jmeno_souboru, int pocet, VEC *p_vec) { FILE *fw; int i; fw = fopen(jmeno_souboru, "wb"); for (i = 0; i < pocet; i++) { if ((fwrite((void *)(p_vec + i), sizeof(VEC), 1, fw)) != 1) { printf("Nepodaril se zapis do souboru %s.\n", jmeno_souboru); exit(1); } } fclose(fw); } void cti_bin_a_vypisuj_a_zapis_do_bin_snizenou_cenu(char *jmeno_souboru, int pocet, VEC *p_vec) { FILE *f; VEC veta; if ((f = fopen(jmeno_souboru, "rb+")) == NULL) { printf("Soubor %s se nepodaril otevrit.\n", jmeno_souboru); printf("Musite nejdriv definovat konstantu VSE a spustit prelozeny program.\n"); exit(1); } while (fread((void *)&veta, sizeof(VEC), 1, f) == 1) { printf("%s;\t%d;\t%s\n", veta.nazev, veta.cena, veta.poznamka); /* Po odtraneni konstanty VSE se misto polozky "poznamka" vypisuje obsah stare pameti, protoze je v souboru jen pointer s adresou, na kterou vypnuta cast programu text nedala. */ /* Je-li definovana konstanta VSE, tak se "poznamka" vypise, protoze po dobu behu programu ma pointer adresu zacatku textu poznamky. */ /* Vytvorime-li binarni soubor a pouzijeme jej v jinem programu, tak by nemel mit textove retezce reprezentovane jako pointer na string ale jako staticke pole, viz polozka "nazev". */ fseek(f, -(long) sizeof(VEC), SEEK_CUR); /* posun na zacatek prave prectene vety */ veta.cena--; if ((fwrite((void *)&veta, sizeof(VEC), 1, f)) != 1) { /* prepsani prave prectene vety */ printf("Nepodaril se zapis do souboru %s.\n", jmeno_souboru); exit(1); } fseek(f, 0L, SEEK_CUR); /* stejne poslouzi i prikaz fflush(f); */ /* posunuti o nula bytu od aktualni pozice, to jest za prave prectenou vetu */ /* Nedojde tak ke zmene, ale program bude spravne fungovat - nezacykli se nebo predcasne neskonci. */ /* http://stackoverflow.com/questions/1713819/why-fseek-or-fflush-is-always-required-between-reading-and-writing-in-the-read-wr */ } fclose(f); } void uvolni_pamet(int pocet, VEC **p_vec) { int i; for (i = 0; i < pocet; i++) { free((void *) (*p_vec + i)->poznamka); (*p_vec + i)->poznamka = NULL; } free((void *) *p_vec); *p_vec = NULL; } int porovnej_cena(const void *p_a, const void *p_b) { VEC *p_1 = (VEC *) p_a, *p_2 = (VEC *) p_b; if (p_1->cena < p_2->cena) return -1; else if (p_1->cena == p_2->cena) return 0; else return +1; } int porovnej_nazev(const void *p_a, const void *p_b) { return (strcmp(((VEC *)p_a)->nazev, ((VEC *)p_b)->nazev)); } int porovnej_poznamka(const void *p_a, const void *p_b) { if (((VEC *)p_a)->poznamka == NULL) return +1; else if (((VEC *)p_b)->poznamka == NULL) return -1; else return (strcmp(((VEC *)p_a)->poznamka, ((VEC *)p_b)->poznamka)); } int main() { int pocet_zaznamu = 0; VEC *p_veci = NULL; #ifdef VSE /* Parametry funkci viz slaidy "Pointer jako skutecny parametr funkce" a "Pointer na funkci". */ nacti(VSTUPNI_SOUBOR, &pocet_zaznamu, &p_veci); qsort((void *)p_veci, pocet_zaznamu, sizeof(VEC), porovnej_poznamka); zapis(VYSTUPNI_SOUBOR, pocet_zaznamu, p_veci); zapis_bin(VYSTUPNI_SOUBOR_BIN, pocet_zaznamu, p_veci); #endif cti_bin_a_vypisuj_a_zapis_do_bin_snizenou_cenu(VYSTUPNI_SOUBOR_BIN, pocet_zaznamu, p_veci); uvolni_pamet(pocet_zaznamu, &p_veci); return 0; }