Author Topic: 2D Dynamic Array in Type Def  (Read 2850 times)

0 Members and 1 Guest are viewing this topic.

Offline rdc

  • Pentium
  • *****
  • Posts: 1495
  • Karma: 140
  • Yes, it is me.
    • View Profile
    • Clark Productions
2D Dynamic Array in Type Def
« on: November 18, 2009 »
The following code example illustrates how to create a dynamic two-dimensional array within a type-def or object def.

Code: [Select]
/'****************************************************************************
*
* Name: 2dtypearray.bas
*
* Synopsis: Demonstrates a 2D dynamic array in type def.
*
* Description: FreeBasic does not support dynamic arrays within a type definition
*              or object definition. However, by using dynamic memory access, you
*              can create a dynamic array of any type in a type def. This example
*              code shows how to implement a dynamic two-dimensional array within
*              a type def, and by extension, an object definiton.
*
* Copyright 2009, Richard D. Clark
*
*                          The Wide Open License (WOL)
*
* Permission to use, copy, modify, distribute and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice and this license appear in all source copies.
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
*
*****************************************************************************'/
'Define our Null.
#Define NULL 0

'Count variable.
Dim cnt As Integer

'2D dynamic array definition.
Type twodarray
elrows As Integer         'The number of rows in the array.     
elcols As Integer Ptr      'The number of elements in each row.
arrptr As Integer Ptr Ptr 'Let's create an integer array.
End Type
'We will define our dynamic array, arrptr, as a pointer to pointer. What we will do is to create a set of pointers
'that will point to a set of integers that will composes our two-dimensional array. The first set of pointers
'will act as the rows of the array, while the second set of pointers will be the data in each array column.
'A rather crude drawing will illustrate this concept:
'
'[0]->[0][1][2]
'[1]->[0][1][2]
'[2]->[0][1][2]
'
'The first number is the first pointer, which is a pointer to an integer pointer. The numbers that follow
'are the actual data that each pointer points to in the array. The first number corresponds to the row index,
'while the second number corresponds to the column index.
'
'Since we are using pointers, there is no inherent way to determine how many elements are in the array, so
'we need to keep track of the number of elements ourself. elrows will be used to keep track of the number
'of rows we have in the array. elcols, which is a pointer to integer, will keep track of the number of columns
'in each row. One way to look at this is a combination of 1D arrays. The rows make up one 1D array. Each
'column of each row make up the other 1D array. In essence, we are constructing a series of 1D arrays,
'arranging them in a fashion that mimics a 2D array. 

'Create a type variable.
Dim dyn2 As twodarray

'Just for some random data.
Randomize Timer

