Conversation started Apr 20, 2018 at 17:29.
Apr 20, 2018 17:29
What about for arrays?
Sub oenuthoeuntheo()
    Dim temp(1 To 4, 1 To 3) As Integer

    Debug.Print LenB(temp)
End Sub
It's not liking the above. LenB(temp(1,1)) is fine.
you can't size array that way - you'll have to basically LenB(<an element of the array>) * ((UBound(<array>) - LBound(<array>)) + 1)
oh, that won't do for the >2d array.
>2d, #YouAreScrewed
I don't think there's a programmatic way to count the # of dimensions, is there?
Isn't the array actually larger than that?
It has all kinds of housekeeping fields.
codeguru.com/vb/gen/vb_misc/algorithms/article.php/c7495/… part about arrays is what I'm working on understanding. It says Dim arr_intTemp(4)(3) As Integer should be 60 bytes.
Was hoping to see that number pop up with LenB. #WishfulThinking
That's true, Max. The above would only give you the raw size of the array data itself
@IvenBach for >2d, you can adapt this solution: stackoverflow.com/questions/6901991/…
you'll have to manually calculate in the size of the structs to get the true size of the array. That includes SAFEARRAY and SAFEARRAYBOUNDS. I don't know if you might have mulitple structures, so you might need to check for that, as well.
skimming, it looks like you get one SAFEARRAYBOUND per dimension.
Apr 20, 2018 17:49
@this The linked source really provides the entire layout for a multidimansional array.
maybe it'd be a good idea if I actually read the article? :)
Apr 20, 2018 18:09
Sub Test()
    Dim temp(4, 3) As Integer
    Debug.Print MemorySizeOfArrayInBytes(temp)
End Sub

Public Function MemorySizeOfArrayInBytes(ByVal temp As Variant) As Long
    Dim maxDimension As Long
    maxDimension = GetArrayDimensions(temp)

    Dim totalElements As Long
    totalElements = 1
    Dim i As Long
    For i = 1 To maxDimension
        totalElements = totalElements * UBound(temp, i)
    Next

    Dim elementBytes As Long
    elementBytes = totalElements * LenB(temp(0, 0))

    Const SAFE_ARRAY As Long = 20
Gives me 60 for the Integer but changing temp to be of type Long it's still 60. I'd expect it to be 120 since 4 bytes is used to store a Long value.
Working with stuff I don't fully understand.
I would have expected 84.
Why 84? I see why 84 now.
You only double the size of the data area.
I speak without thinking all too often.
20 + 8 * 2 + 48 = 84.
Exactly
Apr 20, 2018 18:15
SafeArray + (SizePerDimension * MaxDimension) + (TotalElements * ElementByteStorage)
Where SizePerDimension is always 8 = SizeOfLength + SizeOfLBound
@M.Doerner This is the part where I'm unable to understand myself where the 8 bytes comes from.
Is it because of the SafeArrayBound structure?
The last section of the array base is itself an (unsafe) array storing tuples (size of dimension, lower bound of dimension) for all dimensions. Both numbers are of type Long and thus require 4 bytes each.
Yes
msdn.microsoft.com/en-us/library/windows/desktop/… with ULONG cElements and LONG lLbound?
Well, that makes sense.
Still, a ULONG also takes 4 bytes.
Apr 20, 2018 18:30
That was my assumption but I don't understand what the structure actually is, or what it's doing.
a long is a long. Whether it's signed or not it still takes 4 bytes.
A negative array length would not make to much sense.
The structure does pretty much what its name suggets, it stores the bounds of an array dimension.
Is this what allows RTE-9 for Dim temp(4, 3) as long when I try to do Debug.Print temp(10, 10)?
Well not allow but gives the warning instead of BSOD.
Yes, basically.
Mind that in C++, it might not be always a BSOD.
You safe how long the array dimesion is, which is important to know where to look for elements in the data area, and the offset you have to apply when resolving the indices passed in.
It might be simply corrupted memory.
IN a way, corrupted memory is worse because nothing will seem wrong immediately.
Until you actually need some data from that memory region that was corrupted by the buffer overflow, then.... ????
maybe you get funny results. Maybe you get extra lives. Maybe you get BSOD. Who's to know.
Apr 20, 2018 18:41
@M.Doerner Where it starts and how many are offset to make sure you're getting the correct result. :+1:
I'm just a bit slow when it comes to internalizing the meaning of everything.
@IvenBach Note that you also need the length of all but the last dimension to actually find the correct value in the data area.
Do you mean element instead of dimension? The last dimension comes first in the array.
> The array rgsabound is stored with the left-most dimension in rgsabound[0] and the right-most dimension in rgsabound[cDims - 1].
Apr 20, 2018 19:03
Let's say you have an array arr(1 To 4, 2 To 4, 3 To 4) As Byte, where in the data area would you look for arr(2,3,4)?
I as a human would look in the 2nd row 3rd column 4th compartment.
To the computer though that's nonsensical.
The first dimension of the array has 4 elements with a lowerbound of 1.
It knows you want the second element in dimension 1.
It offsets by 1 from the lowerbound to get the second element.
It does so for each dimension in the array.
Good, go on.
From here on out I've no clue what it's actually doing. Bear with my bumblings.
The storage memory of the computer doesn't have depth nor width, only length.
It can only go down the length of the memory addresses and put/pull information in them.
Reading and regurgitating tells me that the last dimension of the array is the first in the list
Dim arr_intTemp(0 to 1, 1 to 2) As Integer

