11/7/2019 Delphi Initialize Array
Function CloneArray ( const A: array of Integer ): TIntegerDynArray; overload; var Idx: Integer; begin SetLength ( Result, Length ( A ) ); for Idx:= Low ( A ) to High ( A ) do Result Idx - Low ( A ) := A Idx ; end; function CloneArray ( const A: array of string ): TStringDynArray; overload; var Idx: Integer; begin SetLength ( Result, Length ( A ) ); for Idx:= Low ( A ) to High ( A ) do Result Idx - Low ( A ) := A Idx ; end; Noticing how similar these functions were - only the first line differs - I decided to try a generic approach. Since I didn't want to parameterise both the type of the array (e.g. The TIntegerDynArray return value) and the array element (e.g. Integer) I first decided to change the return values of the functions to use the TArray type defined in the System unit. So the function prototypes got changed to. Type TArrayEx = class ( TArray ) public class function CloneArray ( const A: array of T ): TArray; end;. Class function TArrayEx.
CloneArray ( const A: array of T ): TArray; var Idx: Integer; begin SetLength ( Result, Length ( A ) ); for Idx:= Low ( A ) to High ( A ) do Result Idx - Low ( A ) := A Idx ; end; Don't confuse Generics.Collections.TArray with System.TArray - the first is a class, the second a generic dynamic array type. CloneArray assumes that straighforward assignment of array elements is what we want. For example if the array elements are objects, just the object pointer is copied.
If you need the object's fields to be physically copied this simplistic approach won't work. I'll close this post with an example of use. Here's a code fragment that initialises string and integer arrays.
Anonymous said. WRT your opening question, you can in fact do this: uses Types; var A: TIntegerDynArray; begin A:= TIntegerDynArray.Create(1,2,3,4); end; There's nothing special to TIntegerDynArray - it's just to use a predefined typedef. So, this works as well: type TMyIntArray = array of Integer; var A: TMyIntArray; begin A:= TMyIntArray.Create(1,2,3,4); end; I think this syntax was added in something like D2005 or D2006. Thanks Chris. I'd not come across this before.
This makes some of this post redundant with one exception. The TArrayEx.CloneArray method works for cloning another dynamic array stored in a variable whereas the Create construct doesn't work in this case. I've also just noticed that this also works: var K: TArray; begin K:= TArray.Create(1, 2, 3); end; Anonymous said. Actually, now I come to think of it, for cloning, there's the single parameter version of the Copy standard function - A2:= Copy(A1); said. One more new one for me! A:= TIntegerDynArray.Create(1,2,3,4); I can't believe that I have never seen this before.
I was unable to determine the syntax to initialize an array of records. I prefer to do the initialization without writing code to do so. So my example of a record is as follows: const SIZEOFSTUFF = 10; SOMEINFO = record aprompt: string; avalue: integer; asetting: real; end; var (note: in the var section of the unit - some values will change) somestuff: array1.SIZEOFSTUFF of SOMEINFO =????; I would appreciate any comments on how to fill in the???? For this initialization. Quote I was unable to determine the syntax to initialize an array of records.
I prefer to do the initialization without writing code to do so. So my example of a record is as follows: const SIZEOFSTUFF = 10; SOMEINFO = record aprompt: string; avalue: integer; asetting: real; end; var (note: in the var section of the unit - some values will change) somestuff: array1.SIZEOFSTUFF of SOMEINFO =????; I would appreciate any comments on how to fill in the????
For this initialization. Scot somestuff: array1.SIZEOFSTUFF of SOMEINFO = ( (aprompt: 'ComeOn'; avalue: 123; aSetting: 0.5), // 9 more of this lines, the last without ',' ); This should work. I tried your code but it came up with errors this is my way to get it to run Type SomeInfo=Record APrompt:String; AValue:Integer; ASetting:Real; End; Const SizeofStuff=10; Var SomeStuff:Array1.SizeofStuff of SomeInfo; Begin SomeStuff1.APrompt:='Hello'; SomeStuff1.AValue:=1; SomeStuff1.ASetting:=3.45; SomeStuff2.APrompt='Bye'; SomeStuff2.AValue:=0; SomeStuff2.ASetting:=4.56; End; and so on i couldn't actually write these values into a records array maybe someone else knows.
Hopes this helps. Karl On Wed, 6 Oct 1999 09:36:58 -0400, 'Scot Crowner'. Quote wrote: I was unable to determine the syntax to initialize an array of records. I prefer to do the initialization without writing code to do so. So my example of a record is as follows: const SIZEOFSTUFF = 10; SOMEINFO = record aprompt: string; avalue: integer; asetting: real; end; var (note: in the var section of the unit - some values will change) somestuff: array1.SIZEOFSTUFF of SOMEINFO =????; I would appreciate any comments on how to fill in the????
For this initialization. Quote Scot Crowner wrote in message. I was unable to determine the syntax to initialize an array of records. I prefer to do the initialization without writing code to do so. So my example of a record is as follows: const SIZEOFSTUFF = 10; SOMEINFO = record aprompt: string; avalue: integer; asetting: real; end; var (note: in the var section of the unit - some values will change) somestuff: array1.SIZEOFSTUFF of SOMEINFO =????; I would appreciate any comments on how to fill in the???? For this initialization.
Open array parameters and array of const This article describes the syntax and use of open array parameters, and the use of the “array of const” parameter type. It also describes the internals of these two similar types of parameters, discusses lifetime issues, and gives a code solution for these issues.
It has a short discusson on the confusion between open arrays and dynamic arrays, and between Variant arrays and variant open arrays. Open array parameters Open array parameters are special parameters which allow you to write procedures or functions (I will use the word routines, if I mean both) that can act on any array of the same base type, regardless of its size. To declare an open array parameter, you use a syntax like this.
Procedure ListAllIntegers ( const AnArray: array of Integer ); var I: Integer; begin for I:= Low ( AnArray ) to High ( AnArray ) do WriteLn ( 'Integer at index ', I, ' is ', AnArray I ); end; You can call this procedure with any one-dimensional array of Integers, so you can call it with an array0.1 of Integer as well as with an array42.937 of Integer, or even a dynamic type array of Integer. The code also demonstrates how you can determine the size of the array in the routine. Delphi knows the pseudo-functions Low and High. They are not real functions, they are just syntactic items in Delphi that take the form of a function, but actually rely on the compiler to substitute them for code. Low gives the lower bound of an array, and High the upper bound. You can also use Length, which returns the number of elements of the array. But if you call the code with an array that is not zero-based, like for instance in the following (nonsense) example.
Var NonZero: array 7. 9 of Integer; begin NonZero 7 := 17; NonZero 8 := 325; NonZero 9 := 11; ListAllIntegers ( NonZero ); end. You will see that the output is like this: Integer at index 0 is 17 Integer at index 1 is 325 Integer at index 2 is 11 That is because inside the procedure or function, the array is always seen as a zero based array. So for an open array parameter, Low is always 0, and High is adjusted accordingly (note that this is not necessarily true for other uses of High and Low, i.e.
Not on open array parameters). For open arrays, Length is always High + 1.
Slice If you don’t want to use an entire array, but only a part of it, you can do that using the Slice pseudo-function. It is only allowed where an open array parameter is declared. It is used in this fashion.
Var N: Integer; begin N:= 18; ListAllIntegers ( Slice ( Months, N )); end; If ListAllIntegers really tries to access index 12 (remember, the index of an open array parameter is zero-based, so High should be 11) or higher, it is accessing beyond the bounds of the array. This is undefined behaviour. It can result in a crash, or other bad things, depending on what is actually accessed. Without Slice, the compiler passes the right values for High, so this cannot happen. So be careful with this pseudo-function.
Internals But how does that work; how can the function know the size of the array? It is quite simple. An open array parameter is actually a combination of two parameters, a pointer, which contains the address of the start of the array, and an integer, which contains the High value, adjusted for a zero base.
So in fact the real parameter list of the procedure is something like this. Procedure ListAllIntegers ( const AnArray: Pointer; High: Integer ); Each time you pass an array to an open array parameter, the compiler, which knows the size of the array, will pass its address and its adjusted High value to the procedure or function. For arrays of a static size, like array7.9 of Integer, it uses the declared size to pass the High value; for dynamic arrays, it compiles code to get the High value of the array at runtime. Usually, you can pass open arrays as const parameters. Open array parameters that are not passed as const will entirely be copied into local storage of the routine. The array is simply passed by reference, but if it is not declared const, the hidden start code of the routine will allocate room on the stack and copy the entire array to that local storage, using the reference as source address. For large arrays, this can be very inefficient.
So if you don’t need to modify items in the array locally, make the open array parameter const. Open array constructors Sometimes you don’t want to declare and fill an array just so you can use it with an open array parameter. Luckily, Delphi allows you to declare open arrays on the spot, using the so called open array constructor syntax, which uses and to define the array. The above example with the NonZero array could also have been written like this. ListAllIntegers ( 17, 325, 11 ); Here, the array is defined on the spot as 17, 325, 11. Lifetime An array created by an open array constructor is only valid as long as the function or procedure runs and is discarded right afterward.
That is one reason why you can’t pass such an array to a var open array parameter. Internally, the open array constructor simply makes room on the stack (the local variable frame) and puts copies of the values there. In other words, it creates an ad hoc array on the stack. Then it calls the function passing a pointer to the first value on the stack and the High value of that array.
After the function call, the stack room is reclaimed, so the constructed array does not exist anymore. Managed (reference counted) types like strings, interfaces, etc. Are copied raw to the stack array and not finalized after the call, i.e. No reference counting is done. This is equivalent to passing a const parameter. Confusion Although the syntax is unfortunately very similar, an open array parameter should not be confused with a Delphi dynamic array.
A dynamic array is an array that is maintained by Delphi, and of which you can change the size using SetLength. It is declared like.
Type TMonthArray = array of Month; procedure AllKinds ( const Arr: array of Month ); procedure OnlyDyn ( Arr: TMonthArray ); Procedure AllKinds will accept static arrays as well as dynamic arrays, so SetLength can’t be used, since static arrays can’t be reallocated. Procedure OnlyDyn will only accept dynamic arrays, so you can use SetLength here (this will however use a copy, and not change the original array; if you want to change the length of the original array, use var Arr: TMonthArray in the declaration). Procedure OnlyDyn ( Arr: TArray ); The construct is being used more and more, because generic types can circumvent the general rule that type compatibility is not dependent on the form of the declaration, but on where the type is defined. So not all array of Month are assignment compatible with each other, although they have exactly the same form. But all TArray are assignment compatible, even if they are declared on the spot.
This is an exception to the rule I explain in the text box above. TArray can be used as parameter and even as return type, so you can have declarations like the following.
Constructor Create ( Limbs: TArray; Negative: Boolean ); function ToByteArray: TArray; Assembler To use an open array from assembler, you must remember that an open array is in fact a combination of two parameters. The first parameter is a pointer to the start of the array, the second the adjusted High value. Generally, open arrays are passed as const or var. In all cases, the array is passed by reference.
Here is a simple example of a function that sums all integers in an array. Function Sum ( const Data: array of Integer ): Integer; // EAX: address of the array // EDX: adjusted High value asm MOV ECX, EAX // P:= PInteger(Addr(Data)); XOR EAX, EAX // Result:= 0; OR EDX, EDX JS @@Exit // if High(Data). Var Res: string; Int: Integer; Dub: Double; Str: string; begin Int:= Random ( 1000 ); Dub:= Random. 1000; Str:= 'Teletubbies'; Res:= Format ( '%4d%8.3f%s'Int, Dub, Str ); end; Note: The official name for array of const parameters is variant open array parameters. This should not be confused with the Variant type in Delphi, and the arrays it can contain. They are quite different, even though a TVarRec (see below) is a bit similar to how a Variant is internally stored.
Even the name of the internal record of a Variant is confusingly similar: TVarData. Internals Internally, an array of const is an open array of TVarRec. The declaration of TVarRec is given in the online help for Delphi. It is a variant record (also not to be confused with the Variant type), that contains a field called VType, and an overlay of different types, some of which are only pointers.
The compiler creates a TVarRec for each member in the open array constructor, fills the VType field with the type of the member, and places the value, or a pointer to it, in one of the other fields. Then it passes the array of TVarRec to the function. Since each TVarRec contains type information, Format can use this to check if it matches with the type given in the format string. That is why you get a runtime error when passing a wrong type. You can tell the compiler that you want it to store a different type identifier, by casting to the desired type.
If the type doesn’t match one of the allowed types in a TVarRec exactly, the compiler will try to convert it to a matching type, so if you pass a Double, it will convert it to an Extended and pass that instead. Of course there are limitations on what the compiler can do, so for instance passing an object isn’t going to work.
Inside the function or procedure, you can treat the members as TVarRec immediately. The help for Delphi gives an example how to do this. Lifetime issues What you should notice is, that values in the TVarRec which are passed as pointers only exist during the course of the function or procedure. As soon as the routine ends, these values don’t exist anymore. So you should not be tempted to return these pointers from the procedure or function, or to store the TVarRecs in an array outside the routine, unless you can make sure that you manage the values yourself. If you must copy the TVarRecs to an array or variable outside the function (this can also be a var parameter), be sure to make a copy (i.e.
On the heap) of the value, and replace the pointer in the TVarRec with one to the copy. You should also take care that the copy is disposed of when it is not needed anymore. An example follows. Type TConstArray = array of TVarRec; // Copies a TVarRec and its contents. If the content is referenced // the value will be copied to a new location and the reference // updated.
Function CopyVarRec ( const Item: TVarRec ): TVarRec; var W: WideString; begin // Copy entire TVarRec first Result:= Item; // Now handle special cases case Item. VType of vtExtended: begin New ( Result. VExtended ); Result.
VExtended ^:= Item. VExtended ^; end; vtString: begin // Improvement suggestion by Hallvard Vassbotn: only copy real length. GetMem ( Result. VString, Length ( Item.
VString ^ ) + 1 ); Result. VString ^:= Item. VString ^; end; vtPChar: Result. VPChar:= StrNew ( Item. VPChar ); // There is no StrNew for PWideChar vtPWideChar: begin W:= Item.
VPWideChar; GetMem ( Result. VPWideChar, ( Length ( W ) + 1 ). SizeOf ( WideChar )); Move ( PWideChar ( W ) ^, Result. VPWideChar ^, ( Length ( W ) + 1 ). SizeOf ( WideChar )); end; // A little trickier: casting to AnsiString will ensure // reference counting is done properly. VtAnsiString: begin // nil out first, so no attempt to decrement reference count. VAnsiString:= nil; AnsiString ( Result.
VAnsiString ):= AnsiString ( Item. VAnsiString ); end; vtCurrency: begin New ( Result. VCurrency ); Result. VCurrency ^:= Item.
VCurrency ^; end; vtVariant: begin New ( Result. VVariant ); Result. VVariant ^:= Item. VVariant ^; end; // Casting ensures proper reference counting. VtInterface: begin Result. VInterface:= nil; IInterface ( Result. VInterface ):= IInterface ( Item.
VInterface ); end; // Casting ensures a proper copy is created. VtWideString: begin Result. VWideString:= nil; WideString ( Result.
VWideString ):= WideString ( Item. VWideString ); end; vtInt64: begin New ( Result. VInt64 ); Result. VInt64 ^:= Item.
VInt64 ^; end; vtUnicodeString: begin // Similar to AnsiString. VUnicodeString:= nil; UnicodeString ( Result.
VUnicodeString ):= UnicodeString ( Item. VUnicodeString ); end; // VPointer and VObject don't have proper copy semantics so it // is impossible to write generic code that copies the contents end; end; function CreateConstArray ( const Elements: array of const ): TConstArray; var I: Integer; begin SetLength ( Result, Length ( Elements )); for I:= Low ( Elements ) to High ( Elements ) do Result I := CopyVarRec ( Elements I ); end; // use this function on copied TVarRecs only! Procedure FinalizeVarRec ( var Item: TVarRec ); begin case Item.
VType of vtExtended: Dispose ( Item. VExtended ); vtString: Dispose ( Item. VString ); vtPChar: StrDispose ( Item.
VPChar ); vtPWideChar: FreeMem ( Item. VPWideChar ); vtAnsiString: AnsiString ( Item. VAnsiString ):= '; vtCurrency: Dispose ( Item. VCurrency ); vtVariant: Dispose ( Item. VVariant ); vtInterface: IInterface ( Item.
Delphi Initialize Array List
VInterface ):= nil; vtWideString: WideString ( Item. VWideString ):= '; vtInt64: Dispose ( Item. VInt64 ); vtUnicodeString: UnicodeString ( Item. VUnicodeString ):= '; end; Item. VInteger:= 0; end; // A TConstArray contains TVarRecs that must be finalized.
This function // does that for all items in the array. Procedure FinalizeVarRecArray ( var Arr: TConstArray ); var I: Integer; begin for I:= Low ( Arr ) to High ( Arr ) do FinalizeVarRec ( Arr I ); Arr:= nil; end; The functions above can help you manage TVarRecs outside the routine for which they were constructed. You can even use a TConstArray where an open array is declared.
Delphi Initialize Boolean Array
The following little program. Standard Disclaimer for External Links These links are being provided as a convenience and for informational purposes only; they do not constitute an endorsement or an approval of any of the products, services or opinions of the corporation or organization or individual. I bear no responsibility for the accuracy, legality or content of the external site or for that of subsequent links. Contact the external site for answers to questions regarding its content. Disclaimer and Copyright The coding examples presented here are for illustration purposes only. The author takes no responsibility for end-user use. All content herein is copyrighted by Rudy Velthuis, and may not be reproduced in any form without the author's permission.
Source code written by Rudy Velthuis presented as download is subject to the license in the files.
On the following URL, I found some different syntax to initialize an array. Examples there. Var c1: array1.10 of char:= '123456'; int2: array1.100 of integer:= 50 of 1, 50 of 2; Tried those, but didn't seem to to work.
Is a loop the only way to initialize all the values in an array other than Values: array1.2 of integer = (0,0); In the program I am working on, Values will be an array of 128 integers and I would like to initialize them to 0. Right now I just using: for InitialLoop:= 1 to 128 do ValuesInitialLoop:=0; fpc-pascal maillist. Hello, Francisco! Wednesday, March 18, 2009, 2:50:21 AM, you wrote: Is a loop the only way to initialize all the values in an array other than Values: array1.2 of integer = (0,0); In the program I am working on, Values will be an array of 128 integers and I would like to initialize them to 0. Right now I just using: for InitialLoop:= 1 to 128 do ValuesInitialLoop:=0; As far as I know, global variables are initialised with zeros when an application starts. But to ensure your array is filled with zeros you can use FillChar: FillChar(Values,SizeOf(Values),0) - Best regards, Fantomas fpc-pascal maillist.
On the following URL, I found some different syntax to initialize an array. Examples there. var c1: array1.10 of char:= '123456'; int2: array1.100 of integer:= 50 of 1, 50 of 2; Tried those, but didn't seem to to work. Is a loop the only way to initialize all the values in an array other than Values: array1.2 of integer = (0,0); In the program I am working on, Values will be an array of 128 integers and I would like to initialize them to 0. Right now I just using: for InitialLoop:= 1 to 128 do ValuesInitialLoop:=0; fpc-pascal maillist - fpc-pascal maillist.
On the following URL, I found some different syntax to initialize an array. That's another Pascal extension from Sun.
One of the problem (and power) of Pascal is that it's often extended arbitrarily, because no standard (other than too simple ISO 7185 and too complicated ISO 10260) exists. Remember that FPC tries to be compatible with Delphi (at least until version 7) and Turbo Pascal (also version 7), while adding its own extensions.
c1: array1.10 of char:= '123456'; In this case, FPC still follows (not 100% conforms) the standard. C1 is a fixed length array, therefore only strings of the same length can be assigned to it. If you want to follow standards, pad it with spaces. Otherwise, use String10. int2: array1.100 of integer:= 50 of 1, 50 of 2; This is like C's array initialization (extended maybe), which is not supported. Either fill all or do it in a statement. You can fill some followed by FillXXX which is the most commonly used method as it doesn't involve looping (MUCH faster).
IMHO, FPC should consider this kind of extension though (partial filling). begin fillchar(c11,5,0); fillchar(c15,5,#32); You might need @ sign in front of c1 though. FillChar doesn't expect pointers, the above is already correct (note that it's syntactically correct, but it will fill the wrong data if you add @). On the following URL, I found some different syntax to initialize an array.
Delphi Initialize Array Of Record
Examples there. var c1: array1.10 of char:= '123456'; int2: array1.100 of integer:= 50 of 1, 50 of 2; Tried those, but didn't seem to to work. Use only '=' instread of ':='. Working is e.g.: vector: array0.6 of longint = (1, 2, 3, 4, 5, 6, 7); type particlet = record name: array 0.Pred(16) of char; longi: integer; pressure: float; temperature: double; lati: integer; end; wbuf: array 0.Pred(NRECORDSC) of particlet = ( (name:'zero'#0; longi:0; pressure:0.0; temperature:0.0; lati:0), (name:'one'#0; longi:10; pressure:1.0; temperature:10.0; lati:10). Is a loop the only way to initialize all the values in an array other than Values: array1.2 of integer = (0,0); In the program I am working on, Values will be an array of 128 integers and I would like to initialize them to 0.
Use fillchar as others mentioned. Marc Santhoff fpc-pascal maillist. FillChar(Values,SizeOf(Values),0) That worked. However, for an integer is fillword better?
A 'fillword' procedure does not exist. FillChar is an anchient Pascal function to simply fill any arbitrary memory location of any size (determined by a variable) with all the same byte. It is very fast but there is no type checking at all (you can fill any type of variable) and I think there is no range checking either.
So you should use SizeOf to give the number of bytes to be written but in special circumstance you can also use a different value. A similar procedure is move, which copies bytes from one memory location to another (again both determined by variables) also without type and range checking. Ju'rgen Hestermann.
fpc-pascal maillist.
Say I have the variable: Var question: array1.50 of char; When I do: question:= 't'; //What is the correct way to change the value? It returns an error: Incompatible types: 'array1.50 of Char' and 'Char' Note: I want to have a max string size of 50 chars, not 50 different chars. The reason for this question is that I have a record in another unit(This is just a basic example, not what I actually have written above) In that unit I have a Record, which I can't use the string data type in(Or is there a way? Please explain if there is). I just need to know how to give an array of chars a value. While Delphi strings and arrays of char are related, they are not the same. Delphi overloads assignment of strings and literals (char and string) to array of chars, but only when the lower array bound is zero.
The following code works for me in D2007 and Delphi XE: var x: array0.49 of char; begin x:='b'; // char literal x:='bb'; // string literal end. If I change the 0 to 1 it fails. This limitation probably simplifies the language helper that takes care of this, and probably the feature is only meant for dealing with converted C structs where arrays always have lower bound 0.
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |