Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Access Violation mit einfach verketteter Liste (https://www.delphipraxis.net/154649-access-violation-mit-einfach-verketteter-liste.html)

Hybrid666 19. Sep 2010 18:51


Access Violation mit einfach verketteter Liste
 
Moin,

ich habe folgende Struktur meiner Daten:
Delphi-Quellcode:
  PCommandList = ^TCommandList;
  TCommandList = record
    InputName : Integer;
    Pressed : Boolean;
    Next : PCommandList;
  end;

  PMakroList = ^TMakroList;
  TMakroList = record
    TimeStamp : Integer;
    Commands : PCommandList;
    Next : PMakroList;
  end;
Im Prinzip soll das einfach eine Einfach verktettete Liste sein (PMakroList), die eine Reihe von Commands enthält (PCommandList), auch als einfach verkettete Liste.

Das Anlegen der Liste funktioniert einwandfrei und ich habe auch eine Routine in meinem Objekt, das die Struktur speichern soll. Dazu habe ich folgenden Code:

Delphi-Quellcode:
procedure TMakro.SaveToFile(FileName : String);
var
  MRef : PMakroList;
  CRef : PCommandList;
  SaveFile : TextFile;
  I : Integer;
begin
  AssignFile (SaveFile, FileName);
  ReWrite (SaveFile);
  WriteLn (SaveFile, 'ÿNAME' + MakroName);
  WriteLn (SaveFile, 'ÿBEGINDESCRIPTION');
  for I := 0 to Description.Count - 1 do
    writeln (SaveFile, Description[I]);
  WriteLn (SaveFile, 'ÿENDDESCRIPTION');
  WriteLn (SaveFile, 'ÿBEGINMAKRO');
  MRef := Makro;
  while Assigned (MRef) do
  begin
    WriteLn (SaveFile, 'T' + IntToStr (MRef.TimeStamp));
    CRef := MRef.Commands;
    while Assigned (CRef) do
    begin
      writeln (SaveFile, IntToStr (CRef.InputName) + '|' + BoolToStr (CRef.Pressed, True));
      CRef := CRef.Next;
    end;
    MRef := MRef.Next;
  end;
  writeln (SaveFile, 'ÿENDMAKRO');
  CloseFile (SaveFile);

end;
(über den stil sowas zu speichern lässt sich streiten, daher bitte keine große diskussion drüber).

Wie man sieht wird einfach eine Textdatei hergenommen, erst diverse Optionen (name, beschreibung) von dem Objekt gespeichert und dann gehts an die List. Eigentlich dachte ich, dass ich genug kontrollabfragen drin hab, sodass ich nie ins leere laufen kann. Es sei noch gesagt, das alle leeren pointer mit "nil" initialisiert werden beim anlegen, damits bei assigned auch keine probleme gibt.

Nun tritt sporadisch (immer mal wieder) an folgender Stelle ein fehler auf:
Delphi-Quellcode:
WriteLn (SaveFile, 'T' + IntToStr (MRef.TimeStamp))
Und zwar ist der fehler eine Access violation. Ich gehe davon aus, das er auf MRef nicht zugreiffen kann. aber wo ist da mein fehler, bzw wo fehlt die kontrolle?

Danke für die Hilfe

Hybrid

mkinzler 19. Sep 2010 18:54

AW: Bekomme einen Error (sporadisch)
 
Überprüfe doch ob der Zeiger <> Nil is (Assigned())

Hybrid666 19. Sep 2010 18:56

AW: Bekomme einen Error (sporadisch)
 
Sollte doch eigentlich
Code:
while Assigned (MRef) do
tun, oder?

himitsu 19. Sep 2010 18:58

AW: Bekomme einen Error (sporadisch)
 
Abgesehn von der fehlenden Fehlerbehandlung für SaveFile,
welches aber mit diesem Problem nichts zu tun hat,
dürfte dieser Code OK sein,


also vermute ich eher einen Fehler beim Erstellen dieser Listen.


Und ja, bei Pointern entpicht
Delphi-Quellcode:
Assigned(P)
einem
Delphi-Quellcode:
P <> nil
.

mkinzler 19. Sep 2010 18:59

AW: Bekomme einen Error (sporadisch)
 
Eher
Delphi-Quellcode:
if Assigned( MRef) then ...
oder
Delphi-Quellcode:
if not Assigned( MRef) then Exit;

Hybrid666 19. Sep 2010 19:01

AW: Bekomme einen Error (sporadisch)
 
Hier ist der Code zum einfügen in die liste. Das ist der einzige Codeteil, der änderungen an der liste vornimmt:
Delphi-Quellcode:
procedure TMakro.AddInput (Pressed : Boolean; Name : Integer);
begin
  //Liste komplett leer
  if Makro = nil then
  begin
    new (Makro);
    Makro.Next := nil;
    RefMakro := Makro;
    new (RefMakro.Commands);
    Makro.TimeStamp := TimeStamp;
    RefCommand := Makro.Commands;
    Makro.Commands.InputName := Name;
    Makro.Commands.Pressed := Pressed;
  end
  else
  // TimeStamp existiert schon, also nur command in command liste einfügen
  begin
    if TimeStamp = RefMakro.TimeStamp then
    begin
      new (RefCommand.Next);
      RefCommand := RefCommand.Next;
      RefCommand.Next := nil;
      RefCommand.InputName := Name;
      RefCommand.Pressed := Pressed;
    end
    else
    // Timestamp größer als momentaner Referenztimestamp, also neuer Makro-Listen-Eintrag + neuen command einfügen
    begin
      new (RefMakro.Next);
      RefMakro := RefMakro.Next;
      RefMakro.Next := nil;
      RefMakro.TimeStamp := TimeStamp;
      new (RefMakro.Commands);
      RefCommand := RefMakro.Commands;
      RefCommand.Next := nil;
      RefCommand.InputName := Name;
      RefCommand.Pressed := Pressed;
    end;
  end;
end;
Zu sagen: Die Variablen Makro und TimeStamp existieren als private in der Klasse TMakro. TimeStamp ist ein Integer und Makro ist PMakroList. RefCommand und RefMakro existieren ebenfalls als private.

himitsu 19. Sep 2010 19:06

AW: Bekomme einen Error (sporadisch)
 
hmmmm, also wenn es wieder mal zu dieser Exception kommt, dann schau dir doch einfach im Debugger die Listen an.
Und vorallem die Stelle, an welcher dieses Problem auftreten tut.

Sir Rufo 19. Sep 2010 19:07

AW: Bekomme einen Error (sporadisch)
 
Da er aber schon prüft, ob das Object assigned ist, vermute ich, dass sich da ein Zeiger einschleicht, der zwar noch auch einer ehemaligen Struktur steht, diese Struktur ist aber schon wieder freigegeben. Der Zeiger wird dadurch ja nicht automatisch auf nil gesetzt.

Kapsel doch mal die Zugriffe mit try ... except und schau nach, bei welchem Object er diese Zicken macht und ob du evtl. da vorher was gelöscht hast.

Was auch gerne passiert:

Ein Object wird doppelt in eine Liste eingetragen. Dann einmal Free und aus der Liste gelöscht und fertig ist der Zugriffsfehler bei dem immer noch existierenden Eintrag in der Liste.
Delphi-Quellcode:
var
  objlst : TObjectList;
  obj : TObject;
begin
  objlst := TObjectList.Create;
  try
    obj := TObject.Create;
    objlst.Add( obj );
    objlst.Add( obj );
    objlst.Delete( 0 );
  finally
  end;
end;

Hybrid666 19. Sep 2010 19:08

AW: Bekomme einen Error (sporadisch)
 
peinliche frage: ich hab noch nie mit nem debugger geschafft. was nimmt man da und wie schau ich mir die listen an?

Danke!

mkinzler 19. Sep 2010 19:13

AW: Bekomme einen Error (sporadisch)
 
Einfach Breakpoint an der Stelle setzen (oder kurz vorher) dann hält der Debugger hier an. Dann kannst du die Variablen durch Hinzufügen als überwachte Ausdrücke oder durch Überfahren mit der Maus auswerten


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:27 Uhr.
Seite 1 von 2  1 2   

Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf