EAccessViolation... at address + Lista jednokierunkowa

0

Witam. Od kilku dni piszę pewien program, który ma być taką mini bazą danych z możliwością dopisywania, edytowania i szukania elementów oraz zapisywania i wczytywanie jej z pliku (a no i jeszcze sortowania). Do tej pory nie udało mi się wiele napisać - ogólnie rzecz biorąc program generuje listę jednokierunkową (albo stos, sam w zasadzie nie wiem :( ) i daje możliwość dopisywania do niej elementów. Problem w tym, że podczas dopisywania 5/6 elementu wyskakuje taki oto zacny błąd : http://imageshack.us/f/40/eaccess.jpg/ . Gdy kliknie się run, element zostaje dodany do listy, a po ponownej próbie dodania kolejnego znowu wyskakuje ten błąd i tak w kółko.
Oto kod programu:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Tabela: TStringGrid;
    procedure Button1Click(Sender: TObject);
    procedure wypelnij_tabele(Sender: TObject);




  private
    { Private declarations }
  public
procedure dodaj_elem(imie, nazwisko, telefon, pesel : string);
procedure wyswietl;



end;

type
  wskaznik = ^element;
  element = record
      imie : string[10];
      nazwisko : string[22];
      telefon : string[12];
      pesel : string[15];
      next : wskaznik;
  end;

var
    first, prev, last : wskaznik;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}
procedure utworz_liste;
begin
  first:=nil;
end;


procedure TForm1.dodaj_elem(imie, nazwisko, telefon, pesel : string);
var nowy : wskaznik;
begin
  new(Nowy);
  nowy^.imie := imie;
  nowy^.nazwisko := nazwisko;
  nowy^.telefon := telefon;
  nowy^.pesel := pesel;
  if first = nil then
    begin
      first := nowy;
      last := first
    end
  else
    last^.Next := nowy;
    last := nowy;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.ShowModal;
end;



procedure TForm1.wypelnij_tabele(Sender: TObject);
  begin
    Tabela.cells[0,0] := 'Imie';
    Tabela.cells[1,0] := 'Nazwisko';
    Tabela.cells[2,0] := 'Telefon';
    Tabela.cells[3,0] := 'Pesel';
  end;

procedure TForm1.wyswietl;
var tmp : wskaznik;
var i : integer ;
begin
i := 1;
tabela.RowCount := 2;
tmp := first;
  while tmp <> nil do

  begin

    tabela.cells[0,i] := tmp^.imie;
    tabela.cells[1,i] := tmp^.nazwisko;
    tabela.cells[2,i] := tmp^.telefon;
    tabela.cells[3,i] := tmp^.pesel;
    tmp := tmp^.next;
    i:=i+1;
    tabela.RowCount := tabela.RowCount + 1;

  end;

end;

end.


 
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Unit1;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label4: TLabel;
    Label3: TLabel;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;



implementation





{$R *.dfm}


procedure TForm2.Button1Click(Sender: TObject);
begin
  begin
    Form1.dodaj_elem(edit1.Text, edit2.Text, edit3.Text, edit4.Text);

  end;
Form1.wyswietl;

end;

end. 

Z góry uprzedzam że nie jestem najlepszy w delphi.
Pozdrawiam.

0

Nie pracowałem nigdy z listami jedno i dwukierunkowymi, ale porównaj czy nie powinieneś mieć:

procedure TForm1.dodaj_elem(imie, nazwisko, telefon, pesel : string);
var nowy : wskaznik;
begin
  new(Nowy);
  nowy^.imie := imie;
  nowy^.nazwisko := nazwisko;
  nowy^.telefon := telefon;
  nowy^.pesel := pesel;
  if first = nil then
    begin
      first := nowy;
      last := first
    end
  else
    last^.Next := nowy; //tych dwóch instrukcji
    last := nowy;       //w bloku begin .. end?
end;

Pojęcie listy jednokierunkowej nie jest takie trudne, ale łatwo się pogubić w tym wszystkim...

PS: Napisz może w osobym module klasę do obsługi listy jednokierunkowej; Po co masz się męczyć ze zmiennymi globalnymi i procedurami publicznymi, jak można w jednym miejscu zaprogramować i tworzenie takiej listy, i usuwanie elementów, czyszczenie, modyfikowanie i wiele innych; Tworzysz obiekt raz i modyfikujesz zawartość listy eleganckimi metodami; Czy to nie lepsze rozwiązanie..?

0

dodając owe 2 linijki do bloku begin..end program zacnie się zawiesza.

1

zapoznaj się gamoniu z debugerem a nie minusujesz posty z poprawną odpowiedzią

1

Musisz wpakować te dwie instrukcje do bliku begin .. end, bo inaczej cały warunek nie będzie miał sensu; Zwróć uwagę na to, że:

if first = nil then
    begin
      first := nowy;
      last := first
    end
  else
    last^.Next := nowy;
    
  last := nowy;

tak jak w Twoim przypadku ostatnia linijka tego kodu będzie wykonywana zawsze, bez względu na to, czy wskaźnik first jest pusty czy nie, stąd ta linijka:

last := nowy;

wykona się zawsze, a ta:

last := first

nigdy; Przypisanie owszem nastąpi, ale po chwili do last znów zostanie wpisana wartość z first; Stąd brak sensu;

Sugerowałem się artykułem o listach jedno i dwukierunkowych z 4P i tam właśnie jest blok begin .. end przy generowaniu listy:

procedure TForm1.GenerateList(Count: Integer);
 var
  n: Integer;
  NewOne: PElement;
 begin
  Randomize;
  Root := nil;
  Last := nil;
  for n := 1 to Count do
   begin
    New(NewOne);
    NewOne^.Next := nil;
    NewOne^.Dane := Random(10000);
    if Root = nil then
     begin
      Root := NewOne;
      Last := Root;
     end else begin //tutaj blok
      Last^.Next := NewOne;
      Last := NewOne;
     end; //koniec bloku
   end;
 end; 

Formatowanie głupkowate stąd łatwo nie zauważyć begin po else; Tutaj łatwo:

procedure TForm1.GenerateList(Count: Integer);
var
  I: Integer;
  NewOne: PElement;
begin
  Randomize;
  Root := nil;
  Last := nil;

  for I := 1 to Count do
    begin
      New(NewOne);
      NewOne^.Next := nil;
      NewOne^.Dane := Random(10000);

      if Root = nil then
        begin
          Root := NewOne;
          Last := Root;
        end
      else
        begin //tutaj blok
          Last^.Next := NewOne;
          Last := NewOne;
        end; //koniec bloku
    end;
end;

Kwestia gustu; No ale czytać trzeba uważnie...

PS: Jeżeli pomimo tej zmiany lista dalej nie będzie działać jak należy, błąd tkwi gdzie indziej; Popraw także formatowanie swojego kodu, bo masz w nim niezły burdel;

0

Dziękuje za pomoc (zwłaszcza Misiekd, Twój post wniósł wiele do tematu). Problem polegał na tym, że brakowało linijki

 nowy^.next:=NIL; 
  if first = nil then (...) 

Teraz program działa już poprawnie.

0

Trzeba patrzeć w przyszłość, umiejętność debugowania to podstawa.
Jeśli za tydzień będziesz miał podobny błąd, znów będziesz z tym leciał na forum (i tak do usr*nej smierci?), a używając debuggera rozwiążesz to sam w 5 minut (lub mniej).
Sam sobie odpowiedz która droga jest lepsza. Szczególnie, że debugowanie to banał, no, chyba że cię to przerasta...

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