Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Dynamic Arrays 1

Status
Not open for further replies.

LynneJackson

Programmer
May 5, 2003
5
GB
Im currently using delphi 5 and need a true copy of a dynamic array, Ive tried both versions of copy but this results in the copy pointing to the original. I need to store a tempary copy that does not get updated when manipulating the original.
 
Unfortunately you do not show the code which is not working. However this code does work in Delphi 5:

Code:
var
  a1, a2: array of integer;

procedure TForm1.Button1Click(Sender: TObject);
var
  a: integer;
begin
  SetLength( a1, 10 );  // Set size of dynamic array
  for a := 0 to 9 do
    a1[a] := a+1;     // Fill dynamic array with 1 to 10.
  a2 := Copy ( a1, 0, 10 );   // Copy array a1 to array a2
  for a := 0 to 9 do
    a1[a] := - a1[a];     // Make a1 numbers negative
  ShowMessage ( IntToStr(a2[1]) );  //Show that a2 numbers have not changed 
end;

Andrew
 
The only way this seems to work is to set the length of the tempArray to match the length of the origArray then assign value of each element of the origArray to the tempArray.

Mike
 
Are you using Delphi 5 and have you copied and pasted my code exactly into a TButton OnClick event? I've run it again and it still works.

Can you post the code that doesn't work please?

Andrew
 
this is the code for the procedure i had to amend it
to copy the elements of the array individually however
as there could be thousands of elements this is quite
a combersome way of doing the job.

procedure TSimulationEngine.SimpleIteration;
var
TempFrom:TCellSpaceArray;
TempTo:TCellSpaceArray;
begin
SetLength(TempFrom,0,FHeight); //Fheight & fFrom a
TempFrom:=Copy(FFrom,0,FHeight); //are set in the constructor
SimpleSwap(FTo,FFrom); //I had to swap to overcome
SimpleUpdate(orBody,FFrom,FTo);// the problem
SimpleUpdate(orTop,FFrom,FTo);
SimpleUpdate(orBottom,FFrom,FTo);
SimpleUpdate(orLeft,FFrom,FTo);
SimpleUpdate(orRight,FFrom,FTo);
SimpleSwap(FFrom, FTo ); //and swap again once
FRefreshDisplay(FCanvas);//after the manipulation
inc(FCurrentEpoch);
end;
 
Ive run the code with a one dimensional array and it works howevery as the array represents a grid of cellular automaton it needs to be two dimensional. So I tried changing your code and the two arrays seem to point to the same memory location as updating one effects the other
here is the altered code.

procedure TForm1.Button1Click(Sender: TObject);
var
a1, a2: array of array of integer;
a: integer;
b:integer;
begin
SetLength( a1,2, 10 ); // using a two dimensional array
for b:=low(a1) to High(a1) do
for a := low(a1) to high(a1) do
a1[a] := a+1; // fill array

a2 := Copy ( a1, 0, 10 ); // copy
for b := Low(a1) to high(a1) do
for a:= low(a1)to High(a1) do
a1[a] := - a1[a]; // Make a1 numbers negative
ShowMessage ( IntToStr(a2[0][1]) ); //numbers do change to negative
end;
 
Im not sure if i posted the code that i have been using however I did try the code that was posted and found that it worked for a single dimensional array. However changing the code to two dimensions gives the results that i have already experienced. As the array represents a grid of cellular automata it would be unreasonable to copy each item individually (speed).

procedure TForm1.Button1Click(Sender: TObject);
var
a1, a2: array of array of integer;
a: integer;
b:integer;
begin
SetLength( a1,2, 10 ); // using a two dimensional array
for b:=low(a1) to High(a1) do
for a := low(a1) to high(a1) do
a1[a] := a+1; // fill array

a2 := Copy ( a1, 0, 10 ); // copy
for b := Low(a1) to high(a1) do
for a:= low(a1)to High(a1) do
a1[a] := - a1[a]; // Make a1 numbers negative
ShowMessage ( IntToStr(a2[0][1]) ); //numbers do change to negative
end;
 
