Posts: 369
Threads: 71
Joined: Jul 2022
Reputation:
14
I need to know because I am using the following method to read/write a fixed length UDT array string to a random record in a file:
Code: (Select All) ' define an array as string.
Type Datatype
Array As String * 16
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
Print M;
Next
End
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
(11-13-2023, 12:38 AM)eoredson Wrote: I need to know because I am using the following method to read/write a fixed length UDT array string to a random record in a file:
Code: (Select All) ' define an array as string.
Type Datatype
Array As String * 16
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
Print M;
Next
End
Why go through such a complicated setup? Why not just use an array directly?
Code: (Select All)
DIM DataRecord(1 TO 8) AS INTEGER
OPEN "datatest.dat" FOR RANDOM AS #1 LEN = 16
FOR j = 1 TO 10
FOR l = 1 TO 8
count = count + 1
DataRecord(l) = count 'set the data
NEXT
PUT 1, j, DataRecord() '10 records from 1 to 80
NEXT
FOR l = 1 TO 8
DataRecord(l) = 0 'clear the old data
NEXT
x = INT(RND * 10 + 1)
PRINT "Fetching record #"; x
PRINT "Which starts at"; (x - 1) * 8 + 1;
PRINT "and ends at"; x * 8
GET 1, x, DataRecord() 'get the random record
FOR i = 1 TO 8
PRINT DataRecord(i) 'print the array
NEXT
Posts: 128
Threads: 17
Joined: Apr 2022
Reputation:
10
Quote:btw: is
Code: (Select All)
Code: (Select All) array AS _MEM
variable length?
Yes and No. You set the length when you set 'cMAXELEMENTS'. If you want to change the length of the '_MEM' you have to create a new one with the length desired and copy the contents from the old one to the new one, and not forget '_MEMFREE ' the old memory location.
I updated this code a bit and it allows for resizing the array. BEWARE there is no error checking, so if you try to 'set' or 'get' a value outside of whats allocated then it will pop an error.
Code: (Select All) ' Program to create an array of Doubles in a UDT
DIM AS LONG i
DIM AS DOUBLE v
CONST cMAXELEMENTS = 10
TYPE tARRAY
array AS _MEM
END TYPE
DIM AS tARRAY object
SCREEN 12: _FONT 8
' initialize the array
createObject object, cMAXELEMENTS
' set the array to random values
PRINT "Create initial Values"
FOR i = 0 TO cMAXELEMENTS
v = INT(RND * 5)
setElement object, i, v
PRINT "index:"; i; "->"; v
NEXT
' retrieve values from array
PRINT "Retrieve Values"
FOR i = 0 TO cMAXELEMENTS
PRINT "index:"; i; "->"; getElement(object, i)
NEXT
'resize array
resizeObject object, cMAXELEMENTS * 2
' retrieve values from array
PRINT "Double the size of the array"
FOR i = 0 TO cMAXELEMENTS * 2
PRINT "index:"; i; "->"; getElement(object, i)
NEXT
'resize array
resizeObject object, cMAXELEMENTS / 2
' retrieve values from array
PRINT "Half the size of the array"
FOR i = 0 TO cMAXELEMENTS / 2
PRINT "index:"; i; "->"; getElement(object, i)
NEXT
SUB createObject (o AS tARRAY, size AS LONG)
' make array one larger than number of elements
o.array = _MEMNEW((size + 1) * 8) ' 8 is the number of bytes in a double
END SUB
SUB resizeObject (o AS tARRAY, size AS LONG)
DIM AS _MEM old
DIM AS _OFFSET l
DIM AS LONG iter
' Copy old _MEM to a temp _MEM
old = o.array
' Create new array of the new size
createObject o, size
' Copy data from old array to new array
iter = 0: DO WHILE iter < o.array.SIZE AND iter < old.SIZE
_MEMPUT o.array, o.array.OFFSET + iter, _MEMGET(old, old.OFFSET + iter, _BYTE) AS _BYTE
iter = iter + 1: LOOP
' free old array
_MEMFREE old
END SUB
FUNCTION getElement# (o AS tARRAY, element AS LONG)
getElement = _MEMGET(o.array, o.array.OFFSET + (element * 8), DOUBLE)
END FUNCTION
SUB setElement (o AS tARRAY, element AS LONG, v AS DOUBLE)
_MEMPUT o.array, o.array.OFFSET + (element * 8), v AS DOUBLE
END SUB
Posts: 369
Threads: 71
Joined: Jul 2022
Reputation:
14
Quote:Why go through such a complicated setup? Why not just use an array directly?
Because I might have more stuff in the UDT in addition to a single array:
Code: (Select All) ' define an array as string.
Type Datatype
Array As String * 16
Var As Integer
Array2 As String * 16
Var2 As Integer
Array3 As String * 16
Var3 As Integer
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
Print M;
Next
End
Posts: 1,586
Threads: 59
Joined: Jul 2022
Reputation:
52
Code: (Select All) CONST NITEMS = 20, ARLEN = 8
Type Datatype
'Array1 field
Var As Integer
'Array2 field
Var2 As Integer
'Array3 field
Var3 As Integer
End Type
Dim DataRecord(1 to NITEMS) As Datatype
Dim As Integer Array1(1 to NITEMS, 1 to ARLEN), Array2(1 to NITEMS, 1 to ARLEN), Array3(1 to NITEMS, 1 to ARLEN)
' store first array "field".
FOR N = 1 TO NITEMS
For L = 1 To ARLEN
Array1(N, L) = L
Next
NEXT
The "Array1" was the "Array" field in the previous example, which was defined as "STRING * 16". The "Array2" and "Array3" were also supposed to be UDT fields. But they are actually arrays independent of the UDT variable. In QB45 and QB64 it has to be done this way whether you like it or not. Otherwise in QB64 you have ```_MEM``` and its association of statements and functions where you don't have to put a static limit on data storage, but is more difficult sometimes to be counting off things by bytes working in this way. Also needing to ask permission from the operating system to allocate a block of memory, and then in the middle of program run, needing to release that memory for other purposes.
It's sloppy but it works.
Posts: 369
Threads: 71
Joined: Jul 2022
Reputation:
14
(11-13-2023, 01:48 AM)mnrvovrfc Wrote: Code: (Select All) CONST NITEMS = 20, ARLEN = 8
Type Datatype
'Array1 field
Var As Integer
'Array2 field
Var2 As Integer
'Array3 field
Var3 As Integer
End Type
Dim DataRecord(1 to NITEMS) As Datatype
Dim As Integer Array1(1 to NITEMS, 1 to ARLEN), Array2(1 to NITEMS, 1 to ARLEN), Array3(1 to NITEMS, 1 to ARLEN)
' store first array "field".
FOR N = 1 TO NITEMS
For L = 1 To ARLEN
Array1(N, L) = L
Next
NEXT
The "Array1" was the "Array" field in the previous example, which was defined as "STRING * 16". The "Array2" and "Array3" were also supposed to be UDT fields. But they are actually arrays independent of the UDT variable. In QB45 and QB64 it has to be done this way whether you like it or not. Otherwise in QB64 you have ```_MEM``` and its association of statements and functions where you don't have to put a static limit on data storage, but is more difficult sometimes to be counting off things by bytes working in this way. Also needing to ask permission from the operating system to allocate a block of memory, and then in the middle of program run, needing to release that memory for other purposes.
It's sloppy but it works. And how does that put the arrays into the UDT!?
Posts: 128
Threads: 17
Joined: Apr 2022
Reputation:
10
For multiple arrays within a UDT you could do this.
Code: (Select All) ' Program to create an array of Doubles in a UDT
DIM AS LONG i
DIM AS DOUBLE v
CONST cMAXELEMENTS = 10
TYPE tARRAYS
array0 AS _MEM
array1 AS _MEM
array2 AS _MEM
END TYPE
DIM AS tARRAYS object
SCREEN 12: _FONT 8
' initialize the array
createObject object.array0, cMAXELEMENTS
createObject object.array1, cMAXELEMENTS
createObject object.array2, cMAXELEMENTS
PRINT "ARRAY 0 ARRAY 1 ARRAY 2"
' set the array to random values
PRINT "Create initial Values"
FOR i = 0 TO cMAXELEMENTS
v = INT(RND * 5)
setElement object.array0, i, v
PRINT "index:"; i; "->"; v; " ";
v = INT(RND * 5)
setElement object.array1, i, v
PRINT "index:"; i; "->"; v; " ";
v = INT(RND * 5)
setElement object.array2, i, v
PRINT "index:"; i; "->"; v
NEXT
' retrieve values from array
PRINT "Retrieve Values"
FOR i = 0 TO cMAXELEMENTS
PRINT "index:"; i; "->"; getElement(object.array0, i); " ";
PRINT "index:"; i; "->"; getElement(object.array1, i); " ";
PRINT "index:"; i; "->"; getElement(object.array2, i)
NEXT
'resize array
resizeObject object.array0, cMAXELEMENTS * 2
resizeObject object.array1, cMAXELEMENTS * 2
resizeObject object.array2, cMAXELEMENTS * 2
' retrieve values from array
PRINT "Double the size of the array"
FOR i = 0 TO cMAXELEMENTS * 2
PRINT "index:"; i; "->"; getElement(object.array0, i); " ";
PRINT "index:"; i; "->"; getElement(object.array1, i); " ";
PRINT "index:"; i; "->"; getElement(object.array2, i)
NEXT
'resize array
resizeObject object.array0, cMAXELEMENTS / 2
resizeObject object.array1, cMAXELEMENTS / 2
resizeObject object.array2, cMAXELEMENTS / 2
' retrieve values from array
PRINT "Half the size of the array"
FOR i = 0 TO cMAXELEMENTS / 2
PRINT "index:"; i; "->"; getElement(object.array0, i); " ";
PRINT "index:"; i; "->"; getElement(object.array1, i); " ";
PRINT "index:"; i; "->"; getElement(object.array2, i)
NEXT
SUB createObject (o AS _MEM, size AS LONG)
' make array one larger than number of elements
o = _MEMNEW((size + 1) * 8) ' 8 is the number of bytes in a double
END SUB
SUB resizeObject (o AS _MEM, size AS LONG)
DIM AS _MEM old
DIM AS LONG iter
' Copy old _MEM to a temp _MEM
old = o
' Create new array of the new size
createObject o, size
' Copy data from old array to new array
iter = 0: DO WHILE iter < o.SIZE AND iter < old.SIZE
_MEMPUT o, o.OFFSET + iter, _MEMGET(old, old.OFFSET + iter, _BYTE) AS _BYTE
iter = iter + 1: LOOP
' free old array
_MEMFREE old
END SUB
FUNCTION getElement# (o AS _MEM, element AS LONG)
getElement = _MEMGET(o, o.OFFSET + (element * 8), DOUBLE)
END FUNCTION
SUB setElement (o AS _MEM, element AS LONG, v AS DOUBLE)
_MEMPUT o, o.OFFSET + (element * 8), v AS DOUBLE
END SUB
Posts: 369
Threads: 71
Joined: Jul 2022
Reputation:
14
Quote:For multiple arrays within a UDT you could do this.
@justsomeguy: Very good! I had considered multiple _MEM in UDT as well..
Erik.
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
(11-13-2023, 01:34 AM)eoredson Wrote: Quote:Why go through such a complicated setup? Why not just use an array directly?
Because I might have more stuff in the UDT in addition to a single array:
Code: (Select All) ' define an array as string.
Type Datatype
Array As String * 16
Var As Integer
Array2 As String * 16
Var2 As Integer
Array3 As String * 16
Var3 As Integer
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
Print M;
Next
End
Wouldn't this still be easier to just use Array1, Array2, Array3 and Var1, Var2, Var3 naturally? Just swap over to BINARY instead of RANDOM and read each array/variable as needed. Their position is still going to be set in stone and easy to calculate. ((record - 1) * 54 + 1) is the position of the first array record in the data. The other arrays are just offset by 18, if you ever need to get them individually.
Posts: 369
Threads: 71
Joined: Jul 2022
Reputation:
14
The only real reason I brought up this thread is because I have an old project in PDS that has many UDTs with arrays that I ported to 32-bit QB64 and
needed a way to retrieve the UDT from the database to be backwards compatible with PDS..
|