I have a procedure which calls several functions:
procedure TForm1.Button1Click(Sender: TObject);
var
rawData: TRawData;
rawInts: TRawInts;
processedData: TProcessedData;
begin
rawData := getRawData();
rawInts := getRawInts(rawData);
processedData := getProcessedData(rawInts);
end;
The data types are defined like this:
TRawData = array[0..131069] of Byte;
TRawInts = array[0..65534] of LongInt;
TProcessedData = array[0..65534] of Double;
running the program with just:
rawData := getRawData();
rawInts := getRawInts(rawData);
Works totally fine. However, when I try to run:
getProcessedData(rawInts)
I get a stackoverflow error. I don't see why this is. The function code for getProcessedData is very simple:
function getProcessedData(rawInts : TRawInts) : TProcessedData;
var
i: Integer;
tempData: TProcessedData;
scaleFactor: Double;
begin
scaleFactor := 0.01;
for i := 0 to 65534 do
tempData[i] := rawInts[i] * scaleFactor;
Result := tempData;
end;
Why is this causing an error ?
The default maximum stack size for a thread is 1 MB. The three local variables of Button1Click total 131,070 + 65,535 * 4 + 65,535 * 8 = 917,490 bytes. When you call getProcessedData, you pass the parameter by value, which means that the function makes a local copy of the parameter on the stack. That adds SizeOf(TRawInts) = 262,140 bytes to bring the stack to at least 1,179,630 bytes, or about 1.1 MB. There's your stack overflow.
You can reduce the stack use by passing the TRawInts array by reference instead. Then the function won't make its own copy. Zdravko's answer suggests using var, but since the function has no need to modify the passed-in array, you should use const instead.
function getProcessedData(const rawInts: TRawInts): TProcessedData;
Naively, we might expect the tempData and Result variables in getProcessedData to occupy additional stack space, but in reality, they probably won't. First, large return types typically result in the compiler changing the function signature, so it would act more like your function were declared with a var parameter instead of a return value:
procedure getProcessedData(rawInts: TRawInts; var Result: TProcessedData);
Then the call is transformed accordingly:
getProcessedData(rawInts, processedData);
Thus, Result doesn't take up any more stack space because it's really just an alias for the variable in the caller's frame.
Furthermore, sometimes the compiler recognizes that an assignment at the end of your function, like Result := tempData, means that tempData doesn't really need any space of its own. Instead, the compiler may treat your function as though you had been writing directly into Result all along:
begin
scaleFactor := 0.01;
for i := 0 to 65534 do
Result[i] := rawInts[i] * scaleFactor;
end;
However, it's best not to count on the compiler to make those sorts of memory-saving changes. Instead, it's better not to lean so heavily on the stack in the first place. To do that, you can use dynamic arrays. Those will move the large amounts of memory out of the stack and into the heap, which is the part of memory used for dynamic allocation. Start by changing the definitions of your array types:
type
TRawData = array of Byte;
TRawInts = array of Integer;
TProcessedData = array of Double;
Then, in your functions that return those types, use SetLength to assign the length of each array. For example, the function we've seen already might go like this:
function getProcessedData(const rawInts: TRawInts): TProcessedData;
var
i: Integer;
scaleFactor: Double;
begin
Assert(Length(rawInts) = 65535);
SetLength(Result, Length(rawInts));
scaleFactor := 0.01;
for i := 0 to High(rawInts) do
Result[i] := rawInts[i] * scaleFactor;
end;
These objects are all very large. And you appear to be allocating them as local variables. They will reside on the stack which has an fixed size, by default 1MB on Windows. You have allocated enough of these large objects in various parts of the call stack to exceed the 1MB limit. Hence a stack overflow.
Another problem in your code is the way you pass these objects as parameters. Passing large objects as value parameters results in copies being made. Copying an integer or two is nothing to worry about. Copying 65 thousand doubles is wasteful. It hurts performance. Don't do that. Pass references to large objects. Passing as const parameters achieves that.
The stack is well suited for small objects. It is not suited to these large objects. Allocate these objects on the heap. Use dynamic arrays: array of Integer, TArray<Integer> etc.
Do not increase the default stack size for your process. Especially in modern times of multi-core machines this is a recipe for out of memory errors.
Do not use magic constants. Use low() and high() to obtain array bounds.
Do pass input parameters by const. This allows the compiler to make optimisations that are significantly beneficial.
The key issue here is the size of your arrays.
If you use SizeOf you will see that they are probably larger than you think:
program Project3;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TRawData = array[0..131069] of Byte;
TRawInts = array[0..65534] of Longint;
TProcessedData = array[0..65534] of Double;
begin
try
writeln('TProcessedData:':20, SizeOf(TProcessedData):8);
writeln('TRawData:':20, SizeOf(TRawData):8);
writeln('TRawInts:':20, SizeOf(TRawInts):8);
writeln('Total:':20, SizeOf(TRawInts) + SizeOf(TProcessedData) + SizeOf(TRawData):8);
readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
Output:
TProcessedData: 524280
TRawData: 131070
TRawInts: 262140
Total: 917490
So most of the 1MB stack is consumed by the arrays. As some of the stack will already be allocated, you get a stack overflow.
This can be avoid by using dynamic arrays, which have their memory allocated from the heap.
TRawData = array of Byte;
TRawInts = array of Longint;
TProcessedData = array of Double;
...
SetLength(TProcessedData, 65535);
...
Related
I am trying to pass an array of bytes from VBscript to my windows Delphi Application and can't seem to find the correct syntax to interpret the passed data.
The requirement is fairly simple as the VBscript snippet below demonstrates
Dim inst,arr(5)
Sub Main
set inst=instruments.Find("EP1")
arr(0) = 0
arr(1) = 1
arr(2) = 2
arr(3) = 3
arr(4) = 4
inst.writebytes arr,5
end Sub
I can get the server to accept the olevariant passed by the script but the data seems garbled, my example server code is shown below and is based on the Stackoverflow question here How to use variant arrays in Delphi
procedure TInstrument.WriteBytes(Data: OleVariant; Length: Integer);
var i,n:integer; Pdat:Pbyte; Adata:PvarArray;
begin
if VarIsArray(data) then
begin
n:=TVarData(Data).VArray^.Bounds[0].ElementCount;
Adata:= VarArrayLock(Data);
Getmem(Pdat,length);
try
for i:=0 to length-1 do
Pdat[i]:=integerArray(Adata.data^)[i];
Finstrument.WriteBytes(Pdat,Length);
finally
freemem(Pdat)
end;
end;
end;
So the idea is to accept the integers passed by the script, convert it to the local data representation (array of byte) then pass it on to my function to use the data.
I have tried several different data types and methods to try and get some ungarbled data out of the variant all to no avail.
What is the correct method of extracting the array data from the passed variant?
Also, TVarData(Data).VArray^.Bounds[0].ElementCount has a value of zero, why would that be?
Arrays created in VBScript are
zero based
untyped
declared with upper bound (not size as you assumed; size of array declared as Dim arr(5) is 6)
include dimension info in them (so you don't need to pass it along with the array)
When used in COM, they are passed as variant arrays of type varVariant (as the Ondrej Kelle points out in his comment). To process such an array in your method you have to assert that:
the value is a single dimensional array
each element can be converted to byte
You can write helper routine for that:
function ToBytes(const Data: Variant): TBytes;
var
Index, LowBound, HighBound: Integer;
ArrayData: Pointer;
begin
if not VarIsArray(Data) then
raise EArgumentException.Create('Variant array expected.');
if VarArrayDimCount(Data) <> 1 then
raise EArgumentException.Create('Single dimensional variant array expected.');
LowBound := VarArrayLowBound(Data, 1);
HighBound := VarArrayHighBound(Data, 1);
SetLength(Result, HighBound - LowBound + 1);
if TVarData(Data).VType = varArray or varByte then
begin
ArrayData := VarArrayLock(Data);
try
Move(ArrayData^, Result[0], Length(Result));
finally
VarArrayUnlock(Data);
end;
end
else
begin
for Index := LowBound to HighBound do
Result[Index - LowBound] := Data[Index];
end;
end;
for loop in the routine will be horribly slow when processing large arrays, so there's optimization for special case (variant array of bytes) that uses Move to copy bytes to result. But this will never happen with VBScript array. You might consider using VB.Net or PowerShell.
Using such a routine has downside of keeping 2 instances of the array in memory - as variant array and as byte array. Use it as a guide when applying it to your use case.
I have 2 Tbytes var:
A: Tbytes;
B: Tbytes;
Now i want to swap then like this
tmp := A;
A := B;
B := tmp;
But I not sure if this is the most efficient way, especially with the copy-on-write (if it's the same as with String)
maybe something like this :
Tmp := Pointer(a);
pointer(a) := pointer(b);
pointer(b) := Tmp ;
There is no copy-on-write for dynamic arrays, but if there were, it would not matter, because nothing is written (to the contents of the arrays).
Your way is the most efficient: only references are copied, and a few reference counts are updated.
The way using pointers would be slightly more efficient (no refcounting), but also a bit more risky. You can do this because in the end, the reference counts of both arrays should be the same as they were before. If nothing can access the (local) references during the swap, it should not matter.
Update
And if you do what David recommended, i.e. put this code in a separate procedure, then it doesn't matter a lot if you use a local Tempvariable or an external one. But the swap using Pointer casts is 10x (ten times) as fast as the normal swap using TBytes!
See my comment to the other answer: it doesn't matter if you use an external or a local Temp variable: they are almost equally fast. I measured the one with a local Temp variable at an average of 6512 milliseconds, the one with the external Temp variable at 6729 milliseconds and the one using pointers at 589 milliseconds. I did several tests in different orders to eradicate any timing errors. There are timing differences when swapping empty (nil) arrays, but I assume these don't matter a lot
As it was already answered your code of swapping two TBytes between each other is the most efficient.
So my post here isn't an answer to your question but instead with it I'm trying just to warn you about how you can possibly screw up performance by using this code impropriety where performance loss will be actually caused by the code that is calling this code from your question.
Now based on the fact that you are even thinking about performance of such small piece of code I'm guessing you are probably planning on executing of this code in one large loop where slightest gain in performance of this code might have big consequences on overall performance of your application. If you would have called this code a few times I bet you wouldn't worry about its performance at all since it would be negligible to the performance of your entire application.
So if you follow the David's suggestion of putting this code into a procedure I'm guessing you might write something like this:
procedure SwapBytes(var A,B: TBytes);
var Temp: Tbytes;
begin
Temp := A;
A := B;
B := Temp;
end;
Nothing fancy. But the problem with this would be that every time you would call this procedure in your loop your application will have to initialize (allocate memory for it) that local variable upon entering the procedure and then finalize (release its memory) it on exiting the above procedure. Now why is this so bad? Because allocating od deallocating memory is much slower than actually writing to or reading from already allocated memory.
So how can you avoid this problem? You do so by initializing the Temp variable outside of your procedure and pass it to the procedure as additional parameter instead. Performance gain can be significant this way can be significant.
Here is my test example where I used both approaches and measure their performance.
//Basic procedure for swapping two TBytes values between each other
//It has local variable Temp of TBytes type which is automatically created when
//entering the procedure and released when exiting the procedure
procedure SwapBytesLocalTempVariable(var A,B: TBytes);
var Temp: TBytes;
begin
Temp := A;
A := B;
B := Temp;
end;
//Same as above bit this procedure does not contain any local variable so you
//need to pas the Temp variable as an additional input parameter
procedure SwapBytesExternalTempVariable(var A,B,Temp: TBytes);
begin
Temp := A;
A := B;
B := Temp;
end;
//Quick procedure for testing
procedure TForm1.Button1Click(Sender: TObject);
var A,B: TBytes;
I: Integer;
SW: TStopWatch;
Temp: TBytes;
begin
//Calling first procedure with local temp variable in a loop many times can be
//quite slow because your program needs to initialize and release that local
//variable in each loop cycle.
SW := TStopWatch.Create;
SW.Start;
for I := 0 to 100000000 do
begin
SwapBytesLocalTempVariable(A,B);
end;
SW.Stop;
Memo1.Lines.Add(Format('Swap bytes with local variable: %f',[SW.Elapsed.TotalMilliseconds]));
//Calling second procedure which does not have local temp variable and passing
//the temp variable as additional parameter is much quicker because this way
//the Temp variable isn't initialized and then released in each loop cycle but
//instead we created (initialized) it outside the loop (out OnClick method of
//TButton and is therefore being reused in each loop cycle.
SW := TStopWatch.Create;
SW.Start;
for I := 0 to 100000000 do
begin
SwapBytesExternalTempVariable(A,B,Temp);
end;
SW.Stop;
Memo1.Lines.Add(Format('Swap bytes with external variable: %f',[SW.Elapsed.TotalMilliseconds]));
end;
Now as you can see the performance difference of these two approaches is quite significant. During my testing calling first procedure with local variable took about 1800 millisecond (almost two seconds) while calling second procedure where I pas Temp variable as additional parameter to it only took about 800 milliseconds. Now that is one second performance gain between the two mentioned approaches.
Any way the general advice is to try and reduce the number of memory allocations as much as possible and try to reuse variables where possible.
I have a function which creates Pointer to a data from a Stream.
function StreamToByteArray(Stream: TStream): Pointer;
var
ByteArr: array of Byte;
begin
if Assigned(Stream) then
begin
Stream.Position := 0;
SetLength(ByteArr, Stream.Size);
Stream.Read(ByteArr[0], Stream.Size);
end
else
SetLength(ByteArr, 0);
result := #ByteArr[0];
end;
How can I convert it back, from a Pointer to dynamic byte array and
then save the content to a stream. Or maybe it is possible to load stream directly from
a Pointer?
Thanks for help.
Ouch, this code is (unfortunately) very bad. Your function returns a pointer to the ByteArr array, but unfortunately that array runs out of scope when the function exists: you're essentially returning an Invalid Pointer! Even if the error doesn't immediately pop up, you've got a latent Access Violation in there.
Longer explanation
A Pointer is a dangerous structure: it doesn't contain data, it simply says where that data exists. Your example of an untyped Pointer is the most difficult kind of Pointer, it says nothing about the data that exists at the given address. It might point towards some bytes you read from a stream, might point to a string or even a picture of some sorts. You can't even know the amount of data that's at the given address.
The Pointer concept is closely related to the concept of allocating memory. We use many different techniques for allocation memory, using local variables, global variables, objects, dynamic arrays etc. In your sample function you're using a dynamic array, the array of Byte. The compiler does a very nice job of shielding you from the internals of allocating and reallocation memory, you can simply use SetLength() to say how big the array should be. Things work pretty well because the dynamic array is a managed data structure in Delphi: the compiler keeps track of how you're using the dynamic array and will free the associated memory as soon as the dynamic array is no longer needed. As far as the compiler is concerned, the associated memory is no longer required when your function exists.
When you're doing:
Result := #ByteArr[0];
You're essentially taking the address for the compiler-allocated memory block. Since you're using a very low level structure to do that (the Pointer), the compiler can't possibly keep track of your usage of the memory, so it will free the memory when the function exists. That leaves you with a Pointer to un-allocated memory.
How to properly return a Pointer from a function
First of all you should avoid Pointers if possible: they're low-level, the compiler can't help with type-safety or deallocation, they're simply too easy to get wrong. And when you do get Pointers wrong, the errors are usually Access Violations, and they're difficult to track.
That said, if you really want to return a pointer, you should return a pointer to explicitly allocated memory, so you know the compiler doesn't free it for you. When you do that, make sure the receiving code knows it's responsible for the memory (should free the memory when it's no longer needed). For example, your function could be re-written like this:
function StreamToByteArray(Stream: TStream): Pointer;
begin
if Assigned(Stream) then
begin
Result := AllocMem(Stream.Size);
Stream.Position := 0;
Stream.Read(Result^, Stream.Size);
end
else
Result := nil;
end;
How to change a Pointer back to array of byte or TStream
The answer is, there's no way to change it back. A pointer is just that, a pointer to some random data. An array of byte is more then the data it contains. A TStream is even more abstract: it's an interface that tells you how to retrieve data, it doesn't necessarily hold any data. For example, a TFileStream (and that is a TStream) doesn't hold any bytes of data: all the data is in the file on disk.
If you need a pointer to memory to pass to e.g. a function in a DLL, you should make that call while the buffer is still allocated. There are numerous ways to refactor the code below, but the same principle applies regardless of how your code ends up: You must not pass your pointer around after buffer has already been deallocated.
var
ByteArr: array of Byte;
begin
if Assigned(Stream) then
begin
Stream.Position := 0;
SetLength(ByteArr, Stream.Size);
Stream.Read(ByteArr[0], Stream.Size);
end
else
SetLength(ByteArr, 0);
Test(Pointer(ByteArray),Length(ByteArray));
end;
In your Test procedure you can do this:
procedure Test(aData: Pointer; aCount: Integer);
var
ByteArr: array of Byte;
begin
SetLength(ByteArr,aCount);
Move(aData^,Pointer(ByteArr)^,aCount);
Possible solution:
type
TBytes = array of byte;
function StreamToByteArray(Stream: TStream): TBytes;
begin
if Assigned(Stream) then
begin
Stream.Position := 0;
SetLength(result, Stream.Size);
Stream.Read(pointer(result)^, Stream.Size);
end
else
SetLength(result, 0);
end;
procedure Test;
var P: pointer;
begin
P := pointer(StreamToByteArray(aStream)); // returns an allocated TBytes
// ... use P
end; // here the hidden TBytes will be released
You can use pointer() around the result to get the memory location.
And your code won't leak any memory nor trigger any access violation, since an implicit try...finally block will be added by the compiler:
procedure Test;
var P: pointer;
tmp: TBytes; // created by the compiler
begin
tmp := StreamToByteArray(aStream)); // returns an allocated TBytes
try
P := pointer(tmp);
// ... use P
finally // here the hidden TBytes will be released
Finalize(tmp);
end;
end;
You can use RawByteString instead of TBytes if you wish.
Cosmin is right your are returing a pointer to an array that will become out of scope, the pointer will point to an area of memory that was on the stack and may get overwriten, It may appear as though the function works if you use the resust immediatly.
You need to pass the array to be filled into the function as well, or as I usually do (depending upon the data type) simple return a string and use that as a byte array (if you intend to move to a newer Delphi you need to be careful which string type your use).
Also dynamic arrays store the length and data type before the data (8 bytes of) and passing pointers to the 1st element losses the fact its a dynamic array and becomes just a memory buffer making freeing of the array dangerous.
To answer your question, a pointer (+ length) can be put back into a stream with the TStream.WriteBuffer. You may need to clear the stream first as this, as most stream write operations do, will append from the current stream position.
Hope that helps
I am using: HawkNL library.
There is an nlRead procedure as follows:
function nlRead(socket: NLsocket; var buffer; nbytes: NLint): NLint;
In all examples and other resources a static array is used to read the bytes to.
Just something like this:
FBufArray = array [0..1024] of Byte;
I have a few questions regarding this matter.
Which model/type would be appropriate to satisfy nlRead function that I could
dynamically allocate space for read data?
I was trying to use Pointer and GetMem or dynamic table with SetLength, but It seemed not to work as it should.
What is the correct approach in the situation when I have to read bytes with the unknown speed and do it as fast as possible. I mean What should be the size of the buffor for example?
For me it is relevant because read bytes I have to re-send further at the same time.
Generally how can I read and send bytes as fast as it is possible?
If your question is about what to pass as 'buffer'. You can pass anything you like.
If you pass a pointer you have to dereference it. For example when you call nl Read
Procedure read;
Type
TChunk = record
data: pointer;
datasize: NLint;
End;
Var
Chunk: TChunk;
Const
IdealReadSize = 1024;
Begin
GetMem( Chunk.data, IdealReadSize);
Try
Chunk.datasize := nlRead( YourSocket, Chunk.data^, IdealReadSize );
// Chunk.datasize hold the count of bytes which have been effectively read
// (maybe less than 1024 in case of an error)
// do something with your chunk
Finally
Freemem( Chunk.data, IdealReadSize );
End;
End;
It's the same approach as the TStream.Read() procedure.
You could use an untyped pointer: var P: Pointer;, allocate with GetMem or AllocMem, pass it to your function dereferenced: nlRead(Socket, P^, Count); and deallocate with FreeMem.
With regard to speed, a static buffer, sufficiently large: Buf: array[0..BufSize - 1] of Byte is probably the best.
I wrote two methods with a void type parameter:
procedure Method1(const MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
{now copy the data from MyVar to Arr, but how?}
end;
procedure Method2(var MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
{return the data from the array, but how?}
end;
In the first one I would like to access the MyVar as an array of byte. In the second one, I would like to copy the data from the local array Arr to MyVar. Therefore I used the CopyMemory() function, but something is wrong with it.
If I use the following in the second method, it is fine as long as Method2 is called with an array as its parameter (Method2(Pointer(MyString)^, Length(MyString)) or Method2(Pointer(MyArray), Length(MyArray))).
CopyMemory(Pointer(MyVar), Pointer(Arr), size);
If I call Method2 with a, for instance, integer parameter (Method2(MyInteger, SizeOf(MyInteger))), it does not work properly. In this case, the CopyMemory() has to be called this way:
CopyMemory(#MyVar, Pointer(Arr), size);
How to return data from Method2 correctly not knowing whether it is a simple type (or record) or an array? The situation will be similar in Method1, but here I would have to use
CopyMemory(Pointer(Arr), Pointer(MyVar), size);
in case of arrays and
CopyMemory(Pointer(Arr), #MyVar, size);
in case of simple types.
What can I do about it when I don't know what the MyVar parameter is?
There's no such thing a a void type in Delphi. What you're referring to is called an untyped parameter.
An untyped parameter is always the actual thing itself, not a pointer to the thing you're supposed to use. Therefore, the correct way to use CopyMemory with such a parameter is to apply the # operator to it, like so:
CopyMemory(#MyVar, #Arr[0], size);
Notice I've also changed the way I pass the second parameter. It's better if you don't rely on the fact that a dynamic array is really a pointer to the first element. If you need a pointer to the first element, just say so explicitly, like I did here.
Your confusion comes from a test you made where the parameter was used as though it were a pointer, and the test appeared to work. I doubt the validity of that test, though. When you said Pointer(MyString)^, what you had was the first character of the string. When you then said Pointer(MyVar) inside the function, you were type-casting that character into a pointer, which was an invalid type-cast. If your program appeared to work, then it was only by accident; your code was wrong.
The best advice I can give is to not type-cast stuff unless you really have to. And when you do, please be sure that the thing you're type-casting really does have that type. In your case, you don't need to type-cast anything before you pass it as an untyped parameter. You can call Method1 like this:
Method1(MyString[1], Length(MyString) * Sizeof(Char));
(I multiply by SizeOf(Char) since I don't know whether you have Delphi 2009 or not.)
Also, do avoid untyped parameters. One of the great things a compiler can do to help ensure program correctness is to enforce type safety, but when you take away the types, the compiler can't help you anymore.
Your problem is that you pass either data OR pointer to a data to Method1/2. You should always pass data itself.
May be you just forgot that dynamic array is a pointer itself? You should not pass A or Pointer(A) in your methods (A is dynamic array here). Pass A[0] or Pointer(A)^.
procedure Method1(const MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
CopyMemory(Pointer(Arr), #MyVar, Size);
end;
procedure Method2(var MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
Arr[0] := 1;
Arr[1] := 2;
Arr[2] := 3;
Arr[3] := 4;
CopyMemory(#MyVar, Pointer(Arr), Size);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
A: array of Integer;
begin
I := $01020304;
Method1(I, 4); // we pass data itself, not the pointer to it.
Method2(I, 4);
SetLength(A, 2);
A[0] := 0;
A[1] := $01020304;
Method1(A[0], Length(A) * SizeOf(A[0])); // note, that we pass data, not pointer
Method2(A[0], Length(A) * SizeOf(A[0])); // A or Pointer(A) is a pointer to array's data
end;
If A is dynamic array:
A[0] is the same as Pointer(A)^ and represents array's data.
#A[0] is the same as Pointer(A) or just A and represents the array itself, which is pointer to it's data (and some tech info on negative offsets).
If A is static array:
A[0] is the same as A and represents the array itself, which is array's data.
#A[0] is the same as #A and represents the pointer to array.
Pointer(A) or Pointer(A)^ are meaningless.
Note, that Arr in Method1/2 is a dynamic array too, that is why we cast it to pointer (CopyMemory asks pointers, not the data). If we want to use Move routine (which asks data), we should write Pointer(A)^ instead.