Правильное выделение и освобождение памяти для многомерных массивов в C и C++
Введение
Часто в процессе создания кода требуется работать с многомерными массивами. Простейшим примером двумерного массива является матрица. Массивы более высоких порядков (3-го и выше) называются тензорами.
Многие начинающие программисты допускают ошибки при освобождении памяти многомерных массивов.
Сегодня мы рассмотрим, каким образом правильно выделять и освобождать память для таких массивов.
Выделение памяти для матрицы
Назовём матрицу Matrix. Пусть её элементы будут представлены числами с плавающей точкой двойной точности (double). Объявление указателя такой матрицы выглядит следующим образом:
double **Matrix;
Пусть количество строк матрицы равняется numStrings, а столбцов — numColumns (целые беззнаковые числа). Сперва выделим память для строк:
Теперь необходимо выделить память для элементов каждой строки:
Здесь используется псевдоним типа size_t, обозначающий в C++ целое беззнаковое число. Альтернативой является использование unsigned int.
Память для элементов матрицы выделена, теперь её можно использовать по назначению.
Освобождение памяти матрицы
Освобождение памяти матриц следует выполнять в обратном порядке: сначала надо освободить элементы каждой строки и только после этого освободить память массива строк:
После освобождения памяти не допускаются какие-либо обращения к элементам матрицы. Указатель матрицы можно использовать повторно после нового выделения памяти (по аналогии с предыдущим примером).
Выделение памяти для тензоров
Объявим Tensor размерностью N x M x K. Такой тензор можно представить как массив матриц. Выделение памяти происходит следующим образом. Сперва выделяется память для массива двумерных массивов, затем для одномерных массивов, а затем для конкретных элементов:
Этот код можно слегка оптимизировать:
Преимущество этой оптимизации в том, что исключается лишний проход вдоль тензора по пространству N.
Освобождение памяти тензоров
Здесь всё происходит аналогично: необходимо освободить память в обратном порядке относительно её выделения:
Здесь также можно применить оптимизацию:
Заключение
Грамотное освобождение памяти критически важно в больших проектах, во встроенных системах, а также в проектах, надёжность которых важна критически. При неправильном освобождении будут наблюдаться так называемые утечки памяти приводящие к тому, что свободная память будет заканчиваться и продолжение работы приложения станет рано или поздно (по мере расходования ресурсов) невозможным.
