Pointers to arrays

In order to work with arrays created by other languages, such as VB arrays, PowerBASIC supports an extension of the pointer syntax, called "Pointer Indexing".  As noted above, a pointer allows you access a data element at specific address in memory.  An index pointer allows you to access data elements beyond the memory address in the base pointer.  Consider an array with 6 elements:

DIM x%(0 TO 5)

The address of the first element, x%(0), is the base with the remaining elements stored in memory, one after the other.  To access the array using an index pointer, you simply assign the address of the first element to your base pointer:

DIM xPtr AS INTEGER POINTER

xPtr = VARPTR(x%(0))

 

@xPtr[0] = 0     ' same as x%(0)

@xPtr[1] = 1     ' same as x%(1)

@xPtr[2] = 2     ' same as x%(2)

@xPtr[3] = 3     ' same as x%(3)

@xPtr[4] = 4     ' same as x%(4)

@xPtr[5] = 5     ' same as x%(5)

Note the syntax used to access the elements of the array.  It consists of the pointer's name, with the @ prefix, and followed by the array index in square brackets.  The number used inside of the brackets is a multiplier.  The number inside the brackets is multiplied by the size of the target data (a two byte Integer in this case) to calculate the target address.

The primary differences between arrays and index pointers are than index pointers do not allocate any memory of their own - they use memory which has already been allocated elsewhere.  Their lower bound is always zero.  For example, you can dimension your six-element array from 1990 to 1995.  However, to access the array data using an index pointer, you will still need to use 0 through 5:

x%(1990 TO 1995)

DIM xPtr AS INTEGER PTR

xPtr = VARPTR(x%(1990))

 

@xPtr[0] = 0     ' same as x%(1990)

@xPtr[1] = 1     ' same as x%(1991)

@xPtr[2] = 2     ' same as x%(1992)

@xPtr[3] = 3     ' same as x%(1993)

@xPtr[4] = 4     ' same as x%(1994)

@xPtr[5] = 5     ' same as x%(1995)

Consider the following VB code:

Sub Sum_Click()

  ReDim PriceData!(1 TO TotalElements%)

  Call FillSumArray(PriceData!())

  Total! = GetSum(PriceData!(1), TotalElements%)

End Sub

When the "Sum" button is pressed, a dynamic array is created and filled.  FillSumArray() is VB code to read the price data from a database file and place it into the array.  GetSum() is PowerBASIC code to add up all of the prices and return the total, since PowerBASIC handles calculations faster than VB does.

FUNCTION GetSum!(Price!, BYVAL TotalElements%) EXPORT

  DIM PriceData AS SINGLE PTR

  DIM Total!

  DIM k%

  PriceData = VARPTR(Price!)

  FOR k% = 0 TO TotalElements% - 1

    Total! = Total! + @PriceData[k%]

  NEXT

  GetSum! = Total!

END FUNCTION

In the above example, GetSum! takes the Visual Basic array, adds up all the values, and returns the total as a result.  Since a pointer is a memory address, we need the memory address of the first element in the array.  In VB, you can pass the memory address of a variable by passing it "by reference", or BYREF.  This tells Visual Basic not to pass the value of a variable to a Sub or Function, but to pass the address in memory where the variable is located.  This is handled through the DECLARE statement in Visual Basic.

DECLARE FUNCTION GetSum! LIB "SUMS.DLL" (Prices!, BYVAL Elements%)

By not using the BYVAL keyword before the variable Prices!, we've told Visual Basic to pass a memory address to the variable.  You'll notice in the DECLARE statement that the variable Prices! does not include any parentheses to indicate that it is an array.  If we were to change it to Prices!(), VB would pass a handle to an array descriptor, not an address to the array data.  The PowerBASIC code also needs to know how many elements there are in the array, so that is passed as the second parameter.

Since only the first element of the array is passed to GetSum!, we'll need to use a pointer to access the remainder of the elements.

DIM PriceData AS SINGLE PTR

Remember that all pointers are initialized to null (zero).  To access the array, we need to assign the memory address for the element passed.  VARPTR is used to get the address of the passed element.

PriceData = VARPTR(Price!)

An indexed pointer can then be used to access all of the elements in the array.  The VB array was dimensioned from 1 to TotalElements; however indexed pointers in PowerBASIC all start with a subscript of zero.  So to reconcile the difference, we subtract the lower bound (1) from TotalElements in our FOR/NEXT loop.  A DIM statement is not required to access an array using this method.

FOR k% = 0 TO Elems% - 1

  Total! = Total! + @PriceData[k%]

NEXT

It is also possible to use indexed-pointers with dynamic string arrays.  For example:

DIM Arr1(1 TO 3) AS STRING

DIM pArr1 AS STRING POINTER

 

Arr1(1) = "a1"

Arr1(2) = "a2"

Arr1(3) = "a3"

PArr1 = VARPTR(Arr1(1)) ' The 1st array element

DisplayText @pArr1[2]   ' This references Arr1(3)

 

Indexed pointers make it easy to manipulate arrays created by other languages such as VB, Delphi, C/C++, etc.

 

See Also

Pointers (@)

Pointers to nul-terminated and fixed-length strings

Pointers to arrays with dual indexes