Link to home
Start Free TrialLog in
Avatar of henryreynolds
henryreynoldsFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Delphi Access violation : Seacrh list of TString objects

Good Day

I am having a problem where I am searching threw a list of string objects, if I dont find a match I get an access vioaltion, can someone please advice and show i am better way to search quicker if possible.

I have attached sample code
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type
  {Header Records}
  Tafe_DataFieldHeader = class(TObject)
  private
  public
    FsEntryId     : string;
    FsHeader      : string;
    FsDetail      : string;
    FsGetDetail   : string;
  end;

  Tafe_DataRecordHeader = class(TObject)
  private
    function AddFieldHeader(AEntryId, AHeader,ADetail,AGetDetail: string): integer;
    function ReadTheCount: integer;
  public
    Fo_HeaderFields: TStrings;
    constructor Create;
    destructor  Destroy; override;
    function    GetFieldHeader(AIndex: integer)   : Tafe_DataFieldHeader;
    function    GetFieldNameHeader(IName : STring): Tafe_DataFieldHeader;
    property    Count: integer  read ReadTheCount;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var oHeader     : Tafe_DataRecordHeader;
begin
   oHeader     := Tafe_DataRecordHeader.Create;
   Memo1.Lines.Add(oHeader.GetFieldNameHeader('d').FsHeader)
end;


{ Tafe_DataRecordHeader }

function Tafe_DataRecordHeader.AddFieldHeader(AEntryId, AHeader, ADetail,
  AGetDetail: string): integer;
var
  oRecord:  Tafe_DataFieldHeader;
begin
  oRecord               := Tafe_DataFieldHeader.Create;
  oRecord.FsEntryId     := AEntryId;
  oRecord.FsHeader      := AHeader;
  oRecord.FsDetail      := ADetail;
  oRecord.FsGetDetail   := AGetDetail;
  Result                := Fo_HeaderFields.AddObject(AEntryId, oRecord);

end;

constructor Tafe_DataRecordHeader.Create;
begin
   Fo_HeaderFields := TStringList.Create;

   //        Entry Id   Header                          Detail                       GetDetail
   AddFieldHeader('0',  'REPORT ID:  12345',            ''                         ,'NO');
   AddFieldHeader('0',  'REPORTING FOR: 10001 AAAAA' ,  ''                         ,'NO');
   AddFieldHeader('0',  'REPORTING TO: 10001 AAAAA'  ,  ''                         ,'NO');
   AddFieldHeader('0',  'ENTITY: 10001 AAAA'         ,  ''                         ,'NO');
   AddFieldHeader('0',  'SETTLEMENT'                 ,  ''                         ,'NO');
   AddFieldHeader('0',  'FUNDS TRANSFER AMOUNT:'     ,  ''                         ,'NO');
   AddFieldHeader('0',  'REC VALUE',                    'TOTAL BBBB',              'YES');
   AddFieldHeader('0',  'REC VALUE',                    'TOTAL CCCC',              'YES');
end;

destructor Tafe_DataRecordHeader.Destroy;
var
  iLoop: Integer;
begin
  for iLoop := Fo_HeaderFields.Count - 1 downto 0 do
  begin
    Fo_HeaderFields.Objects[iLoop].Free;
    Fo_HeaderFields.Objects[iLoop] := nil;
  end;
  Fo_HeaderFields.Clear;
  FreeAndNil(Fo_HeaderFields);
  inherited;
end;

function Tafe_DataRecordHeader.GetFieldHeader(
  AIndex: integer): Tafe_DataFieldHeader;
begin
  Result := Tafe_DataFieldHeader(Fo_HeaderFields.Objects[AIndex]);
end;

function Tafe_DataRecordHeader.GetFieldNameHeader(
  IName: STring): Tafe_DataFieldHeader;
var I : Integer;
    lnString : Integer;
begin
  Result := nil;
  for I := 0 to Fo_HeaderFields.Count -1  do
  begin
     lnString := Length(Tafe_DataFieldHeader(Fo_HeaderFields.Objects[i]).FsHeader);

     if copy(trim(IName),1,lnstring) = Tafe_DataFieldHeader(Fo_HeaderFields.Objects[i]).FsHeader then
     begin
        //ShowMessage(Tafe_DataFieldStructure(Fo_Fields.Objects[i]).FsReport + ' - '+Tafe_DataFieldStructure(Fo_Fields.Objects[i]).FsGroup + ' - '+Tafe_DataFieldStructure(Fo_Fields.Objects[i]).FsDetail) ;
        Result := Tafe_DataFieldHeader(Fo_HeaderFields.Objects[I]);
        break;
     end;
  end;
end;

function Tafe_DataRecordHeader.ReadTheCount: integer;
begin
  Result := Fo_HeaderFields.Count;
end;



end.

Open in new window

Avatar of MerijnB
MerijnB
Flag of Netherlands image

Which line do you get the AV?
av on this line in the destroy (after you free, not necessary to set nil)
Fo_HeaderFields.Objects[iLoop] := nil;

and entry_id is always '0' !!!

test this:
 
