Pliki rekordowe i struktury dynamiczne

0

Witam wszystkich.

Mam pewien problem z programem, którego zadaniem jest obsługiwanie biblioteki. W programie wykorzystałem struktury dynamiczne (listy). Dane tj. czytelnicy, książki i wypożyczenia muszą być zapisywane i wczytywane z plików. Zaprogramowałem wczytywanie i zapisywanie czytelników i książek z plików tekstowych do odpowiednich list, jednak prowadzący projekt nakazał mi użyć do tego celu plików rekordowych. I tu pojawia się mój problem. Zaprogramowałem wczytywanie i zapisywanie czytelników w ten właśnie sposób, wszystko się kompiluje, jednak przy próbie wyświetlenia wyrzuca mi błąd (external SIGSEGV). Bardzo proszę wszystkich o jakieś sugestie.
(procedury wczytywania/zapisywania/wyświetlania dla czytelników to odpowiednio procedure wczytaj, zapisz, wyswietl).

Pozdrawiam :)

program project2;

type
  czytelnicy=^czytelnik;
  rezerw=^rez;
  ksiazki=^ksiazka;

    rez=record
    wlasciciel:czytelnicy;
    nastepna:rezerw;
    data_wypozyczenia:string;
    ksiazka:ksiazki;

end;

  czytelnik=record
    nazwisko:string;
    nastepny:czytelnicy;
    poprzedni:czytelnicy;
    rezerwacja:rezerw;
 end;



   ksiazka=record
     tytul:string;
     nastepna_ksiazka:ksiazki;
     poprzednia_ksiazka:ksiazki;
     rezerwacja:rezerw;
     czy_wypozyczona:boolean;
 end;




  var

    pierwszy_czytelnik:czytelnicy;
    pierwsza_ksiazka:ksiazki;
    pierwsza_rezerwacja:rezerw;
    plik:text;
    plik2:file of czytelnicy;
    rob:string;

 procedure wczytaj(var glowa:czytelnicy);
    var nowy:czytelnicy;
     begin
      assign(plik2,'dane.ele');
      reset(plik2);
      glowa:=nil;
      while not eof (plik2) do
        begin
          new(nowy);
          read(plik2,glowa);
          writeln(glowa^.nazwisko);
          nowy^.nastepny:=glowa;
          glowa:=nowy;
        end;
      close(plik2);
     end;

  procedure wstaw(var glowa:czytelnicy);
    var nazw:string;nowy:czytelnicy;
      begin
        writeln('podaj nazwisko');
        readln(nazw);
        new(nowy);
        nowy^.nazwisko:=nazw;
        nowy^.nastepny:=glowa;
        glowa:=nowy;
      end;

  procedure wyswietl(glowa:czytelnicy);
    begin
      while glowa<>nil do
        begin
          writeln(glowa^.nazwisko);
          glowa:=glowa^.nastepny;
        end;
    end;

  procedure zapisz(glowa:czytelnicy);
    begin
      assign(plik2,'dane.ele');
      rewrite(plik2);
      while glowa<>nil do
        begin
          write(plik2,glowa);
          glowa:=glowa^.nastepny;
        end;
      close(plik2);
    end;

  procedure wczytaj_ksiazki(var glowa:ksiazki);
    var nowy:ksiazki;
     begin
      assign(plik,'dane_ksiazki.txt');
      reset(plik);
      while not eof (plik) do
        begin
          new(nowy);
          readln(plik,nowy^.tytul);
          nowy^.nastepna_ksiazka:=glowa;
          glowa:=nowy;
        end;
      close(plik);
     end;

 procedure wyswietl_ksiazki(glowa:ksiazki);
    begin
      while glowa<>nil do
        begin
          writeln(glowa^.tytul);
          glowa:=glowa^.nastepna_ksiazka;
        end;
    end;

  procedure wstaw_ksiazke(var glowa:ksiazki);
    var tyt:string;
        nowy:ksiazki;
      begin
        writeln('podaj tytul');
        readln(tyt);
        new(nowy);
        nowy^.tytul:=tyt;
        nowy^.nastepna_ksiazka:=glowa;
        glowa:=nowy;
      end;

  procedure zapisz_ksiazki(glowa:ksiazki);
    begin
      assign(plik,'dane_ksiazki.txt');
      rewrite(plik);
      while glowa<>nil do
        begin
          writeln(plik,glowa^.tytul);
          glowa:=glowa^.nastepna_ksiazka;
        end;
      close(plik);
    end;

