Trying to write a procedure to remove an item from a doubly linked list.

procedure TDataList.DelItem; var PDel: TList; begin // Процедура переводит указатель на выбранный элемент GoToItem(FPointer); PDel := FItems; if FCount = 1 then begin // Если в списке 1 элемент, отчистить список полностью DelAll; end // Если элементов списка больше 1 и Выбран первый элемент в списке else if (FCount > 1) and (FPointer = 1) then begin // Перевод указателя на следующий элемент списка FItems := FItems^.PNext; // Удаление - Вот тут возникает ошибка, вроде что-то из памяти прочитать не может Dispose(PDel); end; end; 

All class code:

 unit UList; interface uses Messages, Dialogs, SysUtils, Classes, Grids, UStudent; type TArray = array of integer; TData = TStudent; TList = ^List; List = record Data: TData; PNext, PPrev: TList; end; TDataList = class private FItems: TList; FCount,FPointer: Integer; public // Конструктор и деструктор constructor Create(); overload; destructor Destroy(); overload; // Процедуры procedure AddItem(Key: Integer; Data: TStudent); procedure DelAll(); procedure DelItem(); procedure GoToItem(Index: Integer); procedure SetPointer(Index: Integer); procedure Go(Key: Integer); // Functions function GetList(): TList; function GetCount(): Integer; function GetPointer(): Integer; property Pointer: Integer read GetPointer write SetPointer; end; implementation procedure TDataList.AddItem(Key: Integer; Data: TStudent); var Item: TList; begin FCount := FCount + 1; New(Item); Item^.Data := Data; // Если список пуст if FItems = Nil then begin Item^.PNext := Nil; Item^.PPrev := Nil; FItems := Item; FPointer := 1; end else begin case Key of // Добавление в начало списка 1: begin while FItems^.PPrev <> Nil do begin FItems := FItems^.PPrev; end; Item^.PNext := FItems; Item^.PPrev := Nil; FItems^.PPrev := Item; FPointer := 1; end; // Добавление в конец списка 2: begin while FItems^.PNext <> Nil do begin FItems := FItems^.PNext; end; Item^.PNext := Nil; Item^.PPrev := FItems; FItems^.PNext := Item; FPointer := FCount; end; // Добавление перед элементом 3: begin if FItems^.PPrev = Nil then begin AddItem(1,Data); end else begin GoToItem(FPointer); Item^.PPrev := FItems^.PPrev; Item^.PNext := FItems; FItems^.PPrev := Item; Item^.PPrev^.PNext := Item; end; end; // Добавление после элемента 4: begin if FPointer = FCount then begin AddItem(2,Data); end else begin GoToItem(FPointer); Item^.PPrev := FItems; Item^.PNext := FItems^.PNext; FItems^.PNext := Item; Item^.PNext^.PPrev := Item; end; end; end; end; end; constructor TDataList.Create; begin FCount := 0; FPointer := 0; FItems := Nil; end; procedure TDataList.DelAll; var PDel: TList; begin Go(1); while FItems <> Nil do begin PDel := FItems; FItems := FITems^.PNext; Dispose(PDel); end; FCount := 0; FPointer := 0; end; procedure TDataList.DelItem; var PDel: TList; begin GoToItem(FPointer); PDel := FItems; // Удалить весь список если в нем всего 1 запись if FCount = 1 then begin DelAll; end // Удаление первого элемента списка else if (FCount > 1) and (FPointer = 1) then begin // Перевожу указатель на следующий элемент FItems := FItems^.PNext; FItems^.PPrev := Nil; Dispose(PDel); // FCount кол-во элементов в списке FCount := FCount - 1; end; end; destructor TDataList.Destroy; begin // end; function TDataList.GetCount: Integer; begin Result := FCount; end; function TDataList.GetList: TList; begin Result := FItems; end; function TDataList.GetPointer: Integer; begin Result := FPointer; end; procedure TDataList.Go(Key: Integer); begin case Key of // Go to First 1: begin while FItems^.PPrev <> Nil do begin FItems := FItems^.PPrev; end; FPointer := 1; end; // Go to Last 2: begin while FItems^.PNext <> Nil do begin FItems := FItems^.PNext; end; FPointer := FCount; end; // Go to Next 3: begin if FItems^.PNext <> Nil then begin FItems := FItems^.PNext; end; FPointer := FPointer + 1; end; // Go to Prev 4: begin if FItems^.PPrev <> Nil then begin FItems := FItems^.PPrev; end; FPointer := FPointer - 1; end; end; end; procedure TDataList.GoToItem(Index: Integer); var I: Integer; begin while FItems^.PPrev <> Nil do begin FItems := FItems^.PPrev; end; for I := 1 to Index - 1 do begin if FItems^.PNext <> Nil then FItems := FItems^.PNext; end; end; procedure TDataList.SetPointer(Index: Integer); begin FPointer := Index; end; end. 

