Single-Dimension Dynamic Arrays In Types

This is the first part of a two-part series on creating dynamic arrays within type definitions.

A Dynamic array in a type definition is a very useful feature, but FreeBasic doesn't support it. Or rather, it doesn't support it directly. However, you can create dynamic arrays by using pointers and the associated memory functions.

An array is simply a contiguous block of memory that holds a certain data type. Arrays in FreeBasic use an array descriptor to describe the data contained within the array, and you can use this same technique to build a dynamic array within a type. The two elements you need within your type-def are a pointer to a particular data type, and a size indicator.

You can then use the ptr field to allocate a block of memory to the needed size, and save that size in the size indicator field. The size field is used to tell you how many elements are currently in the array. Once the array has been initialized, you can then use pointer indexing to access each element in the array.

The following program illustrates the steps in creating, initializing and resizing a dynamic type-def array.

Option Explicit

    'Define type:
    'size is current size of array
    'darray will contain array data
    Type DType
        size As Integer
        darray As Integer Ptr
    End Type

    'Create an instance of type
    Dim myType As DType
    Dim As Integer i, tmp

    'Create enough space for elements
    myType.darray = Callocate(5, Sizeof(Integer))
    'Set the length of the array
    'in the array size indicator
    myType.size = 5

    'Load data into array
    For i = 0 To myType.Size - 1 
        myType.darray[i] = i
    Next

    'Print data
    For i = 0 To myType.Size - 1
        Print "darray[";i;" ]:";myType.darray[i]
    Next
    Print "Press any key..."
    Sleep
    Print

    'Save the current array size
    tmp = myType.size
    'Now resize the array
    myType.darray = Reallocate(myType.darray, 10)
    'Set the length indicator
    myType.size = 10

    'Load in data into new allocation
    For i = tmp - 1 To myType.Size - 1
        myType.darray[i] = i
    Next

    'Print out contents
    For i = 0 To myType.Size - 1
        Print "darray[";i;" ]:";myType.darray[i]
    Next
    Print "Press any key..."
    Sleep

    'Free allocated space
    Deallocate myType.darray

    End

The first step is, of course, to define the type-def:

Type DType
    size As Integer
    darray As Integer Ptr
End Type

Since this is just an example there are only two elements within the type, a size indicator and the array pointer. Notice that the array pointer is defined as an Integer ptr. When you define a pointer to a particular type, you are creating a "typed" pointer. The compiler can use this type information to check to make sure the values being placed into the array are valid, and will also use this information for pointer arithmetic.

The next step is to define the working variables.

Dim myType As DType
Dim As Integer i, tmp

Here an instance of the type is created, as well as some working variables that are used in the following code. WARNING: You must initialize the array pointer before you can use it; using an uninitialized ptr can cause program crashes, system lockups and all sorts of BAD things.

myType.darray = Callocate(5, Sizeof(Integer))
    myType.size = 5

These two lines of code initialize the array pointer to hold 5 integers. Callocate is used to allocate the memory segment, since Callocate will initialize the segment to zeros.

The size field stores the current length of the array. Now, of course, you could calculate the size of the array by simply dividing the number of bytes in the allocation by the size of an integer, but using a size indicator within the type is much cleaner and saves you a calculation in your program.

For i = 0 To myType.Size - 1 
        myType.darray[i] = i
    Next

This section of code loads the array with some values. You can see why saving the size of the array simplifies the coding process. Since the array is a typed pointer, you can access the array using the pointer indexing method, which is almost like accessing a predefined array.
For i = 0 To myType.Size - 1
        Print "darray[";i;" ]:";myType.darray[i]
    Next

This section simply prints out the values using the same method that was used to load the array.

Of course, this should be a dynamic array, so you should be able to resize the array, and this is exactly what the next section of code will do.

tmp = myType.size
    myType.darray = Reallocate(myType.darray, 10)
    myType.size = 10

The first line of code saves the current size of the array so that the new memory segment can be initialized while not overwriting any existing data. You will see this in a moment.

The second line uses the Reallocate function to resize the memory segment, that is, resize the array. In this case, the array is being made larger; you could of course make the array smaller. If you were to make the array smaller, any data not in the new segment would be lost, as you would expect.

The last line of code above saves the new array size in the size indicator.

For i = tmp - 1 To myType.Size - 1
        myType.darray[i] = i
    Next

Here, you can see why the old array size was saved. In the For statement, the initialization procedure starts from the old index and iterates through the newly added indexes, storing data within the memory segment. This is like using the Redim Preserve statement on a normal array.
For i = 0 To myType.Size - 1
        Print "darray[";i;" ]:";myType.darray[i]
    Next

This code section simply prints out the new values.
Deallocate myType.darray

This is vitally important. You should always deallocate any allocated memory that you have created in your program to prevent memory leaks.

When you run the program you should see the following output:

darray[ 0 ]: 0
    darray[ 1 ]: 1
    darray[ 2 ]: 2
    darray[ 3 ]: 3
    darray[ 4 ]: 4
    Press any key...

    darray[ 0 ]: 0
    darray[ 1 ]: 1
    darray[ 2 ]: 2
    darray[ 3 ]: 3
    darray[ 4 ]: 4
    darray[ 5 ]: 5
    darray[ 6 ]: 6
    darray[ 7 ]: 7
    darray[ 8 ]: 8
    darray[ 9 ]: 9
    Press any key...

The first print out shows the original array. The second print out shows the newly resized array.

There you have it, a single-dimension dynamic array in a type. In the next tutorial, you will see how to add a two-dimensional array to a type-def using the same techniques.

Richard D. Clark

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.