function szukaj_czytelnika (nazwa:string; g:czytelnicy):czytelnicy;
  begin
    while g<>nil do
      begin
      if g^.nazwisko=nazwa then szukaj_czytelnika:=g;
      g:=g^.nastepny;

      end;
  end;

function szukaj_ksiazki (nazwa:string; g:ksiazki):ksiazki;
  begin
    while g<>nil do
      begin
      if g^.tytul=nazwa then szukaj_ksiazki:=g;
      g:=g^.nastepna_ksiazka;

      end;
  end;

 procedure wypozycz(var glowa:czytelnicy; var glowa2:ksiazki);
    var nazw:string;
        tyt:string;
        czytelnik:czytelnicy;
        ksiazka:ksiazki;
        wyp:rezerw;
      begin
        writeln('podaj nazwisko');
        readln(nazw);
        writeln('podaj tytul');
        readln(tyt);
        czytelnik:=szukaj_czytelnika(nazw,glowa);
        ksiazka:=szukaj_ksiazki(tyt,glowa2);
        new(wyp);
        wyp^.wlasciciel:=czytelnik;
        ksiazka^.rezerwacja:=wyp;
        ksiazka^.czy_wypozyczona:=true;
        wyp^.nastepna:=nil;
        czytelnik^.rezerwacja:=wyp;
        wyp^.ksiazka:=ksiazka;
        writeln(ksiazka^.tytul);
        WriteLn(czytelnik^.nazwisko);

 end;

procedure wyswietl_k(glowa:rezerw);
  begin
    while glowa<>nil do
      begin
        writeln(glowa^.ksiazka^.tytul);
        glowa:=glowa^.nastepna;
      end;
  end;

procedure wyswietl_wypozeczenie (glowa:czytelnicy);
  var
    czytelnik:czytelnicy;
    nazw:string;
begin
  writeln ('podaj nazwisko');
  readln(nazw);

  czytelnik:=szukaj_czytelnika(nazw,glowa);
  wyswietl_k(czytelnik^.rezerwacja);

end;


  procedure usun_czytelnika(glowa:czytelnicy);
    var nazw:string;
      czytelnik:czytelnicy;
      begin
        writeln('podaj nazwisko');
        readln(nazw);
        czytelnik:=szukaj_czytelnika(nazw,glowa);
        glowa:=glowa^.nastepny;


        dispose(czytelnik);
      end;

begin

  repeat
  writeln('co chcesz zrobic?');
  readln(rob);
  writeln;
  if rob='wczytaj' then
  wczytaj(pierwszy_czytelnik);
   if rob='wstaw' then
  wstaw(pierwszy_czytelnik);
  if rob='wyswietl' then
  wyswietl(pierwszy_czytelnik);
  if rob='zapisz' then
  zapisz(pierwszy_czytelnik);
  if rob='wczytaj2' then
  wczytaj_ksiazki(pierwsza_ksiazka);
  if rob='wyswietl2' then
  wyswietl_ksiazki(pierwsza_ksiazka);
  if rob='wypozycz' then
  wypozycz(pierwszy_czytelnik,pierwsza_ksiazka);
  if rob='wyswietlwyp' then
  wyswietl_wypozeczenie(pierwszy_czytelnik);
  if rob='usun' then
  usun_czytelnika(pierwszy_czytelnik);

 until rob='k';
  readln;
  end.

0

Popraw tagi do wstawienia kodu i formatowanie na bardziej standardowe w całym kodzie, to ktoś spojrzy.

2

Nieco dziwnie masz nazwane typy:

type
  czytelnicy=^czytelnik;

patrzę na procedury i za fiksa nie mogłem znaleźć deklaracji typu czytelnicy - to dosyć mylące; Powinieneś zachować jakąś konwencję, np. typ struktury nazwać TCzytelnik, a wskaźnik na nią PCzytelnik - od razu wiadomo czym te typy są;


