# Thread: Passing 2 dimensional array as one dimensional to a function/sub?

1. ## 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.

2. ## 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.

3. ## 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...

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.

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.

6. ## 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```

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```

8. ## Re: Passing 2 dimensional array as one dimensional to a function/sub?

Hi,

Thanks LaVolpe !
Working on Vb5...

Never seen this kind of code...

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

10. ## 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" !

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.

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```

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.

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.

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.

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.

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•

Featured

Click Here to Expand Forum to Full Width