Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Löschen aus einem Array


knittel - Do 14.04.11 11:22
Titel: Löschen aus einem Array
Hallo allerseits,
vermutlich nerven meine dummen fragen schon, aber ich komme mal wieder nicht weiter. Ich will aus einem array aus pointer ein element löschen. Die pointer zeigen auf einen Record namens TMapPoint. Jeder dieser Punkte ist mit mindestens einem anderen verbunden, und haben deswegen ein eigenes dynamisches Array vom Typ: array of byte, indem sie den index der verbunden Punkte speichern. Beim Löschen erhalte ich auf jeden Fall haufenweise Fehlermeldungen wie Access Violation oder EInvalid Pointer operation.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
      DirectLoad := 
      FindNearest(Point(
      - Form1.Left + CurrentCursorPosition.X - 178,
      - Form1.Top + CurrentCursorPosition.Y - 14)); // Der Index des nächsten Punktes wird gesucht.

      Dispose(MapInfo[DirectLoad]); // Ich gebe den Speicher dieses Punktes frei.
      // Nun sollen die Zeiger ab diesem immer dorthin zeigen, wo der nächste hinzeigt.
      for Index := DirectLoad to Length(MapInfo) - 2 do
        begin
        MapInfo[Index] := MapInfo[Index + 1];
        end;
      // Dann zeigt der sowohl der vorletzte als auch der letzte auf das selbe Objekt. Deswegen können wir den letzten pointer löschen:
      SetLength(MapInfo, Length(MapInfo)-1);
      // Hier versuche ich die Indexe zu reparieren.
      FixArrayItems(DirectLoad);
      end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure FixArrayItems(N: Byte);
var i,j: integer;
begin
for i:= 0 To Length(MapInfo)-1 do // alle Elemente durchgehen.
  begin
  j := Length(MapInfo[i]^.ConnectedTo)-1// durch das array mit den indexen der verbundenen Punkte gehen.
  while j>=0 do
    begin
    // Wird auf den Punkt gezeigt der zerstört wurde, soll das Array gekürzt werden.
    if MapInfo[i]^.ConnectedTo[j] = N then
      DeleteArrayItem(MapInfo[i]^.ConnectedTo, j)
    else
    // Ist der Index größer soll der Index um 1 verringert werden.
      if MapInfo[i]^.ConnectedTo[j] > N then
      MapInfo[i]^.ConnectedTo[j] := MapInfo[i]^.ConnectedTo[j] - 1;
    j:=j-1// Nächste Verbindung.
    end;
  end;
end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure DeleteArrayItem(var A: TXArray; const Index: integer);
var
  ALength: cardinal;
  TailElements: cardinal;
begin
  ALength := Length(A);
  Assert(ALength > 0);
  Assert(Index < ALength);
  TailElements := ALength - Index;
  if TailElements > 0 then
    Move(A[Index + 1], A[Index], SizeOf(TLabel) * TailElements);
  SetLength(A, ALength - 1);
end;


(TXArray = array of byte)

Ich habe mir im Code Breakpoints gesetzt. Doch der Fehler kommt nicht während dieser Berechnung sondern danach in der Prozedur in der die Punkte gezeichnet werden:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
procedure DrawPoints();
var i, j: integer;
begin
with Form1.AdDraw.Canvas do
  begin
  // Set Canvas
  Pen.Color := NewColor;
  Brush.Style := absolid;
for i:= 0 to Length(MapInfo)-1 do
  begin
  for j := 0 To Length(MapInfo[i]^.ConnectedTo)-1 do
    Line(MapInfo[i]^.X + 174 + 3 + random(2), MapInfo[i]^.Y + 14 - 1 + random(2),
         MapInfo[MapInfo[i]^.ConnectedTo[j]].X + 174 + 3 + random(2),
         MapInfo[MapInfo[i]^.ConnectedTo[j]].Y + 14 - 1 + random(2));
  if MapInfo[i].PlayerPoint <> 0 then
    Textout(MapInfo[i]^.X + 174 - 1, MapInfo[i].Y + 14 - 8, IntToStr(MapInfo[i].PlayerPoint))
  else
    Rectangle(MapInfo[i]^.X + 174 + 2, MapInfo[i]^.Y + 14 - 2,
              MapInfo[i]^.X + 174 + 6, MapInfo[i]^.Y + 14 + 2);
  end;

  // Reset Canvas
  Pen.Color := BlackColor;
  Brush.Style := abclear;
  end;
end;


Im Normalfall läuft diese Prozedur gut, nur nach dem Löschen eines Punktes kommt eine Fehlermeldung meistens Access Violation oder EInvalid Pointer Operation.

Vielen Dank im voraus.


Gammatester - Do 14.04.11 11:59

Wenn (TXArray = array of byte) ist, warum benutzt Du dann SizeOf(TLabel) in diesem Schnipsel?

Delphi-Quelltext
1:
2:
  if TailElements > 0 then
    Move(A[Index + 1], A[Index], SizeOf(TLabel) * TailElements);

Wenn SizeOf(TLabel) <> 1 ist, wirst Du ziemlich sicher gegen die Wand moven, da Du mehr verschieben willst als eigentlich da ist.


knittel - Do 14.04.11 12:20

Ich hatte diesen Code Schnipsel mal als Open Source im Internet gefunden und verwendet ohne weiter nachzudenken. Ich probiers mal anders. Danke.

EDIT:
ES FUNKTIONIERT!!!!!!!!!!!!! JAAAAAAAAAAAAAA... Saß gestern 3 und heute nochmal 2 stunden an diesem Problem und bin beinahe verrückt geworden.
Danke :) :) :)