'Let's add 5 rows to our array.
dyn2.elrows = 5
dyn2.arrptr = Allocate (dyn2.elrows * SizeOf (Integer Ptr))
'Here we have created 5 pointers that point to integers. These 5 pointers correspond to the first numbers
'in the drawing above and represent the rows of the array. Since they are pointers and haven't been
'initialized, they don't point to anything yet. We keep track of the number of rows in elrows which will
'need to be updated after each row change. Now we need to allocate 10 integer pointers in elcol so we know
'how many elements each row has, which represents the columns of the array. Initially each row will have zero
'columns since the row pointers haven't been initialized yet.
dyn2.elcols = Allocate(dyn2.elrows * SizeOf(Integer))
'Notice that we are allocating this as integers rather than integer pointers. We simply need a list of integers
'here se we know how many columns each row has. dyn2.elcols[0] would represent the number of columns in row 0,
'dyn2.elcols[1] would represent the number of columns in row 1 and so on.
'
'At this point we should initialize our structure so that we have consistent values in our array. When allocating
'memory like this, the values that our pointers contain are just random data. We will iterate through the structure
'and set all the pointers to NULL and column values to 0. Since our array will start at 0 for each row and column
'we need to use the format 0 to max - 1.
For i As Integer = 0 To dyn2.elrows - 1
dyn2.arrptr[i] = NULL 'Set each row to NULL since it doesn't point to anything yet.
dyn2.elcols[i] = 0 'Set each column count to 0.
Next
'Now we can add some columns to each row, and load some data into the array. Each row will have a different
'number of columns to illustrate the fact that our dynamic array doesn't have to be square.
For i As Integer = 0 To dyn2.elrows - 1
cnt = Int(Rnd * 5) + 1 'Random number of columns.
dyn2.arrptr[i] = Allocate(cnt * SizeOf(Integer)) 'Allocate cnt number of integers.
dyn2.elcols[i] = cnt 'Save the number of columns in the row.
For j As Integer = 0 To dyn2.elcols[i] - 1
dyn2.arrptr[i][j] = Int(Rnd * 10) 'Load some random data into the array.
Next
Next
'Notice that the syntax to access a 2D array is [row][col]. This corresponds to the fact that the array is
'is a pointer to a pointer. We can now print out the data we currently have.
For i As Integer = 0 To dyn2.elrows - 1       'The number of rows.
Print dyn2.elcols[i] & " columns in row " & i & "."
For j As Integer = 0 To dyn2.elcols[i] - 1 'The number of columns in the current row.
Print "Row " & i & " Col " & j & " = " & dyn2.arrptr[i][j]
Next
Next
Print "*****************************************************************************"
'Since this is a dynamic array, we can add and subtract rows and columns as needed. Let's first delete
'the last row of the array. Before we delete the row, we must deallocate the columns within the row so
'we do not get a memory leak.
DeAllocate dyn2.arrptr[dyn2.elrows - 1]
'Now we can resize the array.
dyn2.elrows -= 1
dyn2.arrptr = ReAllocate(dyn2.arrptr, dyn2.elrows * SizeOf(Integer Ptr))
'We also need to reallocate the column counter as well.
dyn2.elcols = ReAllocate(dyn2.elcols, dyn2.elrows * SizeOf(Integer))
'Print out the data to see what we have now.
For i As Integer = 0 To dyn2.elrows - 1       'The number of rows.
Print dyn2.elcols[i] & " columns in row " & i & "."
For j As Integer = 0 To dyn2.elcols[i] - 1 'The number of columns in the current row.
Print "Row " & i & " Col " & j & " = " & dyn2.arrptr[i][j]
Next
Next
Print "*****************************************************************************"
'To add a new row, we do what we did when we first created the array, except we use
'ReAllocate instead of Allocate.
dyn2.elrows += 1
dyn2.arrptr = ReAllocate(dyn2.arrptr, dyn2.elrows * SizeOf(Integer Ptr))
'Since this is a new row, we need to add some columns.
cnt = Int(Rnd * 5) + 1
dyn2.arrptr[dyn2.elrows - 1] = Allocate(cnt * SizeOf(Integer))
'We also need to reallocate the column counter as well.
dyn2.elcols = ReAllocate(dyn2.elcols, dyn2.elrows * SizeOf(Integer))
'Save the number of columns.
dyn2.elcols[dyn2.elrows - 1] = cnt
'Load some data into the new columns. Since the new row as added to the end of the array we
'are working with max - 1 here.
For i As Integer = 0 To dyn2.elcols[dyn2.elrows - 1] - 1
dyn2.arrptr[dyn2.elrows - 1][i] = Int(Rnd * 5)
Next
'Let's see what we have now in the array.
For i As Integer = 0 To dyn2.elrows - 1       'The number of rows.
Print dyn2.elcols[i] & " columns in row " & i & "."
For j As Integer = 0 To dyn2.elcols[i] - 1 'The number of columns in the current row.
Print "Row " & i & " Col " & j & " = " & dyn2.arrptr[i][j]
Next
Next
Print "*****************************************************************************"
Sleep
'Before we exit the program, we will deallocate the array.
For i As Integer = 0 To dyn2.elrows - 1
DeAllocate dyn2.arrptr[i] 'Deallocate all the columns.
Next
'Deallocate the rows.
DeAllocate dyn2.arrptr
'Deallocate the column count.
DeAllocate dyn2.elcols
'Set everything to NULL and 0. Not really necessary here, but it would be necessary
'if this was an object for example.
dyn2.elrows = 0
dyn2.elcols = NULL
dyn2.arrptr = NULL