procedure TForm1.Button1Click(Sender: TObject);
var oHeader: Tafe_DataRecordHeader;
begin
  oHeader := Tafe_DataRecordHeader.Create;
  if oHeader.GetFieldNameHeader('d') = nil 
    Memo1.Lines.Add('You didn''t add a "d" !, so i can''t find one !')
  else  
    Memo1.Lines.Add(oHeader.GetFieldNameHeader('d').FsHeader);
end;

Open in new window



fwiw, your indentation is very odd
Avatar of henryreynolds

ASKER

in the function GetFieldNameHeader

imeediately if I dont find a match I get an av
ASKER CERTIFIED SOLUTION
Avatar of Geert G
Geert G
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
your sample for the header constructor is also very odd: you have mixed header and detail
 
constructor Tafe_DataRecordHeader.Create;
begin
  Fo_HeaderFields := TStringList.Create;

  //        Entry Id   Header                          Detail                       GetDetail
  AddFieldHeader('0', 'REPORT ID', '12345', 'NO');
  AddFieldHeader('0', 'REPORTING FOR', '10001 AAAAA', 'NO');
  AddFieldHeader('0', 'REPORTING TO', '10001 AAAAA', 'NO');
  AddFieldHeader('0', 'ENTITY', '10001 AAAA', 'NO');
  AddFieldHeader('0', 'SETTLEMENT', '', 'NO');
  AddFieldHeader('0', 'FUNDS TRANSFER AMOUNT', '', 'NO');
  AddFieldHeader('0', 'REC VALUE', 'TOTAL BBBB', 'YES');
  // AddFieldHeader('0', 'REC VALUE', 'TOTAL CCCC', 'YES'); >>>>> double header !!!!
end;

Open in new window

now try this code:
 
procedure TForm1.Button1Click(Sender: TObject);
var oHeader     : Tafe_DataRecordHeader;
begin
   oHeader     := Tafe_DataRecordHeader.Create;
   Memo1.Lines.Add(oHeader.GetFieldNameHeader('REPORT ID').FsHeader)
end;

Open in new window

Hi Geert_Gruwez

thank you very much for your help

it is just very frustrating with the AV

if I use this exactly

oHeader     := Tafe_DataRecordHeader.Create;
   Memo1.Lines.Add(oHeader.GetFieldNameHeader('REPORT ID').FsHeader)

then I still get av

do you think I must you the if each time i seacrh ?
AV ...
for short: Access violation

please do not limit your information that much

when you go to a garage with your car, how do you think the mechanic will react when you say:"it's broken"
he will ask lots and lots of questions
to prevent that, please explain your problem in detail

like:
when my wife, me and the kids are all in the car and we start driving, the car makes screeching noises from the back left wheel
at least the mechanic would now have an idea of which part is broken

when you get an AV, hit Ctrl-C
and paste that to the forum
of course you get AV !
1) GetFieldNameHeader can return nil (if header not found), and pretty muchas it SHOULD be with GetFieldHeader if your index is <0 or >=Count - but in these cases you don't even check these conditions and get an Index out of bound exception

2) When you do receive nil, GetFieldNameHeader('REPORT ID').FsHeader will create the AV

so yes, you HAVE to test the returned header <> nil before accessing it's properties. OR you manage the exceptions - having an AV exception is not too bad, if you KNOW it is normal to have some here, and that you MANAGE them properly each time you use the code that can throw it.

If you want to test the header <> nil each time before using it, be smart : save it in a variable first, in order to avoid precisely the quick sample Geert gave you :
  if oHeader.GetFieldNameHeader('d') = nil 
    Memo1.Lines.Add('You didn''t add a "d" !, so i can''t find one !')
  else  
    Memo1.Lines.Add(oHeader.GetFieldNameHeader('d').FsHeader);

Open in new window

this is bad because in the case the header exist (which should be the most common case) you'll SEARCH TWICE
instead :

Var 
 TempHeader:Tafe_DataFieldHeader;
...
  TempHeader:=oHeader.GetFieldNameHeader('d')
  if TempHeader = nil 
    Memo1.Lines.Add('You didn''t add a "d" !, so i can''t find one !')
  else  
    Memo1.Lines.Add(TempHeader.FsHeader);

Open in new window


other way to do it with exception management (there are many ways to do it, depending on what you do with the object)
with oHeader.GetFieldNameHeader('d') do 
 try 
    Memo1.Lines.Add(TempHeader.FsHeader);
 except
    Memo1.Lines.Add('You didn''t add a "d" !, so i can''t find one !');
 end;

Open in new window

typo error on last sample code (Inside a With .. do I can/must use the field name directly. In my previous code I used the field of TempHeader variable - which I don't even use anymore in this sample
with oHeader.GetFieldNameHeader('d') do 
 try 
    Memo1.Lines.Add(FsHeader); // accessing Fsheader field of a 'nil' returned value will raise AV
 except
    Memo1.Lines.Add('You didn''t add a "d" !, so i can''t find one !');
 end;

Open in new window

hey ... that's my quote: "You didn''t add a "d" !, so i can''t find one !"
use your own ! :)
Hi Geert_Gruwez

Everything is fine, thanx a lot for your help.
thank you very much
I have most difficulties to see why the selected answer solves anything concerning access violation