Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[c] Zapis i odczyt pliku bianrnego

EBC41 18 Maj 2010 17:41 2664 4
  • #1 18 Maj 2010 17:41
    EBC41
    Poziom 28  

    Witam kolegów znowu (niestety). Mam, nie ukrywam, rozpaczliwe pytanie. Ostatnio coś się popsuło w moim programie na projekt z informatyki, chodzi mi dokładnie o funkcję które odpowiedzialne są za odczyt i zapis tablicy struktur stanowiącej bazę danych do pliku. Nie ukrywam że jest to ewidentnie moja wina, ponieważ w poniedziałek wszystko poprawnie działało, ale potem chciałem parę zmiennych które i tak były używane prawie wszędzie wyrzucić powyżej main i przestać używać bez przerwy wskaźników do nich. Potem zaczęły się schody, nie udało mi się zrobić tego do końca, a backupu nie mam :( .


    Problem polega na czymś takim:
    Po wpisaniu czegoś do bazy danych i próbie zapisania do pliku "coś" się tam pojawia. Ale jest to przedzielone śmieciami z pamięci, wcześniej tego nie było. Odczytywać się w ogólę nie chcę. W prawdzie żaden błąd się nie pojawia ale nie mogę się dostać to danych w pliku (to też działało wcześniej). Kod jest jeszcze niedopracowany bo walczę żeby działało to, dlatego lepiej najpierw zrobić od nowa plik z bazą, wpisać coś do niej (kilka rekordów wystarczy), zapisać. Potem zamknąć program i spróbować otworzyć
    Aktualnie kod wygląda tak
    main.c

    Code:
    #include <stdio.h>
    
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #include "struct.h"                               
    #include "func.h"

     

    int main(int argc, char *argv[])
    {                                   
        char __file_name[]= "baza.bin";
        int selector=99;
        unsigned int menu;                           
        struct __book_data* db;                     
                   
       printf("\n                       Binarna baza danych ksiazek \n");
       printf("                      Autor: Mateusz \"EBC41\" Lubecki \n\n\t\t\t\tKONTAKT:\n");
       printf("                   e-mail: granicanet(malpa)kopernik.idl.pl\n");
       printf("                gadu-gadu: 7080821  skype: mateuszlubecki");




       printf("\n\n\n\n\n\n\tNacisnij dowolny klawisz aby przejsc do menu glownego");
       system("PAUSE > NUL");
       do {
       system("cls");
       printf("\n\t\tMENU GLOWNE\n");
       printf("\n\t\t1. Otwarcie istniejacej bazy danych\n\t\t2. Zapis bazy danych na dysk\n\t\t3. Dopisywanie nowych rekordow");
       printf("\n\t\t4. Przegladanie bazy danych\n\t\t5. Stworzenie nowej pustej bazy"); 
       printf("\n\n\t\t0. Wyjscie z programu bez zapisu danych");
       scanf("%d", &menu);
       if (menu == 1)
          OpenDb(__file_name, &DB_SIZE_COUNTER, db);
       if (menu == 2)
          SaveDbToFile(__file_name, &DB_SIZE_COUNTER, db);
       if (menu == 3)
          InsertData(&DB_SIZE_COUNTER, db);
       if (menu == 4)
          DbExplorer(&DB_SIZE_COUNTER, db);
       if (menu == 5)
          CreateDbFile(__file_name, &DB_SIZE_COUNTER, db);
     /* 
     CreateDbFile(__file_name);
     */
    } while (menu != 0);
    /*   
       scanf("%d", &selector);
       fflush(stdin);
       if (selector == 1) {
          OpenDb(__file_name, &DB_SIZE_COUNTER, db);
          DbExplorer(&DB_SIZE_COUNTER, db);
          }
       else {
       InsertData(&DB_SIZE_COUNTER, db);
       SaveDbToFile(__file_name, &DB_SIZE_COUNTER, db);
    }
    */

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

    func.h
    Code:

    extern unsigned long int ALLOC_SIZE;
    extern short int LCREATE;
    int CreateDbFile(char* __file_name, unsigned long int* DB_SIZE_COUNTER, struct __book_data* db)
    {
        unsigned long int SIZE_FWRITE;
         FILE* __FileToCreate;
         __FileToCreate = fopen(__file_name, "wb");   
        SIZE_FWRITE = *DB_SIZE_COUNTER + 1;
         if (__FileToCreate!=NULL)
        {     
            fputs("ddf", __FileToCreate);                     
            fwrite(&SIZE_FWRITE, sizeof(unsigned long int), 1, __FileToCreate); 
            fclose(__FileToCreate);
            db = (struct __book_data*)malloc(80 * sizeof(struct __book_data));
            if (db == NULL) {
                   printf ("Blad alokacji pamieci przy tworzeniu bazy danych");
                   system ("PAUSE");
                   LCREATE = 0;
                   return -1;
                   }
          else {
             printf("Pomyslnie utworzono nowa baze danych");
             system("PAUSE > NUL");
          }
         } 
       
    }

    int OpenDb(char* __file_name, unsigned long int* DB_SIZE_COUNTER, struct __book_data* db)
    {
        FILE* __FileToOpen;
        char __RedHeader[3];
        char __Header[4] = "ddf\0";
        __FileToOpen = fopen(__file_name, "rb");
        if (__FileToOpen!=NULL)
        {
           fgets(__RedHeader, 4, __FileToOpen);
           printf("%s\n", __Header);
           printf("%s\n", __RedHeader);
           printf("%d\n", strcmp(__RedHeader, __Header));
           if (strcmp(__RedHeader, __Header) == 0) {
              puts("Sprawdzanie pliku przebieglo poprawnie");
              fread(DB_SIZE_COUNTER, sizeof(unsigned long int), 1, __FileToOpen);
              if (*DB_SIZE_COUNTER>0) {
                 printf("Baza danych zawiera %d rekordow\n", *DB_SIZE_COUNTER);
                 if (*DB_SIZE_COUNTER < 80) {
                    db = (struct __book_data*)malloc(80 * sizeof(struct __book_data));
                    printf("Zaakowano pamiec na 80");
                    system("PAUSE");
                    ALLOC_SIZE = 80;
                    }
                       else {
                          db = (struct __book_data*)malloc(*DB_SIZE_COUNTER * sizeof(struct __book_data));
                          ALLOC_SIZE = 80 + *DB_SIZE_COUNTER;
                          printf("Zaalokowano pamiec na wiecej");
                          system("PAUSE");
                    }
                 if(db == NULL) {
                    printf("Blad alokacji pamieci, baza danych nie wczytana");
                    }     
                       
                 fread(db, sizeof(struct __book_data), *DB_SIZE_COUNTER, __FileToOpen);
                 }
              if (*DB_SIZE_COUNTER==0) {
                 printf("Baza danych jest pusta\n");
                 system("PAUSE > NUL");
                 }
              }
              else {
                 puts("Niepoprawny naglowek pliku. Mozliwe uszkodzenie bazy danych\n");
                 system("PAUSE >NUL");
                 return -1;
                 }
                               
          }                       
         else {
              printf("Blad otwarcia pliku bazy danych, sprawdz czy nie jest on w uzyciu przez inny program\n");
              return -1;
              }
       
                     
        fclose(__FileToOpen);
       
    }

    int SaveDbToFile(char* __file_name, unsigned long int* DB_SIZE_COUNTER, struct __book_data* db) {
        FILE* __File;
        __File = fopen(__file_name, "wb");
        if (__File!=NULL) {
           printf("Zapisuje naglowek... ");
           fputs("ddf", __File);
           printf("OK\n");
           printf("Zapisuje licznik rekordow... ");
           fwrite(DB_SIZE_COUNTER, sizeof(unsigned long int), 1, __File);
           printf("OK\n");
           printf("Zapisuje baze danych...");
           fwrite(db, sizeof(struct __book_data), *DB_SIZE_COUNTER, __File);
           printf("OK\n");
           printf("Gotowe..!!");
           fclose(__File);
    }
    }

    int InsertData(unsigned long int* DB_SIZE_COUNTER, struct __book_data* db) {
        char c;
        do {
        printf("W bazie danych jest %d pozycji\n", *DB_SIZE_COUNTER);
        printf("Podaj autora: ");
        fflush(stdin);
        scanf("%[^\n]%*1[\n]", &db[*DB_SIZE_COUNTER].__Author);
        fflush(stdin);
        printf("Podaj tytuł: ");
        scanf("%[^\n]%*1[\n]", &db[*DB_SIZE_COUNTER].__Title);
        fflush(stdin);
        printf("Podaj numer wydania: ");
        scanf("%d", &db[*DB_SIZE_COUNTER].__Anniversary_no);
        fflush(stdin);
        printf("Podaj rok wydania: ");
        scanf("%d", &db[*DB_SIZE_COUNTER].__Anniversary_y);
        fflush(stdin);
        printf("Podaj wydawnictwo: ");
        scanf("%[^\n]%*1[\n]", &db[*DB_SIZE_COUNTER].__Publisher);
        fflush(stdin);
        printf("Wprowadzono: \n");
        printf("Autor %s\n", db[*DB_SIZE_COUNTER].__Author);
        printf("Tytul %s\n", db[*DB_SIZE_COUNTER].__Title);
        printf("Numer wydania %d\n", db[*DB_SIZE_COUNTER].__Anniversary_no);
        printf("Rok wydania %d\n", db[*DB_SIZE_COUNTER].__Anniversary_y);
        printf("Wydawnictwo %s\n", db[*DB_SIZE_COUNTER].__Publisher);
        ++*DB_SIZE_COUNTER;
        printf("Dodac nastepny?");
        scanf("%c", &c);
        fflush(stdin);
    } while (c == 't');
    }

    int DbExplorer(unsigned long int* DB_SIZE_COUNTER, struct __book_data* db) {
        int i=0;
        char next;
        system("cls");
        do {
        if (i<*DB_SIZE_COUNTER && i>=0) {
           system("cls");
           printf("********************************************************************************");
           printf("*                         Rekord nr: %-41d *", i+1);
           printf("********************************************************************************");
           printf("\tAutor: %-9s\n", db[i].__Author);
           printf("\tTytul: %-9s\n", db[i].__Title);
           printf("\tNumer wydania: %-9d\n", db[i].__Anniversary_no);
           printf("\tRok wydania: %-9d\n", db[i].__Anniversary_y);
           printf("\tWydawnictwo: %-9s\n", db[i].__Publisher);
           printf("\n\n\n ");
           printf("Sterowanie: \n z - do tylu o 2 rekordy / x - do tylu o 1 rekord \n c - do przodu o 1 rekord / v - do przodu o 2 rekordy\n");
        }
        else {
             printf("Koniec bazy\n");
             if (next == 'z' || next == 'x') {
                      i = 0;
                      printf ("Przenosze na poczatek\n");
                      }
             else if (next == 'c' || next == 'v') {
                      i = *DB_SIZE_COUNTER-1;
                      printf ("Przenosze na koniec\n");
             }
    }
        scanf("%c", &next);
        fflush(stdin);
        if (next == 'z')
             i-=2;
        else if (next == 'x')
             i-=1;
        else if (next == 'c')
             i+=1;
        else if (next == 'v')
             i+=2;         
          }while (next != 'q');
    }

    struct.h
    Code:

        struct __book_data {                           
             char __Author[30];
             char __Title[50];
             int __Anniversary_no;
             int __Anniversary_y;
             char __Publisher[30];
             };   
             
    unsigned long int DB_SIZE_COUNTER = 0;
    unsigned long int ALLOC_SIZE = 0;
    short int LCREATE;

    0 4
  • #2 18 Maj 2010 22:28
    Dr.Vee
    VIP Zasłużony dla elektroda

    Podstawowy problem - "ryjesz" po pamięci :)
    Np. free(db), a db nie zostało zainicjalizowane.
    Albo - przekazujesz wskaźnik db przez wartość do funkcji, tam modyfikujesz kopię wskaźnika, wracasz z funkcji... ciąg dalszy dopowiedz sobie sam.
    Poza tym tak się nie dzieli projektu na pliki. Robi się tak:
    func.h:

    Code:
    #include "struct.h"
    
    extern int DbExplorer(unsigned long int* DB_SIZE_COUNTER, struct __book_data* db);

    func.c:
    Code:
    #include "func.h"
    
    int DbExplorer(unsigned long int* DB_SIZE_COUNTER, struct __book_data* db)
    {
    /* kod kod kod */
    }

    main.c:
    Code:
    #include "func.h"
    
    int main(void)
    {
        DbExplorer(abc, def);
    }

    Kompilujesz main.c, func.c, a później konsolidujesz (linkujesz) do program.exe

    Powodzenia,
    Dr.Vee

    0
  • #3 19 Maj 2010 08:03
    EBC41
    Poziom 28  

    Dzięki Vee że mi pomagasz :) A projekt właśnie rozwaliłem sobie jak m.in próbowałem go podzielić na pliki tak jak wyżej. Z tym ryciem po pamięci to też doskonale sobie zdaje z tego sprawę. Funkcja wczytująca bazę w przypadku gdy jest pusta nie alokuje pamięci, a ja jeszcze nie napisałem zabezpieczenia przed próbą edycji nieistniejących rekordów. Wcześniej miałem taki problem że niektóre rekordy się zapisywały a niektóre nie. Okazało się że program nie zadeklarował pamięci a potem umożliwił mimo tego pisanie do niej. Kompilator nie zgłaszał najmniejszych błędów tak samo nie było "Program przestał działać..."

    Cały czas pozostaje tylko problem z zapisem. Sprawdzałem jakąś starą kopię i tam po zapisie pliku binarnego w przerwach pomiędzy rekordami są wszędzie 00 a tutaj zdarzają się jakieś śmieci. Jak się nie uda to będę musiał przerzucić to co działa do starej wersji i to jakoś połatać (pomijając ile czasu na to strace)

    0
  • #4 19 Maj 2010 09:09
    utak3r
    Poziom 25  

    A próbowałeś debugować kod? Samą funkcję zapisu... Z czytania niewiele wynika, bo jest wręcz najeżony miejscami, gdzie może się powalić i można by tu przytoczyć w sumie całą funkcję jako "coś do sprawdzenia" ;)
    Ponadto: sprawdzałeś, czy funkcja insert dobrze działa? W sensie, czy to na pewno zapis się wali - czy też może już na wcześniejszym etapie. Wiesz, funkcja scanf też wcale do przyjemniaczków nie należy, a Ty tutaj zapodajesz niezłe kombinacje - jak np. wyłuskanie wskaźnika do pola we wskaźniku ;) - a scanf jest czuła na tym punkcie właśnie.

    Reasumując: co mówi debugger?

    0
  • #5 19 Maj 2010 17:48
    EBC41
    Poziom 28  

    Insert działa bo po rozwiązaniu problemu pisania po śmieciach w pamięci mogę te rekordy normalnie przeglądać w explorerze i się ładnie wszystkie wyświetlają. A używanie jakiej funkcji byś sugerował zamiast scanf?

    Dodano po 2 [godziny] 46 [minuty]:

    Dodam że chodziło mi o to że mogę je przeglądać jak dodam je w programie. Dalej pozostaje problem niemożności odczytania ich z pliku. Dalej drążę temat (mimo iż mnie lekko mówiąc szlak trafia) i wychodzi na to że jednak funkcja do odczytu działa. A o to screeny to poświadczające
    [c] Zapis i odczyt pliku bianrnego [c] Zapis i odczyt pliku bianrnego [c] Zapis i odczyt pliku bianrnego

    Dodano po 38 [minuty]:

    Zauważyłem też następną ciekawą rzecz. Kiedy kod na wczytywanie jest tak jak na screenie czyli &db[*SIZE............. to to co wpisuje nie zapisuje się do struktury tylko zupełnie gdzieś indziej.. Widać to na następnym screenie]
    [c] Zapis i odczyt pliku bianrnego [c] Zapis i odczyt pliku bianrnego [c] Zapis i odczyt pliku bianrnego
    Tam gdzie struktura została zadeklarowana czyli pod adresem 3e4a28 szesnastkowo nic nie ma, a pod &db czyli 22ff24 szesnastkowo są kompletne śmiecie. Wychodzi że dalej program pisze po pamięci jak mu się podoba.

    Natomiast następna ciekawa rzecz. Nie mogę z funkcji scanf zdjąć tej małpy przy intach bo wtedy w tym miejscu dostaje segmentation fault

    Dodano po 3 [godziny] 36 [minuty]:

    Już wszystko działa :). Alokacja pamięci na samym początku maina po utworzeniu wskaźnika na strukture pomogła :) Tylko teraz pytanie, jak to dokładnie podzielić na pliki.. Zrobiłem tak
    func.c

    Code:

    #include "func.h"
    int CreateDbFile(char* __file_name, unsigned long int* DB_SIZE_COUNTER, struct __book_data* db)
    {
        unsigned long int SIZE_FWRITE;
         FILE* __FileToCreate;
    (...)

    func.h
    Code:

    #include "struct.h" 
    extern unsigned long int ALLOC_SIZE;
    int CreateDbFile(char* __file_name, unsigned long int* DB_SIZE_COUNTER, struct __book_data* db);
    int OpenDb(char* __file_name, unsigned long int* DB_SIZE_COUNTER, struct __book_data* db);

    (...)

    main.c
    Code:

                           
    #include "func.h"

     

    int main(int argc, char *argv[])
    {                                 

    (...)

    I linker twierdzi że
    Code:

    1>main.obj : error LNK2005: _DB_SIZE_COUNTER already defined in func.obj
    1>main.obj : error LNK2005: _ALLOC_SIZE already defined in func.obj

    0