Delphi7, "Variable Required" error when accessing address of array element

Ioannis Anifantakis
Ioannis Anifantakis used Ask the Experts™
on
Hello experts,
I have delphi 7 running and I face a problem with a method I write:

I have created this method:

procedure TCRMEasyListview.getCheckedList(var ListToFill: TList);
var i: integer;
begin
    ListToFill.Clear;

    with Self.Items do begin
        for i:=0 to Count-1 do begin
            if Items[i].Checked then
                ListToFill.Add(@Items[i]);     //<-- "Variable Required" compiler error          
        end; // end of for loop
    end; // end of with declaration

end; // end of method

TList adds pointers.  So I try to get the pointer for a pointed item.  The pointed item is a TEasyItem (so its an object).  Strangely I cannot get the compiler to finish without error.

Any suggestions plz?
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
Maybe try something like this

procedure TCRMEasyListview.getCheckedList(var ListToFill: TList);
var
  i: integer;
  ea: TEasyItem;
begin
    ListToFill.Clear;

    with Self.Items do begin
        for i:=0 to Count-1 do begin
            if Items[i].Checked then
             begin
             ea := Items[i];
                ListToFill.Add(ea);     //<-- "Variable Required" compiler error          
             end;
        end; // end of for loop
    end; // end of with declaration

end; // end of method

Top Expert 2007

Commented:
>>ListToFill.Add(@Items[i]);   // i think @ is the problem.Remove @ and try



procedure TCRMEasyListview.getCheckedList(var ListToFill: TList);
var i: integer;
begin
    ListToFill.Clear;

    with Self.Items do begin
        for i:=0 to Count-1 do begin
            if Items[i].Checked then
                //ListToFill.Add(@Items[i]);     //<-- "Variable Required" compiler error  
                ListToFill.Add(Items[i]);     //<--    
        end; // end of for loop
    end; // end of with declaration

end; // end of method
Ioannis AnifantakisProgramming Instructor

Author

Commented:
Thank you both for your answers

Giving directly the item gives error when trying to retrieve that.  You need to assign pointer to item and not item itself...

a) mokule:
Since I declare ea, I can assign it by "mylist.add(@ea)" and not ea directly for the reason I explained above.  But that gives me a question...

Doesn't declaration of ea give me memory leak?  When I declare ea and then assign as value the value held by the array item, I infact clone the array item to the ea variable.  That would give me memory leak.  If on the other hand I call "free" after i "add" my ea then the list will hold a nil.

So:

ea:=items[i];
mylist.add(ea); -> will compile but will give runtime error since ea is object and not pointer.
(This is similar approach to expert dinlud so, sorry it won't work)

------------------------

ea:=items[i];
mylist.add(@ea); -> correct but with memory leak

-------------

ea:=items[i];
mylist.add(@ea);
ea.free; --> Since mylist holds reference to ea object since I free it here, it wil have problem by the method that calls this code.
Starting with Angular 5

Learn the essential features and functions of the popular JavaScript framework for building mobile, desktop and web applications.

Ioannis AnifantakisProgramming Instructor

Author

Commented:
b) dinilud:

the "@" denotes "The address of".  Since I must add pointers to TList, I need it otherwise even though it compiles you get "Access Violation" runtime error.

Therefore its necessary to include either "@" or "Addr" to specify address of object referenced

Quite a wridle this question, ah? :)
Top Expert 2007
Commented:
i know @ is address oparator.

Can you please check this eg:


unit1.dfm
=========

object Form1: TForm1
  Left = 211
  Top = 285
  Width = 340
  Height = 178
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnClose = FormClose
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 200
    Top = 16
    Width = 89
    Height = 25
    Caption = 'Create Label'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 200
    Top = 48
    Width = 89
    Height = 25
    Caption = 'Create Edit Box'
    TabOrder = 1
    OnClick = Button2Click
  end
  object Button3: TButton
    Left = 200
    Top = 80
    Width = 89
    Height = 25
    Caption = 'Chang Text'
    TabOrder = 2
    OnClick = Button3Click
  end
  object Button4: TButton
    Left = 200
    Top = 114
    Width = 89
    Height = 25
    Caption = 'Free'
    TabOrder = 3
    OnClick = Button4Click
  end
end

unit1.pas
========

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
    FList:TList;
    Count:Integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FList:=TList.Create;
  Count:=1;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FList.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var lbl:TLabel;
begin
  Button1.Enabled:=False;
  lbl :=TLabel.Create(Self);
  lbl.Caption:='Label';
  lbl.Left:=10; lbl.Top:=10;
  lbl.Parent :=Self;
  FList.Add(lbl);
end;

procedure TForm1.Button2Click(Sender: TObject);
var txt:TEdit;
begin
  Button2.Enabled:=False;
  txt:=TEdit.Create(Self);
  txt.Left:=10; txt.Top:=50;
  txt.Parent:=Self;
  FList.Add(txt);
end;

procedure TForm1.Button3Click(Sender: TObject);
var i:Integer;
begin
  for i:=0 to FList.Count-1 do
  begin
     if TComponent(FList[i]) is TLabel then
       TLabel(FList[i]).Caption:='Temp'+IntToStr(Count)
     else if TComponent(FList[i]) is TEdit then
       TEdit(FList[i]).Text:='Temp'+IntToStr(Count);
    Inc(Count);
  end;
end;

procedure TForm1.Button4Click(Sender: TObject);
var i:Integer;
begin
  for i:=0 to FList.Count-1 do
  begin
    TComponent(FList[i]).Free;
  end;
  FList.Clear;
  Button1.Enabled:=True;
  Button2.Enabled:=True;
end;

end.
Mokule is correct.  What you don't understand is that ea is also a pointer.  Delphi is just hiding that detail from you.  The actual object is a bunch of memory allocated on the heap.  You don't have to worry about using @ when storing objects in a TList, just dump them in there and use type casting to retrieve them.  I do it all the time.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial