Einzelnen Beitrag anzeigen

Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#6

AW: EAccessViolence bei Linearer Liste

  Alt 6. Mär 2016, 14:37
Eine Access Violation tritt immer dann auf, wenn du versuchst auf einen ungültigen Speicherbereich zuzugreifen (lesend oder schreiben). Ungültig ist ein Speicherbereich dann, wenn er vorher nicht allocated wurde.

Sowas passiert häuftig, wenn man beispielsweise mit Objekten arbeitet und vorher den Create Aufruf vergessen hat, oder wenn man Objekte bereits mit Free wieder zerstört hat, aber danach noch mit Ihnen arbeiten will. In deinem Falle ist die fehlerhafte Pointer-Arithmetik Schuld (präziser gesagt, wird dein Zeiger irgendwann entweder auf nil , oder eine andere nicht existente Speicherstelle zeigen. Sobald du dann mit ^ dereferenzierst, knallt es).

Generell ist es btw. immer eine gute Idee, Funktionalitäten in Klassen zu kapseln. Hier wäre auf die Schnelle mal eine an deine Delphi Version (keine Standard-Queue-Klasse, keine Generics) angepasste Implementierung einer FIFO-Liste (Queue):
Delphi-Quellcode:
type
  TQueueData = record
  public
    Foo: Integer;
    Bar: String;
  end;

  TQueue = class(TObject)
  strict private type
    PQueueItem = ^TQueueItem;
    TQueueItem = record
    public
      FLink: PQueueItem;
      BLink: PQueueItem;
      Data: TQueueData;
    end;
  strict private
    FFirst: PQueueItem;
    FLast: PQueueItem;
    FCount: Integer;
  public
    procedure Enqueue(const Data: TQueueData);
    function Dequeue: TQueueData;
    function Peek: TQueueData;
    procedure Clear;
  public
    destructor Destroy; override;
  public
    property Count: Integer read FCount;
  end;

{ TQueue }

procedure TQueue.Clear;
var
  Temp: PQueueItem;
begin
  while Assigned(FFirst) do
  begin
    Temp := FFirst^.FLink;
    Dispose(FFirst);
    FFirst := Temp;
  end;
  FLast := nil;
  FCount := 0;
end;

function TQueue.Dequeue: TQueueData;
var
  Temp: PQueueItem;
begin
  if (FCount = 0) then raise Exception.Create('No items in queue');
  Result := FFirst^.Data;
  Temp := FFirst^.FLink;
  Dispose(FFirst);
  if Assigned(Temp) then
  begin
    Temp^.BLink := nil;
    FFirst := Temp;
  end else
  begin
    FFirst := nil;
    FLast := nil;
  end;
  Dec(FCount);
end;

destructor TQueue.Destroy;
begin
  Clear;
  inherited;
end;

procedure TQueue.Enqueue(const Data: TQueueData);
var
  Item: PQueueItem;
begin
  New(Item);
  Item^.FLink := nil;
  Item^.BLink := FLast;
  Item^.Data := Data;
  if (not Assigned(FFirst)) then
  begin
    FFirst := Item;
  end;
  if Assigned(FLast) then
  begin
    FLast^.FLink := Item;
  end;
  FLast := Item;
  Inc(FCount);
end;

function TQueue.Peek: TQueueData;
begin
  if (FCount = 0) then raise Exception.Create('No items in queue');
  Result := FFirst^.Data;
end;
Auch ist es eigentlich immer schlecht, wenn man Business-Logik in die GUI reinwurschtelt. So ein Label als Counter zu verwenden, ist ein No-Go Dafür ist es einfach nicht gemacht, was man schon an deinem umständlichen StrToInt und IntToStr Gemenge sieht.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl ( 6. Mär 2016 um 15:16 Uhr)
  Mit Zitat antworten Zitat