@arteq - Twój kod wczytywania danych węzłów do listy (procedura wczytaj) nie zadziała z prostego powodu - próbujesz wczytać adres dla wskaźnika, a nie wartość dla niego, dokładnie w tej linii:

read(plik2,glowa);

glowa jest zwykłym typowanym pointerem, zaś glowa^ jest strukturą, na która wskaźnik wskazuje; O dziwo następna linijka jest już poprawna:

writeln(glowa^.nazwisko);

i odwołujesz się ładnie do wartości wskaźnika; Ten sam błąd popełniasz w procedurze zapisz, więc w pliku na pewno nie znajdą się poprawne dane;

Kod się kompiluje, bo pod względem składni i zgodności typów jest poprawny (chodzi o procedurę Write i Read), ale działa nieprawidłowo; Popraw te dwa mankamenty, a powinno być już dobrze (chyba, że to nie jedyne błędy);

Co do samego sposobu zapisu - nie zapisuj całych rekordów razem ze wskaźnikami, a utwórz sobie rekord, który zawierać będzie tylko dane węzła i te rekordy zapisuj do pliku typowanego; Przy wczytywaniu twórz nowe rekordy, ustawiaj im wskaźniki, a do rekordu z danymi wczytaj dane z pliku; Rzecz najprostsza.

0

Furious Programming, bardzo dziękuję Ci za odpowiedź, jednak po wprowadzeniu sugerowanych przez Ciebie poprawek (glowa^) kompilator wyrzuca błąd:** incompatible types: got"czytelnik" expected "czytelnicy"**. Co jest nie tak z tym typem?

1

Problem nie jest z typem, tylko z plikiem:

plik2:file of czytelnicy;

Typ czytelnicy to wskaźnik, więc zmienna plik2 oznacza plik typowany do przechowywania nie rekordów czytelnik, a wskaźników czytelnicy; Zmień deklarację zmiennej plik2 na poniższą:

plik2: file of Czytelnik;

I powinno się dać skompilować, chyba że znów gdzie indziej sa błędy.

0

Niestety po tej poprawce kompilator wyrzuca: Typed files cannot contain reference-counted types. Wcześniej już tego próbowałem. Brakuje mi pomysłów :(

2

Problemem jest deklaracja struktury:

type
  czytelnik=record
    nazwisko:string;
    nastepny:czytelnicy;
    poprzedni:czytelnicy;
    rezerwacja:rezerw;
  end;

a dokładniej pole nazwisko, które tak jak w komunikacie błędu posiada licznik referencji i nie ma z góry ustalonego rozmiaru; Musisz go ustalić podając w nawiasach kwadratowych jego długość, np.:

nazwisko: String[50]; // 50 znaków

bo w pliku typowanym każdy rekord musi zajmować tyle samo miejsca, a dynamiczny String na to nie pozwala.

0
procedure wczytaj(var glowa:czytelnicy);
    var nowy:czytelnicy;
     begin
      assign(plik2,'dane.ele');
      reset(plik2);
      glowa:=nil;
      while not eof (plik2) do
        begin
          new(nowy);
          read(plik2,glowa^);
          writeln(glowa^.nazwisko);
          nowy^.nastepny:=glowa;
          glowa:=nowy;
        end;
      close(plik2);
     end; 

Wydaje się że zamiast read(plik2,glowa) powinno byc read(plik2,nowy</sup>). Wielki dzięki @Furious Programming. Kompilator już nie wyrzuca błędów ale nadal podczas wywołania wczytywania mam problem z błędem external SIGSEGV. Asembler wyrzuca mi coś takiego:

00407CFB 0fb607 movzbl (%edi),%eax

Dodam jeszcze, że używam środowiska Lazarus.

Problem rozwiązany, wystarczyło z procedury wczytaj wyrzucić linijkę writeln(glowa^.nazwisko);. Biorę się do dalszej pracy. Ogromne podziękowania dla użytkownika Furious Programming.

Pozdrawiam :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1