• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 182
  • Last Modified:

Short question about copying array contents and pointer assignment

Considering the following:

TCell = packed record
  status : cell_status;
  to_update : cell_status;
  lifetime: word;
  resist: byte;
  activated: boolean;
end;

type cell_pointer = ^TCell;

TMargolusBlock = packed record
  cell : array[0..3] of cell_pointer;
end;

TMargolusArray = class(TObject)
  mblock : array of array of TMargolusBlock;
  constructor create(size : Integer);
  destructor Destroy;
    override;
end;


currentMargolusArray : TMargolusArray;


Then:

currentMargolusArray := MargolusArrayA;

doesn't work, I just get a TMargolusArray object with an array filles with nils.
How can I get the contents of MargolusArrayA in currentMargolusArray ? Or do I really need to copy the whole thing?
(like: for teller := 0 to ...: currentMargolusArray.cell[0] := MargolusArrayA.cell[0] etc..)

Furthermore, a bit related, what is the difference between:

type cell_pointer = ^TCell;
cpointer : cell_pointer;
cell : Tcell;

cpointer := @cell;

and

cpointer^ := cell;??
0
reynaerde
Asked:
reynaerde
  • 2
  • 2
3 Solutions
 
LRHGuyCommented:
You just cannot simply "copy" an object.

But you can create a method to do so!

procedure tMargolusArray.CopyFrom(aOrig:tMargolusArray);
begin
  SetLength(MBlock,aOrig.dimension1,aOrig,dimension2);  // get array size from original object
  Move(aOrig.MBlock,MBlock,sizeof(aOrig.MBlock)); // copy array
end;

This puts the address of cell into cpointer:

cpointer := @cell;

This puts the contents of cell into the tcell referenced by cpointer:

cpointer^ := cell;??
0
 
Wim ten BrinkSelf-employed developerCommented:
The only way: (Not tested in compiler)

var
  I:Integer;
begin
  SetLength(Target, Length(Source));
  for I := Low(Source) to High(Source) do Target[I] := Source[I];
end;

And if the array contains pointers to objects or records, then those things aren't copied either, just the references.

The thing you have to keep in mind is the difference between the actual data and references to data. For a better performance, you should just keep copying those references. Because copying data costs a little bit of time and the more data you have to copy, the more performance you'll lose. Do you really need to copy those arrays?
0
 
Wim ten BrinkSelf-employed developerCommented:
cpointer := @cell;
Here, cpointer is told to point to a reference pointer that is pointing at cell.

cpointer^ := cell;
Here, the reference that cpointer is pointing to is changed to reference to cell.

Pointers to pointers can make life real complicated. :-)
0
 
LRHGuyCommented:
What Workshop_Alex indicates is true...if TCell is an object...but in your example, tcell is a record, so be careful!

type
  tcell=record  
  cellptr=^tcell   // pointer to a record

var
  cell:tcell;  //the actual record
  cp:cellptr;

  cp:=@tcell  //cp points to actual record
 
type
  tcell=class
  cellptr=^tcell   //pointer to a pointer

var
  cell:tcell;  //pointer to class object
  cp:cellptr;

  cp:=@tcell; //cp points to a pointer that points to the actual object data

As Workshop said, it can be complicated!
 
0
 
Slick812Commented:
hi again, , first I wonder about having a Record with only ONE elements as your -

TMargolusBlock = packed record
  cell : array[0..3] of cell_pointer;
end;

 this seems kind of "not needed" to me, since a Record was made to hold more then ONE element, so I changed it to a type -

type
  cellMB = array[0..3] of cell_pointer;

I also wondered why you always want to use a pointer to something instead of the something that is pointed to, you use a "cell_pointer" instead of a "TCell", but for me, it seems this would not have any advantage, and would just mean I would have to write more code to initialize and free this cell_pointer, so I changed it to a TCell -

type
  cellMB = array[0..3] of TCell;

  TMargolusArray = class
    FSize: Integer;
    mblock : array of array of CellMB;
    procedure Assign(MArray: TMargolusArray);
    constructor create(size: Integer);
    destructor Destroy; override;
  end;

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

I also had to change the class  TMargolusArray , as seen above

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

for your
currentMargolusArray := MargolusArrayA;
doesn't work question. . .

when you use the
 :=
with a TObject, it DOES NOT  create a new TObject, the  currentMargolusArray  will be one and the same as  MargolusArrayA, (the object pointer value is ALL that is copied, no object elements are involved), ,  if you free one of them the other is also gone (because the other is the same thing), as in the code below -



procedure TForm1.sbut_ObjectAsgnClick(Sender: TObject);
var
MArray1, curMArray: TMargolusArray;
begin
MArray1 := TMargolusArray.Create(6);
Marray1.mBlock[5,5,3].lifetime := 12345;
curMArray := MArray1;
// the line above does not create a separate TMargolusArray
// it just copy the Object Pointer, so now they are the same TMargolusArray
ShowMessage(IntToStr(curMArray.mBlock[5,5,3].lifetime));
FreeAndNil(MArray1); // this also frees the curMArray, since they are the same
ShowMessage(IntToStr(curMArray.mBlock[5,5,3].lifetime));
// I get an access violation in the line above
end;


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

and Yes, you will really need to copy every array element from one to the  other, here is my code for the  TMargolusArray  , I have added an Assign procedure -

constructor TMargolusArray.create(size: Integer);
begin
FSize := size;
SetLength(mblock, Size, Size);
mblock[0,0,0].status := H; // just for looks, not know your initialize
end;

destructor TMargolusArray.Destroy;
begin
SetLength(mblock, 0,0);
end;

procedure TMargolusArray.Assign(MArray: TMargolusArray);
var
i, j, k: Integer;
begin
if (not Assigned(MArray)) then Exit;
FSize := MArray.FSize;
SetLength(mblock, FSize, FSize);

for i := 0 to FSize-1 do
  for j := 0 to FSize-1 do
    for k := 0 to 3 do
      mblock[i,j,k] := MArray.mblock[i,j,k];
end;

the Assign method is in to the TPersistent Class and not in the TObject class, but I have added it here.
below is some button click code for this -


procedure TForm1.sbut_ObjectAsgnClick(Sender: TObject);
var
MArray1, curMArray: TMargolusArray;
begin
MArray1 := TMargolusArray.Create(6);
Marray1.mBlock[5,5,3].lifetime := 12345;
curMArray := TMargolusArray.Create(Marray1.FSize);
ShowMessage(IntToStr(curMArray.mBlock[5,5,3].lifetime));
curMArray.Assign(MArray1);
FreeAndNil(MArray1);
ShowMessage(IntToStr(curMArray.mBlock[5,5,3].lifetime));
// show the same number in the Marray1
FreeAndNil(curMArray);
end;


- - - - - - - - - - - - - - - - - -  - - - -  - - - - -
maybe some ides from this
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now