You didn't say it was a two dimensional array in your first posting!

You need to consider a1 as a dynamic array of dynamic arrays.

So your code should look something like this:-

Code:
var
  a1, a2: array of array of integer;

procedure TForm1.Button1Click(Sender: TObject);
var
  a: integer;
  b: integer;
begin
// Set Dimensions of array a1
  SetLength ( a1, 2 );
  for a := Low(a1) to High(a1) do
    SetLength( a1[a], 10 );

// Fill up a1 with positive numbers
  for a := Low(a1) to High(a1) do
    for b := Low(a1[0]) to High(a1[0]) do
      a1[a,b] := a+1;

// Copy a1 to a2
  SetLength ( a2, 2 );
  for a := Low(a1) to High(a1) do
    a2[a] := Copy ( a1[a], 0, 10 );

// Fill up a1 with negative numbers
  for a := Low(a1) to High(a1) do
    for b := Low(a1[0]) to High(a1[0]) do
      a1[a,b] := - a1[a,b];

// Show that a2 still has positive numbers
  ShowMessage ( IntToStr(a2[1,5] ) );

end;

Andrew
 
Why do the arrays have to be dynamic? Simply pre-define your arrays to the largest size required. (I.e. use Static Arrays.) Then you can copy from one to another directly with the Windows CopyMemory API (for speed):
[blue]
Code:
unit Unit1;

interface

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

type
  TCellGrid = Array[0..999] of Array[0..999] of integer;

  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
   private
    { Private declarations }
    Grid1: TCellGrid;
    Grid2: TCellGrid;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
[red]
Code:
{ Initialize an element of Grid1. }
[/color]
Code:
procedure TForm1.FormCreate(Sender: TObject);
begin
  Grid1[789,789] := 789;
end;
[red]
Code:
{ Copy Grid1 to Grid2 and increment test element of Grid1.  Then show both.}
[/color]
Code:
procedure TForm1.Button1Click(Sender: TObject);
begin
  CopyMemory(Pointer(@Grid2),Pointer(@Grid1),SizeOf(Grid1));
  Grid1[789,789] := Grid1[789,789] + 1;
  Edit1.Text := IntToStr( Grid1[789,789] );
  Edit2.Text := IntToStr( Grid2[789,789] );
end;

end.
[/color]

 
A simple

Code:
  Grid2 := Grid1;

appears to be more efficient and quicker for moving static arrays than using CopyMemory.
 
towerbase, Thanks for that. I always seem to be doing things the hard way [upsidedown].
 
The Arrays have to be dynamic because they can hold anything from a small grid of 5 by 5 upto the limit that would feasibly run with each element representing an automaton state within a spatial array.

Each cell having a function, which is defined by the user and then parsed and compiled at the start of the simulation and the applied to each cell and it sourounding neighbours.

Each cell also has a graphical visualisation (rendered as a geometric shape with either a bitmap colour or text associated depending upon the user requiremnt), which is updated to represent the cells change of state.

As such the application is quite process intensive and it would slow the application down to continually allocate more space than would be absolutely necessary to store and integer representation of the automata.

The code that i have implemented at the moment is given below and which is closest to that given by Towerbase.

procedure TSimulationEngine.SimpleIteration;
Index:Integer;
begin
FCurrentEpoch:=0;
while FCurrentEpoch<FEpochs do
begin
for Index := Low(FFrom) to High(FFrom) do
FTo[Index]:=Copy(FFrom[Index],0,Length(FFrom[Index]));
SimpleUpdate(orBody,FFrom,FTo);
SimpleUpdate(orTop,FFrom,FTo);
SimpleUpdate(orBottom,FFrom,FTo);
SimpleUpdate(orLeft,FFrom,FTo);
SimpleUpdate(orRight,FFrom,FTo);
for Index := Low(FTo) to High(FTo) do
FFrom[Index]:=Copy(FTo[Index],0,Length(FTo[Index]));
FRefreshDisplay(FCanvas);
inc(FCurrentEpoch);
end;
end;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top