C++ | Многомерные массивы
Последнее обновление: 22.02.2023
Каждый массив имеет такую характеристику как размерность. Количество размерностей соотвествует числу пар квадратных скобок. Например:
int numbers[3];
В данном случае массив numbers имеет одну размерность (одна пара квадратных скобок), то есть он одномерный. При этом не важно, сколько элементов содержит этот массив. В любом случае его можно представить в виде ряда элемента значений — в виде строки или столбца.
Но кроме одномерных массивов в C++ есть и многомерные. Элементы таких массивов сами в свою очередь являются массивами, в которых также элементы могут быть массивами. Как правило, распространены двухмерные и трехмерные массивы. Например, определим двухмерный массив чисел:
int numbers[3][2];
Здесь массив numbers имеет две размерности (две пары квадратных скобок): первая размерность равна 3, а вторая размерность — 2. Такой массив состоит из трех элементов, при этом каждый элемент представляет массив из двух элементов.
Подобным образом можно определять массивы и с большим количеством размерностей, например, трехмерный массив:
int numbers[3][2][2];
Как и в общем случае многомерный массив можно инициализировать некоторыми значениями, например, нулями:
int numbers[3][2] {};
Также можно инициализировать все элементы индивидуальными значениями. Так, массив numbers состоит из трех элементов (строк), каждый из которых представляет массив из двух элементов (столбцов). Поэтому такой массив мы можем проинициализировать, например, следующим образом:
int numbers[3][2] { {1, 2}, // первая строка {4, 5}, // вторая строка {7, 8} // третья строка };
Вложенные фигурные скобки очерчивают элементы для каждого подмассива. Такой массив еще можно представить в виде таблицы:
1 | 2 |
4 | 5 |
7 | 8 |
Возможна также инициализация не всех элементов, а только некоторых:
int numbers[3][2] { {1, 2}, {}, {7} };
В этом случае значения присваиваются первым элементам массивов, а остальные элементы инициализируются нулями.
При рассмотрении одномерных массивов мы видели, что компилятор можем автоматически выводить длину массива на основании количества элементов. При инициализации многомерных массивов тоже тоже можно опустить длину массива, но только первую размерность (первые квадратные скобки):
int numbers[][2] { {1, 2}, {3, 4}, {5, 6} };
Обращение к элементам
И чтобы обратиться к элементам многомерного массива, потребуется индексы для каждой размерности. Так, если речь идет о двухмерном массиве, нам надо указать индексы для обоих его размерностей:
#include <iostream> int main() { int nums[3][2] { {1, 2}, {3, 4}, {5, 6} }; // получаем значение элемента int n = nums[1][0]; // вторая строка, первый столбец std::cout << "n =" << n << std::endl; // n = 3 std::cout << "nums[2][1] = " << nums[2][1] << std::endl; // nums[2][1] = 6 // изменяем значение элемента nums[2][1] = 123; // третья строка, второй столбец std::cout << "nums[2][1] = " << nums[2][1] << std::endl; // nums[2][1] = 123 }
Здесь массив nums можно разобрать по индексам следующим образом:
nums[0][0] | nums[0][1] | |
nums[0] | 1 | 2 |
nums[1][0] | nums[1][1] | |
nums[1] | 3 | 4 |
nums[2][0] | nums[2][1] | |
nums[2] | 5 | 6 |
Соответственно выражение nums[1][0]
представляет обращение к первому элементу второго подмассива (первый столбец второй строки)
Перебор многомерного массива
Переберем двухмерный массив:
#include <iostream> int main() { const int rows = 3, columns = 2; int numbers[rows][columns] { {1, 2}, {3, 4}, {5, 6} }; for(int i=0; i < rows; i++) { for(int j=0; j < columns; j++) { std::cout << numbers[i] [j] << "\t"; } std::cout << std::endl; } }
Также для перебора элементов многомерного массива можно использовать другую форму цикла for, которая специально предназначена для перебора последовательностей:
#include <iostream> int main() { const int rows = 3, columns = 2; int numbers[rows][columns] { {1, 2}, {3, 4}, {5, 6} }; for(auto &subnumbers : numbers) { for(int number : subnumbers) { std::cout << number << "\t"; } std::cout << std::endl; } }
Для перебора массивов, которые входят в массив, применяются ссылки. То есть во внешнем цикле for(auto &subnumbers : numbers)
&subnumbers представляет ссылку на подмассив в массиве. Во внутреннем цикле for(int number : subnumbers)
из каждого
подмассива в subnumbers получаем отдельные его элементы в переменную number и выводим ее значение на консоль.
НазадСодержаниеВперед
10.5 – Многомерные массивы
Добавлено 5 июня 2021 в 17:57
Элементы массива могут быть любого типа данных, включая массивы! Массив массивов называется многомерным массивом.
int array[3][5]; // 3-элементный массив из 5-элементных массивов
Поскольку здесь у нас есть 2 индекса, это двумерный массив.
В двумерном массиве удобно рассматривать первый (левый) индекс как строку, а второй (правый) индекс как столбец. Это называется строковым порядком. Концептуально представленный выше двумерный массив имеет следующую структуру:
[0][0] [0][1] [0][2] [0][3] [0][4] // строка 0 [1][0] [1][1] [1][2] [1][3] [1][4] // строка 1 [2][0] [2][1] [2][2] [2][3] [2][4] // строка 2
Чтобы получить доступ к элементам двумерного массива, просто используйте два индекса:
array[2][3] = 7;
Инициализация двумерных массивов
Для инициализации двумерного массива проще всего использовать вложенные фигурные скобки, где каждый набор чисел представляет собой строку:
int array[3][5] { { 1, 2, 3, 4, 5 }, // строка 0 { 6, 7, 8, 9, 10 }, // строка 1 { 11, 12, 13, 14, 15 } // строка 2 };
Хотя некоторые компиляторы позволяют вам опускать внутренние фигурные скобки, мы настоятельно рекомендуем вам включать их в любом случае, как для удобства чтения, так и из-за того, как C++ заменяет отсутствующие инициализаторы на 0.
int array[3][5] { { 1, 2 }, // строка 0 = 1, 2, 0, 0, 0 { 6, 7, 8 }, // строка 1 = 6, 7, 8, 0, 0 { 11, 12, 13, 14 } // строка 2 = 11, 12, 13, 14, 0 };
Двумерные массивы со списками инициализаторов могут опускать (только) крайнюю левую спецификацию длины:
int array[][5] { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 11, 12, 13, 14, 15 } };
Компилятор может вычислить, чему равна длина массива. Однако следующее не допускается:
int array[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 } };
Как и обычные массивы, многомерные массивы могут быть инициализированы значением 0 следующим образом:
int array[3][5]{};
Доступ к элементам в двумерном массиве
Для доступа ко всем элементам двумерного массива требуются два цикла: один для строки и один для столбца. Поскольку доступ в двумерных массивах обычно осуществляется построчно, индекс строки обычно используется в качестве внешнего цикла.
for (int row{ 0 }; row < numRows; ++row) // пройти по строкам в массиве { for (int col{ 0 }; col < numCols; ++col) // пройти по каждому элементу в строке { std::cout << array[row][col]; } }
В C++11 циклы for-each также могут использоваться с многомерными массивами. Цикл for-each мы подробно рассмотрим позже.
Многомерные массивы больше двух измерений
Многомерные массивы могут быть больше двух измерений. Вот объявление трехмерного массива:
int array[5][4][3];
Трехмерные массивы сложно инициализировать каким-либо интуитивно понятным способом с использованием списков инициализаторов, поэтому обычно лучше инициализировать массив значением 0, а затем явно присвоить значения с помощью вложенных циклов.
Доступ к элементу трехмерного массива аналогичен двумерному случаю:
std::cout << array[3][1][2];
Пример двумерного массива
Давайте посмотрим на практический пример двумерного массива:
#include <iostream> int main() { constexpr int numRows{ 10 }; constexpr int numCols{ 10 }; // Объявление массива 10x10 int product[numRows][numCols]{}; // Рассчитываем таблицу умножения for (int row{ 1 }; row < numRows; ++row) { for (int col{ 1 }; col < numCols; ++col) { product[row][col] = row * col; } } // Распечатываем таблицу for (int row{ 1 }; row < numRows; ++row) { for (int col{ 1 }; col < numCols; ++col) { std::cout << product[row][col] << '\t'; } std::cout << '\n'; } return 0; }
Эта программа вычисляет и распечатывает таблицу умножения для всех значений от 1 до 9 (включительно).
Обратите внимание, что при печати таблицы циклыfor
начинаются с 1 вместо 0. Это позволяет не печатать столбец 0 и строку 0, которые будут просто набором нулей! Вот результат:1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81
Двумерные массивы обычно используются в играх с тайловой (плиточной) графикой, где каждый элемент массива представляет один тайл. Они также используются в трехмерной компьютерной графике (в качестве матриц) для поворота, масштабирования и отражения фигур.
Оригинал статьи:
- 9.5 — Multidimensional Arrays
Теги
C++ / CppLearnCppДля начинающихМассивМногомерный массивОбучениеПрограммированиеНазад
Оглавление
Вперед
многомерных массивов — MATLAB & Simulink
Open Live Script
Многомерный массив в MATLAB® — это массив с более чем двумя измерениями. В матрице два измерения представлены строками и столбцами.
Каждый элемент определяется двумя нижними индексами: индексом строки и индексом столбца. Многомерные массивы являются расширением двумерных матриц и используют дополнительные индексы для индексации. Трехмерный массив, например, использует три нижних индекса. Первые два похожи на матрицу, но третье измерение представляет страниц или листов элементов.
Создание многомерных массивов
Многомерный массив можно создать, сначала создав двумерную матрицу, а затем расширив ее. Например, сначала определите матрицу 3 на 3 как первую страницу в трехмерном массиве.
А = [1 2 3; 4 5 6; 7 8 9]
А = 3×3 1 2 3 4 5 6 7 8 9
Теперь добавьте вторую страницу. Для этого назначьте другую матрицу 3 на 3 значению индекса 2 в третьем измерении. Синтаксис A(:,:,2)
использует двоеточие в первом и втором измерениях, чтобы включить все строки и все столбцы из правой части назначения.
А(:,:,2) = [10 11 12; 13 14 15; 16 17 18]
А = А(:,:,1) = 1 2 3 4 5 6 7 8 9 А(:,:,2) = 10 11 12 13 14 15 16 17 18
Функция cat
может быть полезным инструментом для построения многомерных массивов. Например, создайте новый трехмерный массив B
путем объединения A
с третьей страницей. Первый аргумент указывает, какое измерение следует конкатенировать.
B = кошка(3,A,[3 2 1; 0 9 8; 5 3 7])
B = В(:,:,1) = 1 2 3 4 5 6 7 8 9 В(:,:,2) = 10 11 12 13 14 15 16 17 18 В(:,:,3) = 3 2 1 0 9 8 5 3 7
Еще один способ быстро расширить многомерный массив — назначить один элемент на всю страницу. Например, добавьте четвертую страницу к B
, содержащий все нули.
Б(:,:,4) = 0
Б = В(:,:,1) = 1 2 3 4 5 6 7 8 9 В(:,:,2) = 10 11 12 13 14 15 16 17 18 В(:,:,3) = 3 2 1 0 9 8 5 3 7 В(:,:,4) = 0 0 0 0 0 0 0 0 0
Доступ к элементам
Для доступа к элементам в многомерном массиве используйте целочисленные индексы так же, как для векторов и матриц. Например, найдите элемент 1,2,2 числа 9.0023 A , который находится в первой строке, втором столбце и на второй странице A
.
А = А(:,:,1) = 1 2 3 4 5 6 7 8 9 А(:,:,2) = 10 11 12 13 14 15 16 17 18
элА = А(1,2,2)
элА = 11
Используйте индексный вектор [1 3]
во втором измерении, чтобы получить доступ только к первому и последнему столбцам каждой страницы A
.
С = А(:,[1 3],:)
С = С(:,:,1) = 1 3 4 6 7 9С(:,:,2) = 10 12 13 15 16 18
Чтобы найти вторую и третью строки каждой страницы, используйте оператор двоеточия для создания индексного вектора.
Д = А(2:3,:,:)
Д = Д(:,:,1) = 4 5 6 7 8 9 Д(:,:,2) = 13 14 15 16 17 18
Манипулирование массивами
Элементы многомерных массивов можно перемещать разными способами, подобно векторам и матрицам. изменить форму
, переставить
и сжатия
полезные функции для перестановки элементов. Рассмотрим трехмерный массив с двумя страницами.
Изменение формы многомерного массива может быть полезно для выполнения определенных операций или визуализации данных. Используйте функцию reshape
, чтобы изменить порядок элементов трехмерного массива в матрицу 6 на 5.
А = [1 2 3 4 5; 9 0 6 3 7; 8 1 5 0 2]; A(:,:,2) = [9 7 8 5 2; 3 5 8 5 1; 6 9 4 3 3]; B = изменить форму (A, [6 5])
B = 6×5 1 3 5 7 5 96 7 5 5 8 5 2 9 3 2 4 9 8 2 0 3 3 8 1 1 0 6 4 3
reshape
работает по столбцам, создавая новую матрицу, беря последовательные элементы вниз по каждому столбцу A
, начиная с первой страницы, затем переходя ко второй странице.
Перестановки используются для изменения порядка измерений массива. Рассмотрим трехмерный массив M
.
М(:,:,1) = [1 2 3; 4 5 6; 7 8 9]; М(:,:,2) = [0 5 4; 2 7 6; 9 3 1]
М = М(:,:,1) = 1 2 3 4 5 6 7 8 9 М(:,:,2) = 0 5 4 2 7 6 9 3 1
Используйте функцию permute
, чтобы поменять местами индексы строк и столбцов на каждой странице, указав порядок измерений во втором аргументе. Исходные строки M
теперь являются столбцами, а столбцы теперь строками.
P1 = перестановка (M,[2 1 3])
P1 = Р1(:,:,1) = 1 4 7 2 5 8 3 6 9Р1(:,:,2) = 0 2 9 5 7 3 4 6 1
Аналогичным образом поменяйте местами индексы строк и страниц M
.
P2 = переставить (M, [3 2 1])
P2 = Р2(:,:,1) = 1 2 3 0 5 4 Р2(:,:,2) = 4 5 6 2 7 6 Р2(:,:,3) = 7 8 9 9 3 1
При работе с многомерными массивами вы можете столкнуться с тем, у которого есть ненужная размерность длины 1. сжать
выполняет другой тип манипуляции, которая устраняет измерения длины 1. Например, используйте функцию repmat
для создания массива 2 на 3 на 1 на 4, элементы которого равны 5, а третье измерение имеет длину 1.
A = repmat(5,[2 3 1 4])
A = А(:,:,1,1) = 5 5 5 5 5 5 А(:,:,1,2) = 5 5 5 5 5 5 А(:,:,1,3) = 5 5 5 5 5 5 А(:,:,1,4) = 5 5 5 5 5 5
размер A = размер (A)
размер A = 1×4 2 3 1 4
numdimsA = ndims(A)
numdimsA = 4
Используйте функцию сжатия
, чтобы удалить третье измерение, в результате чего получится трехмерный массив.
B = сжать(A)
B = В(:,:,1) = 5 5 5 5 5 5 В(:,:,2) = 5 5 5 5 5 5 В(:,:,3) = 5 5 5 5 5 5 В(:,:,4) = 5 5 5 5 5 5
szB = размер(B)
szB = 1×3 2 3 4
numdimsB = ndims(B)
numdimsB = 3
- Создание, объединение и расширение матриц
- Индексирование массивов
- Изменение формы и реорганизации массивов
У вас есть модифицированная версия этого примера. Хотите открыть этот пример со своими правками?
Вы щелкнули ссылку, соответствующую этой команде MATLAB:
Запустите команду, введя ее в командном окне MATLAB. Веб-браузеры не поддерживают команды MATLAB.
Выберите веб-сайт
Выберите веб-сайт, чтобы получить переведенный контент, где он доступен, и увидеть местные события и предложения. В зависимости от вашего местоположения мы рекомендуем вам выбрать: .
Вы также можете выбрать веб-сайт из следующего списка:
Европа
Обратитесь в местный офис
c++ — Невозможно использовать find() с двумерным массивом
Задавать вопрос
спросил
Изменено 6 лет, 3 месяца назад
Просмотрено 2к раз
У меня проблема с поиском в двумерных массивах. Каждый раз, когда я пытаюсь выполнить такой поиск, я получаю непонятную ошибку
Мой код:
#include#include #include <алгоритм> использование пространства имен std; интервал ст[200*1000][2]; интервал си[200*1000][2]; интервал основной () { если (найти(si, si+200000, правда) == si+200000){ //сделай что-нибудь } for (int j = 0; j < ileSt; j++){ для (int k = 0; k < 2; k++){ если (найти(st[j], st[j]+2, si[znakSi][k]) != st[j]+2){ // делаем еще что-нибудь } } } вернуть 0; }
Ошибка:
В файле, включенном из /usr/include/c++/5/bits/stl_algobase. h:71:0, из /usr/include/c++/5/bits/char_traits.h:39, из /usr/include/С++/5/ios:40, из /usr/include/С++/5/ostream:38, из /usr/include/С++/5/iostream:39, из прог.cpp:1: /usr/include/c++/5/bits/predefined_ops.h: при создании экземпляра 'bool __gnu_cxx::__ops::_Iter_equals_val<_Value>::operator()(_Iterator) [с _Iterator = int (*)[2]; _Value = константное логическое значение]': /usr/include/c++/5/bits/stl_algo.h:120:14: требуется от '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [с _RandomAccessIterator = int (*)[2] ; _Predicate = __gnu_cxx::__ops::_Iter_equals_val]' /usr/include/c++/5/bits/stl_algo.h:161:23: требуется от '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [с _Iterator = int (*)[2]; _Predicate = __gnu_cxx::__ops::_Iter_equals_val ]' /usr/include/С++/5/бит/stl_algo.h:379
Кроме того, это мой первый вопрос, поэтому, если вы считаете, что его можно было бы написать лучше, не стесняйтесь его редактировать!
- c++
- массивы
- многомерный массив
- find
Вы можете переписать его, используя прямую адресацию к элементам 2d массива. Например:
для (int j = 0; j < ileSt; j++) { для (целое k = 0; k < 2; k++) { если (найти(&st[j][0], &st[j][0] + 2, si[znakSi][k]) != &st[j][0] + 2 ) { // делаем еще что-нибудь } } }
Или с помощью std::begin получить адрес строки для вашего массива
find(std::begin(st[j]), std::begin(st[j]) + 2, si[znakSi][k] ) != std::begin(st[j]) + 2
2
Каждый из si[n]
является int[2]
, а не int
или bool
. Поэтому вы не можете выполнить find
на si
, который представляет собой массив int[2]
, для значения true
, которое равно bool
(или int
с неявным преобразованием). Сообщение об ошибке говорит вам в основном то же самое:
/usr/include/c++/5/bits/predefined_ops.h:194:17: error: ISO C++ запрещает сравнение между указателем и целым числом [-fpermissive]
Вместо этого следующий код должен позволить вам найти любое истинное
(т. е. 1) в двумерном массиве:
int* const si_begin = &si[0][0]; int* const si_end = &si[200*1000][0]; если (найти(si_begin, si_end, true) == si_end){ //сделай что-нибудь }
Если вы намеревались найти true
только в 1-м элементе внутреннего массива, то, как предложил Swift в комментарии, лучше использовать для поиска собственный цикл. std::find()
используется только для поиска соответствующего элемента в одномерном массиве.
2
Вы пытаетесь обратиться к памяти за пределами массива, и вы должны использовать указатель на один элемент массива для обращения к многомерному массиву как к одномерному.
Указатели si
и st
имеют тип int*[2]
не int*
, поэтому (si+1)
точки в 3-м int (второй подмассив int *[2 ]
type), (si+200000)
точки на 400001-м int в этом массиве. Компилятор пытается специализировать шаблон find(), предполагая, что вы дали ему правильный итератор, следует этой семантике и работает неправильно.