Как мне объявить 2d массив, используя новый?
Мол, для «нормального» массива я бы:
int* ary = new int[Size]
но
int** ary = new int[sizeY][sizeX]
а) не работает / не компилируется и б) не выполняет то, что:
int ary[sizeY][sizeX]
делает.
Как мне объявить 2d массив, используя новый?
Мол, для «нормального» массива я бы:
int* ary = new int[Size]
но
int** ary = new int[sizeY][sizeX]
а) не работает / не компилируется и б) не выполняет то, что:
int ary[sizeY][sizeX]
делает.
Ответы:
Динамический двумерный массив - это в основном массив указателей на массивы . Вы можете инициализировать его с помощью цикла, например так:
Выше, для
colCount= 5
иrowCount = 4
, будет производить следующее:источник
new
, создается в куче и должно быть отмененоdelete
, просто имейте это в виду и обязательно удалите эту память из кучи, когда вы закончите с ней, чтобы предотвратить утечки.T (*ptr)[M] = new T[N][M];
правильное решение ... Никакое количество массивов указателей никогда не будет таким же, как массив массивов ...должно быть:
а потом убирать будет:
РЕДАКТИРОВАТЬ: как отметил Дитрих Эпп в комментариях, это не совсем легкое решение. Альтернативный подход заключается в использовании одного большого блока памяти:
источник
i*sizeX+j
? Если я правильно помню, при мажорном порядке строки это должно быть row * numColumns + col.Хотя этот популярный ответ даст вам желаемый синтаксический индекс, он вдвойне неэффективен: большой и медленный как в пространстве, так и во времени. Есть лучший способ.
Почему этот ответ большой и медленный
Предлагаемое решение заключается в создании динамического массива указателей, а затем инициализации каждого указателя своим собственным независимым динамическим массивом. Преимущество этого подхода заключается в том, что она дает вам синтаксис индексации вы привыкли, так что если вы хотите , чтобы найти значение матрицы в позиции х, у, вы говорите:
Это работает, потому что matrix [x] возвращает указатель на массив, который затем индексируется с помощью [y]. Разбивая это:
Удобно, да? Нам нравится наш [x] [y] синтаксис.
Но у решения есть большой недостаток , который заключается в том, что оно и жирное, и медленное.
Почему?
Причина, по которой он толстый и медленный, на самом деле одна и та же. Каждая «строка» в матрице представляет собой отдельно выделенный динамический массив. Распределение кучи требует больших затрат как во времени, так и в пространстве. Распределитель требует времени, чтобы выполнить выделение, иногда запуская O (n) алгоритмы, чтобы сделать это. И распределитель «дополняет» каждый из ваших массивов строк дополнительными байтами для учета и выравнивания. Это дополнительное место стоит ... ну ... дополнительное место. Сделка также будет матрицы потребуется дополнительное время для освобождения матрицы, кропотливого освобождения каждого отдельного выделения строки. Встает в меня, просто думая об этом.
Есть еще одна причина, по которой это медленно. Эти отдельные распределения, как правило, живут в прерывистых частях памяти. Одна строка может быть по адресу 1000, другая по адресу 100 000 - вы поняли. Это означает, что когда вы пересекаете матрицу, вы перепрыгиваете через память, как дикий человек. Это приводит к потере кеша, что значительно замедляет время обработки.
Так что, если у вас есть абсолютный синтаксис индексации [x] [y], используйте это решение. Если вы хотите быстроты и малости (и если вас это не волнует, почему вы работаете в C ++?), Вам нужно другое решение.
Другое решение
Лучшее решение - выделить всю матрицу в виде единого динамического массива, а затем использовать (слегка) умную собственную индексную математику для доступа к ячейкам. Индексная математика очень умна; нет, это совсем не умно: это очевидно.
Учитывая, что эта
index()
функция (которую я представляю, является членом класса, потому что она должна знатьm_width
вашу матрицу), вы можете получить доступ к ячейкам внутри вашего матричного массива. Матричный массив выделяется так:Итак, эквивалент этого в медленном, жирном растворе:
... это быстрое, маленькое решение:
Грустно, я знаю. Но вы привыкнете к этому. И ваш процессор поблагодарит вас.
источник
class Matrix { int* array; int m_width; public: Matrix( int w, int h ) : m_width( w ), array( new int[ w * h ] ) {} ~Matrix() { delete[] array; } int at( int x, int y ) const { return array[ index( x, y ) ]; } protected: int index( int x, int y ) const { return x + m_width * y; } };
если вы исправите этот код, он может иметь смысл и пролить свет на ответ выше.#define ROW_COL_TO_INDEX(row, col, num_cols) (row*num_cols + col)
тогда вы можете использовать его, так какint COLS = 4; A[ ROW_COL_TO_INDEX(r, c, COLS) ] = 75;
издержки действительно влияют, когда мы выполняем умножения матриц, имеющие сложность O (n ^ 3) или O (n ^ 2.81) для алгоритма Штрассена .a[x][y]
, что вы на самом деле делаете*(*(a + x) + y)
: два дополнения и два извлечения памяти. С темa[index(x, y)]
, что вы на самом деле делаете*(a + x + w*y)
: два сложения, одно умножение и одно извлечение памяти. Последнее часто предпочтительнее по причинам, указанным в этом ответе (т. Е. Обмен дополнительной выборки памяти с умножением того стоит, особенно потому, что данные не фрагментированы и, следовательно, вы не пропустите кэш-память).В C ++ 11 это возможно:
Таким образом, память не инициализируется. Для инициализации сделайте это вместо:
Пример программы (скомпилируйте с помощью «g ++ -std = c ++ 11»):
Вывод:
источник
using arr2d = double(*)[2]; arr2d array = new double[M][N];
double (*)[M][N]
илиdouble(*)[][N]
с М, N быть постоянные выражения.Из вашего примера статического массива я предполагаю, что вам нужен прямоугольный массив, а не зубчатый. Вы можете использовать следующее:
Тогда вы можете получить доступ к элементам как:
Не забудьте использовать delete [] on
ary
.источник
Существует два основных метода, которые я бы порекомендовал для этого в C ++ 11 и выше, один для измерений времени компиляции и один для времени выполнения. Оба ответа предполагают, что вам нужны единообразные двумерные массивы (не зубчатые).
Размеры времени компиляции
Используйте
std::array
из ,std::array
а затем использовать ,new
чтобы поместить его в кучу:Опять же, это работает, только если размеры размеров известны во время компиляции.
Измерения времени выполнения
Лучший способ создания двумерного массива с размерами, известными только во время выполнения, - заключить его в класс. Класс выделит массив 1d, а затем перегружается,
operator []
чтобы обеспечить индексацию для первого измерения. Это работает, потому что в C ++ двумерный массив имеет мажорную строку:(Взято с http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/ )
Непрерывная последовательность памяти хороша из соображений производительности, а также легко очищается. Вот пример класса, который пропускает много полезных методов, но показывает основную идею:
Итак, мы создаем массив с
std::make_unique<int[]>(rows * columns)
записями. Мы перегружаем,operator []
что будет индексировать строку для нас. Он возвращаетint *
указатель на начало строки, который затем может быть разыменован как обычно для столбца. Обратите внимание, чтоmake_unique
сначала поставляется в C ++ 14, но вы можете при необходимости заполнить его в C ++ 11.Для этих типов структур также характерно перегрузка
operator()
:Технически я не использовал
new
здесь, но это тривиально , чтобы перейти отstd::unique_ptr<int[]>
кint *
и использованиеnew
/delete
.источник
std::array
изstd::array
с:std::array<std::array<int, columns> rows>
.asserts
отладочные сборки для проверки доступа к памяти и т. Д. Эти дополнения, как правило, облегчают и делают работу удобнее.make_unique
вместоnew/delete
.Этот вопрос меня беспокоил - это достаточно распространенная проблема, что хорошее решение уже должно существовать, что-то лучше, чем вектор векторов или циклическая индексация массива.
Когда что-то должно существовать в C ++, но его нет, первое, на что нужно обратить внимание, это boost.org . Там я обнаружил библиотеку многомерных массивов Boost
multi_array
. Он даже включает в себяmulti_array_ref
класс, который можно использовать для переноса собственного буфера одномерного массива.источник
auto
ключевое слово. Я удивлен, что они не пытались взяться за 2D-массивы, тем более что Boost уже показал путь.Почему бы не использовать STL: вектор? Так просто, и вам не нужно удалять вектор.
Вы также можете инициализировать «массивы», просто установите для него значение по умолчанию
Источник: Как создать 2, 3 (или мульти) размерные массивы в C / C ++?
источник
2D-массив - это, в основном, одномерный массив указателей, где каждый указатель указывает на одномерный массив, который будет содержать фактические данные.
Здесь N - строка, а M - столбец.
динамическое распределение
заливка
Распечатать
бесплатно
источник
Как выделить непрерывный многомерный массив в GNU C ++? Существует расширение GNU, позволяющее работать «стандартному» синтаксису.
Кажется, проблема исходит от оператора new []. Убедитесь, что вы используете оператор new вместо:
И это все: вы получаете C-совместимый многомерный массив ...
источник
double (*in)[m][n] = (double (*)[m][n])new double[k*m*n];
тоже не работает. Я получаю ошибки C2057, C2540,n
потому что это не известно во время компиляции. Я не понимаю, почему я не могу этого сделать, потому что память выделена правильно, и это всего лишь указатели, чтобы удобно обрабатывать эту память. (VS 2010)gcc
обманул меня, когда я написал это: поставки-std=c++11
не достаточно для включения строгого соответствия стандартам, также-pedantic-errors
требуется. Без более позднего флага,gcc
счастливо принимает приведение, даже если оно действительно не соответствует стандарту C ++. С тем, что я знаю сейчас, я могу только посоветовать обращаться к C, когда делаю вещи, которые сильно зависят от многомерных массивов. С99 в этом отношении гораздо мощнее, чем даже С ++ 17.typedef твой друг
Обратившись назад и посмотрев на многие другие ответы, я обнаружил, что необходимо дать более глубокое объяснение, поскольку многие другие ответы либо страдают от проблем с производительностью, либо вынуждают вас использовать необычный или обременительный синтаксис для объявления массива, либо обращаются к массиву. элементы (или все вышеперечисленное).
Во-первых, этот ответ предполагает, что вы знаете размеры массива во время компиляции. Если вы это сделаете, то это лучшее решение, так как оно даст лучшую производительность и позволит вам использовать стандартный синтаксис массива для доступа к элементам массива .
Причина, по которой это дает лучшую производительность, заключается в том, что он выделяет все массивы как непрерывный блок памяти, а это означает, что вы, скорее всего, будете иметь меньше пропусков страниц и лучшую пространственную локализацию. Выделение в цикле может привести к тому, что отдельные массивы будут разбросаны по нескольким несмежным страницам в пространстве виртуальной памяти, поскольку цикл выделения может быть прерван (возможно, несколько раз) другими потоками или процессами, или просто по усмотрению распределитель заполняет небольшие пустые блоки памяти, которые у него есть.
Другими преимуществами являются простой синтаксис объявления и стандартный синтаксис доступа к массиву.
В C ++ используется новое:
Или стиль C с использованием calloc:
источник
Эта проблема беспокоила меня в течение 15 лет, и все поставленные решения не были удовлетворительными для меня. Как создать динамический многомерный массив непрерывно в памяти? Сегодня я наконец нашел ответ. Используя следующий код, вы можете сделать это:
Когда вы вызываете программу со значениями sizeX = 20 и sizeY = 15, вывод будет следующим:
Как вы можете видеть, многомерный массив непрерывно находится в памяти, и никакие два адреса памяти не перекрываются. Даже процедура освобождения массива проще, чем стандартный способ динамического выделения памяти для каждого отдельного столбца (или строки, в зависимости от того, как вы просматриваете массив). Поскольку массив в основном состоит из двух линейных массивов, только эти два должны быть (и могут быть) освобождены.
Этот метод может быть расширен для более чем двух измерений с одной и той же концепцией. Я не буду делать это здесь, но когда у вас есть идея, это простая задача.
Я надеюсь, что этот код поможет вам так же, как и мне.
источник
array2d[i] = buffer + i * sizeX
. Так что это помогает в небольшой степени, но в коде, использующем массив, компилятор не может просто увеличивать указатели для сканирования массива.make_unique<int[]>(sizeX*sizeY)
для установки непрерывного хранилища иmake_unique<int*[]>(sizeX)
для хранения указателей (которые должны быть назначены так, как вы показываете). Это освобождает вас от необходимостиdelete[]
дважды звонить в конце.temp
? Учитывая преимущества (непрерывный 2d массив с неизвестными измерениями во время компиляции), я не уверен, что меня волнует, что он болтается. Я не понимал, что означает @PeterCordesextra layer of indirection
, что это? Почему в скобкахarray2d[i] = (temp + i * sizeX)
;Цель этого ответа не состоит в том, чтобы добавить что-то новое, что другие еще не покрывают, а в том, чтобы расширить ответ @Kevin Loney.
Вы можете использовать легкую декларацию:
и синтаксис доступа будет:
но это громоздко для большинства и может привести к путанице. Итак, вы можете определить макрос следующим образом:
Теперь вы можете получить доступ к массиву, используя очень похожий синтаксис
ary(i, j) // means ary[i][j]
. Это имеет то преимущество, что оно простое и красивое, и в то же время использование выражений вместо индексов также проще и менее запутанно.Например, чтобы получить доступ к ary [2 + 5] [3 + 8], вы можете писать
ary(2+5, 3+8)
вместо сложного вида,ary[(2+5)*SizeY + (3+8)]
то есть он сохраняет скобки и помогает удобочитаемости.Предостережения:
SizeY
он должен быть передан с тем же именем (или вместо этого объявлен как глобальная переменная).Или, если вам нужно использовать массив в нескольких функциях, вы можете добавить SizeY также в качестве другого параметра в определении макроса, например так:
Вы поняли идею. Конечно, это становится слишком длинным, чтобы быть полезным, но все же может предотвратить путаницу + и *.
Это определенно не рекомендуется, и большинство опытных пользователей сочтут это плохой практикой, но я не удержался от того, чтобы делиться этим из-за его элегантности.
Изменить:
Если вы хотите портативное решение, которое работает для любого числа массивов, вы можете использовать этот синтаксис:
и затем вы можете передать на вызов любой массив любого размера, используя синтаксис доступа:
PS: я проверял их, и тот же синтаксис работает (как lvalue и rvalue) на компиляторах g ++ 14 и g ++ 11.
источник
Попробуйте сделать это:
источник
Здесь у меня есть два варианта. Первый показывает концепцию массива массивов или указателей указателей. Я предпочитаю второй, потому что адреса являются смежными, как вы можете видеть на картинке.
источник
Если ваш проект CLI (Common Language Runtime Support) , то:
Вы можете использовать класс массива, а не тот, который вы получаете, когда пишете:
Другими словами, не класс неуправляемого массива, который вы получаете при использовании пространства имен std и при включении заголовка массива, не класс неуправляемого массива, определенный в пространстве имен std и в заголовке массива, но массив управляемых классов CLI.
с помощью этого класса вы можете создать массив любого ранга, который вы хотите.
Следующий код ниже создает новый двумерный массив из 2 строк и 3 столбцов типа int, и я называю его «arr»:
Теперь вы можете получить доступ к элементам в массиве, назвав его и записав только одну квадратную скобку
[]
, а внутри них добавьте строку и столбец и разделите их запятой,
.Следующий код ниже обращается к элементу во 2-й строке и 1-м столбце массива, который я уже создал в предыдущем коде выше:
запись только этой строки означает чтение значения в этой ячейке, т.е. получение значения в этой ячейке, но если вы добавите равное
=
знак , вы собираетесь записать значение в этой ячейке, т.е. установить значение в этой ячейке. Вы также можете использовать операторы + =, - =, * = и / =, конечно, только для чисел (int, float, double, __int16, __int32, __int64 и т. Д.), Но вы уже знаете это.Если ваш проект не CLI, то вы можете использовать класс неуправляемого массива пространства имен std, если вы
#include <array>
, конечно, но проблема в том, что этот класс массива отличается от массива CLI. Создать массив этого типа так же, как CLI, за исключением того, что вам придется удалить^
знак иgcnew
ключевое слово. Но, к сожалению, второй параметр int в<>
скобках указывает длину (т.е. размер) массива, а не его ранг!В этом массиве нет возможности указать ранг, а ранг - это только функция массива CLI . ,
Массив std ведет себя как обычный массив в c ++, который вы определяете с помощью указателя, например,
int*
а затем:new int[size]
или без указателя:,int arr[size]
но в отличие от обычного массива c ++, массив std предоставляет функции, которые вы можете использовать с элементами массива, как заполнение, начало, конец, размер и т. д., но обычный массив ничего не дает .Но все же массив std - это одномерный массив, как и обычные массивы c ++. Но благодаря решениям, которые предлагают другие ребята, о том, как сделать обычный одномерный массив c ++ для двумерного массива, мы можем адаптировать те же идеи к массиву std, например, согласно идее Мехрада Афшари, мы можем написать следующий код:
Эта строка кода создает «совмещенный массив» , который является одномерным массивом, которым каждая из его ячеек является или указывает на другой одномерный массив.
Если все одномерные массивы в одномерном массиве равны по длине / размеру, то вы можете рассматривать переменную array2d как реальный двумерный массив, плюс вы можете использовать специальные методы для обработки строк или столбцов, в зависимости от того, как вы их просматриваете в 2D-массиве этот массив std поддерживает.
Вы также можете использовать решение Кевина Лони:
но если вы используете массив std, код должен выглядеть иначе:
И все же есть уникальные функции массива std.
Обратите внимание, что вы по-прежнему можете обращаться к элементам массива std, используя
[]
скобки, и вам не нужно вызыватьat
функцию. Вы также можете определить и назначить новую переменную int, которая будет вычислять и хранить общее количество элементов в массиве std и использовать его значение вместо повторения.sizeX*sizeY
Вы можете определить свой собственный универсальный класс двумерного массива и определить конструктор класса двумерного массива для получения двух целых чисел, чтобы указать количество строк и столбцов в новом двумерном массиве, и определить функцию get, которая получает два параметра целого числа которые обращаются к элементу в двумерном массиве и возвращают его значение, и устанавливают функцию, которая получает три параметра, что первые два являются целыми числами, которые определяют строку и столбец в двумерном массиве, а третий параметр является новым значением элемент. Его тип зависит от типа, который вы выбрали в обобщенном классе.
Вы сможете реализовать все это, используя либо нормальный C ++ массив (указатели или без него ) или в станд массив и использовать одну из идей , что другие люди предложили, и сделать его простым в использовании , как Cli массив, или как два размерный массив, который вы можете определить, назначить и использовать в C #.
источник
Начнем с определения массива с помощью указателей (строка 1):
источник
Приведенный ниже пример может помочь,
источник
Если вам нужен 2d массив целых чисел, элементы которого расположены последовательно в памяти, вы должны объявить его следующим образом:
где вместо x вы можете написать любое измерение, но n должно быть одинаковым в двух местах. пример
должен напечатать 6.
источник
Я оставил вам решение, которое в некоторых случаях работает лучше для меня. Особенно, если известно [размер?] Одного измерения массива. Очень полезно для массива символов, например, если нам нужен массив с переменным размером массивов char [20].
Ключ - это круглые скобки в объявлении массива.
источник
Я использовал эту не элегантную, но БЫСТРО, ЛЕГКО и РАБОЧУЮ систему. Я не понимаю, почему не может работать, потому что единственный способ для системы разрешить создание массива большого размера и доступ к частям, не разрезая его на части:
источник
Я не знаю наверняка, не был ли дан следующий ответ, но я решил добавить некоторые локальные оптимизации к распределению 2d-массива (например, квадратная матрица выполняется только через одно выделение):
int** mat = new int*[n]; mat[0] = new int [n * n];
Однако удаление происходит следующим образом из-за линейности распределения выше:
delete [] mat[0]; delete [] mat;
источник
динамическое объявление 2D-массива:
Теперь в приведенном выше коде мы взяли двойной указатель, присвоили ему динамическую память и дали значение столбцов. Здесь память выделяется только для столбцов, теперь для строк нам просто необходим цикл for и присваиваем значение для каждой строки динамической памяти. Теперь мы можем использовать указатель так же, как мы используем 2D-массив. В вышеприведенном примере мы затем присвоили случайные числа нашему двумерному массиву (указателю). Это все о DMA двумерного массива.
источник
Я использую это при создании динамического массива. Если у вас есть класс или структура. И это работает. Пример:
источник