Passing Arrays to Procedures


Declaring/defining array parameters and passing array arguments to procedures

Syntax for array symbol name
As parameter in procedure declaration:
( [ any [, any...] ] ) as datatype
array_name( [ any [, any...] ] ) as datatype
As parameter in procedure definition:
array_name( [ any [, any...] ] ) as datatype
As argument in procedure call:
array_name()

Parentheses (even empty) are mandatory to specify that the parameter/argument is an array.

Usage of array symbol name
When declaring procedure with array parameter:
declare { sub | function } proc_name ... ( ( [ any [, any...] ] ) as datatype , ... ) [ ... ]
declare { sub | function } proc_name ... ( array_parameter_name( [ any [, any...] ] ) as datatype , ... ) [ ... ]
When defining procedure with array parameter:
{ sub | function } proc_name ... ( array_parameter_name( [ any [, any...] ] ) as datatype , ... ) [ ... ]
When passing array argument to procedure:
sub_name ( array_argument_name() , ... )
sub_name array_argument_name() , ...
funct_name ( array_argument_name() , ... )
funct_name array_argument_name() , ...
... funct_name ( array_argument_name() , ... ) [ ... ]

Note (same rules as for any parameter/argument list):
When declaring/defining a procedure, parentheses surrounding a non empty parameter list are required.
When calling a subroutine, parentheses surrounding an argument list (empty or non empty) are optional.
When calling a function as a subroutine (without using the return variable), the same rules as for subroutine apply.
When calling a function in an expression (which uses the return value), parentheses surrounding a non empty argument list are required.
But it is a common convention to always use parentheses (empty or non empty) after the procedure name, to signify a procedure call.

Description
Array parameter can not have a byval or byref keyword before them, because arrays don't get passed the same way as normal parameters. While variables get passed by value or by reference, arrays get passed by descriptor (see below). In fact when an array is passed to a procedure, it is a reference to its descriptor which is passed.
All the elements of a passed array can be modified, and those changes are reflected at the calling level. Perhaps byref should be allowed by similarity with variable-length string (which are also passed by descriptor).

There is no direct possibility of passing an array by value. Declaring a passed array parameter as constant only forbids any modification in the procedure body. A workaround would be to pass a user copy of the array.

Note:
A function return can not be an array type variable.
A fixed-length string array can not be passed to a procedure.
A zstring/wstring array can not be simply passed to a procedure because the zstring/wstring size is not passed (the "as zstring/wstring * 1" type is taken by default by compiler in procedure body). It is a bug at the moment because compiler just fails silently while it badly computes in the procedure body the address of each array element (except the first obviously).

Array descriptor (for information purposes only):
For a fixed-length array, the descriptor is only used for passing the array to a procedure (otherwise the compiler does not use it because knowing the fixed characteristics of the array).
For a variable-length array, the descriptor is always used (the array descriptor is the only defining the array characteristics).

The array descriptor has the following structure (each item is coded on an 'Any Ptr' or an 'Uinteger', except on an 'Integer' for lbound and ubound):
- pointer to the real or virtual element: @array(0, 0, ...)
- pointer to the first real element: @array(lbound1, lbound2, ...)
- "global" size in bytes: (ubound1 - lbound1 + 1) * (ubound2 - lbound2 + 1) * ... * (size of 1 element in bytes)
- size of one element in bytes
- number of dimensions
- flags(*): array points to fixed-length memory (1-bit) / array has fixed nb of dimensions (1-bit) / nb of dimensions allocated in descriptor (4-bit)
then for each dimension:
- number of elements: (ubound - lbound + 1)
- lbound
- ubound

(*): Additional member field (an 'Uinteger') for fbc versions >= 1.08
(see the include file ./inc/fbc-int/array.bi for fbc versions >= 1.07)

Example

Declare Sub splitString(ByVal As String, (Any) As String, ByVal As UByte = Asc(","))


Dim As String s = "Programmer's Guide/Variables and Datatypes/Arrays/Passing Arrays to Procedures"
Dim As String array(Any)

splitString(s, array(), Asc("/"))

Print "STRING TO SPLIT:"
Print s
Print
Print "RESULT ARRAY FROM SPLITTING:"
For i As Integer = LBound(array) To UBound(array)
    Print i, array(i)
Next i

Sleep


Sub splitString(ByVal source As String, destination(Any) As String, ByVal delimitor As UByte)
    Do
        Dim As Integer position = InStr(1, source, Chr(delimitor))
        ReDim Preserve destination(UBound(destination) + 1)
        If position = 0 Then
            destination(UBound(destination)) = source
            Exit Do
        End If
        destination(UBound(destination)) = Left(source, position - 1)
        source = Mid(source, position + 1)
    Loop
End Sub

See also
Back to Programmer's Guide
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki



sf.net phatcode