DelFreak
asked on
Dynamic Array problem. For Madshi or AvonWyss
I decided to create a new unit with the code you guys supplied. The problem is, I get an error saying
something about TMyStringList not being initialized. Could you tell me what I'm doing wrong. The code for the new unit I created is below. Thanks!
unit NewStringList;
interface
uses Windows;
type
TStringArray = record
Size: Integer;
Capacity: Integer;
Items: Array of String;
end;
TMyStringList = class(TObject)
List: TStringArray;
// constructor Create; //Don't know how to do this!
// destructor Destroy; //Don't know how to do this!
procedure Add(Item: String);
procedure Delete(Index: Integer);
function Count: Integer;
procedure LoadFromFile(FileName: String);
procedure SaveToFile(FileName: String);
end;
implementation
constructor TMyStringList.Create;
begin
//Don't know how to do this!
end;
destructor TMyStringList.Destroy;
begin
//Don't know how to do this!
end;
procedure TMyStringList.Add(Item: String);
begin
if List.Size = List.Capacity then
begin
if List.Capacity = 0 then
List.Capacity := 64
else
List.Capacity := List.Capacity * 3 div 2;
SetLength(List.Items, List.Capacity);
end;
List.Items[List.Size] := Item;
Inc(List.Size);
end;
procedure TMyStringList.Delete(Index : Integer);
begin
if (Index > 0) and (Index < List.Size) then
begin
Dec(List.Size);
List.Items[Index] := '';
if Index < List.Size then
begin
Move(List.Items[Index + 1], List.Items[Index], (List.Size - Index) * 4);
Integer(List.Items[List.Si ze]) := 0;
end;
end;
end;
function TMyStringList.Count: Integer;
begin
Result := List.Size;
end;
procedure TMyStringList.LoadFromFile (FileName: String);
var
InFile: Text;
S: String;
begin
AssignFile(InFile, FileName);
Reset(InFile);
while not EOF(InFile) do
begin
ReadLn(InFile, S);
Add(S);
end;
CloseFile(InFile);
end;
procedure TMyStringList.SaveToFile(F ileName: String);
var
OutFile: Text;
i: Integer;
begin
AssignFile(OutFile,FileNam e);
Rewrite(OutFile);
for i := Low(List.Items) to High(List.Items) do
WriteLn(OutFile, List.Items[i]);
CloseFile(OutFile);
end;
end.
something about TMyStringList not being initialized. Could you tell me what I'm doing wrong. The code for the new unit I created is below. Thanks!
unit NewStringList;
interface
uses Windows;
type
TStringArray = record
Size: Integer;
Capacity: Integer;
Items: Array of String;
end;
TMyStringList = class(TObject)
List: TStringArray;
// constructor Create; //Don't know how to do this!
// destructor Destroy; //Don't know how to do this!
procedure Add(Item: String);
procedure Delete(Index: Integer);
function Count: Integer;
procedure LoadFromFile(FileName: String);
procedure SaveToFile(FileName: String);
end;
implementation
constructor TMyStringList.Create;
begin
//Don't know how to do this!
end;
destructor TMyStringList.Destroy;
begin
//Don't know how to do this!
end;
procedure TMyStringList.Add(Item: String);
begin
if List.Size = List.Capacity then
begin
if List.Capacity = 0 then
List.Capacity := 64
else
List.Capacity := List.Capacity * 3 div 2;
SetLength(List.Items, List.Capacity);
end;
List.Items[List.Size] := Item;
Inc(List.Size);
end;
procedure TMyStringList.Delete(Index
begin
if (Index > 0) and (Index < List.Size) then
begin
Dec(List.Size);
List.Items[Index] := '';
if Index < List.Size then
begin
Move(List.Items[Index + 1], List.Items[Index], (List.Size - Index) * 4);
Integer(List.Items[List.Si
end;
end;
end;
function TMyStringList.Count: Integer;
begin
Result := List.Size;
end;
procedure TMyStringList.LoadFromFile
var
InFile: Text;
S: String;
begin
AssignFile(InFile, FileName);
Reset(InFile);
while not EOF(InFile) do
begin
ReadLn(InFile, S);
Add(S);
end;
CloseFile(InFile);
end;
procedure TMyStringList.SaveToFile(F
var
OutFile: Text;
i: Integer;
begin
AssignFile(OutFile,FileNam
Rewrite(OutFile);
for i := Low(List.Items) to High(List.Items) do
WriteLn(OutFile, List.Items[i]);
CloseFile(OutFile);
end;
end.
if you are going to use your TMyStringList
do this
var mystinglist : TMyStringList ;
begin
MyStringList := TMyStringList.create;
...
...
TMyStringList.free;
end;
do this
var mystinglist : TMyStringList ;
begin
MyStringList := TMyStringList.create;
...
...
TMyStringList.free;
end;
ASKER
So TMyStringList should be = class and not = class(TObject)?
is the same...
anyway your TMyStringList not being initialized has more to do with
var
x : TMyStringList;
begin
x.add(...); <-x wasn't created.
still got problems?
anyway your TMyStringList not being initialized has more to do with
var
x : TMyStringList;
begin
x.add(...); <-x wasn't created.
still got problems?
I go with God_Ares in that you probably simply forgot to instantiate the class. Please show us the part of the code where the exception was raised, and please mark the line where the exception occured exactly.
BTW, you don't need no constructor nor a destructor in this situation. Class variables are always initialized to 0, so the constructor is not needed. Also dynamic arrays are automatically freed by Delphi, so you don't need a destructor here, either. You can leave the code exactly as it is in your original question text. Just one little bug in the code:
In the SaveToFile method the loop has to look like this:
for i := 0 to List.Size - 1 do
E.g. if you add only one item to the list, it would be like this:
List.Size -> 1
List.Capacity -> 64
List.Items -> ['item1', '', '', '', '', '', [...], ''];
low(List.Items) -> 0
high(List.Items) -> 63
So if you loop to high(List.Items), you're saving 64 items, though you only have one in the list.
Regards, Madshi.
P.S: Usually one names class variables with a leading "F", so you should name it "FList", not "List". That's up to you, of course, just wanted to mention, what is usual...
BTW, you don't need no constructor nor a destructor in this situation. Class variables are always initialized to 0, so the constructor is not needed. Also dynamic arrays are automatically freed by Delphi, so you don't need a destructor here, either. You can leave the code exactly as it is in your original question text. Just one little bug in the code:
In the SaveToFile method the loop has to look like this:
for i := 0 to List.Size - 1 do
E.g. if you add only one item to the list, it would be like this:
List.Size -> 1
List.Capacity -> 64
List.Items -> ['item1', '', '', '', '', '', [...], ''];
low(List.Items) -> 0
high(List.Items) -> 63
So if you loop to high(List.Items), you're saving 64 items, though you only have one in the list.
Regards, Madshi.
P.S: Usually one names class variables with a leading "F", so you should name it "FList", not "List". That's up to you, of course, just wanted to mention, what is usual...
BTW, you don't need no constructor nor a destructor in this situation. Class variables are always initialized
to 0, so the constructor is not needed. Also dynamic arrays are automatically freed by Delphi, so you
don't need a destructor here, either.
Don't you just love Delphi... :)
to 0, so the constructor is not needed. Also dynamic arrays are automatically freed by Delphi, so you
don't need a destructor here, either.
Don't you just love Delphi... :)
Yeah, I do, really... (-:
ASKER
Well, the error I get is runtime error 2 at 00005073
This is my procedure for logging:
procedure AddLogEntry(S: String);
var
SS, SSS: String;
i: Integer;
begin
with TStringList.Create do
begin
try
LoadFromFile('Application. log');
except
SS := 'Application Log - Generated on ' + CurrentDateAndTime;
Add(SS);
Add('Process ID: '{ + GetProcessID(ParamStr(0))} );
SSS := '';
for i := 1 to Length(SS) do
SSS := SSS + '-';
Add(SSS);
Add('');
end;
Add(CurrentDateAndTime + ':');
Add(' ' + S);
Add('');
SaveToFile('Application.lo g'));
Free;
end;
end;
In my program, I use it like this:
begin
AddLogEntry('Program has started.');
...
end;
This is my procedure for logging:
procedure AddLogEntry(S: String);
var
SS, SSS: String;
i: Integer;
begin
with TStringList.Create do
begin
try
LoadFromFile('Application.
except
SS := 'Application Log - Generated on ' + CurrentDateAndTime;
Add(SS);
Add('Process ID: '{ + GetProcessID(ParamStr(0))}
SSS := '';
for i := 1 to Length(SS) do
SSS := SSS + '-';
Add(SSS);
Add('');
end;
Add(CurrentDateAndTime + ':');
Add(' ' + S);
Add('');
SaveToFile('Application.lo
Free;
end;
end;
In my program, I use it like this:
begin
AddLogEntry('Program has started.');
...
end;
Please run the stuff inside of Delphi's IDE. In which line is the exception raised? For me it failed in the write routine. I don't like that assign too much, anyway, I'm generally using this logic instead:
procedure TMyStringList.SaveToFile(F ileName: String);
const CLineFeed : string = #$D#$A;
var i1 : integer;
begin
with TFileStream.Create(FileNam e, fmCreate) do
try
for i1 := 0 to List.Size - 1 do begin
WriteBuffer(pointer(List.I tems[i1])^ , Length(List.Items[i1]));
WriteBuffer(pointer(CLineF eed)^, 2);
end;
finally Free end;
end;
You should give in the whole file path (both when loading and saving), not only the file name. E.g., if you want to have the file stored in the same directory, where your exe is, you should use this:
SaveToFile(ExtractFileName (ParamStr( 0)) + 'Application.log');
Regards, Madshi.
procedure TMyStringList.SaveToFile(F
const CLineFeed : string = #$D#$A;
var i1 : integer;
begin
with TFileStream.Create(FileNam
try
for i1 := 0 to List.Size - 1 do begin
WriteBuffer(pointer(List.I
WriteBuffer(pointer(CLineF
end;
finally Free end;
end;
You should give in the whole file path (both when loading and saving), not only the file name. E.g., if you want to have the file stored in the same directory, where your exe is, you should use this:
SaveToFile(ExtractFileName
Regards, Madshi.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
What is this: const CLineFeed : string = #$D#$A;?
ASKER
What is this: const CLineFeed : string = #$D#$A;?
Ehm, the name sais it all, does it not? Those are the two characters, that define a line feed in text files. The difference between a Write and a WriteLn is exactly those 2 characters... Just look at a text file in a hex editor, you'll again see those 2 characters...
ASKER
Oh! I was kinda wondering if it was a #10#13. Anyway, I believe the error happens when I first start the app and it tries to do: AddLogEntry('Program has started.');
I'll try using your code though and see what happens.
I'll try using your code though and see what happens.
>> Oh! I was kinda wondering if it was a #10#13.
It is, "$" is hexadecimal:
$D = 13
$A = 10
#$D = #13
#$A = #10
>> Anyway, I believe the error happens when I first start
the app and it tries to do: AddLogEntry('Program has started.');
Of course, but this AddLogEntry line calls the whole bunch of code you posted here, and somewhere in that code the real exception occurs, the big question is where exactly. You should see that if you run your program inside of the IDE.
It is, "$" is hexadecimal:
$D = 13
$A = 10
#$D = #13
#$A = #10
>> Anyway, I believe the error happens when I first start
the app and it tries to do: AddLogEntry('Program has started.');
Of course, but this AddLogEntry line calls the whole bunch of code you posted here, and somewhere in that code the real exception occurs, the big question is where exactly. You should see that if you run your program inside of the IDE.
ASKER
Nevermind. Your "log" code works better and doesn't add much to my app. One more question though, if I want to use this code to create a file and read from it line by line, will that be possible? How can I do it?
The created file is nothing but a plain text file. So you can read it in by using TStringList.ReadFromFile or by using the LoadFromFile method that you posted in your question text.
ASKER
Oh! Thanks!
ASKER
Thank you! The code you supplied is excellent and just what I was hoping for.
ASKER
Also, maybe you could help me here: https://www.experts-exchange.com/delphi/Q.20289518.html
ASKER
Madshi, there is one other problem. How can I make it so that the log it creates looks like this:
Application Log - Generated on April 14, 2002
-------------------------- ---------- ---------
Program started.
The first time the log is created, it writes the Application Log... and the -------------. Afterwards, it starts logging stuff.
Please help! I tried doing it but failed miserably. Thanks!
Application Log - Generated on April 14, 2002
--------------------------
Program started.
The first time the log is created, it writes the Application Log... and the -------------. Afterwards, it starts logging stuff.
Please help! I tried doing it but failed miserably. Thanks!
ASKER
Madshi, new Q for you here: https://www.experts-exchange.com/delphi/Q.20291880.html
interface
uses Windows;
type
TStringArray = record
Size: Integer;
Capacity: Integer;
Items: Array of String;
end;
TMyStringList = class
List: TStringArray;
constructor Create; //Don't know how to do this!
destructor Destroy; override;
procedure Add(Item: String);
procedure Delete(Index: Integer);
function Count: Integer;
procedure LoadFromFile(FileName: String);
procedure SaveToFile(FileName: String);
end;
implementation
constructor TMyStringList.Create;
begin
with list do
Begin
Size:=0;
Capacity:=0;
Setlength(items,size);
end;
end;
destructor TMyStringList.Destroy;
begin
with list do
Begin
Size:=0;
Capacity:=0;
Setlength(items,size);
end;
end;
procedure TMyStringList.Add(Item: String);
begin
if List.Size = List.Capacity then
begin
if List.Capacity = 0 then
List.Capacity := 64
else
List.Capacity := List.Capacity * 3 div 2;
SetLength(List.Items, List.Capacity);
end;
List.Items[List.Size] := Item;
Inc(List.Size);
end;
procedure TMyStringList.Delete(Index
begin
if (Index > 0) and (Index < List.Size) then
begin
Dec(List.Size);
List.Items[Index] := '';
if Index < List.Size then
begin
Move(List.Items[Index + 1], List.Items[Index], (List.Size - Index) * 4);
Integer(List.Items[List.Si
end;
end;
end;
function TMyStringList.Count: Integer;
begin
Result := List.Size;
end;
procedure TMyStringList.LoadFromFile
var
InFile: Text;
S: String;
begin
AssignFile(InFile, FileName);
Reset(InFile);
while not EOF(InFile) do
begin
ReadLn(InFile, S);
Add(S);
end;
CloseFile(InFile);
end;
procedure TMyStringList.SaveToFile(F
var
OutFile: Text;
i: Integer;
begin
AssignFile(OutFile,FileNam
Rewrite(OutFile);
for i := Low(List.Items) to High(List.Items) do
WriteLn(OutFile, List.Items[i]);
CloseFile(OutFile);
end;
end.
somthing like this... regards me
ps.
if you WARE using a stinglist you should create one in the
constructor "list := Tstringlist.create;"
destuctor and destory it in the destructor "list.free"