С++ для начинающих. Выделение памяти для трехмерного массива. Многомерные массивы.

Ответы на вопросы создания многомерных массивов есть в просторах интернета. Ответы на вопросы о создании трёхмерных, четырёхмерных и более многомерных массивов выступают в качестве притесняемого меньшинства. На самом деле трёхмерные и более мерные массивы не так уж и нужны. Они не очень удобны, их сложно обрабатывать.
Можно использовать или чистый трёхмерный массив, или эмулировать трёхмерный массив с помощью указательных переменных. Алгоритм эмуляции указателями многомерных массивов в принципе один и тот же: сначала выделяется память основной указательной переменной, указывающей на массив. Для каждой внутренней указательной переменной выделяется собственная память. И пока указатели указывают на указатели — так и выделяется память каждому указателю.
  • Любой многомерный массив — это массив массивов.
Создавать трёхмерный массив можно несколькими способами:

  1. Использовать чистый массив:
    [10][20][30] — массив, хранящий 20 массивов, где каждый из 20 массивов хранит 30 массивов
  2. Использовать указатель на чистый двумерный массив:
    (*)[20][30] — указатель на начало массива, хранящего 20 массивов, где каждый из 20 массивов хранит 30 массивов. В этом случае указателю нужно выделить память или направить указатель на уже зарезервированную программой память, т. е. сделать так, чтобы указатель указывал на доступную область памяти, а не не пойми куда.
  3. Использовать указатель на указатель, указывающий на одномерный массив:
    (**)[30] — эту штуку можно называть [массивом] [указателей, указывающих на указатели]. Всем указателям нужно выделять память или направлять их на уже выделенное место в памяти.
  4. Использовать указатель на указатель на указатель:
    *** — В этом случае всё как и в предыдущих, указатели нужно делать валидными.
Для любой большей мерности массивам — всё происходит по похожей схеме.
Очень тесно связана с этой темой тема:

В случае чистого трёхмерного массива много проблем не возникает:

Поскольку трёхмерный массив — это массив двумерных массивов, а любой двумерный массив легко представлять в виде таблицы, вы видите на экране массив таблиц. Если у вас консольное окно узкое, то вывод произойдёт не очень красиво, нужно будет изменить ширину в свойствах окна консоли. Если у вас Borland C++3.1 или что-то похожее, то вы не сможете в полной мере насладиться красивым видом массива таблиц. При первых попытках запусков программ, создаваемых из показанных кодов, не задавайте слишком большие числа, иначе в третьем, например, варианте, у вас вывод на экран может происходить больше суток, если так получится, что суммарно ячеек будет нужно слишком много.
В случае добавления указателей, нужно выделять и чистить память. В первом случае, когда добавляется один указатель, у вас появляется возможность сказать программе, сколько ячеек для таблиц вы хотите создать, сказать об этом прямо в ходе работы программы:

Когда вы делаете указатель на двухмерный массив, обязательно оборачивать указательную часть в скобки, иначе вы получите не указатель не массив, а двухмерный массив указателей.
Благодаря использованию свойств указателей мы получили возможность задавать, сколько таблиц должен хранить наш массив. Для этого мы использовали добавление одной звёздочки.
  • То, что написано ниже — это для саморазвития. Будете делать на практике, оторвут уши и руки.
В случае добавления ещё одной звёздочки можно будет и задавать количество таблиц, и хранить таблицы с разным числом строк:

