Динамические массивы в типах
 
Написано автором rdc

Введение


Динамический массив в определении типа — это очень полезная функция, но FreeBasic не поддерживает его. Вернее он не поддерживает напрямую. Однако динамические массивы можно создать с помощью связанных функций памяти и указателей.

Массив это просто непрерывный блок памяти, который содержит определенный тип данных. Массивы в FreeBASIC используют дескриптор массива, чтобы описать данные, содержащиеся в массиве, и вы можете использовать эту же технику для создания динамического массива в пределах типа. Два элемента, которые нужно в пределах вашего типа, это указатель на определенный тип данных, и индикатор размера.

Вы можете использовать поле PTR , для выделения блока памяти до нужного размера, и сохранить этот размер в поле индикатора размера. Индикатор размера используется, чтобы сказать вам, сколько элементов в настоящее время в массиве. После того, как массив инициализирован, вы можете использовать указатель индексации для доступа к каждому элементу в массиве.

Получение Point(er) в коде


Следующая программа иллюстрирует шаги в создании, инициализации и изменения размера динамического массива.
'Декларация типа:
'size это текущий размер массива
'darray будет содержать данные массива
Type DType
    size As Integer
    darray As Integer Ptr
End Type

'Создание экземпляра типа
Dim myType As DType
Dim As Integer i, tmp

'Создаем достаточное пространство для элементов
myType.darray = CAllocate(5, SizeOf(Integer))
'Устанавливаем размер массива
'в индикаторе размера массива
myType.size = 5

'загружаем данные в массив
For i = 0 To myType.Size - 1 
    myType.darray[i] = i
Next

'Печатаем данные
For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next
Print "Press any key..."
Sleep
Print

'Сохраняем текущий размер массива
tmp = myType.size
'Изменяем размер массива
myType.darray = Reallocate(myType.darray, 10)
'Устанавливаем длину индикатора
myType.size = 10

'Загружаем данные в новую выделенную память
For i = tmp - 1 To myType.Size - 1
    myType.darray[i] = i
Next

'Печатаем наше содержимое
For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next
Print "Press any key..."
Sleep

'освобождаем выделенную память
Deallocate myType.darray

End


Как это работает


Первым шагом является конечно объявление типа:
Type DType
    size As Integer
    darray As Integer Ptr
End Type


Так как это только один пример, то только два элемента в типе, размер индикатора и указатель на массив. Обратите внимание, что указатель массива определяется как integer ptr. Когда вы определяете указатель к определенному типу, вы создаете «типизированный» указатель. Компилятор может использовать эту информацию типа для проверки допустимости помещенных значений в массив.

Следующий шаг состоит в определении рабочих переменных.
Dim myType As DType
Dim As Integer i, tmp

Здесь создается экземпляр типа, а также некоторые рабочие переменные, которые используются в следующем коде. Предупреждение: Вам необходимо инициализировать указатель массива, прежде чем вы можете использовать его; использование неинициализированной ptr может вызвать сбой в программе, зависания системы и другие плохие вещи.
myType.darray = CAllocate(5, SizeOf(Integer))
myType.size = 5

Эти две строки кода инициализуют указатель массива для хранения 5 чисел с типом Integer. Callocate используется для выделения сегмента памяти, и так как это Callocate, то массив будет инициализирован нулями.

Поле size сохраняет текущую длину массива. Конечно, можно вычислить размер массива путем простого деления на число байт в распределении по размеру integer, но с помощью индикатора size в пределах типа намного удобнее и кроме того, этот размер сохраняется.
For i = 0 To myType.Size - 1 
    myType.darray[i] = i
Next

Этот раздел кода загружает массив некоторыми значениями. Вы можете видеть, почему сохранение размера массива упрощает процесс кодирования. Поскольку массив является типизированным указателем, выполнение доступа к массиву осуществляется, используя метод индексации указателей, который является почти такой же, как доступ к предопределенному массиву.
For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next

В этом разделе просто печатаются значения, используя тот же метод, который использовался для загрузки массив.

Конечно это должно быть динамический массив, так что мы должны иметь возможность изменения размера массива, и это именно то, что будет делаться в следующем разделе кода.
tmp = myType.size
myType.darray = Reallocate(myType.darray, 10)
myType.size = 10

Первая строка кода сохраняет текущий размер массива, чтобы новый сегмент памяти можно было инициализировать , не перезаписывая существующие данные. Вы увидите важность tmp ниже.

Вторая строка использует функцию перераспределения памяти, чтобы изменить размер сегмента памяти, то есть, измененить размера массива. В нашем случае, массив делается больше; Конечно, вы можете сделать массив меньше. Если массив будет уменьшен, то любые данные, находящиеся вне нового сегмента будут потеряны, как и следовало ожидать.

Последняя строка кода выше сохраняет новый размер массива в индикаторе размера.
For i = tmp - 1 To myType.Size - 1
    myType.darray[i] = i
Next

Здесь вы можете увидеть, почему старый размер массива был сохранен. В заявлении FOR, процедура инициализации начинается от старого индекса и перебирает вновь добавленные индексы, хранящихся данных в рамках сегмента памяти. Получается как бы симуляция Redim Preserve в обычных массивах.
For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next

В этом разделе , код просто выводит новые значения.
Deallocate myType.darray

Это жизненно важно. Вы всегда должны освободить любую выделенную память, которую вы создали в вашей программе, чтобы предотвратить утечки памяти.

Когда вы запустите программу, вы должны увидеть следующий вывод:
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...

Первая распечатка показывает исходный массив. Вторая распечатка показывает данные после изменения размера массива.