-
Oct 7th, 2019, 02:43 AM
#1
Thread Starter
Lively Member
Passing 2 dimensional array as one dimensional to a function/sub?
Hi
Say, I have an 2 dimensional array Array(5,40) as single
And say, I have a procedure working with one dimensional array as follows
Public sub Calculate (NewArray() as single)
for i=1 to 40
Sum=Sum+NewArray(i)
next i
end sub
The question:
I want to pass the 40 values of second dimension to the sub. Like Array(2,1), Array(2,2), Array(2,3)... Array(2.40)
How to pass the Array to this procedure?
I want to call the function like CALCULATE(Array(2, () )
Thanks in advance.
Last edited by ucanbizon; Oct 7th, 2019 at 03:01 AM.
Reason: Additional information
-
Oct 7th, 2019, 03:27 AM
#2
Member
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Hi Ucanbizon,
Something like that:
Code:
Private Sub Command1_Click()
Dim gMyArray(5, 40) As Single
Dim Index As Integer
Dim Sum As Long
For i = 1 To 40
gMyArray(0, i) = i
Next i
For i = 2 To 40
gMyArray(1, i) = i + 8
Next i
Sum = 0
Index = 0
Calculate gMyArray, Index, Sum
Debug.Print Sum
Sum = 0
Index = 1
Calculate gMyArray, Index, Sum
Debug.Print Sum
End Sub
Public Sub Calculate(ByRef MyArray() As Single, gIndex As Integer, ByRef Sum As Long)
For i = 1 To 40
Sum = Sum + MyArray(gIndex, i)
Next i
End Sub
Have a look to the ByRef and ByVal functions to share values in the SUBs functions.
Have Fun.
-
Oct 7th, 2019, 03:58 AM
#3
Thread Starter
Lively Member
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Hi XavSnap,
Thank you for the information.
The way you offer is passing whole array to the sub and making calculations according to the index parameters.
I want to learn if there is a way to pass a part (say a single dimensional) of a multi-dimensional array to the sub?
Thanks yo anyway...
-
Oct 7th, 2019, 04:10 AM
#4
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Simple answer, no you can't
Just pass the complete array.
There is no overhead because the pointer of the array is passed.
-
Oct 7th, 2019, 05:56 AM
#5
Re: Passing 2 dimensional array as one dimensional to a function/sub?
There is a fairly simple way to do this, but it requires a couple APIs: CopyMemory and VarPtrArray
Basically, you create a new 1D SAFEARRAY structure, overlay it on the 2D array, then pass that. On return, you would remove the overlay so the array is 2D again. You should not attempt to resize the array while the overlay is in play.
-
Oct 7th, 2019, 02:49 PM
#6
Member
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Hi,
Yes, APIs Copymemory able to copy all bytes from 4 bytes single values, but save the Array value on a temporary file…
array(0,0);array(1,0);array(2,0);array(3,0);array(4,0);array(5,0);
array(0,1);array(1,1);array(2,1);array(3,1);array(4,1);array(5,1);
(...)
id 0;id 1;id 2;id 3;...
xxxxx;xxxxx;xxxxx; …
You had to jump 5x4 bytes to retrieve values, and get them using a FOR/NEXT loop.
Just retrieve a single array using …
Code:
Dim gMyArray(5, 40) As Single
Dim gMyArray2(40) As Single
Index=0
For cnt = 0 To 40
gMyArray2(cnt) = gMyArray(Index, cnt)
Next
Sum = 0
Calculate2 gMyArray2, Sum
Debug.Print Sum
Code:
Public Sub Calculate2(ByRef MyArray() As Single, ByRef Sum As Long)
For i = 1 To 40
Sum = Sum + MyArray(i)
Next i
End Sub
-
Oct 7th, 2019, 04:09 PM
#7
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Originally Posted by XavSnap
Hi,
... but save the Array value on a temporary file…
No file is needed.
In a test form...
Code:
Option Explicit
Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (ByRef Ptr() As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Type SAFEARRAYBOUND
cElements As Long
lLbound As Long
End Type
Private Type SAFEARRAY
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As Long
Bounds As SAFEARRAYBOUND
End Type
Private Sub Form_Load()
Dim myArray(5, 20) As Single, tSA As SAFEARRAY
Dim tmpArray() As Single
myArray(0, 0) = 1908 ' test values
myArray(5, 20) = 2016
With tSA
.cbElements = 4 ' 4 bytes per array item: 1 Single = 4 bytes & array is Single
.cDims = 1 ' want 1D array
.pvData = VarPtr(myArray(0, 0)) ' pointer to 1st array item
.Bounds.cElements = (Abs(UBound(myArray, 1) - LBound(myArray, 1)) + 1) * _
(Abs(UBound(myArray, 2) - LBound(myArray, 2)) + 1)
.Bounds.lLbound = 0 ' change if want different LBound
End With
' overlay onto an empty array
CopyMemory ByVal VarPtrArray(tmpArray), VarPtr(tSA), 4
' test overlay
TestIt tmpArray
' undo overlay
CopyMemory ByVal VarPtrArray(tmpArray), 0&, 4
Debug.Print myArray(0, 0), myArray(5, 20)
End Sub
Private Sub TestIt(inArray() As Single)
' swap the 2 test values
inArray(LBound(inArray)) = 2016
inArray(UBound(inArray)) = 1908
End Sub
Last edited by LaVolpe; Oct 7th, 2019 at 04:12 PM.
Reason: changed Longs to Singles
-
Oct 7th, 2019, 05:43 PM
#8
Member
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Hi,
Thanks LaVolpe !
Working on Vb5...
Never seen this kind of code...
-
Oct 7th, 2019, 06:17 PM
#9
Re: Passing 2 dimensional array as one dimensional to a function/sub?
@XavSnap, think the code works for VB5 also, just need to change the DLL in the API declaration from msvbvm60.dll to msvbvm50.dll
-
Oct 7th, 2019, 08:46 PM
#10
Member
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Hi LaVolpe,
Confirmed, steel to use it !
We had to change "Visual Basic 6 and Earlier" to "Visual Basic 5 and Earlier" !
-
Oct 7th, 2019, 11:17 PM
#11
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Originally Posted by LaVolpe
There is a fairly simple way to do this, but it requires a couple APIs: CopyMemory and VarPtrArray
Basically, you create a new 1D SAFEARRAY structure, overlay it on the 2D array, then pass that. On return, you would remove the overlay so the array is 2D again. You should not attempt to resize the array while the overlay is in play.
Are you sure that would work? The OP wants to pass an array that contains only the last dimension (i.e., row) of a 2D array, but the problem is, VB6 arrays (SAFEARRAYs) are column-major (i.e., row elements aren't contiguous in memory), so creating a 1D array from the last dimension of a 2D array isn't so simple.
-
Oct 8th, 2019, 02:28 AM
#12
Re: Passing 2 dimensional array as one dimensional to a function/sub?
We need to know why the TS wants to pass only the last dimension!
Because passing arrays to functions/subs is not causing any overhead.
And if you, like already suggested by XavSnap, specify also the column/row index then the subroutine can work only on that given part of the multi-dimensional part of the array.
In some other situation you can also create arrays of arrays (using UDT) then you can easily pass a single dimension.
Code:
Option Explicit
Private Type tpLongArray
lValues() As Long
End Type
Private Sub Form_Load()
Test
End Sub
Private Sub Test()
Dim tMatrix() As tpLongArray
Dim lRow As Long, lCol As Long
Randomize
ReDim tMatrix(9)
For lRow = 0 To 9
ReDim tMatrix(lRow).lValues(9)
For lCol = 0 To 9
tMatrix(lRow).lValues(lCol) = Rnd * 500&
Next lCol
Next lRow
Debug.Print SumValues(tMatrix(3).lValues)
Debug.Print SumValues(tMatrix(7).lValues)
Debug.Print SumValues(tMatrix(0).lValues)
End Sub
Private Function SumValues(lValues() As Long) As Long
Dim i As Long
For i = 0 To UBound(lValues)
SumValues = SumValues + lValues(i)
Next i
End Function
-
Oct 8th, 2019, 06:00 AM
#13
Re: Passing 2 dimensional array as one dimensional to a function/sub?
Originally Posted by Victor Bravo VI
Are you sure that would work? The OP wants to pass an array that contains only the last dimension (i.e., row) of a 2D array
Crud, I misread the intent. I thought the entire array was to be passed.
In that case I will agree with what everyone else is saying... just loop through the passed 2D array.
-
Oct 8th, 2019, 11:20 AM
#14
Re: Passing 2 dimensional array as one dimensional to a function/sub?
If your arrays aren't dynamic arrays, and you're willing to exploit a bug in VB6, you can do it with UDT arrays (and have your actual fixed arrays in the UDTs):
Code:
Option Explicit
Private Type OneDimType
a(1 To 9) As Long
End Type
Private Type TwoDimType
a(1 To 3, 1 To 3) As Long
End Type
Private Function Test1() As TwoDimType()
Dim b(0) As TwoDimType
b(0).a(1, 1) = 11
b(0).a(2, 1) = 12
b(0).a(3, 1) = 13
b(0).a(1, 2) = 21
b(0).a(2, 2) = 22
b(0).a(3, 2) = 23
b(0).a(1, 3) = 31
b(0).a(2, 3) = 32
b(0).a(3, 3) = 33
Test1 = b
End Function
Private Sub Form_Load()
Dim b() As OneDimType
b = Test1
Debug.Print b(0).a(1)
Debug.Print b(0).a(2)
Debug.Print b(0).a(3)
Debug.Print b(0).a(4)
Debug.Print b(0).a(5)
Debug.Print b(0).a(6)
Debug.Print b(0).a(7)
Debug.Print b(0).a(8)
Debug.Print b(0).a(9)
End Sub
Now, a word of caution. The actual elements in each UDT must be the same size, and you can't use dynamic arrays as the nested/child arrays. If you don't obey those rules, you'll just crash.
So, it's not an approach I'd recommend, but it will work. Also, what Victor Bravo said in post #11 still holds.
Personally I'd never use what I outlined, but I thought I'd include it for completeness. If I really wanted to do this, I'd probably use CopyMemory to get it done.
Last edited by Elroy; Oct 8th, 2019 at 12:07 PM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Oct 8th, 2019, 12:05 PM
#15
Re: Passing 2 dimensional array as one dimensional to a function/sub?
And just for grins, here's how I'd possibly do it if I wanted to:
Code:
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Dest As Any, ByRef Source As Any, ByVal Bytes As Long)
Private Sub Form_Load()
Dim a2() As Single
ReDim a2(1 To 3, 1 To 3)
a2(1, 1) = 11
a2(2, 1) = 12
a2(3, 1) = 13
a2(1, 2) = 21
a2(2, 2) = 22
a2(3, 2) = 23
a2(1, 3) = 31
a2(2, 3) = 32
a2(3, 3) = 33
Dim a1() As Single
a1 = CopySingleFrom2To1Dim(a2)
Debug.Print a1(1)
Debug.Print a1(2)
Debug.Print a1(3)
Debug.Print a1(4)
Debug.Print a1(5)
Debug.Print a1(6)
Debug.Print a1(7)
Debug.Print a1(8)
Debug.Print a1(9)
End Sub
Private Function CopySingleFrom2To1Dim(a2() As Single) As Single()
' a2 MUST be a two dimension array. It can have as many elements as you like.
' The return will be a ONE based array, with the same number of elements as a2.
Dim a1() As Single
Dim iOneDims As Long
iOneDims = (UBound(a2, 1) - LBound(a2, 1) + 1) * (UBound(a2, 2) - LBound(a2, 2) + 1)
ReDim a1(1 To iOneDims)
CopyMemory ByVal VarPtr(a1(1)), ByVal VarPtr(a2(LBound(a2, 1), LBound(a2, 2))), iOneDims * 4
CopySingleFrom2To1Dim = a1
End Function
It has the advantage that the arrays can be dynamic. Also, no UDTs are required. However, a bit of superfluous copying the array around is done.
I didn't study it in detail but it looks like what LaVolpe did in post #7 is what I'd call aliasing (two variables pointing at the same data). That's a nice way to do it, but you've got to be very careful to clean up after yourself when you do that, or crash. The advantage is that you don't copy the entire array. I'd probably have used GetMem4 for some of his work, but he knows that.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Oct 8th, 2019, 03:57 PM
#16
Re: Passing 2 dimensional array as one dimensional to a function/sub?
The real take away, I think, is that the array is probably defined backwards. If you want to access the 40 elements efficiently, regardless of how you pass it, it should have been declared (40, 5), so the 40 (41) elements would be contiguous in memory and more likely to fit in local CPU cache so access can possibly be many times faster than, the other way around.
"Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|