Mistake

  • "// The procedure translates the pointer to the selected element" - show - Igor
  • @Igor added procedure - Huffy Grams
  • one
    Try to draw on the leaflet elements and links to the elements of the previous / next. What happens when you delete. Did you link all the links before freeing the memory; what will happen with the variable FCount; what will happen to your linked list if you delete the last item in the list, namely what will be in the FItems variable ... Hint: at the moment you are destroying the list in almost all cases. - Yura Ivanov
  • @YuraIvanov Tried to draw, did everything in the picture. There you can see in the code that I am trying to delete only the first element so far and logically I need a pointer to the first element (PDel is right), then I need to transfer the FItems pointer to the next element in order not to try to delete the element that FItems now points to (FItems : = FItems ^ .PNext - that's how I do it). Now, since FItems has two pointers (to the next element and to the previous element) I need to get rid of the pointer to the previous element, since the previous element will now be deleted and I do this as FItems ^ .PPrev: = Nil. - Huffy Grams
  • one
    Already better. In general, the list implementation should contain a method of searching for an element by number, for which only a reference to the first element is needed is constant, and the concept of the current element should not be. And you do not need to break the algorithm into types of elements (the first, last, in the middle, the only element). To remove any (found by the number) element, it is necessary to concatenate neighbors, having previously checked their existence. Similarly, to add: future (found by number) neighbors need links to throw on yourself ... A lot of excess, get rid of. - Yura Ivanov

1 answer 1

Do you call Dispose feeding TList there? It is not right. PDel.Free;

Or your Dispose and TList not Delphi-ev?

Update

Now, the question lacks the code in which you work with your TDataList class, and when executed, an exception occurs. But that's not the point. Your code will not work, it must be rewritten.

  1. To begin with, the person who calls the type of the element of the TList list and eventually gets the non-working code has what it deserves. The same applies to the name of a member of the FPointer class.

  2. Integers — the parameters of the Go method — should be replaced with an enumerator.

  3. The AddItem method begins with allocating memory to a new item, which it safely forgets when it calls itself.

  4. In the Go method (cases 3 and 4) you change the value of FItems , if possible, but no conditions are checked when the FPointer value FPointer .

  5. The GoToItem method generally FPointer not change the value of FPointer .

You were unable to write code that supports FPointer and FItems in a synchronized state. Leave this venture.

And I did not understand the code in detail yet :).

  • TList is a pointer, and judging by the reference and examples, the pointer should be passed to the Dispose procedure. Yes, and my DelAll procedure works quite normally with Dispose. - Huffy Grams
  • Is TList your type or from library? Dispose works with a pointer that points to memory allocated by calling New . - Igor
  • "Here an error occurs" - which one? - Igor
  • Added screen. There seems to be an error reading from some address. I checked whether the PDel refers to anything and yes it refers. I tried to take data from the list element PDel ^ .Data and everything is OK. But you can not delete. TList is my type, which is TList = ^ List, a List = record .... there is a code - Huffy Grams
  • Add a code to the question that allocates memory to the list items. Well of you have to drop a drop of information! - Igor