In Delphi, I declared a 3x3 matrix table as an array of array of Single, like this:
m_Table: array [0..2] of array [0..2] of Single;
Now I want to memory compare the content with another table, or memory copy the table content from another table. I know that I can create a nested loop to do that, but I want to do the job without any loop, if possible.
My question is, it is correct to copy or compare the memory like this:
CompareMem(m_Table, other.m_Table, 9 * SizeOf(Single));
CopyMemory(m_Table, other.m_Table, 9 * SizeOf(Single));
If not, what is the correct way to do that?
And as a subsidiary question, is there a better way to get the length to copy instead of 9 * SizeOf(Single), like e.g. SizeOf(m_Table^)?
Regards
The code in the question works fine. Personally I would say that Move is the idiomatic way to copy memory. Further I would use SizeOf(m_Table) to obtain the size of the type.
I would point out that your comparison differs from the floating point equality operator. Perhaps that's what you want, but you should be aware of this. For instance zero and minus zero compare equal using floating point comparison but not with memory compare. And NaNs always compare not equal, even with identical bit patterns.
Let me also comment that it would make your code more extendible if you declared a type for these matrices. Without that you won't be able to write functions that accept such objects.
The correct and easiest way may be to define a type:
type
TMatrix3x3 = array [0..2,0..2] of Single;
Then you can directly write:
var
v1, v2: TMatrix3x3;
begin
fillchar(v1,sizeof(v1),0);
move(v1,v2,sizeof(v1));
if comparemem(#v1,#v2,sizeof(v1)) then
writeln('equals');
end;
Using sizeof() make your code safe and readable.
You may define a wrapper type with methods:
{ TMatrix3x3 }
type
TMatrix3x3 = record
v: array [0..2,0..2] of Single;
procedure Zero;
procedure Copy(var dest: TMatrix3x3);
procedure Fill(const source: TMatrix3x3);
function Equals(const other: TMatrix3x3): boolean;
end;
procedure TMatrix3x3.Copy(var dest: TMatrix3x3);
begin
move(v,dest,sizeof(v));
end;
function TMatrix3x3.Equals(const other: TMatrix3x3): boolean;
begin
result := CompareMem(#v,#other.v,sizeof(v));
end;
procedure TMatrix3x3.Fill(const source: TMatrix3x3);
begin
move(source,v,sizeof(v));
end;
procedure TMatrix3x3.Zero;
begin
fillchar(v,sizeof(v),0);
end;
Including then advanced features like implicit assignment, and operators, if needed.
But don't reinvent the wheel, if you really to work with matrix arithmetic. Use an already existing and fully tested library, which will save you a lot of trouble and debugging time.
You should use standard TMatrix type from System.Math.Vectors unit, then you can just compare it directly as if Matrix1 = Matrix2 then and assign as Matrix1 := Matrix2
Related
Given the following:
LBytes: TBytes;
LArr: array[1..512] of Byte;
...
SetLength(LBytes, 512);
What is the correct Move() call to copy all bytes from LBytes to LArr?
Move(LBytes[0], LArr, Length(LBytes)); // works
Move(LBytes[0], LArr[1], Length(LBytes)); // works, too
Move(LBytes, LArr[1], Length(LBytes)); // fail
Can someone explain why it makes no difference between using Larr and Larr[1] but makes a difference between LBytes[0] and LBytes?
Can someone explain why it makes no difference between using Larr and Larr1 but makes a difference between LBytes[0] and LBytes?
That's because LBytes is a dynamic array which is, ultimately, a pointer to the array. On the other hand, LArr is the array.
Another way to say this is that dynamic arrays are reference types, and fixed length arrays are value types.
In my book, there are two viable ways to do this:
Assert(Length(LBytes)<=Length(LArr));
Move(LBytes[0], LArr, Length(LBytes));
or
Assert(Length(LBytes)<=Length(LArr));
Move(Pointer(LBytes)^, LArr, Length(LBytes));
I prefer the latter, because it is resilient to a zero length array when range checking is enabled. In that scenario, the first block of code leads to a run time range check error.
You might also be motivated to avoid such low-level trickery. I have a utility class that allows me to write:
TArray.Move<Byte>(LBytes, LArr);
The signature of the method is:
class procedure Move<T>(const Source: array of T; var Dest: array of T); overload; static;
Just a little question, I'm not finding a specific answer so i guessed it might be faster to ask here.
The compiler rejects the code below with the following error:
incompatible types 'dynamic array' and 'array of string'
TMailInfo = record
FileName,
MailAdresse,
MailBCC,
MailCC,
MailBetreff: string;
MailText,
Anhang: array of string;
MailAcknowledge,
MailTXT: Boolean
end;
class function TEMail.SendOutlookCOMMail(aFileName, aMailAdresse,
aMailBCC, aMailCC, aMailBetreff: string;
aMailText, aAnhang: array of string;
const aMailAcknowledge, aMailTXT: Boolean): Boolean;
var
mailInfo: TMailInfo;
begin
...
mailInfo.MailBetreff := aMailBetreff; // these two lines cause the error
mailInfo.MailText := aMailText;
...
end;
What am I doing wrong? Both are arrays of string, so I don't get why one seems to be dynamic.
You cannot readily assign to MailText and Anhang because you cannot declare another object with a compatible type. That's because you used a dynamic array type inline in your record declaration. You really need to use a type that can be named. To illustrate a bit better, consider this:
X: array of Integer;
Y: array of Integer;
Now X and Y are of different types and X := Y does not compile.
The other problem is your open array parameter. An open array parameter is assignment compatible with nothing. You can copy element by element, but you cannot assign the array in one go.
The best way out of this is to declare the field like this:
MailText,
Anhang: TArray<string>;
And change the open array parameters in the function to also be of that type.
Then you need to decide whether you want to copy the reference or the array:
MailText := aMailText; // copy reference, or
MailText := Copy(aMailText); // copy array
You have two problems. First, as David says, two declarations of a type that look the same, but are declared separately, make them different, assignment incompatible types.
Weirdly enough, this is not so for generic types, like TArray<string>, so it makes sense to use that, if you version of Delphi supports it.
But the second problem is that you are confusing an open array parameter like aMailText with a dynamic array like mailInfo.MailText. aMailText, the parameter, is not necessarily a dynamic array at all, it can be any kind of array.
Take a look at the documentation: Open Arrays
Another explanation: Open array parameters and array of const
How to alpha sort a stringgrid on a form on a given column in Delphi?
There's no built in sort facility for TStringGrid, so you need to roll your own. Personally, I use some general purpose sorting code that can sort anything provided a compare function and an exchange function:
type
TCompareIndicesFunction = function(Index1, Index2: Integer): Integer of object;
TExchangeIndicesProcedure = procedure(Index1, Index2: Integer) of object;
procedure Sort(const First, Last: Integer; Compare: TCompareIndicesFunction; Exchange: TExchangeIndicesProcedure);
begin
//insert search algorithm here
end;
You could look at how Generics.Collections.TArray.Quicksort is implemented to see how to fill in the missing code above.
The essential point is that your Compare and Exchange functions, which are methods of objects, contain the knowledge of how to compare items in the string grid, and then how to swap them.
Var
A : Array [1..4] of Integer;
B : Array [1..4] of Integer;
Begin
A := B;
Won't work as loren-pechtel said here
the problem is A and B for me are in different units. So, is there a way to define a type definition from a existing one in another class?
Define type in interface block of some unit and then include that unit via uses clause in other units where you need that type.
unit A;
interface
type
TMyArray = array [1..4] of Integer;
...
When you need to use TMyArray in another unit:
unit B;
interface
uses A;
...
var x : TMyArray;
Alternatively, define your type in the interface section of unit C and use this unit in both A and B.
Array types in Delphi are a bit odd. It looks like A and B are of exactly the same type, but Delphi doesn't consider that they are the same. "Array [1..4] of Integer" appears twice, so Delphi thinks there are two different types. That's just an oddity of Delphi. Most other languages, I think, wouldn't care. It's not a problem in practice; it's just a bit strange. Maybe there is a good reason for it. Who knows. The solution, as the others have said, is define your own type, which you can put in a unit that can be used by other units. I just mention this issue of array types because it may be confusing you.
Another approach, a bit old school but still works, is to use the ABSOLUTE keyword to force the memory of one to overlay another, and make the other type compatible. For example, in unit a lets say you have the following:
TYPE
TArrayA = Array[1..4] of integer;
then in unit b, you have the following:
TYPE
TArrayB = Array[1..4] of integer;
For compatibility, you can do the following:
VAR
InstanceA : TArrayA;
InstanceB : TArrayB;
InstanceBasA : TArrayA ABSOLUTE InstanceB;
What this does is create a variable "InstanceBasA" of type ArrayA which overlays the same memory space as the variable "InstanceB". This allows you to do the following command:
InstanceA := InstanceBasA;
One more method of moving data from variablea to variableb is to use the MOVE command. For example, to move from ArrayA to ArrayB you can do the following:
var
ArrayA : array[1..4] of Integer;
ArrayB : Array[1..4] of Integer;
begin
FillChar(ArrayB[1],SizeOf(ArrayB),#0);
ArrayA[1] := 1234;
ArrayA[2] := 3456;
ArrayA[3] := 7890;
ArrayA[4] := 9876;
// This is where the move from ArrayA to ArrayB happens.
Move( ArrayA[1], ArrayB[1], SizeOf(ArrayA) );
Assert( ArrayA[4] = ArrayB[4], 'ArrayA[4] <> ArrayB[4]');
end;
This works by the fact that the array is layed out in a linear fashion, so your copying the bytes starting at the first array position, for the length of the array.
You can force the compiler to assume they are of the same type by typecasting them:
type
TIntArray = array[1..4] of integer;
begin
Assert(SizeOf(ArrayA) = SizeOf(TIntArray));
Assert(SizeOf(ArrayB) = SizeOf(TIntArray));
TIntArray(ArrayA) := TIntArray(ArrayB);
But you should make sure that both actually are array[1..4] of otherwise you will overwrite some memory. That's why I added the two assertions.
Just use UnitA in UnitB after inteface and before the implementation ...!!!!
Never, never, NEVER use code like this:
// This is where the move from ArrayA to ArrayB happens.
Move( ArrayA[1], ArrayB[1], SizeOf(ArrayA) );
Where's the flaw? You're using the SOURCE size to get the number of bytes to move, not the DESTINATION size!!! If SizeOf(A) > SizeOf(B) you have a buffer overflow and you're overwriting memory. If you're luck you get an AV, if you're not you have an exploitable vulnerability. It's far better to always use the destination size, although this way you can end up reading memory you shouldn't if Size(B) > Size(A), maybe exposing unwanted data.
Anyway, always check structure boundaries when moving data - some companies banned operations like this (i.e. memcpy() ) from their code.
I'm developing class to represent special kind of matrix:
type
DifRecord = record
Field: String;
Number: Byte;
Value: smallint;
end;
type
TData = array of array of MainModule.DataRecord;
type
TDifference = array of DifRecord;
type
TFogelMatrix = class
private
M: Byte;
N: Byte;
Data: ^TData;
DifVector: ^TDifference;
procedure init();
public
constructor Create(Rows, Cols: Byte);
destructor Destroy;
end;
Now in constructor I need to reserve memory for Data and DifVector class members. I use pointers to array of records, as you see. So, the main question is, how can I correctly reserve memory? I suppose I can not use something like that:
new(Data);
new(DifVector);
cause I`m loosing the main idea - to reserve memory space, as much as I want to, at run-time. Thanks for comments.
Since you're using dynamic arrays, array of, then you should use SetLength to specify the length of the array, which can be done dynamically.
ie. like this:
SetLength(Data, 100);
This will not reserve 100 bytes, but will reserve enough space to hold 100 elements of whatever type the array holds.
Change your declarations for the arrays to simple arrays:
Data: TData;
DifVector: TDifference;
and use it with SetLength, it should do the trick.
Also note that In Delphi variables of a dynamic array type are stored as a pointer (in DotNet-speak you would call this a reference-type).
Unless you cast this variable to a pointer, the compiler won't let you do the allocation yourself. You should use SetLength() like lassevk mentioned already.
With a multi-dimensional array (like TData), you could set both dimensions in one go, by setting all dimension with one call to SetLength(). This results in a cube-like structure (each dimension has equal length). But it's also possible to give each index within a dimension a different length to it's next dimension. With two dimensions, this is sometimes called a 'jagged' array.
To do this, you would write it out like this :
SetLength(Data, SizeOfFirstDimension);
for i = 0 to SizeOfFirstDimension - 1 do
SetLength(Data[i], SizeOfSecondDimensionPerIndex(i));
In this example, I use a function called 'SizeOfSecondDimensionPerIndex' to determine the size of each array in the 2nd dimension, but you could determine this size any way you want.
On a side-note, I would advise you to use the 'R'-prefix for record-type definitions. I know this not in any of the major coding-style guides, but if you look at 'P'-prefixes for pointers, 'I'-prefixes for interfaces, 'F'-prefixes for class-fields, 'a'-prefixes for arguments, 'C'-prefixes for constants, 'S'-prefixes for resourcestring's, you can follow this logic and use an 'R'-prefix for records. I know this has helped me to get a better grasp of my code!
Good luck!