Версия:
Аннотация
Показаны различные традиционные способы задания матриц, как двумерных, так и многомерных.
Цель. Научится работать с матрицами.
Предварительный вариант!
В первом подразделе будет показано как создавать многомерный массив статического размера, т.е. заданного до компиляции. Во втором и третьем будет показаны различные способы задания матрицы динамического размера. В четвертом подведем итог.
Объявление Напомню как происходит взаимодействие с одномерным массивом.
По аналогии с одномерным массивом можно объявить и двумерный массив, т.е. матрицу:
Размер очередной размерности указывается в квадратных скобках. В данном случае arr2 – это двумерная матрицы размера 6 на 5 элементов. Как эти размерности интерпретировать с точки зрения математики зависит от задачи, т.е. можно считать что, например, это матрица из 6 строк и 5 столбцов, а можно наоборот. По аналогии можно задавать массивы и большей размерности:
С точки зрения языка Си правильная интерпретация повышения размерности (т.е. добавления числа в квадратных скобках) гласит, что, например, arr3 – это массив из трех элементов, каждый из которых является двумерным массивом (матрицей) размера на . Точнее даже так: arr3 – это массив из трех элементов, каждый из которых является массивом из элементов, каждый из которых является массивом из 5 элементов, каждый из которых имеет тип плавающая точка (double).
Элементы массива arr2 задаются двумя индексами – неотрицательными целыми числами. Каждый из индексов меняется в соответствующем диапазоне, а именно – от до размера минус 1. Тогда элементами массива arr2 являются следующие элементы: arr2[0][0], ..., arr[0][4], arr2[1][0], ..., arr[1][4], ..., arr2[5][0], ..., arr[5][4]. Отмечу, что после объявления матрицы во всех её элементах естественно мусор.
Вычисления Зная последнее далее можно выполнить вычисления над её элементами:
При выходе индексов за пределы возможных значений возникнет ошибка.
Снизу индекс ограничен , а сверху строго меньше размера.
Инициализация В одномерном случае было возможно выполнить инициализацию массива:
По аналогии в двумерном (и соответственно в многомерном) случае
Инициализация элементов матрицы выполняется в ранее отмеченном порядке. Так, например, элемент arr3[0][0] , arr3[0][1], arr3[1][1], а arr3[2][0]. Если массив больше указанного списка, то хвостовые элементы не будут проинициализированы – в них будет мусор. Если список содержит большее количество чисел, то это вызовет ошибку компиляции.
При инициализации можно прервать инициализацию элементов текущей строки:
Для перехода на следующую строчку (т.е. в начало следующего массива) используется запятая. В данном случае, все элементы за исключением элемента с индексом 1,1 будут проинициализированы как и ранее. Отмеченный элемент будет содержать мусор.
Объект любого типа Естественно, что вместо типа double можно применить любой другой тип данных: int, а то и частные типы (структуры).
Связь с указателем Напомню какая есть связь массива с указателем:
По аналогии с этим
Но можно пойти и дальше:
Последние выражения вычисляются на этапе компиляции, т.е. нельзя написать:
Создание Зададимся целью создания двумерного (а также и многомерного) массива имеющий динамический размер, т.е. размер который задается при запуске программы, а не при её компиляции. По аналогии с выше описанным, нам нужно создать массив массивов. Если последние имеют тип double*, то тогда массив, элементы которого имеют тип double*, будет иметь тип double**. Напишем соответствующий код:
Каждый из элементов созданного массива arr4 имеет тип double*, и содержит мусор. т.е. для корректной работы им нужно присвоить массивы соответствующего размера.
Всё, матрица создана. Отмечу, что размер каждого из массивов соответствует количеству столбцов, т.е. равно . Тип элементов массива выбран double.
Важно отметить о порядке освобождения памяти. Сначала нужно освободить память выделенную под каждую из строчек матрицы:
а уже далее память выделенную под массив массивов:
В противоположном порядке ничего не получится, так как если сначала освободить память массива arr4, то после этого любое обращение к его элементам будет считаться ошибкой.
Вычисления над элементами Все вычисления соответствуют ранее рассмотренному массиву статического размера. Так,
Последнее естественно справедливо в случае, если размер указанного массива при запуске программы будет превосходить рассмотренные индексы.
Взаимодействие с указателями также справедливо:
Замечу, что в обще говоря ничто не мешает для каждой строчки выделить массив своего размера. Такое может быть полезным, например, для эффективного хранения треугольной матрицы.
Многомерный случай Естественно, что сами строчки (в данном случае, элементы массива arr4) могут быть многомерными массивами, в частности, двумерными. Тогда объединяя получим трехмерный массив.
Каждый из элементов созданного массива arr5 имеет тип double**, т.е. необходимо выполнить аналогичные действия для двумерного массива.
Упражнение. Напишите код освобождающий память.
В данном подходе выделяется одномерный массив по размеру соответствующий двумерному (многомерному).
При обращении к элементу выполняется вычисление соответствие индексов. Существуют два традиционных способа обхода элементов: по строкам и по столбцам.
По строкам В данном подходе элементы матрицы обходятся строка за строкой. Последнее означает, что соседние элементы в строке являются соседними в одномерном массиве. А также, последний элемент строки является соседним к первому элементу следующей строки. Формула будет такой: где , – это индекс элемента матрицы. Исходя из последнего:
Работа с указателями следует из способа отображения индексов.
По столбцам В полной аналогии с предыдущим, в данном подходе элементы матрицы обходятся столбец за столбцом. Формула будет: где , – это индекс элемента матрицы. Все остальное тоже по полной аналогии, но только для столбцов.
Освобождение памяти Память освобождается крайне просто.
Показано как выделять память под многомерные массивы. Тип естественно можно заменить на произвольный, например на структуры.
У каждого подхода есть свои преимущества. Например, в представлении матрицы как массив массивов операция перестановки двух строк очень быстрая, тогда как в представлении одномерного массива тяжелая.
В представлении массива массивов очень высокая нагрузка на систему выделения памяти, а в случае представления одномерным массивом такой проблемы нет.