Sprawdzenie kodu - kolejka

0

Mam program realizujący kolejkę:

 program Projekt;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };

type TZesp = class
  Re, Im: real;
  constructor Create(a, b: real);
end;

constructor TZesp.Create(a, b: real);
begin
        Re := a;
        Im := b;
end;

type PKolejka = ^TKolejka;
    TKolejka = record
    Number: TZesp;
    Next: PKolejka;
    end;

type KKolejka = class
  Head: PKolejka;
  Tail: PKolejka;
  constructor Create;
  procedure Push(e: TZesp);
  function Pop:TZesp;
  procedure Show;
  procedure Remove;
  procedure RemoveAll;
end;

constructor KKolejka.Create;
begin
        Head := nil;
        Tail := nil;
end;

procedure KKolejka.Push(e: TZesp); //dodawanie elmentu do kolejki
var Nowy: PKolejka;
begin
        New(Nowy);
        Nowy^.Number := TZesp.Create(e.Re, e.Im);
        Nowy^.Next := nil;
        if Head = nil then  //<---------------------------------------------------------------
        begin
          Head := Nowy;
          Tail := Nowy;
        end
        else begin
          Tail^.Next := Nowy;
          Tail := Nowy;
        end;
end;

function KKolejka.Pop: TZesp;  //pobieranie elementu z kolejki
var Temp: PKolejka;
begin
        if Head = nil then
        begin
          writeln('Kolejka pusta');
        end
        else begin
          Result := Head^.Number;
          Temp := Head;
          Head := Head^.Next;
          Dispose(Temp);
        end;
end;

procedure KKolejka.Show;  //wypisanie kolejki
var Temp: PKolejka;
begin
        if Head = nil then writeln('Kolejka pusta')
        else Temp := Head;
        while Temp <> nil do
        begin
             writeln(Temp^.Number.Re,' + ',Temp^.Number.Im,'j');
             Temp := Temp^.Next;
        end;
end;

procedure KKolejka.RemoveAll; //usuniecie kolejki
var Temp: PKolejka;
begin
        while Head <> nil do
        begin
             Temp := Head^.Next;
             Dispose(Head);
             Head := Temp;
        end;
end;

procedure KKolejka.Remove; //usuniecie jednego elementu
var Temp: PKolejka;
begin
        if Head <> nil then
        begin
          Temp := Head^.Next;
          Dispose(Head);
          Head := Temp;
        end;
end;

var
  kolejka: KKolejka;
  liczba: TZesp;

begin
  kolejka.Create;
  kolejka.Push(TZesp.Create(3.5,4.5));
  kolejka.Push(TZesp.Create(3,5));
  kolejka.Push(TZesp.Create(35,4));
  kolejka.Show;
  liczba := kolejka.Pop;
  kolejka.Show;
  readln;
end.

#Przy uruchomieniu, w zaznaczonym miejscu wyrzuca wyjątek External: SIGSEGV. Debugowanie w Lazarusie jest trochę toporne, ale udało mi się dowiedzieć, że w momencie zwracania wyjątku, Head ma wartość Cannot access memory at address 0x8. Nie wiem co z tym zrobić.
#Czy taka realizacja kolejki jest poprawna?

2

poczytaj jak się tworzy instancję klasy bo to kolejka.Create; jest źle

0

Fakt. Zmieniłem na kolejka := KKolejka.Create;
Teraz pytanie 2.

2
  1. TZesp jako klasa mi się nie podoba bo wtedy traci sens cała lista na wskaźnikach
  2. Masz wycieki pamięci bo nigdzie nie zwalniasz TKolejka.Number
  3. RemoveAll powinno "korzystać" z Remove - nie bawimy się w kopiego pasta
  4. w metodzie Push niepotrzebnie tworzysz kolejną instancję klasy TZesp nie zwalniając nigdzie tej przekazanej do metody - kolejny wyciek pamięci
  5. w metodzie Pop jak kolejka jest pusta to by wypadało np. nil zwrócić albo rzucić błędem

Generalnie za dużo namieszałeś. Kolejka powinna być albo cała jako klasa albo cała jako rekordy i wskaźniki, inaczej to nie ma sensu i jak widać sprawia Ci duże problemy

0

Heh, program napisałem na wzór stosu podanego przez prowadzącego. Powiedzmy, że nie mam zaufania do jego programów i widać miałem dobre przeczucie.

  1. Jakie masz inne rozwiązanie?
  2. Czyli trzeba najpierw Dispose(Temp^.Number);, a później Dispose(Temp);?
  3. Ok
  4. Nowy^.Number := e;
  5. if Head = nil then
        begin
          Result := nil;
          writeln('Kolejka pusta');
        end

    Generalnie muszą być wskaźniki. Da się zrobić wskaźniki i klasę?