arr_intTemp(0, 1) = 1
arr_intTemp(0, 2) = 2
arr_intTemp(1, 1) = 3
arr_intTemp(1, 2) = 4
Has the information stored as
1
3
2
4
Assuming this holds true for 3D arrays.
arr(1,2,3)=1
arr(1,2,4)=2
...
arr(4,4,3)=23
arr(4,4,4)=24
It'd be listed as follows
Wait a sec for me, just got really hard mentally.
arr(1,2,3) = 1
arr(1,2,4) = 2
arr(1,3,3) = 3
arr(1,3,4) = 4
arr(1,4,3) = 5
arr(1,4,4) = 6
arr(2,2,3) = 7
arr(2,2,4) = 8
arr(2,3,3) = 9
arr(2,3,4) = 10
arr(2,4,3) = 11
arr(2,4,4) = 12
arr(3,2,3) = 13
arr(3,2,4) = 14
arr(3,3,3) = 15
arr(3,3,4) = 16
arr(3,4,3) = 17
arr(3,4,4) = 18
arr(4,2,3) = 19
arr(4,2,4) = 20
arr(4,3,3) = 21
arr(4,3,4) = 22
arr(4,4,3) = 23
arr(4,4,4) = 24
List how humans understand ^
1 'arr(1,2,3)
7 'arr(2,2,3)
13 'arr(3,2,3)
19 'arr(4,2,3)
3 'arr(1,3,3)
9 'arr(2,3,3)
15 'arr(3,3,3)
21 'arr(4,3,3)
5 'arr(1,4,3)
11 'arr(2,4,3)
17 'arr(3,4,3)
23 'arr(4,4,3)
2 'arr(1,2,4)
8 'arr(2,2,4)
14 'arr(3,2,4)
20 'arr(4,2,4)
4 'arr(1,3,4)
10 'arr(2,3,4)
16 'arr(3,3,4)
22 'arr(4,3,4)
6 'arr(1,4,4)
12 'arr(2,4,4)
18 'arr(3,4,4)
24 'arr(4,4,4)
^ As computer has it stored, based on my reading.
@M.Doerner That's what I think is going on.
Apr 20, 2018 19:22
Looking at that, what has the size of the dimensions to do with the resolution of indices?
Sub RedimTest()
    Dim foo() As Long
    ReDim Preserve foo(1 To 3, 2 To 5)
    ReDim Preserve foo(1 To 3, 2 To 4)
End Sub
Playing around earlier I came across failures but the above works.
ReDim Preserve foo(1 To 3, 2 To 5)
ReDim Preserve foo(1 To 3, 1 To 5)
^ Barfs
I can't figure out how to say what I'm thinking...
The lowerbound of the highest dimension can't be altered because it's the first in the list.
The upperbound of the highest dimension can be altered because it's the last in the list and it's only adding to or removing from the array.
Interesting, that should actually work.
Oh, I see.
Subscript out of range occurs on ReDim Preserve foo(1 To 3, 1 To 5)
I did notice.
Sub RedimTest()
    Dim foo() As Long
    ReDim Preserve foo(2, 2)
    ReDim Preserve foo(2, 1 To 4)
End Sub
^ Also breaks but
Sub RedimTest2()
    Dim foo() As Long
    ReDim Preserve foo(2, 2)
    ReDim Preserve foo(2, 0 To 4)
End Sub
^ Doesn't.
Think about where the element (1,1) would have to go in the data area.
Assuming option base isn't altered.
If you alter the lbound of the outermost dimension it'd cause the entire list to have to be shifted.
Apr 20, 2018 19:30
What does preserve tell the compiler?
foo(1,1) would go in as the second entry for dimension 1 and dimension2.
preserve tells the compiler to keep whatever was there and not wipe it.
Sub RedimTest2()
    Dim foo() As Long
    ReDim Preserve foo(2, 2)
    ReDim foo(2, 1 To 4)
End Sub
Works since there is no instruction for preservation of data and it can all be wiped clean.
I was still talking about the initial example.
(2 To 5) to (1 To 5)
That I'm not sure.
Per how the data area is layed out, it has to go to position one.
What would you find there with preserve?
Since the lbound is stated and you're changing it the array would have to remap all the elements.
Apr 20, 2018 19:36
Yes, thus, preserve is illegal in this case.
What would have been in element2 now would be in element1. I'm guessing this would have lead to too many headaches and that's the reason they disallowed it.
I'm starting to understand why the RTE9 subscript out of range message makes sense.
 
Conversation ended Apr 20, 2018 at 19:37.