Операция new должна разобраться, какая из размерностей динамическая и что здесь есть указатель. Из-за синтаксической особенности типа массива приходится выделывать такие страшные штуки, которые были проделаны при выделении памяти. Тут сложности с тем, что могут быть массивы указателей, указатели на массивы указателей, массивы указателей на указатели, массивы указателей, указывающих на массивы и много ещё чего, а компилятор должен точно знать, чего мы от него хотим.
В том случае, если массив не смешивается с указателями, такие страшные штуки не нужны. Если мы добавим третью звёздочку к нашей сущности, выполняющей роль массива, то тогда мы получим массив, способный хранить таблицы и с разным числом строк, и с разным числом колонок.
Если использовать все три звёздочки, то можно задавать и количество строк для каждой таблицы, и количество колонок для каждой строки таблицы. Но я немного в упрощённом варианте покажу. В моём случае для каждой конкретной таблицы будет задаваться определённое число строк и определённое для конкретной таблицы число колонок:

Основная возможная сложность, которая идёт за осознанием природы указателей и массивов — может быть в том, что нужно дополнительно отслеживать, сколько в таблице вообще строк и сколько колонок в каждой отдельной строке таблицы. Поскольку у меня немного упрощённый вариант, я отслеживаю количество колонок не для каждой отдельной строки, а только для конкретной таблицы. Но развить можно таким образом, чтобы у каждой строки было своё число колонок, тогда таблицы мало будут похожи на таблицы.
Но ещё раз напоминаю, что делать таких вещей совсем не нужно (если только для спортивного интереса в самом глубоком бомбоубежище, чтобы никто вас не застал за этим грязным делишком). Эти примеры даны вам больше для того, чтобы вы получили некоторое представление о работе указателей и массивов, получили некоторое представление о трёхмерном массиве, который задаётся с помощью указателей, чтобы поняли в чём сложности работы с указательными переменными и поняли некоторые другие вещи. Даже когда вы поймёте, как эти примеры работают, почему они работают, и когда сможете сами писать такие же коды, писать таким образом ни в коем случае не нужно: если есть большое желание решить задачу, требующую похожих поведений, и хочется использовать именно показанный в этой статье способ, вам нужно переосмыслить вариант решения, наверняка найдётся что-то проще, читабельней и понятнее всем, чем то, что показывал я сейчас.
Эта статья не затрагивает массивы двухуровневых указателей и двумерные массивы указателей, но эти массивы тоже возможно трактовать как трёхмерные и использовать их при определённых нуждах, но как и ранее, указателей имеет смысл избегать, особенно многоуровневых указательных сущностей. В подавляющем большинстве случаев вам может хватить или обычного трёхмерного массива, размерности которому задаются сразу в исходном коде программы, или одноуровневого указателя на двухмерный массив, чтобы можно было сообщать в ходе работы программы, какой нужна первая (слева) мерность трёхмерному массиву. Всё остальное от лукавого.

2 комментария на «“С++ для начинающих. Выделение памяти для трехмерного массива. Многомерные массивы.”»

  1. Константин:

    Я в книге нашел два способа выделения памяти для динамических массивов и использовал вот этот int (*a)[6][5]= new int [3][6][5];

    Правда там был пример для двухмерного дин. массива, но методом тыка я переделал под трехмерный.

    Так вот по условию задачи мне нужно увеличить индексация начального элемента на 1 (из [0][0][0] сделать [1][1][1]).
    Для одномерного массива я писал бы а+=1, но тут эта строка меняет лишь номер матрицы (из [0][0][0] делает [1][0][0]).
    Кто знаком с такой конструкцией и принято ли ею пользоваться ?

    • Это указатель на начало массива двумерных массивов [6][5], т.е. это как массив из массивов [6][5].(только оно не массив, а указатель на набор массивов [6][5]. Это важно).
      int (*a)[6][5] = new int[3] -> здесь а становится массивом с тремя значениями, каждое из которых массив фиксированного размера [6][5].
      a[0] — массив[6][5], a[1] — массив[6][5], a[2] — массив [6][5]

      Вот пример кода.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поиск

 
     

Случайная книга в электронном формате

https://www.litres.ru/dzhon-vlissides/priemy-obektno-orientirovannogo-proektirovaniya-patterny-proektirovaniya-16419747/?lfrom=15589587
Яндекс.Метрика