dodanie znacznika <code class="delphi"> - fp

0

@Przeszczep - a musisz koniecznie korzystać z klas, jeśli i tak wszystko robisz na wskaźnikach?

Deklaracja Twoich klas jest bardzo dziwna - nawet nie korzystasz z sekcji określających poziomy dostępu, tylko wszystko na kupę...

0

Czyli jak to najlepiej zrobić z użyciem wskaźników?

type PKolejka = ^TKolejka;
    TKolejka = record
    Re, Im: real;
    Next: PKolejka;
    end; 

Do tego funkcje, a Head i Tail tworzyć w programie głównym?

0

jeśli masz zadanie, że ma być i klasa i wskaźniki to jak zmienisz rekord na taki jak z powyższego postu i pozbędziesz się klasy TZesp to rozwiąże to większość moich uwag. Klasa opakowująca kolejkę z metodami pop i push jest OK tylko ta nieszczęsna TZesp psuje wszystko

0

push i pop to raczej określenia związane ze stosem - do kolejki przyjęło się używać enqueue i dequeue.

Czyli pop i push powinny zwracać/pobierać rekord? Czy do push podawać zmienne i tworzyć nowy element?

Niech przyjmuje/oddaje pointer na rekord;

Poczytaj sobie w ogóle jak wygląda kolejka i jak się jej używa, bo mam wrażenie, że nie do końca wiesz z czym się to je.

0

Nowa wersja:

program Projekt;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, crt
  { you can add units after this };

type PKolejka = ^TKolejka;
    TKolejka = record
    Re, Im: real;
    Next: PKolejka;
    end;

type KKolejka = class     // klasa kolejki
  private
         Head: PKolejka;
         Tail: PKolejka;
  public
        constructor Create;
        destructor Destroy;
        procedure Enqueue(e: PKolejka);
        function Dequeue: PKolejka;
        procedure Show;
        procedure Remove;
        procedure RemoveAll;
        function IsEmpty: boolean;
end;

constructor KKolejka.Create;   // konstruktor
begin
        Head := nil;
        Tail := nil;
end;

destructor KKolejka.Destroy;   // destruktor
begin
        RemoveAll;
end;

procedure KKolejka.Enqueue(e: PKolejka); // dodawanie elmentu do kolejki
var Nowy: PKolejka;
begin
        New(Nowy);
        Nowy^.Re := e^.Re;
        Nowy^.Im := e^.Im;
        Nowy^.Next := nil;
        if Head = nil then
        begin
          Head := Nowy;
          Tail := Nowy;
        end
        else begin
          Tail^.Next := Nowy;
          Tail := Nowy;
        end;
end;

function KKolejka.Dequeue: PKolejka;  // pobieranie elementu z kolejki
var Temp: PKolejka;
begin
        if Head = nil then
        begin
          Result := nil;
          writeln('Kolejka pusta');
        end
        else begin
          Result := Head;
          Temp := Head;
          Head := Head^.Next;
          Dispose(Temp);
        end;
end;

procedure KKolejka.Show;  // wypisanie kolejki
var Temp: PKolejka;
begin
        Temp := Head;
        if Temp = nil then writeln('Kolejka pusta');
        while Temp <> nil do
        begin
             writeln(Temp^.Re:6:2,' + ',Temp^.Im:6:2,'j');
             Temp := Temp^.Next;
        end;
end;

procedure KKolejka.RemoveAll; // usuniecie calej kolejki
begin
        while Head <> nil do
        begin
             Remove();
        end;
end;

procedure KKolejka.Remove; // usuniecie jednego elementu
var Temp: PKolejka;
begin
        if Head <> nil then
        begin
          Temp := Head^.Next;
          Dispose(Head);
          Head := Temp;
        end;
end;

function KKolejka.IsEmpty: boolean;  // czy pusta
begin
        if Head = nil then Result := True
        else Result := False;
end;

procedure FillE(var e: PKolejka; Re, Im: real);
begin
        e^.Re := Re;
        e^.Im := Im;
end;

function Losuj: real;
begin
        Result := (random(20000)-10000)/100;
end;

var
  kolejka: KKolejka;
  element: PKolejka;
  i: integer;

begin
  Randomize;
  kolejka := KKolejka.Create;
  New(element);
  for i := 1 to 10 do
  begin
       FillE(element, Losuj, Losuj);
       kolejka.Enqueue(element);
  end;
  repeat
    begin
         kolejka.Show;
         element := kolejka.Dequeue;
         readln;
         clrscr;
    end;
  until kolejka.IsEmpty;
  kolejka.Show;
  Dispose(element);
  readln;
end.

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