Как правильно создать и использовать двумерный массив в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Работа с массивами в 1С:Предприятие кажется простой только на первый взгляд. Начинающие разработчики часто сталкиваются с ситуацией, когда при изменении значения в одной «ячейке» двумерного массива данные магическим образом меняются во всех строках сразу. Это происходит из-за непонимания механизмов работы системы с объектами и ссылками.

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

Разбор типичной ошибки: ссылка вместо объекта

Рассмотрим ситуацию, описанную автором темы. Программист пытается создать структуру «массив массивов», используя следующий код:


Для i=1 По ВсегоСтрок Цикл
    ДанныеИзЭкселевскогоФайлаЯчейка.Добавить(i);
КонецЦикла;

Для i=1 По ВсегоКолонок Цикл
    ДанныеИзЭкселевскогоФайла.Добавить(ДанныеИзЭкселевскогоФайлаЯчейка);    
КонецЦикла;

Проанализируем, что здесь происходит на уровне памяти. В 1С объект Массив является ссылочным типом данных. Когда вы создаете переменную ДанныеИзЭкселевскогоФайлаЯчейка, система выделяет область памяти для одного объекта. В первом цикле вы заполняете этот единственный объект данными.

Во втором цикле вы вызываете метод Добавить() для основного массива. Однако вместо того, чтобы создать копию данных, вы добавляете ссылку на один и тот же объект ДанныеИзЭкселевскогоФайлаЯчейка несколько раз. В итоге ваш основной массив превращается в список указателей, которые все ведут к одной и той же области памяти. Именно поэтому при изменении ДанныеИзЭкселевскогоФайла[0][0] вы видите изменения во всех остальных «строках» — физически это одна и та же строка.

Способ 1: Использование многомерного конструктора

Если вам заранее известна размерность массива, в 1С предусмотрен штатный механизм создания истинно многомерных массивов через конструктор. Это самый простой и эффективный способ избежать ошибок с дублированием ссылок.

Рассмотрим пример создания двумерного массива размером 10 на 5 (10 строк, 5 колонок):


// Создание прямоугольного массива
ДвумерныйМассив = Новый Массив(10, 5);

// Обращение к элементам (индексация начинается с 0)
ДвумерныйМассив[0][0] = "Значение 1";
ДвумерныйМассив[9][4] = "Значение 50";

В этом случае система самостоятельно инициализирует структуру, где каждый элемент доступен по двум индексам, и они независимы друг от друга. Вы можете указать до 8 измерений в конструкторе: Новый Массив(Размер1, Размер2, ..., Размер8).

Способ 2: Динамическое создание «массива массивов»

Часто на практике количество «колонок» в каждой строке может быть разным или структура должна строиться динамически. В этом случае мы используем вложенные массивы (так называемые зубчатые массивы — jagged arrays). Чтобы избежать проблемы, описанной в начале статьи, необходимо на каждой итерации цикла создавать новый экземпляр вложенного массива.

Посмотрим на правильный алгоритм реализации:


// Основной контейнер
ДанныеИзФайла = Новый Массив;

Для НомерСтроки = 1 По ВсегоСтрок Цикл
    // КРИТИЧЕСКИ ВАЖНО: Создаем НОВЫЙ объект массива для каждой строки
    НоваяСтрока = Новый Массив;
    
    Для НомерКолонки = 1 По ВсегоКолонок Цикл
        НоваяСтрока.Добавить("Данные " + Строка(НомерСтроки) + ":" + Строка(НомерКолонки));
    КонецЦикла;
    
    // Добавляем уникальный объект в основной массив
    ДанныеИзФайла.Добавить(НоваяСтрока);
КонецЦикла;

Теперь ДанныеИзФайла[0] и ДанныеИзФайла[1] указывают на разные объекты в памяти. Изменение одного не затронет другой.

Сравнение с Таблицей Значений

В процессе обсуждения на форуме часто звучит вопрос: «Зачем использовать двумерный массив, если есть ТаблицаЗначений?». Выясним причины выбора того или иного инструмента:

  1. Массивы универсальны: Они работают и на стороне клиента, и на стороне сервера. ТаблицаЗначений — это объект, доступный только на сервере (или в толстом клиенте). Если вам нужно передать двумерную матрицу с сервера на клиент в тонком клиенте, массив — ваш единственный выбор.
  2. Типизация и удобство: В ТаблицаЗначений нужно определять колонки, типы данных. В массиве вы можете хранить любые типы вперемешку без предварительного описания схемы.
  3. Производительность: Для простых математических операций (матрицы, СЛАУ) массивы работают быстрее, так как не несут накладных расходов на механизмы поиска, сортировки и событий таблиц.

Однако помните: у многомерных массивов, созданных через Новый Массив(X, Y), нет встроенных методов Найти() или Сортировать(). Эти методы работают только для одномерных структур. Для поиска в двумерном массиве вам придется писать вложенные циклы самостоятельно.

Особенности работы с COMSafeArray

Если ваша задача связана с интеграцией (например, передача данных в Excel или запуск скриптов на других языках через COM), обычный массив 1С может не подойти. В таких случаях используется COMSafeArray.

Проанализируем пример создания такого массива:


// Создаем описание типа для элементов
ОписаниеТиповСтрока = Новый ОписаниеТипов("Строка");

// Создаем безопасный массив для передачи во внешнюю систему
// Параметры: Тип элементов, Размер1, Размер2
КомМассив = Новый COMSafeArray(ОписаниеТиповСтрока, 10, 10);

КомМассив.Установить(0, 0, "Данные для Excel");

Главное отличие COMSafeArray в том, что он строго типизирован и имеет фиксированный размер, который нельзя изменить после создания методом Добавить(). Это «честный» массив в понимании классического программирования (как в C++ или VB).

Практические советы и ограничения

Рассмотрим несколько важных нюансов, которые помогут избежать ошибок в будущем:

Выясним причину, по которой листинг 2.4 из старых учебников казался неверным. В учебниках часто приводится пример добавления одного и того же объекта для краткости кода, подразумевая, что читатель понимает разницу между ссылкой и значением. На практике же всегда следуйте правилу: один вызов Новый Массив — один независимый объект.

Таким образом, для создания двумерного динамического массива мы рекомендуем либо использовать прямой конструктор с двумя параметрами (если матрица прямоугольная), либо создавать новый массив внутри цикла (если структура сложная или динамическая).

← На главную