Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Delete-Routine von verketteter Liste erzeugt AV


Marco D. - Mi 14.02.07 17:12
Titel: Delete-Routine von verketteter Liste erzeugt AV

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:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
procedure TAttributelist.Delete(index: integer);
var i: integer;
begin
  if (index <= High) and (index > -1then
  begin
    //there's only one item in the list (FFirst)
    if (FCount = 1then
    begin
      FreeAndNil(FFirst.Data);
      FFirst.Next := nil;
      FFirst := nil;
      FCurrently := nil;
    end
    else begin
    //there are more items in the list
      //first item should be deleted
       if (index = 0then
       begin
         FreeAndNil(FFirst.Data);
         for i := 0 to High do
         begin
            SetPointerAtPosition(i);
            if (i <> High) then
              FCurrently := FCurrently.Next
            else
              FCurrently := nil;
         end;
       end
       else begin
         SetPointerAtPosition(index);
         FreeAndNil(FCurrently.Data);
         for i := index to High do
         begin
            SetPointerAtPosition(i);
            if (i <> High) then
              FCurrently := FCurrently.Next
            else
              FCurrently := nil;
         end;
       end;
    end;
    dec(FCount);
    //Changed;
    showmessage(explode);
  end;
end;

procedure TAttributelist.SetPointerAtPosition(index: integer);
var i: integer;
begin
  if (index <= High) and (FFirst <> nilthen
  begin
    FCurrently := FFirst;
    i := 0;
    while (i < index) do
    begin
      FCurrently := FCurrently.Next;
      inc(i);
    end;
  end;
end;

Wenn ich zwei Einträge hinzufüge und dann Delete(0) aufrufe, also den ersten Eintrag löschen will, gibt es eine AV.
Findet ihr den Fehler?


Delete - Mi 14.02.07 17:16

ohne mich einzudenken, ist mir folgendes an deinen code aufgefallen.

hier solltest mal die sequenz umstellen, erst die pointer umhängen, dann erst das objekt welches die pointer beherbergt freigeben. <HTH>


Marco D. - Mi 14.02.07 17:22

user profile iconGrenzgaenger hat folgendes geschrieben:
ohne mich einzudenken, ist mir folgendes an deinen code aufgefallen.
  • du gibtst das objekt frei
  • anschliessend greifst du auf das objekt zu, um die pointer zu verschieben

hier solltest mal die sequenz umstellen, erst die pointer umhängen, dann erst das objekt welches die pointer beherbergt freigeben. <HTH>

Ich greife bei deinem zweiten Punkt nicht auf das Objekt zu. Das Objekt ist wie gesagt frei gegeben.
Das Objekt (Data) enthält ja nicht die Pointer:

Delphi-Quelltext
1:
2:
3:
4:
5:
  PItem = ^TItem;
  TItem = record
    Data: TAttribute;
    Next: PItem;
  end;


Delete - Mi 14.02.07 17:27

was ist z.b. hiermit:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TAttributelist.Delete(index: integer);
var i: integer;
begin
  if (index <= High) and (index > -1then
  begin
    //there's only one item in the list (FFirst)
    if (FCount = 1then
    begin
      FreeAndNil(FFirst.Data); //hier freigabe von FFirst
      FFirst.Next := nil;      //hier existiert das objekt/record nicht mehr
      FFirst := nil;           //hier auch nicht...
      FCurrently := nil;
    end


oder wo gibst du sonst dein objekt/record frei? im anderen falle, würdest du dir ja nur den hauptspeicher zumüllen..


Marco D. - Mi 14.02.07 17:30


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TAttributelist.Delete(index: integer);
var i: integer;
begin
  if (index <= High) and (index > -1then
  begin
    //there's only one item in the list (FFirst)
    if (FCount = 1then
    begin
      FreeAndNil(FFirst.Data); //hier freigabe von FFirst => ich gebe FFirst.Data frei, nicht FFIrst!!
      FFirst.Next := nil;      //hier existiert das objekt/record nicht mehr => doch
      FFirst := nil;           //hier auch nicht... => doch
      FCurrently := nil;
    end

:zwinker:
Dieser Abschnitt funzt ja, das habe ich schon getestet.

Poste hier nochmal eine neuere Version der Routine. Der Fehlerbereich ist markiert.
Es crasht, wenn ich zwei oder mehr Einträge habe und den ersten löschen will.

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:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
procedure TAttributelist.Delete(index: integer);
var ptemp: PItem;
begin
  if (FFirst <> nilthen
  begin
    if (index = 0then
    begin
      if (Count = 1then
      begin
        //we just have ONE item in list
        //blow it away! ;)
        FreeAndNil(FFIrst.Data);
        FFirst := nil;
        FCurrently := nil;
      end
      else begin
        //first item should be deleted
        //but there are more items that one in the list =)
        SetPointerAtPosition(index);
        showmessage(FCUrrently.Data.Name);
        FreeAndNil(FCurrently.Data);
        FCurrently := FCurrently.Next;
        FCurrently.Next := nil;
        

       end;
    end else
      if (index < High) then
      begin
       //there are more items in the list
       SetPointerAtPosition(index);
       ptemp := FCurrently.Next;
       FreeAndNil(FCurrently.Data);
       FCurrently.Next := nil;
       SetPointerAtPosition(index - 1);
       FCurrently.Next := ptemp;
      end;
  dec(FCount);
  Changed;
  end;
end;


Marco D. - Mi 14.02.07 19:31

Man ey :P Jetzt funktioniert's :party:

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:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
procedure TAttributelist.Delete(index: integer);
var ptemp: PItem;
begin
  if (FFirst <> nilthen
  begin
    if (index = 0then
    begin
      if (Count = 1then
      begin
        //we just have ONE item in list
        //blow it away! ;)
        FreeAndNil(FFIrst.Data);
        FFirst := nil;
        FCurrently := nil;
      end
      else begin
        //first item should be deleted
        //but there are more items that one in the list =)
        FreeAndNil(FFirst.Data);
        FFirst := FFirst.Next
       end;
    end else
      if (index < High) then
      begin
       //there are more items in the list
       SetPointerAtPosition(index);
       ptemp := FCurrently.Next;
       FreeAndNil(FCurrently.Data);
       FCurrently.Next := nil;
       SetPointerAtPosition(index - 1);
       FCurrently.Next := ptemp;
      end;
  dec(FCount);
  Changed;
  end;
end;

Sorry für das Schiebeposting 8)