Results 1 to 16 of 16

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

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Oct 2013
    Posts
    110

    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

  2. #2
    Member
    Join Date
    Oct 2019
    Posts
    37

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

    Thread Starter
    Lively Member
    Join Date
    Oct 2013
    Posts
    110

    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. #4
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,872

    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. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    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.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6
    Member
    Join Date
    Oct 2019
    Posts
    37

    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. #7
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

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

    Quote Originally Posted by XavSnap View Post
    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
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  8. #8
    Member
    Join Date
    Oct 2019
    Posts
    37

    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. #9
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    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
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  10. #10
    Member
    Join Date
    Oct 2019
    Posts
    37

    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. #11
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

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

    Quote Originally Posted by LaVolpe View Post
    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. #12
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,872

    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. #13
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

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

    Quote Originally Posted by Victor Bravo VI View Post
    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.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  14. #14
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,855

    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.

  15. #15
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,855

    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.

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    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
  •  



Click Here to Expand Forum to Full Width